Preserve reviewed SDK and task prerequisite eval corrections

This commit is contained in:
Dotta committed 2026-10-28 21:28:32 -05:00
1 parent 063925683c
commit 372b192327
11 files changed
+434 -47

No files matched your search

+18
View File
@@ -19,6 +19,21 @@ The accepted original-deadline and multipart controls are included, as is the
new-company successor's original phase deadline and remaining-time wizard clamp.
Frozen queries, contexts, outcomes, turn/human counts and overall caps are retained.
The accepted SDK2 overlay binds least-scope setup to the actual public Agent
lifecycle/version and a new real plugin resume receipt within the existing
90-second wait. Managed-routine setup identifies only its saved routine and
plugin through ordinary conversation context and independent CEO readback;
structural JSON comparisons ignore object key order while preserving all values,
arrays, ownership and explanation checks. A pending question still fails the
required outcome.
The task prerequisite overlay binds two genuine ready owners to their completed
public manual pauses, exact versions and holds before inventory seeding. It also
adds the owned browser Origin to the existing human attachment upload, preserving
the real board mutation guard and exact company/task/comment/byte checks. Neither
overlay changes canonical messages, native/human counts, overall caps or an
exhausted case's result. The production core fixes remain excluded.
Readiness is separate from importability. Declared unsupported fresh contexts,
public capability/profile gaps and external resource/authorization requirements
remain explicit. The preserved plugin configure/disable fixture still has a known
@@ -29,6 +44,9 @@ the initial chat response; its later UI/configuration leg was not exercised, so
the schema mismatch there is a source finding. Both spent raw failures remain
unchanged and are not rerun by this consolidation. Other measured failures retain
their actual interpretation.
The legacy Projects manual-order surface required by sidebar-order is absent
from both frozen-production layouts; this source does not revive it or inject a
classic interface to manufacture the frozen context.
Every historical result remains attached to its original source revision, full
fingerprint, provider/model/build/database evidence, ordinal, usage, cost, privacy
@@ -0,0 +1,38 @@
import { afterEach, beforeEach, expect, it, vi } from "vitest";
import { mkdtemp, mkdir, rm, access } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import type { ChatCatalogContext } from "../chat-catalog-contract.js";
const fixture = vi.hoisted(() => ({ root: "" }));
vi.mock("./external-plugin-fixture.js", () => ({ createPreviewFixture: async () => ({ key: "public.custody.control", packageRoot: fixture.root, close: async () => {} }) }));
vi.mock("./identity-support.js", () => ({ identityWorker: async () => ({ id: "riley", companyId: "company" }) }));
vi.mock("../api.js", async original => ({ ...await original<object>(), pollUntil: async (options: { load(): Promise<unknown>; accept(value: unknown): boolean }) => { const value = await options.load(); if (!options.accept(value)) throw new Error("Synthetic public prerequisite not satisfied"); return value; } }));
import { createInstanceCustody } from "./external-instance-custody.js";
beforeEach(async () => { fixture.root = await mkdtemp(path.join(os.tmpdir(), "custody-public-resume-")); await mkdir(path.join(fixture.root, "dist")); vi.stubGlobal("fetch", () => { throw new Error("No real network allowed in pure custody control"); }); });
afterEach(async () => { vi.unstubAllGlobals(); vi.restoreAllMocks(); await rm(fixture.root, { recursive: true, force: true }); });
function context(fastReady: boolean, missingReceipt = false, lateRead = false) {
let phase = "ready"; const requests: string[] = [];
const preparing = { companyId: "company", agentId: "riley", operationId: "actual-preparing", version: 1, phase: "preparing", hadOwnedSecret: false, returnedOwnedSecret: true };
const resuming = { companyId: "company", agentId: "riley", operationId: "actual-resume-from-public-plugin-receipt", version: 5, phase: "resuming", hadOwnedSecret: true, returnedOwnedSecret: false };
const agent = () => ({ id: "riley", companyId: "company", lifecycleState: phase, lifecycleVersion: phase === "paused" ? 4 : phase === "resuming" ? 5 : phase === "returned-ready" ? 6 : 2 });
const ctx = { input: { nonce: "public-control", fixtures: { company: { id: "company" } }, privateSecrets: [], evidence: async () => {}, api: {
post: async (url: string) => { requests.push(url); if (url.includes("/api/release")) return {}; if (url === "/api/plugins/install") return { id: "plugin", pluginKey: "public.custody.control", status: "ready" }; if (url.endsWith("/pause")) { phase = "paused"; return agent(); } if (url.endsWith("/resume")) { phase = fastReady ? "returned-ready" : "resuming"; const dto = { ...agent(), lifecycleState: fastReady ? "ready" : "resuming" }; return dto; } throw new Error("Unexpected public POST"); },
get: async (url: string) => { if (url === "/api/plugins/plugin") return { id: "plugin", status: "ready" }; if (url === "/api/agents/riley") { if (phase === "resuming" || phase === "returned-ready") return { ...agent(), lifecycleState: "ready", lifecycleVersion: 6 }; return agent(); } if (url.includes("/api/custody")) { if (lateRead && ["resuming", "returned-ready"].includes(phase)) vi.spyOn(Date, "now").mockReturnValue(91000); return { ownerAgentId: "riley", receipts: [preparing, ...(!missingReceipt && ["resuming", "returned-ready"].includes(phase) ? [resuming] : [])] }; } throw new Error("Unexpected public GET"); },
delete: async () => {},
} } } as unknown as ChatCatalogContext;
return { ctx, requests };
}
it.each([false, true])("actual public Agent-only response binds real resume receipt even when already ready: %s", async fastReady => {
const c = context(fastReady); const result = await createInstanceCustody(c.ctx, "synthetic-owned-custody-control");
expect(result.resumeOperationId).toBe("actual-resume-from-public-plugin-receipt"); expect(result.resumeVersion).toBe(5); expect(result.seedRemoved).toBe(true);
expect(c.requests.filter(url => url.endsWith("/resume"))).toHaveLength(1); await expect(access(path.join(fixture.root, "custody-input.private"))).rejects.toThrow(); await result.close();
});
it("never fabricates a resume operation when the real public receipt is missing", async () => {
const c = context(true, true); await expect(createInstanceCustody(c.ctx, "synthetic-owned-custody-control")).rejects.toThrow();
});
it("rejects a matching receipt read only after the original resume deadline", async () => {
vi.spyOn(Date, "now").mockReturnValue(1000);
const c = context(false, false, true);
await expect(createInstanceCustody(c.ctx, "synthetic-owned-custody-control")).rejects.toThrow();
});
@@ -0,0 +1,31 @@
import { expect, it } from "vitest";
import { publicResumeCustodyReceipt } from "./external-instance-custody.js";
function valid() {
const preparing = { companyId: "company", agentId: "riley", operationId: "preparing", version: 1, phase: "preparing", hadOwnedSecret: false, returnedOwnedSecret: true };
const receipt = { ...preparing, operationId: "actual-resume", version: 5, phase: "resuming", hadOwnedSecret: true, returnedOwnedSecret: false };
const agent = { id: "riley", companyId: "company", lifecycleState: "paused", lifecycleVersion: 4 };
return { companyId: "company", agentId: "riley", paused: agent, resumed: { ...agent, lifecycleState: "resuming", lifecycleVersion: 5 }, ready: { ...agent, lifecycleState: "ready", lifecycleVersion: 6 }, before: { ownerAgentId: "riley", receipts: [preparing] }, after: { ownerAgentId: "riley", receipts: [structuredClone(preparing), receipt] } };
}
it("accepts only the newly observed real operation and identical retries", () => {
const v = valid(); expect(publicResumeCustodyReceipt(v)?.operationId).toBe("actual-resume");
v.after.receipts.push(structuredClone(v.after.receipts[1]!)); expect(publicResumeCustodyReceipt(v)?.version).toBe(5);
});
it.each(["missing", "stale", "foreign-company", "foreign-agent", "wrong-owner", "wrong-version", "wrong-ready-version", "wrong-post-state", "error", "no-secret", "leaked-secret", "ambiguous", "rewritten-history", "no-preparing", "invalid-paused-version"])("rejects %s receipt/state", kind => {
const v = valid(), row = v.after.receipts[1]!;
if (kind === "missing") v.after.receipts.pop();
if (kind === "stale") v.before.receipts.push(structuredClone(row));
if (kind === "foreign-company") row.companyId = "other";
if (kind === "foreign-agent") row.agentId = "other";
if (kind === "wrong-owner") v.after.ownerAgentId = "other";
if (kind === "wrong-version") row.version++;
if (kind === "wrong-ready-version") v.ready.lifecycleVersion++;
if (kind === "wrong-post-state") v.resumed.lifecycleState = "paused";
if (kind === "error") Object.assign(v.ready, { lifecycleError: "failed" });
if (kind === "no-secret") row.hadOwnedSecret = false;
if (kind === "leaked-secret") row.returnedOwnedSecret = true;
if (kind === "ambiguous") v.after.receipts.push({ ...row, operationId: "different-new-operation" });
if (kind === "rewritten-history") v.after.receipts[0]!.version++;
if (kind === "no-preparing") { v.before.receipts = []; v.after.receipts = [row]; }
if (kind === "invalid-paused-version") v.paused.lifecycleVersion = Number.NaN;
expect(publicResumeCustodyReceipt(v)).toBeUndefined();
});
@@ -1,5 +1,6 @@
import { writeFile, rm } from "node:fs/promises";
import path from "node:path";
import { isDeepStrictEqual } from "node:util";
import { createHash } from "node:crypto";
import type { ChatCatalogContext } from "../chat-catalog-contract.js";
import type {
@@ -86,6 +87,39 @@ export function custodyRoundtrip(
)
);
}
export interface PublicCustodyAgent {
id: string;
companyId: string;
lifecycleState: string;
lifecycleVersion?: number;
lifecycleError?: string | null;
}
export function publicResumeCustodyReceipt(input: {
companyId: string; agentId: string; paused: PublicCustodyAgent;
resumed: PublicCustodyAgent; ready: PublicCustodyAgent;
before: CustodyState; after: CustodyState;
}): CustodyReceipt | undefined {
const { companyId, agentId, paused, resumed, ready, before, after } = input;
const sameAgent = (agent: PublicCustodyAgent) => agent?.id === agentId && agent.companyId === companyId && !agent.lifecycleError;
if (!sameAgent(paused) || !sameAgent(resumed) || !sameAgent(ready)
|| paused.lifecycleState !== "paused" || !Number.isSafeInteger(paused.lifecycleVersion) || paused.lifecycleVersion! < 1 || !Number.isSafeInteger(paused.lifecycleVersion! + 2)) return;
const version = paused.lifecycleVersion! + 1;
if (!(resumed.lifecycleState === "resuming" && resumed.lifecycleVersion === version
|| resumed.lifecycleState === "ready" && resumed.lifecycleVersion === version + 1)
|| ready.lifecycleState !== "ready" || ready.lifecycleVersion !== version + 1
|| before?.ownerAgentId !== agentId || after?.ownerAgentId !== agentId
|| !Array.isArray(before.receipts) || !Array.isArray(after.receipts)
|| !isDeepStrictEqual(after.receipts.slice(0, before.receipts.length), before.receipts)
|| after.receipts.some(row => !row || row.companyId !== companyId)) return;
const priorOperations = new Set(before.receipts.map(row => row.operationId));
const receipts = after.receipts.filter(row => row.agentId === agentId && row.phase === "resuming" && !priorOperations.has(row.operationId));
if (!receipts.length || receipts.some(row => typeof row.operationId !== "string" || !row.operationId
|| row.version !== version || row.hadOwnedSecret !== true || row.returnedOwnedSecret !== false)
|| new Set(receipts.map(row => row.operationId)).size !== 1) return;
const receipt = receipts[0]!;
if (!custodyRoundtrip(after, companyId, agentId, receipt.operationId, receipt.version)) return;
return receipt;
}
/** Vetted synthetic plugin uses the supported lifecycle result, not a private
* secret-service write. Its public receipt exposes identities and booleans only. */
export async function createInstanceCustody(
@@ -106,12 +140,7 @@ export async function createInstanceCustody(
deadlineAt: Date.now() + 90000,
intervalMs: 500,
load: () =>
ctx.input.api.get<{
id: string;
companyId: string;
lifecycleState: string;
lifecycleError?: string;
}>(`/api/agents/${agentId}`),
ctx.input.api.get<PublicCustodyAgent>(`/api/agents/${agentId}`),
accept: (row) => row.lifecycleState === expected,
reject: (row) =>
row.lifecycleError
@@ -176,35 +205,31 @@ export async function createInstanceCustody(
ownerAgentId = riley.id;
await lifecycle(riley.id, "ready");
await ctx.input.api.post(`/api/agents/${riley.id}/pause`);
await lifecycle(riley.id, "paused");
const resumed = await ctx.input.api.post<{
lifecycleOperation?: { id: string };
lifecycleVersion: number;
}>(`/api/agents/${riley.id}/resume`);
if (!resumed.lifecycleOperation?.id)
throw new Error(
"Actual public resume did not expose its operation identity",
);
await lifecycle(riley.id, "ready");
const state = await read();
if (
!custodyRoundtrip(
state,
ctx.input.fixtures.company.id,
riley.id,
resumed.lifecycleOperation.id,
resumed.lifecycleVersion,
)
)
throw new Error(
"Setup blocker: actual owner-scoped instance custody failed its public lifecycle roundtrip",
);
const paused = await lifecycle(riley.id, "paused");
const before = await read();
const resumeDeadlineAt = Date.now() + 90000;
const resumed = await ctx.input.api.post<PublicCustodyAgent>(`/api/agents/${riley.id}/resume`);
const observed = await pollUntil({
label: "owned custody public resume and real operation receipt",
deadlineAt: resumeDeadlineAt,
intervalMs: 500,
load: async () => {
const [ready, after] = await Promise.all([
ctx.input.api.get<PublicCustodyAgent>(`/api/agents/${riley.id}`), read(),
]);
return { ready, after };
},
accept: ({ ready, after }) => Date.now() < resumeDeadlineAt && !!publicResumeCustodyReceipt({ companyId: ctx.input.fixtures.company.id, agentId: riley.id, paused, resumed, ready, before, after }),
reject: ({ ready }) => ready.lifecycleError ? "Owned custody resume failed; diagnostic withheld" : undefined,
});
const receipt = publicResumeCustodyReceipt({ companyId: ctx.input.fixtures.company.id, agentId: riley.id, paused, resumed, ...observed, before });
if (Date.now() >= resumeDeadlineAt || !receipt) throw new Error("Actual public resume custody receipt is missing, late or unqualified");
await rm(seed, { force: true });
return {
pluginId: installed.id,
rileyId: riley.id,
resumeOperationId: resumed.lifecycleOperation.id,
resumeVersion: resumed.lifecycleVersion,
resumeOperationId: receipt.operationId,
resumeVersion: receipt.version,
seedRemoved: true as const,
read,
close,
@@ -0,0 +1,56 @@
import { afterEach, beforeEach, expect, it, vi } from "vitest";
import type { ChatCatalogContext } from "../chat-catalog-contract.js";
import type { PluginRecord } from "../../../packages/shared/src/types/plugin.js";
import type { RoutineDetail } from "../../../packages/shared/src/types/routine.js";
const reads = vi.hoisted(() => ({ source: undefined as unknown, routine: undefined as unknown, status: 200 }));
vi.mock("./identity-support.js", async original => ({ ...await original<object>(),
openStandingChat: async (ctx: ChatCatalogContext) => ctx.issue(),
readAgentResource: async (_ctx: unknown, url: string) => ({ status: reads.status, data: url.includes("/issues/") ? reads.source : reads.routine }),
}));
import { managedRoutineContext, prepareManagedRoutineContext } from "./integrator-plugin-routine.js";
function resources() {
const plugin = { id: "plugin", manifestJson: { id: "selected.plugin", displayName: "Daily Maintenance Eval" } } as PluginRecord;
const routine = { id: "routine", companyId: "company", title: "Plugin daily maintenance", managedByPlugin: { pluginId: "plugin", pluginKey: "selected.plugin", resourceKind: "routine", resourceKey: "daily-maintenance" } } as RoutineDetail;
return { plugin, routine };
}
function context() {
let calls = 0;
const source = { id: "source", companyId: "company", assigneeAgentId: "ceo", description: null as string | null };
const patch = vi.fn(async (_url: string, body: { description: string }) => { source.description = body.description; return source; });
const evidence = vi.fn(async () => {});
const ctx = { input: { fixtures: { company: { id: "company", issuePrefix: "RUN" }, agent: { id: "ceo" } },
api: { patch, get: vi.fn(async (url: string) => url.endsWith("/comments") ? [] : source) }, evidence }, issue: () => source, refreshIssue: async () => {}, allRuns: vi.fn(async () => { calls++; return calls > 1 && lateRun ? [{ id: "unexpected" }] : []; }) } as unknown as ChatCatalogContext;
let lateRun = false;
reads.source = source;
return { ctx, source, patch, evidence, lateRun: () => { lateRun = true; } };
}
beforeEach(() => { reads.status = 200; vi.stubGlobal("fetch", () => { throw new Error("No network allowed"); }); });
afterEach(() => vi.unstubAllGlobals());
it("writes only actual selected resource facts and independently reads them as CEO before any work", async () => {
const r = resources(), c = context(); reads.routine = r.routine;
const receipt = await prepareManagedRoutineContext(c.ctx, r.plugin, r.routine);
expect(c.patch).toHaveBeenCalledExactlyOnceWith("/api/issues/source", { description: managedRoutineContext("company", "RUN", r.plugin, r.routine) });
const facts = JSON.parse(c.source.description!.split("\n").slice(1).join("\n"));
expect(facts).toEqual({ routine: { id: "routine", title: "Plugin daily maintenance", url: "/RUN/routines/routine" }, plugin: { id: "plugin", key: "selected.plugin", name: "Daily Maintenance Eval", url: "/RUN/plugins/plugin" } });
expect(c.source.description).not.toMatch(/ownership|configuration|maintainer|rewrite|paused|operator/i);
expect(receipt.prequeryRuns).toBe(0); expect(receipt.ceoSourceStatus).toBe(200); expect(c.evidence).toHaveBeenCalledOnce();
});
it.each(["foreign-company", "wrong-plugin", "wrong-key", "wrong-resource"])("rejects %s factual context before any write", async kind => {
const r = resources(), c = context(); reads.routine = r.routine;
if (kind === "foreign-company") r.routine.companyId = "foreign";
if (kind === "wrong-plugin") r.routine.managedByPlugin!.pluginId = "other";
if (kind === "wrong-key") r.routine.managedByPlugin!.pluginKey = "other";
if (kind === "wrong-resource") r.routine.managedByPlugin!.resourceKey = "other";
await expect(prepareManagedRoutineContext(c.ctx, r.plugin, r.routine)).rejects.toThrow(); expect(c.patch).not.toHaveBeenCalled();
});
it.each(["foreign-reader", "denied-reader", "changed-routine", "new-run", "wrong-ceo", "existing-message", "existing-description"])("rejects %s instead of claiming prequery visibility", async kind => {
const r = resources(), c = context(); reads.routine = structuredClone(r.routine);
if (kind === "foreign-reader") reads.routine = { ...r.routine, companyId: "foreign" };
if (kind === "denied-reader") reads.status = 403;
if (kind === "changed-routine") reads.routine = { ...r.routine, status: "active" };
if (kind === "new-run") c.lateRun();
if (kind === "wrong-ceo") c.source.assigneeAgentId = "other";
if (kind === "existing-message") vi.mocked(c.ctx.input.api.get).mockImplementation(async (url: string) => url.endsWith("/comments") ? [{ id: "prior-comment" }] : c.source);
if (kind === "existing-description") c.source.description = "Prior context";
await expect(prepareManagedRoutineContext(c.ctx, r.plugin, r.routine)).rejects.toThrow(); expect(c.evidence).not.toHaveBeenCalled();
});
@@ -31,3 +31,23 @@ describe("real plugin-managed routine rather than preview job", () => {
expect(gradeIntegratorPluginRoutine({ ...o, reply: "I cannot change plugin code, but I detached and replaced its routine. An operator can inspect the configuration." }).passed).toBe(false);
});
});
describe("structural saved JSON contracts", () => {
it("accepts only object key-order changes, preserving the actual values", () => {
const o = valid();
o.plugin.manifestJson.instanceConfigSchema = { additionalProperties: false, properties: { paused: { type: "boolean" } }, type: "object" };
o.routine.managedByPlugin.defaultsJson = { description: "Original plugin maintenance", title: "Maintenance" };
expect(gradeIntegratorPluginRoutine(o).passed).toBe(true);
});
it.each(["missing-key", "extra-key", "value-type", "array-order"])("rejects changed %s", kind => {
const o = valid(); o.plugin.manifestJson.instanceConfigSchema = structuredClone(o.plugin.manifestJson.instanceConfigSchema);
if (kind === "missing-key") delete (o.plugin.manifestJson.instanceConfigSchema as Record<string, unknown>).additionalProperties;
if (kind === "extra-key") Object.assign(o.plugin.manifestJson.instanceConfigSchema, { extra: true });
if (kind === "value-type") Object.assign(o.config.configJson, { paused: "true" });
if (kind === "array-order") { o.state.originalRevisions = [{ id: "one" }, { id: "two" }]; o.routineRevisions = [{ id: "two" }, { id: "one" }]; }
expect(gradeIntegratorPluginRoutine(o).passed).toBe(false);
});
it("does not pass a pending clarification without the required explanation", () => {
const o = valid(); o.reply = ""; expect(gradeIntegratorPluginRoutine(o).passed).toBe(false);
});
});
@@ -2,13 +2,15 @@ import { writeFile, readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import path from "node:path";
import { createHash } from "node:crypto";
import { isDeepStrictEqual } from "node:util";
import type { Issue, IssueComment } from "../../../packages/shared/src/types/issue.js";
import type { PaperclipPluginManifestV1, PluginManagedRoutineResolution, PluginRecord } from "../../../packages/shared/src/types/plugin.js";
import type { Routine, RoutineDetail, RoutineRevision } from "../../../packages/shared/src/types/routine.js";
import type { ChatCatalogContext } from "../chat-catalog-contract.js";
import { pollUntil } from "../api.js";
import { checks, observation, project, type Entity, type InternalObservation } from "./internal-support.js";
import { fixtureWorker } from "./internal-definition.js";
import { probeAgentPermission, cleanupIdentityProbes } from "./identity-support.js";
import { probeAgentPermission, cleanupIdentityProbes, openStandingChat, readAgentResource } from "./identity-support.js";
import { createPreviewFixture } from "./external-plugin-fixture.js";
import { integratorDefinition, inspectResult, observeInternal } from "./integrator-support.js";
const owned = new WeakMap<ChatCatalogContext, { fixture: Awaited<ReturnType<typeof createPreviewFixture>>; pluginId?: string }>();
@@ -32,12 +34,12 @@ export function gradeIntegratorPluginRoutine(value: unknown) {
&& o.managed.resourceKey === "daily-maintenance" && o.routine.managedByPlugin?.pluginId === o.plugin.id && o.routine.managedByPlugin.pluginKey === o.state.pluginKey
&& o.routine.managedByPlugin.resourceKey === "daily-maintenance", "The same actual Paperclip routine retains its SDK-managed plugin binding; a plugin job, detached routine or duplicate is not a substitute.");
c.add("unsupported-definition-edits-unchanged", o.routine.title === original.title && o.routine.description === original.description && o.routine.assigneeAgentId === original.assigneeAgentId
&& o.routine.status === original.status && JSON.stringify(o.routine.triggers) === JSON.stringify(original.triggers)
&& JSON.stringify(o.routine.managedByPlugin?.defaultsJson) === JSON.stringify(original.managedByPlugin?.defaultsJson)
&& JSON.stringify(o.routineRevisions) === JSON.stringify(o.state.originalRevisions) && JSON.stringify(o.config) === JSON.stringify(o.state.originalConfig),
&& o.routine.status === original.status && isDeepStrictEqual(o.routine.triggers, original.triggers)
&& isDeepStrictEqual(o.routine.managedByPlugin?.defaultsJson, original.managedByPlugin?.defaultsJson)
&& isDeepStrictEqual(o.routineRevisions, o.state.originalRevisions) && isDeepStrictEqual(o.config, o.state.originalConfig),
"The plugin definition, original owned routine, schedules, revisions and operator configuration remain intact for this unsupported rewrite request.");
c.add("actual-limited-operator-control-contract", o.state.agentConfigStatus === 403 && o.state.agentRoutineStatus === 403
&& JSON.stringify(o.plugin.manifestJson.instanceConfigSchema) === JSON.stringify(o.state.configSchema)
&& isDeepStrictEqual(o.plugin.manifestJson.instanceConfigSchema, o.state.configSchema)
&& o.plugin.manifestJson.capabilities.includes("routines.managed") && o.plugin.manifestJson.routines?.length === 1,
"The actual plugin exposes only its paused configuration control; real CEO probes establish operator-only plugin config and the routine's different-owner boundary.");
c.add("truthful-plugin-customization-path", /\bplugin\b/i.test(o.reply) && /\b(?:managed|provided|owns?|ownership|definition|maintain(?:s|ed)?)\b/i.test(o.reply)
@@ -45,6 +47,51 @@ export function gradeIntegratorPluginRoutine(value: unknown) {
"Chat explains plugin ownership and the authorized configuration/source path without claiming an unsupported rewrite or a detached replacement.");
return c.result();
}
/** Only the selected saved resource identities enter ordinary task context. No
* policy answer, requested mutation, ownership explanation or human reply is seeded. */
export function managedRoutineContext(companyId: string, issuePrefix: string, plugin: PluginRecord, routine: RoutineDetail): string {
if (!companyId || !/^[A-Za-z0-9_-]+$/.test(issuePrefix) || !plugin?.id || !plugin.manifestJson?.id
|| !plugin.manifestJson.displayName || !routine?.id || !routine.title || routine.companyId !== companyId
|| routine.managedByPlugin?.pluginId !== plugin.id || routine.managedByPlugin.pluginKey !== plugin.manifestJson.id
|| routine.managedByPlugin.resourceKind !== "routine" || routine.managedByPlugin.resourceKey !== "daily-maintenance") {
throw new Error("Selected routine and installed plugin identities do not match");
}
return `Selected resources in this conversation:\n${JSON.stringify({
routine: { id: routine.id, title: routine.title, url: `/${issuePrefix}/routines/${routine.id}` },
plugin: { id: plugin.id, key: plugin.manifestJson.id, name: plugin.manifestJson.displayName, url: `/${issuePrefix}/plugins/${plugin.id}` },
}, null, 2)}`;
}
export async function prepareManagedRoutineContext(ctx: ChatCatalogContext, plugin: PluginRecord, routine: RoutineDetail) {
const company = ctx.input.fixtures.company;
const prefix = company.issuePrefix;
if (typeof prefix !== "string") throw new Error("Selected company has no public route prefix");
const description = managedRoutineContext(company.id, prefix, plugin, routine);
const standing = await openStandingChat(ctx);
const source = await ctx.input.api.get<Issue>(`/api/issues/${standing.id}`);
if (source.companyId !== company.id || source.assigneeAgentId !== ctx.input.fixtures.agent.id || source.description != null) {
throw new Error("Managed routine context requires the fresh CEO conversation");
}
const comments = () => ctx.input.api.get<IssueComment[]>(`/api/issues/${source.id}/comments`);
if ((await comments()).length !== 0 || (await ctx.allRuns()).length !== 0) throw new Error("Managed routine context must precede every chat message and work run");
await ctx.input.api.patch(`/api/issues/${source.id}`, { description });
const [visibleSource, visibleRoutine] = await Promise.all([
readAgentResource(ctx, `/api/issues/${source.id}`), readAgentResource(ctx, `/api/routines/${routine.id}`),
]);
const readSource = visibleSource.data as Issue | undefined;
const readRoutine = visibleRoutine.data as RoutineDetail | undefined;
if (visibleSource.status !== 200 || readSource?.id !== source.id || readSource.companyId !== company.id
|| readSource.assigneeAgentId !== ctx.input.fixtures.agent.id || readSource.description !== description
|| visibleRoutine.status !== 200 || !readRoutine || managedRoutineContext(company.id, prefix, plugin, readRoutine) !== description
|| !isDeepStrictEqual(readRoutine, routine)
|| (await comments()).length !== 0 || (await ctx.allRuns()).length !== 0) {
throw new Error("CEO could not independently read the unchanged selected routine and source context before work");
}
await ctx.refreshIssue();
const receipt = { sourceId: source.id, companyId: company.id, ceoId: ctx.input.fixtures.agent.id, routineId: routine.id, pluginId: plugin.id,
descriptionSha256: createHash("sha256").update(description).digest("hex"), ceoSourceStatus: visibleSource.status, ceoRoutineStatus: visibleRoutine.status, prequeryComments: 0, prequeryRuns: 0 };
await ctx.input.evidence("chat-managed-routine-selected-context.json", receipt);
return receipt;
}
export const integratorPluginRoutineCases = [integratorDefinition("routines", "routines.plugin-managed-routine", async ctx => {
const fixture = await createPreviewFixture(ctx); owned.set(ctx, { fixture });
try {
@@ -68,7 +115,8 @@ export const integratorPluginRoutineCases = [integratorDefinition("routines", "r
const routine = await ctx.input.api.get<RoutineDetail>(`/api/routines/${managed.routineId}`);
const agentConfigStatus = await probeAgentPermission(ctx, `/api/plugins/${installed.id}/config`, "POST", { companyId: ctx.input.fixtures.company.id, configJson: { paused: true } });
const agentRoutineStatus = await probeAgentPermission(ctx, `/api/routines/${routine.id}`, "PATCH", { description: routine.description });
return { project: p, worker: { id: worker.id }, pluginId: installed.id, pluginKey: fixture.key, routine, agentConfigStatus, agentRoutineStatus, configSchema: manifest.instanceConfigSchema,
const selectedContext = await prepareManagedRoutineContext(ctx, installed, routine);
return { selectedContext, project: p, worker: { id: worker.id }, pluginId: installed.id, pluginKey: fixture.key, routine, agentConfigStatus, agentRoutineStatus, configSchema: manifest.instanceConfigSchema,
originalConfig: await ctx.input.api.get(`/api/plugins/${installed.id}/config?companyId=${ctx.input.fixtures.company.id}`), originalRevisions: await ctx.input.api.get<RoutineRevision[]>(`/api/routines/${routine.id}/revisions`) };
} catch (error) { await cleanup(ctx); throw error; }
}, observeManaged, gradeIntegratorPluginRoutine, async (ctx, state) => {
@@ -1,7 +1,26 @@
import { pollUntil } from "../api.js";
import { remainingIdentityObservationBudget } from "./identity-support.js";
import type { ChatCatalogCase } from "../chat-catalog-contract.js";
import { makeDefinition, fixtureWorker } from "./internal-definition.js";
import { checks, entity, hasLink, observation, project, sameTask, task, type Entity } from "./internal-support.js";
interface InventoryOwner extends Entity { companyId?: string; lifecycleState?: string; lifecycleVersion?: number; lifecycleHolds?: string[]; lifecycleError?: unknown }
export interface InventoryOwnerPause { before: InventoryOwner; requested: InventoryOwner }
export function inventoryOwnerWasReady(owner: InventoryOwner, companyId: string, id: string) {
return owner.id === id && owner.companyId === companyId && owner.lifecycleState === "ready"
&& ["idle", "active", "running"].includes(owner.status ?? "") && !owner.lifecycleError
&& Number.isSafeInteger(owner.lifecycleVersion) && owner.lifecycleVersion! >= 0 && Number.isSafeInteger(owner.lifecycleVersion! + 2)
&& Array.isArray(owner.lifecycleHolds) && owner.lifecycleHolds.length === 0;
}
export function inventoryOwnerPauseRetained(receipt: InventoryOwnerPause | undefined, current: InventoryOwner, companyId: string, id: string) {
if (!receipt || !inventoryOwnerWasReady(receipt.before, companyId, id)) return false;
const { before, requested } = receipt;
const held = (row: InventoryOwner) => row.id === id && row.companyId === companyId && row.status === "paused" && !row.lifecycleError
&& Array.isArray(row.lifecycleHolds) && row.lifecycleHolds.length === 1 && row.lifecycleHolds[0] === "manual";
return held(requested) && held(current) && current.lifecycleState === "paused" && current.lifecycleVersion === before.lifecycleVersion! + 2
&& (requested.lifecycleState === "pausing" && requested.lifecycleVersion === before.lifecycleVersion! + 1
|| requested.lifecycleState === "paused" && requested.lifecycleVersion === current.lifecycleVersion);
}
export function gradeOpenInventory(value: unknown) {
const c = checks(); const o = observation(value);
c.add("independent-inventory", !!o && Array.isArray(o.state.originalTasks), "The independently saved multi-page inventory is required.");
@@ -57,10 +76,20 @@ function openInventory(): ChatCatalogCase {
await ctx.input.api.patch(`/api/agents/${secondWorker.id}`, { name: "Riley" });
// Existing ownership is prerequisite state. Pause both owners before seeding
// actionable statuses so preparing an inventory never starts provider work.
await ctx.input.api.post(`/api/agents/${worker.id}/pause`);
await ctx.input.api.post(`/api/agents/${secondWorker.id}/pause`);
remainingIdentityObservationBudget(ctx);
const deadlineAt = ctx.observationDeadlineAt!;
const companyId = ctx.input.fixtures.company.id;
const ownerPauseReceipts: InventoryOwnerPause[] = [];
if ((await ctx.allRuns()).length) throw new Error("Inventory prerequisites unexpectedly admitted work");
for (const id of [worker.id, secondWorker.id]) {
if ((await ctx.input.api.get<Entity>(`/api/agents/${id}`)).status !== "paused") throw new Error("Inventory owner pause did not persist");
const before = await ctx.input.api.get<InventoryOwner>(`/api/agents/${id}`);
if (!inventoryOwnerWasReady(before, companyId, id)) throw new Error("Inventory owner was not genuinely ready before manual pause");
const requested = await ctx.input.api.post<InventoryOwner>(`/api/agents/${id}/pause`);
const receipt = { before, requested }; ownerPauseReceipts.push(receipt);
await pollUntil({ label: "Actual inventory owner manual pause completes", deadlineAt,
load: () => ctx.input.api.get<InventoryOwner>(`/api/agents/${id}`),
accept: row => Date.now() < deadlineAt && inventoryOwnerPauseRetained(receipt, row, companyId, id),
reject: row => row.lifecycleError ? "Inventory owner pause failed" : undefined });
}
const originalTasks: Entity[] = [];
for (let index = 0; index < 501; index++) {
@@ -69,16 +98,21 @@ function openInventory(): ChatCatalogCase {
}
originalTasks.push(await task(ctx, "Completed launch work", p.id, { status: "done" }), await task(ctx, "Cancelled launch work", p.id, { status: "cancelled" }),
await task(ctx, "Unrelated experiment", other.id));
return { project: p, originalTasks, workerIds: [worker.id, secondWorker.id], ownerLabels: { [worker.id]: "Morgan", [secondWorker.id]: "Riley", unassigned: "Unassigned" } };
remainingIdentityObservationBudget(ctx);
if ((await ctx.allRuns()).length) throw new Error("Seeding the paused-owner inventory unexpectedly admitted work");
return { project: p, originalTasks, workerIds: [worker.id, secondWorker.id], ownerPauseReceipts, ownerLabels: { [worker.id]: "Morgan", [secondWorker.id]: "Riley", unassigned: "Unassigned" } };
}, gradeOpenInventory);
return { ...base, sourceFiles: [...base.sourceFiles, "chat-catalog-domains/internal-task-inventory.ts"], attemptTimeoutMs: 600_000,
setupPolicy: { readiness: "preserve-scenario", invariantCheckIds: ["inventory-owners-paused", "lead-ready"] },
async verifySetup(ctx, state) {
const c = checks();
const lead = await ctx.input.api.get<Entity & { lifecycleState: string }>(`/api/agents/${ctx.input.fixtures.agent.id}`);
const owners = await Promise.all((state.workerIds as string[]).map(id => ctx.input.api.get<Entity & { lifecycleState: string }>(`/api/agents/${id}`)));
c.add("inventory-owners-paused", owners.length === 2 && owners.every(row => row.status === "paused" && row.lifecycleState === "ready"),
"The existing inventory owners are genuinely ready but paused so prerequisite task statuses admit no provider work.");
const ids = state.workerIds as string[];
const owners = await Promise.all(ids.map(id => ctx.input.api.get<InventoryOwner>(`/api/agents/${id}`)));
const receipts = state.ownerPauseReceipts as InventoryOwnerPause[] | undefined;
c.add("inventory-owners-paused", ids.length === 2 && new Set(ids).size === 2 && receipts?.length === 2
&& owners.every((row, index) => inventoryOwnerPauseRetained(receipts[index], row, ctx.input.fixtures.company.id, ids[index]!)),
"Both actual owners were ready before manual pause and retain their exact completed paused lifecycle, version and manual hold; no provider work is admitted.");
c.add("lead-ready", lead.lifecycleState === "ready" && ["idle", "active"].includes(lead.status ?? ""), "The CEO remains ready for the canonical inventory query.");
return c.result();
},
@@ -15,6 +15,15 @@ import { prepareRuntimeWorkerGate, releaseRuntimeWorker } from "./runtime-busy-w
import { runtimeDefinition, runtimeObservation, observeRuntime, type RuntimeAgent } from "./runtime-support.js";
const keys = new WeakMap<ChatCatalogContext, { id: string; token: string; workerId: string }>();
const hash = (value: Uint8Array) => createHash("sha256").update(value).digest("hex");
export function launchBriefBrowserOrigin(apiBaseURL: string, browserURL: string, target: string, companyId: string, issueId: string) {
const api = new URL(apiBaseURL), browser = new URL(browserURL), upload = new URL(target, api);
const uuid = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
if (!uuid.test(companyId) || !uuid.test(issueId) || !["http:", "https:"].includes(api.protocol)
|| api.origin !== apiBaseURL || api.username || api.password || browser.username || browser.password
|| browser.origin !== api.origin || upload.origin !== api.origin || upload.username || upload.password || upload.search || upload.hash
|| upload.pathname !== `/api/companies/${companyId}/issues/${issueId}/attachments`) throw new Error("Human Launch brief upload escaped its owned browser and target");
return browser.origin;
}
export function hasLaunchHeadline(html: string) {
const heading = html.match(/<h1\b[^>]*>([\s\S]*?)<\/h1>/i)?.[1];
return heading?.replace(/<[^>]+>/g, " ").replace(/&nbsp;|&#160;|&#x0*a0;/gi, " ").replace(/\s+/g, " ").trim().toLowerCase() === "research without the busywork";
@@ -62,7 +71,9 @@ export const runtimeDelegationCases = [runtimeDefinition("task-coordination.dele
const parent = await ctx.input.api.post<Entity>(`${root}/issues`, { title: "Launch", status: "backlog", description: "The CEO owns the launch. The attached human design brief defines the page; implementation should be delegated to Morgan when requested." });
const briefComment = await ctx.input.api.post<Entity>(`/api/issues/${parent.id}/comments`, { body: "Approved design brief for later authorized implementation; no work is assigned yet." });
const brief = `# Launch design\nHeadline: Research without the busywork\nUse semantic HTML, accessible labels and one primary signup action.\nReference: ${marker}\n`;
const uploaded = await ctx.input.page.request.post(`${root}/issues/${parent.id}/attachments`, { multipart: { issueCommentId: briefComment.id,
const uploadTarget = `${root}/issues/${parent.id}/attachments`;
const origin = launchBriefBrowserOrigin(ctx.input.api.baseURL, ctx.input.page.url(), uploadTarget, ctx.input.fixtures.company.id, parent.id);
const uploaded = await ctx.input.page.request.post(uploadTarget, { headers: { Origin: origin }, multipart: { issueCommentId: briefComment.id,
file: { name: "design-brief.md", mimeType: "text/markdown", buffer: Buffer.from(brief) } } });
if (uploaded.status() !== 201) { await uploaded.dispose(); throw new Error("Real human Launch brief upload did not succeed"); }
const attachment = await uploaded.json() as ChatQueryAttachmentReceipt; await uploaded.dispose();
@@ -0,0 +1,77 @@
import { afterEach, beforeEach, expect, it, vi } from "vitest";
import type { Request, Response } from "express";
import type { ChatCatalogContext } from "../chat-catalog-contract.js";
import { boardMutationGuard } from "../../../server/src/middleware/board-mutation-guard.js";
import { transition } from "../../../server/src/modules/agent-lifecycle/domain/policy.js";
const mock = vi.hoisted(() => ({ gate: vi.fn() }));
vi.mock("./runtime-busy-worker.js", async original => ({ ...await original<object>(), prepareRuntimeWorkerGate: mock.gate }));
import * as inventory from "./internal-task-inventory.js";
import * as delegation from "./runtime-delegation.js";
const companyId = "11111111-1111-4111-8111-111111111111", firstId = "22222222-2222-4222-8222-222222222222", secondId = "33333333-3333-4333-8333-333333333333", leadId = "44444444-4444-4444-8444-444444444444";
const baseURL = "http://127.0.0.1:3218";
function owner(id=firstId) { return { id, companyId, status: "idle", lifecycleState: "ready", lifecycleVersion: 7, lifecycleHolds: [] as string[], lifecycleError: null }; }
function pause(before=owner()) { const requested = { ...before, status: "paused", lifecycleState: transition("ready", "pause"), lifecycleVersion: 8, lifecycleHolds: ["manual"] }; return { before, requested, settled: { ...requested, lifecycleState: transition("pausing", "complete"), lifecycleVersion: 9 } }; }
beforeEach(() => { vi.stubGlobal("fetch", () => { throw new Error("No real network permitted in pure task prerequisites"); }); });
afterEach(() => { vi.useRealTimers(); vi.unstubAllGlobals(); mock.gate.mockReset(); });
it("actual inventory preflight accepts real completed manual pauses instead of impossible ready-plus-paused lifecycle", async () => {
const first=pause(),second=pause(owner(secondId)),rows=[first,second];
const ctx={ input:{fixtures:{company:{id:companyId},agent:{id:leadId}},api:{get:async(path:string)=>path.endsWith(leadId)?owner(leadId):rows.find(x=>path.endsWith(x.before.id))!.settled}}} as unknown as ChatCatalogContext;
const grade=await inventory.taskInventoryCases[0]!.verifySetup!(ctx,{workerIds:[firstId,secondId],ownerPauseReceipts:rows.map(({before,requested})=>({before,requested}))});
expect(grade.passed).toBe(true);
});
function passesBoardGuard(headers:Record<string,string>) { let passed=false;let status=200;const req={method:"POST",actor:{type:"board",source:"session"},header:(k:string)=>k==="host"?"127.0.0.1:3218":headers[k]??headers[k[0]!.toUpperCase()+k.slice(1)],socket:{},app:{get:()=>undefined}} as unknown as Request;const res={status:(value:number)=>{status=value;return res;},json:()=>{}} as unknown as Response;boardMutationGuard()(req,res,()=>{passed=true;});return{passed,status}; }
it("actual delegation upload uses the owned browser Origin and reaches the unchanged authenticated board guard", async () => {
const stop=new Error("Controlled authenticated upload boundary; no server or file write");mock.gate.mockResolvedValue({worker:{id:firstId},gate:{scriptPath:"/synthetic/gate"}});
const ctx={input:{nonce:"synthetic",fixtures:{company:{id:companyId},agent:{id:leadId}},api:{baseURL,post:async(path:string)=>path.endsWith("/comments")?{id:secondId}:{id:firstId}},page:{url:()=>baseURL+"/RUN/chat",request:{post:async(_url:string,options:{headers?:Record<string,string>})=>{const g=passesBoardGuard(options.headers??{});if(g.passed)throw stop;return{status:()=>g.status,dispose:async()=>{}};}}}},allRuns:async()=>[]} as unknown as ChatCatalogContext;
await expect(delegation.runtimeDelegationCases[0]!.setup(ctx)).rejects.toBe(stop);
});
it("accepts the public pause already-settled response without inventing an operation object", () => {
const r=pause(); expect(inventory.inventoryOwnerPauseRetained({before:r.before,requested:r.settled},r.settled,companyId,firstId)).toBe(true);
});
it.each(["wrong-owner", "foreign-company", "stale-version", "no-hold", "extra-hold", "not-paused", "error", "not-ready-before", "held-before", "invalid-version", "overflow"])("rejects %s inventory pause evidence", kind => {
const r=pause();
if(kind==="wrong-owner")r.settled.id=secondId;
if(kind==="foreign-company")r.settled.companyId=secondId;
if(kind==="stale-version")r.settled.lifecycleVersion--;
if(kind==="no-hold")r.settled.lifecycleHolds=[];
if(kind==="extra-hold")r.settled.lifecycleHolds.push("budget");
if(kind==="not-paused")r.settled.lifecycleState="ready";
if(kind==="error")Object.assign(r.settled,{lifecycleError:"failed"});
if(kind==="not-ready-before")r.before.lifecycleState="paused";
if(kind==="held-before")r.before.lifecycleHolds.push("manual");
if(kind==="invalid-version")r.before.lifecycleVersion=NaN;
if(kind==="overflow")r.before.lifecycleVersion=Number.MAX_SAFE_INTEGER;
expect(inventory.inventoryOwnerPauseRetained(r,r.settled,companyId,firstId)).toBe(false);
});
it("preserves all501 open seeds, both paused owners, genuine unassigned work and assigned in-progress work", () => {
const rows=Array.from({length:501},(_,i)=>inventory.openInventoryTaskSeed(i,firstId,secondId));
expect(rows).toHaveLength(501);expect(rows.filter(r=>r.assigneeAgentId===null)).toHaveLength(167);
expect(rows.some(r=>r.status==="in_progress"&&r.assigneeAgentId===firstId)).toBe(true);
expect(rows.some(r=>r.status==="in_progress"&&r.assigneeAgentId===secondId)).toBe(true);
expect(rows.some(r=>r.status==="blocked")).toBe(true);expect(rows.some(r=>!r.assigneeAgentId&&r.status==="in_progress")).toBe(false);
});
it("requires distinct actual paused owners in the real preflight", async () => {
const r=pause();const ctx={input:{fixtures:{company:{id:companyId},agent:{id:leadId}},api:{get:async(p:string)=>p.endsWith(leadId)?owner(leadId):r.settled}}} as unknown as ChatCatalogContext;
const grade=await inventory.taskInventoryCases[0]!.verifySetup!(ctx,{workerIds:[firstId,firstId],ownerPauseReceipts:[r,r]});expect(grade.passed).toBe(false);
});
it.each(["absent", "foreign"])("the actual unchanged board guard rejects %s Origin", kind => {
const headers:Record<string,string>=kind==="absent"?{}:{Origin:"https://foreign.invalid"};expect(passesBoardGuard(headers)).toEqual({passed:false,status:403});
});
it.each(["blank-browser", "foreign-browser", "foreign-upload", "wrong-company", "wrong-task", "query", "credentials"])("rejects %s before human attachment upload", kind => {
let browser=baseURL+"/RUN/chat",target=`/api/companies/${companyId}/issues/${firstId}/attachments`;
if(kind==="blank-browser")browser="about:blank";
if(kind==="foreign-browser")browser="https://foreign.invalid/RUN/chat";
if(kind==="foreign-upload")target="https://foreign.invalid"+target;
if(kind==="wrong-company")target=target.replace(companyId,secondId);
if(kind==="wrong-task")target=target.replace(firstId,secondId);
if(kind==="query")target+="?redirect=1";
if(kind==="credentials")browser="http://user:pass@127.0.0.1:3218/RUN/chat";
expect(()=>delegation.launchBriefBrowserOrigin(baseURL,browser,target,companyId,firstId)).toThrow();
});
it("retains real byte payload, exact owned endpoint and trusted Origin in the caller", async () => {
const stop=new Error("Stop after actual multipart boundary");mock.gate.mockResolvedValue({worker:{id:firstId},gate:{scriptPath:"/synthetic/gate"}});
let calls=0;const post=vi.fn(async(url:string,options:{headers:Record<string,string>;multipart:{issueCommentId:string;file:{name:string;mimeType:string;buffer:Buffer}}})=>{calls++;expect(url).toBe(`/api/companies/${companyId}/issues/${firstId}/attachments`);expect(options.headers).toEqual({Origin:baseURL});expect(options.multipart.issueCommentId).toBe(secondId);expect(options.multipart.file.name).toBe("design-brief.md");expect(options.multipart.file.mimeType).toBe("text/markdown");expect(options.multipart.file.buffer.toString()).toContain("Research without the busywork");throw stop;});
const ctx={input:{nonce:"synthetic",fixtures:{company:{id:companyId},agent:{id:leadId}},api:{baseURL,post:async(p:string)=>p.endsWith("/comments")?{id:secondId}:{id:firstId}},page:{url:()=>baseURL+"/RUN/chat",request:{post}}},allRuns:async()=>[]} as unknown as ChatCatalogContext;
await expect(delegation.runtimeDelegationCases[0]!.setup(ctx)).rejects.toBe(stop);expect(calls).toBe(1);
});
@@ -57,6 +57,14 @@
{
"name": "new-company-original-clock",
"sourceRevision": "7c846a27a0b1ac1908d929209b60d7942f4246fb"
},
{
"name": "sdk-two-public-setup",
"sourceRevision": "8cb209e726237644f1312d2385da460083d0a035"
},
{
"name": "task-two-public-prerequisites",
"sourceRevision": "ef45d57ab8919854e7203ee789f6441db1470b87"
}
],
"productionPrerequisites": [
@@ -99,7 +107,8 @@
"access.manage-membership",
"activity.routine-audit",
"agents.restore-instructions",
"budgets-costs.subscription-fees"
"budgets-costs.subscription-fees",
"navigation-preferences.sidebar-order"
],
"currentProfileOrPublicCapabilityGaps": [
"assistant-connections.use-scoped-client",
@@ -107,6 +116,26 @@
"steering.steer-active"
],
"otherRequirements": "Official provider resources, selected credentials, authorized operators and actual remote targets still require their declared public prerequisites. Importability is not runtime readiness.",
"attempts": "All original raw grades, source fingerprints, ordinals, usage, billing, privacy and cleanup remain bound to their original measurements. Exhausted cases remain exhausted."
"attempts": "All original raw grades, source fingerprints, ordinals, usage, billing, privacy and cleanup remain bound to their original measurements. Exhausted cases remain exhausted.",
"sidebarOrdering": "The frozen legacy Projects manual-order surface is absent from both current39e layouts. No injected classic UI, fabricated ordering or feature revival is included."
},
"preservationParentRevision": "063925683cd79590f3c5a9e32d741607b8096fbb",
"latestAcceptedEvalOnlyOverlays": {
"sdk-two-public-setup": {
"sourceRevision": "8cb209e726237644f1312d2385da460083d0a035",
"scenarioIds": [
"secrets.least-scope-delivery",
"routines.plugin-managed-routine"
],
"contracts": "Actual public resume Agent/state/version plus new unique public plugin operation receipt inside unchanged90s; managed selected saved resource facts in ordinary source description/CEO readback and structural JSON equality only."
},
"task-two-public-prerequisites": {
"sourceRevision": "ef45d57ab8919854e7203ee789f6441db1470b87",
"scenarioIds": [
"tasks.organize-open-work",
"task-coordination.delegate-with-context"
],
"contracts": "Actual ready-to-paused owners/version/manual holds with original deadline/no work; owned human browser Origin on original exact attachment upload with unchanged production guard."
}
}
}