mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 20:21:50 +01:00
fix(runner): preserve closed native startup diagnostics
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
8406047b4e
commit
0c904a7e42
18 files changed
+330
-29
No files matched your search
@@ -26,6 +26,11 @@ acknowledgement and the effective model before a prompt. A lazy restored handle
|
||||
must connect through read-only native session inspection first. Reapplying the
|
||||
bound metadata on restore prevents Grok from resetting effort to its default.
|
||||
Missing configuration, a rejected value, or effort drift stops admission.
|
||||
Admission failures keep a closed Grok reason code through the sidecar boundary.
|
||||
Other startup failures retain their closed admission stage when no more specific
|
||||
known error code is available. These diagnostics contain no native payload,
|
||||
credential, arbitrary provider message, or workspace path. They do not change
|
||||
admission or retry policy.
|
||||
Omitting effort retains Grok's provider default. This setting remains outside
|
||||
the model-visible task prompt. Historical execution inputs retain their schemas.
|
||||
|
||||
|
||||
@@ -32,12 +32,12 @@
|
||||
"requiresProviderPolicy": true
|
||||
},
|
||||
"copilot": {
|
||||
"agentProfileVersion": 69,
|
||||
"agentProfileVersion": 70,
|
||||
"agentServerPackage": "@github/copilot",
|
||||
"agentServerVersion": "1.0.88",
|
||||
"agentRuntimePackage": null,
|
||||
"agentRuntimeVersion": null,
|
||||
"commandDigest": "sha256:5444547ca83543bc899ae5a8a2e895c19a86559339e60a1970786ce900742719",
|
||||
"commandDigest": "sha256:6326444af8fd447032ca8ad10ce3a1280af9aeeddacd563cf48b430202dbbefd",
|
||||
"requiresProviderPolicy": true
|
||||
},
|
||||
"claude": {
|
||||
|
||||
@@ -893,6 +893,23 @@ fn stderr_diagnostic_categories(value: &str) -> BTreeSet<&'static str> {
|
||||
|
||||
fn response_error_classification(error: &ResponseError) -> &'static str {
|
||||
match error.code.as_str() {
|
||||
"GROK_EFFORT_ACKNOWLEDGEMENT_MISSING" => return "grok_effort_acknowledgement_missing",
|
||||
"GROK_EFFORT_MISMATCH" => return "grok_effort_mismatch",
|
||||
"GROK_MODEL_MISMATCH" => return "grok_model_mismatch",
|
||||
"GROK_SESSION_MISMATCH" => return "grok_session_mismatch",
|
||||
"GROK_CONFIGURATION_CONFLICT" => return "grok_configuration_conflict",
|
||||
"GROK_CONFIGURATION_DRIFT" => return "grok_configuration_drift",
|
||||
"GROK_ADMISSION_PROTOCOL_VIOLATION" => return "grok_admission_protocol_violation",
|
||||
"ACPX_ADMISSION_BINDING" => return "admission_binding",
|
||||
"ACPX_ADMISSION_INSTALLATION" => return "admission_installation",
|
||||
"ACPX_ADMISSION_SANDBOX" => return "admission_sandbox",
|
||||
"ACPX_ADMISSION_CREDENTIAL" => return "admission_credential",
|
||||
"ACPX_ADMISSION_CONFIGURATION" => return "admission_configuration",
|
||||
"ACPX_ADMISSION_SKILLS" => return "admission_skills",
|
||||
"ACPX_ADMISSION_COMMAND" => return "admission_command",
|
||||
"ACPX_ADMISSION_TOOL_BRIDGE" => return "admission_tool_bridge",
|
||||
"ACPX_ADMISSION_RUNTIME" => return "admission_runtime",
|
||||
"ACPX_ADMISSION_IDENTITY" => return "admission_identity",
|
||||
"ACPX_RUNTIME_PACKAGE_MISSING" => return "runtime_package_missing",
|
||||
"ACP_MODEL_UNSUPPORTED" => return "requested_model_unsupported",
|
||||
"AGENT_STARTUP_FAILED" => return "agent_startup_failed",
|
||||
@@ -1120,6 +1137,20 @@ mod tests {
|
||||
message: message.to_owned(),
|
||||
retryable: false,
|
||||
};
|
||||
for (code, expected) in [
|
||||
("ACPX_ADMISSION_SANDBOX", "admission_sandbox"),
|
||||
("ACPX_ADMISSION_CREDENTIAL", "admission_credential"),
|
||||
("ACPX_ADMISSION_RUNTIME", "admission_runtime"),
|
||||
(
|
||||
"GROK_EFFORT_ACKNOWLEDGEMENT_MISSING",
|
||||
"grok_effort_acknowledgement_missing",
|
||||
),
|
||||
] {
|
||||
assert_eq!(
|
||||
response_error_classification(&error(code, "private-token-canary")),
|
||||
expected
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
response_error_classification(&error(
|
||||
"acpx_sidecar_command_failed",
|
||||
|
||||
@@ -262,7 +262,7 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
"id": id,
|
||||
"ok": false,
|
||||
"error": {
|
||||
"code": "Q7Z9",
|
||||
"code": request["params"]["errorCode"].as_str().unwrap_or("Q7Z9"),
|
||||
"message": "violet-circuit-4821",
|
||||
"retryable": false,
|
||||
},
|
||||
|
||||
@@ -47,7 +47,7 @@ pub(crate) fn acpx_release_profile(agent: &str) -> Option<AcpxReleaseProfile> {
|
||||
agent_runtime_package: None,
|
||||
agent_runtime_version: None,
|
||||
command_digest:
|
||||
"sha256:5444547ca83543bc899ae5a8a2e895c19a86559339e60a1970786ce900742719",
|
||||
"sha256:6326444af8fd447032ca8ad10ce3a1280af9aeeddacd563cf48b430202dbbefd",
|
||||
requires_provider_policy: true,
|
||||
},
|
||||
"claude" => AcpxReleaseProfile {
|
||||
|
||||
@@ -219,6 +219,34 @@ fn keeps_valid_command_rejections_separate_from_protocol_failures() {
|
||||
transport.shutdown().expect("fake sidecar should stop");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_closed_admission_categories_over_the_sidecar_pipe() {
|
||||
let mut transport = transport("remote-error", Duration::from_secs(1));
|
||||
for (code, category) in [
|
||||
("ACPX_ADMISSION_INSTALLATION", "admission_installation"),
|
||||
("ACPX_ADMISSION_CREDENTIAL", "admission_credential"),
|
||||
(
|
||||
"GROK_EFFORT_ACKNOWLEDGEMENT_MISSING",
|
||||
"grok_effort_acknowledgement_missing",
|
||||
),
|
||||
("GROK_MODEL_MISMATCH", "grok_model_mismatch"),
|
||||
("ACPX_ADMISSION_CREDENTIAL_SECRET", "unclassified"),
|
||||
("GROK_MODEL_MISMATCH_SECRET", "unclassified"),
|
||||
] {
|
||||
let error = transport
|
||||
.request(
|
||||
GeneratedAcpxSidecarCommand::SessionOpen,
|
||||
json!({"errorCode":code}),
|
||||
)
|
||||
.unwrap_err();
|
||||
let message = error.to_string();
|
||||
assert!(message.contains(&format!("classification={category}")));
|
||||
assert!(!message.contains("violet-circuit-4821"));
|
||||
assert!(!message.contains("SECRET"));
|
||||
}
|
||||
transport.shutdown().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redacts_sidecar_stderr_when_the_process_exits() {
|
||||
let mut transport = transport("exit-secret", Duration::from_secs(1));
|
||||
|
||||
@@ -7,9 +7,9 @@ import { fileURLToPath } from "node:url";
|
||||
import { resolve, dirname } from "node:path";
|
||||
|
||||
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const fixture = resolve(root, "test/fixtures/copilot-profile-v69-identity.json");
|
||||
const fixture = resolve(root, "test/fixtures/copilot-profile-v70-identity.json");
|
||||
const historical = JSON.parse(readFileSync(resolve(root, "test/fixtures/copilot-profile-v12-identity.json"), "utf8"));
|
||||
const declaration = { ...historical.declaration, agentProfileVersion: 69 };
|
||||
const declaration = { ...historical.declaration, agentProfileVersion: 70 };
|
||||
delete declaration.permissionIdentitySourceSha256;
|
||||
const sources = {
|
||||
displayEventSourceSha256: "src/drivers/acpx/copilot-events.ts",
|
||||
@@ -44,6 +44,8 @@ const sources = {
|
||||
assetOwnershipSourceSha256: "src/drivers/acpx/provider-assets-root.ts",
|
||||
assetInstallerSourceSha256: "scripts/install-copilot-assets.mjs",
|
||||
credentialBindingSourceSha256: "src/drivers/acpx/environment.ts",
|
||||
admissionDiagnosticsSourceSha256: "src/drivers/acpx/admission-diagnostics.ts",
|
||||
grokAdmissionSourceSha256: "src/drivers/acpx/grok-effort.ts",
|
||||
sidecarErrorSourceSha256: "src/cli/acpx-sidecar-input.ts",
|
||||
profileSourceSha256: "src/drivers/acpx/copilot-profile.ts",
|
||||
metadataProbeSourceSha256: "src/drivers/copilot-metadata-probe.ts",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createGrokEffortAdmission } from "../drivers/acpx/grok-effort.js";
|
||||
import { recordAcpxAdmissionFailure } from "../drivers/acpx/admission-diagnostics.js";
|
||||
|
||||
import {
|
||||
acpxBootstrapBlockedError,
|
||||
@@ -8,6 +10,35 @@ import {
|
||||
} from "./acpx-sidecar-input.js";
|
||||
|
||||
describe("ACPX sidecar input sequencing", () => {
|
||||
it("prefers a known cause to a stage and ignores provider-supplied stage fields", () => {
|
||||
const cause = Object.assign(new Error("private-token-canary"), { code: "AUTH_REQUIRED" });
|
||||
const error = new AggregateError([cause], "private-wrapper");
|
||||
recordAcpxAdmissionFailure(error, "runtime");
|
||||
expect(acpxSidecarErrorCode(error)).toBe("AUTH_REQUIRED");
|
||||
expect(acpxSidecarErrorCode(Object.assign(new Error("private-token-canary"), {
|
||||
acpxAdmissionStage: "credential", code: "ACPX_ADMISSION_CREDENTIAL",
|
||||
}))).toBe("acpx_sidecar_command_failed");
|
||||
});
|
||||
it("retains a closed fallback stage through aggregate cleanup without changing the original error", () => {
|
||||
const error = Object.freeze(new Error("private-token-canary"));
|
||||
expect(recordAcpxAdmissionFailure(error, "credential")).toBe(error);
|
||||
recordAcpxAdmissionFailure(error, "runtime");
|
||||
expect(acpxSidecarErrorCode(new AggregateError([error], "private-wrapper"))).toBe("ACPX_ADMISSION_CREDENTIAL");
|
||||
expect(acpxSidecarErrorCode(new Error("ACPX_ADMISSION_CREDENTIAL private-token-canary"))).toBe("acpx_sidecar_command_failed");
|
||||
});
|
||||
it("preserves a Grok admission rejection without exporting the native payload", () => {
|
||||
const admission = createGrokEffortAdmission("high", "grok-4.7");
|
||||
const guard = admission.createGuard();
|
||||
guard("outbound", { id: 1, method: "session/new", params: {} });
|
||||
let failure: Error | undefined;
|
||||
try {
|
||||
guard("inbound", { id: 1, result: { sessionId: "private-session", _meta: { privateToken: "private-token-canary" } } });
|
||||
} catch (error) { failure = error as Error; }
|
||||
expect(failure).toBeInstanceOf(Error);
|
||||
expect(acpxSidecarErrorCode(failure!)).toBe("GROK_EFFORT_ACKNOWLEDGEMENT_MISSING");
|
||||
expect(failure!.message).not.toContain("private-token-canary");
|
||||
expect(() => admission.assertReady()).toThrow(failure);
|
||||
});
|
||||
it("classifies a retired tool callback without copying provider text into its identity", () => {
|
||||
const error = Object.assign(new Error("private-token-canary"), { code: "ACPX_TOOL_CALL_STALE" });
|
||||
expect(acpxSidecarErrorCode(error)).toBe("ACPX_TOOL_CALL_STALE");
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { GROK_ADMISSION_ERROR_CODES } from "../drivers/acpx/grok-effort.js";
|
||||
import { enqueueSerialInput } from "./serial-input-queue.js";
|
||||
import { acpxAdmissionFailureCode } from "../drivers/acpx/admission-diagnostics.js";
|
||||
|
||||
const ACPX_BOOTSTRAP_COMMANDS = new Set(["initialize", "session.open"]);
|
||||
|
||||
@@ -38,10 +40,12 @@ export function acpxBootstrapBlockedError(
|
||||
export function acpxSidecarErrorCode(error: Error): string {
|
||||
const pending: Error[] = [error];
|
||||
const observed = new Set<Error>();
|
||||
let admissionCode: string | undefined;
|
||||
while (pending.length > 0 && observed.size < 16) {
|
||||
const current = pending.shift()!;
|
||||
if (observed.has(current)) continue;
|
||||
observed.add(current);
|
||||
admissionCode ??= acpxAdmissionFailureCode(current);
|
||||
const code = directAcpxSidecarErrorCode(current);
|
||||
if (code !== null) return code;
|
||||
|
||||
@@ -53,7 +57,7 @@ export function acpxSidecarErrorCode(error: Error): string {
|
||||
}
|
||||
if (details.cause instanceof Error) pending.push(details.cause);
|
||||
}
|
||||
return "acpx_sidecar_command_failed";
|
||||
return admissionCode ?? "acpx_sidecar_command_failed";
|
||||
}
|
||||
|
||||
function directAcpxSidecarErrorCode(error: Error): string | null {
|
||||
@@ -131,6 +135,7 @@ const GENERIC_ACPX_OUTPUT_CODES = new Set([
|
||||
]);
|
||||
|
||||
const STABLE_ACPX_SIDECAR_CODES = new Set([
|
||||
...GROK_ADMISSION_ERROR_CODES,
|
||||
"ACPX_RUNTIME_PACKAGE_MISSING",
|
||||
"COPILOT_POLICY_VIOLATION",
|
||||
"COPILOT_DETACHED_WORK_UNSUPPORTED",
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/** Closed startup stages, independent of provider output and credentials. */
|
||||
export const ACPX_ADMISSION_CODES = {
|
||||
binding: "ACPX_ADMISSION_BINDING",
|
||||
installation: "ACPX_ADMISSION_INSTALLATION",
|
||||
sandbox: "ACPX_ADMISSION_SANDBOX",
|
||||
credential: "ACPX_ADMISSION_CREDENTIAL",
|
||||
configuration: "ACPX_ADMISSION_CONFIGURATION",
|
||||
skills: "ACPX_ADMISSION_SKILLS",
|
||||
command: "ACPX_ADMISSION_COMMAND",
|
||||
tool_bridge: "ACPX_ADMISSION_TOOL_BRIDGE",
|
||||
runtime: "ACPX_ADMISSION_RUNTIME",
|
||||
identity: "ACPX_ADMISSION_IDENTITY",
|
||||
} as const;
|
||||
|
||||
const failures = new WeakMap<Error, keyof typeof ACPX_ADMISSION_CODES>();
|
||||
|
||||
/** Preserve the original error and cleanup semantics, including cancellation. */
|
||||
export function recordAcpxAdmissionFailure(error: unknown, stage: keyof typeof ACPX_ADMISSION_CODES): unknown {
|
||||
if (error instanceof Error && !failures.has(error)) failures.set(error, stage);
|
||||
return error;
|
||||
}
|
||||
|
||||
export function acpxAdmissionFailureCode(error: Error): string | undefined {
|
||||
const stage = failures.get(error);
|
||||
return stage === undefined ? undefined : ACPX_ADMISSION_CODES[stage];
|
||||
}
|
||||
@@ -87,9 +87,26 @@ vi.mock("./installation-integrity.js", () => ({ verifyNativeAcpxInstallation: vi
|
||||
|
||||
describe("Copilot build-owned installation", () => {
|
||||
it("admits the current profile with environment launch preparation", () => {
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.agentProfileVersion).toBe(69);
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.agentProfileVersion).toBe(70);
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.qualificationStatus).toBeUndefined();
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.commandDigest).toBe("sha256:5444547ca83543bc899ae5a8a2e895c19a86559339e60a1970786ce900742719");
|
||||
expect(QUALIFIED_ACPX_PROFILES.copilot.commandDigest).toBe("sha256:6326444af8fd447032ca8ad10ce3a1280af9aeeddacd563cf48b430202dbbefd");
|
||||
});
|
||||
|
||||
it("preserves v69 while binding closed startup diagnostics in v70", async () => {
|
||||
const bytes = readFileSync(new URL("../../../test/fixtures/copilot-profile-v69-identity.json", import.meta.url));
|
||||
expect(createHash("sha256").update(bytes).digest("hex")).toBe("a878caa5f40cfad517e852384507b50c1098e219f1dd6822335b1119b03eaea5");
|
||||
const prior = JSON.parse(bytes.toString("utf8"));
|
||||
const current = JSON.parse(readFileSync(new URL("../../../test/fixtures/copilot-profile-v70-identity.json", import.meta.url), "utf8"));
|
||||
expect(Object.keys(current.declaration).filter(key => current.declaration[key] !== prior.declaration[key]).sort()).toEqual([
|
||||
"admissionDiagnosticsSourceSha256", "agentProfileVersion", "grokAdmissionSourceSha256",
|
||||
"profileCompatibilitySourceSha256", "runtimeHostSourceSha256", "sidecarErrorSourceSha256",
|
||||
]);
|
||||
for (const [name, field] of [["admission-diagnostics.ts", "admissionDiagnosticsSourceSha256"], ["grok-effort.ts", "grokAdmissionSourceSha256"]]) {
|
||||
expect(current.declaration[field]).toBe(createHash("sha256").update(readFileSync(new URL(name!, import.meta.url))).digest("hex"));
|
||||
}
|
||||
expect(isSupportedAcpxProfileVersion("copilot", 69)).toBe(true);
|
||||
await expect(verifyCopilotInstallation({ ...QUALIFIED_ACPX_PROFILES.copilot,
|
||||
agentProfileVersion: 69, commandDigest: prior.commandDigest })).rejects.toThrow("exact pinned");
|
||||
});
|
||||
|
||||
it("preserves published and candidate history while binding native Grok admission in v69", async () => {
|
||||
|
||||
@@ -48,12 +48,12 @@ export const QUALIFIED_ACPX_PROFILE_DATA = {
|
||||
"protocolVersion": 1,
|
||||
"acpxVersion": "0.13.1",
|
||||
"agent": "copilot",
|
||||
"agentProfileVersion": 69,
|
||||
"agentProfileVersion": 70,
|
||||
"agentServerPackage": "@github/copilot",
|
||||
"agentServerVersion": "1.0.88",
|
||||
"agentRuntimePackage": null,
|
||||
"agentRuntimeVersion": null,
|
||||
"commandDigest": "sha256:5444547ca83543bc899ae5a8a2e895c19a86559339e60a1970786ce900742719",
|
||||
"commandDigest": "sha256:6326444af8fd447032ca8ad10ce3a1280af9aeeddacd563cf48b430202dbbefd",
|
||||
"permissionPolicy": "interactive"
|
||||
},
|
||||
"claude": {
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
export const GROK_ADMISSION_ERROR_CODES = [
|
||||
"GROK_EFFORT_ACKNOWLEDGEMENT_MISSING",
|
||||
"GROK_EFFORT_MISMATCH",
|
||||
"GROK_MODEL_MISMATCH",
|
||||
"GROK_SESSION_MISMATCH",
|
||||
"GROK_CONFIGURATION_CONFLICT",
|
||||
"GROK_CONFIGURATION_DRIFT",
|
||||
"GROK_ADMISSION_PROTOCOL_VIOLATION",
|
||||
] as const;
|
||||
|
||||
export type GrokEffort = "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||
export function resolveGrokEffort(agent: string, value: unknown): GrokEffort | undefined {
|
||||
if (value === undefined || value === "") return undefined;
|
||||
@@ -8,22 +18,23 @@ export function resolveGrokEffort(agent: string, value: unknown): GrokEffort | u
|
||||
export function createGrokEffortAdmission(expected: GrokEffort, expectedModel: string) {
|
||||
type State = { sessionId: string | null; ready: boolean; error: Error | null };
|
||||
let current: State | null = null;
|
||||
const failure = (detail: string) => new Error(`Grok effort admission failed: ${detail}`);
|
||||
const failure = (code: typeof GROK_ADMISSION_ERROR_CODES[number], detail: string) =>
|
||||
Object.assign(new Error(`Grok effort admission failed: ${detail}`), { code });
|
||||
const assertReady = () => {
|
||||
if (current?.error) throw current.error;
|
||||
if (!current?.sessionId || !current.ready) throw failure("native session does not acknowledge the selected effort");
|
||||
if (!current?.sessionId || !current.ready) throw failure("GROK_EFFORT_ACKNOWLEDGEMENT_MISSING", "native session does not acknowledge the selected effort");
|
||||
};
|
||||
const readAcknowledgement = (result: Record<string, unknown>) => {
|
||||
const config = object(object(result._meta)["x.ai/sessionConfig"]);
|
||||
const options = Array.isArray(config.options) ? config.options.map(object) : [];
|
||||
const selected = options.filter(option => option.category === "mode" && option.selected === true);
|
||||
if (selected.length !== 1) throw failure("native effort selection is missing or ambiguous");
|
||||
if (selected[0]!.id !== expected) throw failure("native effort differs from the selected effort");
|
||||
if (selected.length !== 1) throw failure("GROK_EFFORT_ACKNOWLEDGEMENT_MISSING", "native effort selection is missing or ambiguous");
|
||||
if (selected[0]!.id !== expected) throw failure("GROK_EFFORT_MISMATCH", "native effort differs from the selected effort");
|
||||
const model = object(result.models).currentModelId;
|
||||
const selectedModels = options.filter(option => option.category === "model" && option.selected === true);
|
||||
if (typeof model !== "string" || !model.trim() || model !== expectedModel
|
||||
|| selectedModels.length > 1 || selectedModels.length === 1 && selectedModels[0]!.id !== model) {
|
||||
throw failure("native model acknowledgement conflicts with the selected model");
|
||||
throw failure("GROK_MODEL_MISMATCH", "native model acknowledgement conflicts with the selected model");
|
||||
}
|
||||
};
|
||||
return {
|
||||
@@ -34,26 +45,26 @@ export function createGrokEffortAdmission(expected: GrokEffort, expectedModel: s
|
||||
current = state;
|
||||
let pending: { id: string | number; method: string; sessionId: unknown } | null = null;
|
||||
return (direction: "inbound" | "outbound", value: unknown): void => {
|
||||
if (current !== state) throw failure("connection authority was replaced");
|
||||
if (current !== state) throw failure("GROK_ADMISSION_PROTOCOL_VIOLATION", "connection authority was replaced");
|
||||
if (state.error) throw state.error;
|
||||
const message = object(value), params = object(message.params);
|
||||
try {
|
||||
if (direction === "outbound") {
|
||||
if (message.method === "session/prompt") {
|
||||
assertReady();
|
||||
if (params.sessionId !== state.sessionId) throw failure("prompt belongs to a different session");
|
||||
if (params.sessionId !== state.sessionId) throw failure("GROK_SESSION_MISMATCH", "prompt belongs to a different session");
|
||||
} else if (message.method === "session/new" || message.method === "session/load" || message.method === "session/resume") {
|
||||
if (typeof message.id !== "string" && typeof message.id !== "number" || pending) throw failure("uncorrelated or overlapping session admission");
|
||||
if (typeof message.id !== "string" && typeof message.id !== "number" || pending) throw failure("GROK_ADMISSION_PROTOCOL_VIOLATION", "uncorrelated or overlapping session admission");
|
||||
const meta = object(params._meta);
|
||||
if (meta.reasoningEffort !== undefined && meta.reasoningEffort !== expected
|
||||
|| meta.modelId !== undefined && meta.modelId !== expectedModel) {
|
||||
throw failure("native session request conflicts with the bound configuration");
|
||||
throw failure("GROK_CONFIGURATION_CONFLICT", "native session request conflicts with the bound configuration");
|
||||
}
|
||||
params._meta = { ...meta, modelId: expectedModel, reasoningEffort: expected };
|
||||
state.ready = false; state.sessionId = null;
|
||||
pending = { id: message.id, method: message.method, sessionId: params.sessionId };
|
||||
} else if (message.method === "session/set_config_option" || message.method === "session/set_model") {
|
||||
throw failure("model and effort must be selected when the native session opens");
|
||||
throw failure("GROK_ADMISSION_PROTOCOL_VIOLATION", "model and effort must be selected when the native session opens");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -61,7 +72,7 @@ export function createGrokEffortAdmission(expected: GrokEffort, expectedModel: s
|
||||
if (!state.ready) return;
|
||||
const update = object(params.update);
|
||||
if (params.sessionId !== state.sessionId || update.reasoning_effort !== expected
|
||||
|| update.model_id !== expectedModel) throw failure("native model or effort drifted from the selected configuration");
|
||||
|| update.model_id !== expectedModel) throw failure("GROK_CONFIGURATION_DRIFT", "native model or effort drifted from the selected configuration");
|
||||
return;
|
||||
}
|
||||
if (message.method !== undefined || !pending || message.id !== pending.id) return;
|
||||
@@ -69,14 +80,14 @@ export function createGrokEffortAdmission(expected: GrokEffort, expectedModel: s
|
||||
if (message.error !== undefined) return;
|
||||
const result = object(message.result);
|
||||
const sessionId = request.method === "session/new" ? result.sessionId : request.sessionId;
|
||||
if (typeof sessionId !== "string" || !sessionId.trim()) throw failure("native acknowledgement has no session identity");
|
||||
if (typeof sessionId !== "string" || !sessionId.trim()) throw failure("GROK_SESSION_MISMATCH", "native acknowledgement has no session identity");
|
||||
const detail = object(object(result._meta)["x.ai/sessionDetail"]);
|
||||
if (result.sessionId !== undefined && result.sessionId !== sessionId
|
||||
|| detail.sessionId !== undefined && detail.sessionId !== sessionId) throw failure("native acknowledgement belongs to a different session");
|
||||
|| detail.sessionId !== undefined && detail.sessionId !== sessionId) throw failure("GROK_SESSION_MISMATCH", "native acknowledgement belongs to a different session");
|
||||
readAcknowledgement(result);
|
||||
state.sessionId = sessionId; state.ready = true;
|
||||
} catch (error) {
|
||||
state.error = error instanceof Error ? error : failure("invalid native acknowledgement");
|
||||
state.error = error instanceof Error ? error : failure("GROK_ADMISSION_PROTOCOL_VIOLATION", "invalid native acknowledgement");
|
||||
throw state.error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,6 +5,38 @@ import { join } from "node:path";
|
||||
import { createAcpRuntime, createAgentRegistry, createRuntimeStore, type AcpRuntimeHandle } from "acpx/runtime";
|
||||
import { expect, it } from "vitest";
|
||||
import { createGrokEffortAdmission } from "./grok-effort.js";
|
||||
import { acpxSidecarErrorCode } from "../../cli/acpx-sidecar-input.js";
|
||||
|
||||
it("retains a native Grok acknowledgement failure through the real ACPX connection", async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), "grok-rejected-admission-"));
|
||||
const fixture = join(root, "grok.cjs");
|
||||
await writeFile(fixture, String.raw`
|
||||
const readline = require("node:readline");
|
||||
readline.createInterface({input:process.stdin}).on("line", line => {
|
||||
const request = JSON.parse(line);
|
||||
const result = request.method === "initialize"
|
||||
? {protocolVersion:1,agentCapabilities:{},authMethods:[]}
|
||||
: {sessionId:"private-session",models:{currentModelId:"grok-4.7",availableModels:[{modelId:"grok-4.7",name:"grok-4.7"}]},_meta:{privateToken:"private-token-canary"}};
|
||||
process.stdout.write(JSON.stringify({jsonrpc:"2.0",id:request.id,result})+"\n");
|
||||
});
|
||||
`);
|
||||
const admission = createGrokEffortAdmission("high", "grok-4.7");
|
||||
const children: ReturnType<typeof spawn>[] = [];
|
||||
const runtime = createAcpRuntime({ cwd: root, sessionStore: createRuntimeStore({stateDir:join(root,"state")}),
|
||||
agentRegistry: createAgentRegistry({overrides:{grok:[fixture,"agent","stdio"]}}), permissionMode:"approve-reads",
|
||||
protocolGuardFactory: () => admission.createGuard(),
|
||||
spawnAgent: () => { const child = spawn(process.execPath,[fixture],{cwd:root,env:{},stdio:"pipe"}); children.push(child); return child; },
|
||||
});
|
||||
try {
|
||||
const failure = await runtime.ensureSession({sessionKey:"native-rejection",agent:"grok",mode:"persistent",sessionOptions:{model:"grok-4.7"}}).catch(error => error);
|
||||
expect(acpxSidecarErrorCode(failure)).toBe("GROK_EFFORT_ACKNOWLEDGEMENT_MISSING");
|
||||
expect(failure.message).not.toContain("private-token-canary");
|
||||
expect(() => admission.assertReady()).toThrow("missing or ambiguous");
|
||||
} finally {
|
||||
for (const child of children) if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
|
||||
await rm(root,{recursive:true,force:true});
|
||||
}
|
||||
});
|
||||
|
||||
it.each(["low", "high"] as const)("transports and restores native Grok %s effort through the real ACPX client", async effort => {
|
||||
const root = await mkdtemp(join(tmpdir(), "grok-native-session-options-"));
|
||||
|
||||
@@ -2,13 +2,13 @@ import { QUALIFIED_ACPX_PROFILE_DATA } from "./generated-profiles.js";
|
||||
|
||||
/** Decodable historical profile revisions, not permission to launch them.
|
||||
* Exact current profile/package/digest admission is checked separately. */
|
||||
type HistoricalAcpxProfileVersion = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68;
|
||||
type HistoricalAcpxProfileVersion = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69;
|
||||
type CurrentAcpxProfileVersion = typeof QUALIFIED_ACPX_PROFILE_DATA[keyof typeof QUALIFIED_ACPX_PROFILE_DATA]["agentProfileVersion"];
|
||||
export type AcpxProfileVersion = HistoricalAcpxProfileVersion | CurrentAcpxProfileVersion;
|
||||
|
||||
const historicalVersions: Readonly<Record<string, readonly HistoricalAcpxProfileVersion[]>> = {
|
||||
pi: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], claude: [1, 2, 3, 4, 5], codex: [1, 2, 3, 4, 5],
|
||||
grok: [1, 2, 3, 4, 5], copilot: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68],
|
||||
grok: [1, 2, 3, 4, 5], copilot: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
|
||||
cursor: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
} from "../../contracts/runtime-context.js";
|
||||
import { releaseMaterializedNativeRuntimeSkills } from "../runtime-context-materializer.js";
|
||||
import { openCodexAcpxRuntime } from "./codex-runtime-adapter.js";
|
||||
import { acpxSidecarErrorCode } from "../../cli/acpx-sidecar-input.js";
|
||||
import { stageManagedCodexCredential } from "./codex-credentials.js";
|
||||
import type {
|
||||
VerifiedAcpxCommandLease,
|
||||
@@ -202,6 +203,21 @@ afterEach(async () => {
|
||||
});
|
||||
|
||||
describe("ACPX runtime host", () => {
|
||||
it.each(["installation", "sandbox", "credential", "runtime"] as const)("retains the failed %s admission stage through the sidecar boundary", async stage => {
|
||||
const fixture = await hostFixture();
|
||||
const failure = new Error("private-token-canary");
|
||||
const openRuntime = vi.fn(async () => { throw failure; });
|
||||
const dependencies = fixture.dependencies({ openRuntime });
|
||||
if (stage === "installation") dependencies.verifyInstallation = async () => { throw failure; };
|
||||
if (stage === "sandbox") dependencies.prepareSandbox = async () => { throw failure; };
|
||||
if (stage === "credential") dependencies.stageCredential = async () => { throw failure; };
|
||||
const rejected = await AcpxRuntimeHost.open({ ...fixture.options, agent: "codex", model: "gpt-5.6-sol",
|
||||
permissionMode: "approve-all", environment: { OPENAI_API_KEY: "synthetic-test-key" } }, dependencies).catch(error => error);
|
||||
expect(rejected).toBe(failure);
|
||||
expect(acpxSidecarErrorCode(rejected)).toBe(`ACPX_ADMISSION_${stage.toUpperCase()}`);
|
||||
if (stage !== "runtime") expect(openRuntime).not.toHaveBeenCalled();
|
||||
if (stage === "runtime") expect(fixture.commandClose).toHaveBeenCalledOnce();
|
||||
});
|
||||
it("rejects preconfigured Codex before admission resources or runtime launch", async () => {
|
||||
const fixture = await hostFixture();
|
||||
const openRuntime = vi.fn(), prepareSandbox = vi.fn();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { resolveGrokDisableWebSearch } from "./grok-web-search.js";
|
||||
import { recordAcpxAdmissionFailure, type ACPX_ADMISSION_CODES } from "./admission-diagnostics.js";
|
||||
import { composeCopilotSystemInstructions } from "./copilot-profile.js";
|
||||
import { resolveClaudeEffort } from "./claude-effort.js";
|
||||
import { resolveGrokEffort } from "./grok-effort.js";
|
||||
@@ -384,7 +385,7 @@ export class AcpxRuntimeHost {
|
||||
? { providerPolicy: options.providerPolicy } : {}),
|
||||
}),
|
||||
dependencies.retainAdmissionCleanup,
|
||||
);
|
||||
).catch(error => { throw recordAcpxAdmissionFailure(error, "binding"); });
|
||||
if (options.expectedIdentity) {
|
||||
verifyExpectedAcpxIdentity(options.expectedIdentity, binding, null);
|
||||
}
|
||||
@@ -405,7 +406,7 @@ export class AcpxRuntimeHost {
|
||||
profile,
|
||||
),
|
||||
dependencies.retainAdmissionCleanup,
|
||||
);
|
||||
).catch(error => { throw recordAcpxAdmissionFailure(error, "installation"); });
|
||||
if (installation.commandDigest !== profile.commandDigest) {
|
||||
throw new Error("Verified ACPX installation does not match its profile");
|
||||
}
|
||||
@@ -451,6 +452,7 @@ export class AcpxRuntimeHost {
|
||||
retainedRejectedRuntimeAdmissions.add(retained);
|
||||
retainRuntimeHostCleanup(ownedCleanup);
|
||||
};
|
||||
let admissionStage: keyof typeof ACPX_ADMISSION_CODES = "sandbox";
|
||||
try {
|
||||
const sandbox = await runAbortableAdmissionStage(
|
||||
options.signal,
|
||||
@@ -473,6 +475,7 @@ export class AcpxRuntimeHost {
|
||||
}),
|
||||
dependencies.retainAdmissionCleanup,
|
||||
);
|
||||
admissionStage = "credential";
|
||||
if (options.agent === "codex" && !preconfigured) {
|
||||
credential = await acquireAbortableAdmissionResource({
|
||||
signal: options.signal,
|
||||
@@ -508,6 +511,7 @@ export class AcpxRuntimeHost {
|
||||
});
|
||||
}
|
||||
options.signal?.throwIfAborted();
|
||||
admissionStage = "configuration";
|
||||
const configurationLifetime = credential;
|
||||
await runAbortableAdmissionStage(
|
||||
options.signal,
|
||||
@@ -570,6 +574,7 @@ export class AcpxRuntimeHost {
|
||||
PAPERCLIP_PI_READ_ROOTS: JSON.stringify([...(options.providerPolicy?.readRoots ?? []), ...skills.readRoots]),
|
||||
});
|
||||
}
|
||||
admissionStage = "skills";
|
||||
if (!preconfigured && (options.agent === "claude" || options.agent === "grok")) {
|
||||
// The lifetime lease proves the previous provider has stopped. Refresh
|
||||
// the assigned snapshot before every launch, including durable resume;
|
||||
@@ -582,6 +587,7 @@ export class AcpxRuntimeHost {
|
||||
);
|
||||
options.signal?.throwIfAborted();
|
||||
}
|
||||
admissionStage = "command";
|
||||
command = await acquireAbortableAdmissionResource({
|
||||
signal: options.signal,
|
||||
acquire: () => installation.openCommand({ signal: options.signal }),
|
||||
@@ -595,6 +601,7 @@ export class AcpxRuntimeHost {
|
||||
signal => installation.openCommand({ signal }),
|
||||
);
|
||||
command = commandOwner.command;
|
||||
admissionStage = "tool_bridge";
|
||||
toolBridge = options.semanticTools
|
||||
? await acquireAbortableAdmissionResource({
|
||||
signal: options.signal,
|
||||
@@ -613,6 +620,7 @@ export class AcpxRuntimeHost {
|
||||
if (admittedLifetime === null) {
|
||||
throw new Error("ACPX provider lifetime lease is unavailable");
|
||||
}
|
||||
admissionStage = "runtime";
|
||||
runtime = await acquireAbortableAdmissionResource({
|
||||
signal: options.signal,
|
||||
acquire: async () => {
|
||||
@@ -683,6 +691,7 @@ export class AcpxRuntimeHost {
|
||||
});
|
||||
},
|
||||
});
|
||||
admissionStage = "identity";
|
||||
const runtimeIdentity = await runAbortableAdmissionStage(
|
||||
options.signal,
|
||||
() =>
|
||||
@@ -733,6 +742,7 @@ export class AcpxRuntimeHost {
|
||||
: [],
|
||||
});
|
||||
} catch (error) {
|
||||
recordAcpxAdmissionFailure(error, admissionStage);
|
||||
error = classifyAcpxProfileError(options.agent, error) ?? error;
|
||||
const cleanup = cleanupRuntimeResources(
|
||||
runtime,
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"commandDigest": "sha256:6326444af8fd447032ca8ad10ce3a1280af9aeeddacd563cf48b430202dbbefd",
|
||||
"declaration": {
|
||||
"schema": "paperclip.acpx_profile_declaration.v1",
|
||||
"agent": "copilot",
|
||||
"agentProfileVersion": 70,
|
||||
"acpxVersion": "0.13.1",
|
||||
"agentServerVersion": "1.0.88",
|
||||
"protocolPolicyRevision": "copilot-agent-manual-v1",
|
||||
"acpxPatchSha256": "00d6af17216cb0cad902b48633eb19bf0ec6b05837a984cb24661fca593f09c1",
|
||||
"policySha256": "a4be69be43db84052560420a3ca546a665c9165573c24d543eb33d144ba138a3",
|
||||
"distributionSourceSha256": "c0a65e247fc47b263bd369a3d5ab505c4b323d4e6493be8a9ecbeb0e9dbb9107",
|
||||
"agentFilesBinding": "registered-runtime-context-v1",
|
||||
"systemInstructionDelivery": "COPILOT_HOME/copilot-instructions.md:replace-under-lifetime-lease-before-launch:v1",
|
||||
"sharedRuntimeContract": "paperclip.acpx-runtime-contract.v1",
|
||||
"innerDistributionSourceSha256": "9bb08347eed01f1ab44e065c8b06ead9be3a25973d6e6329dc4c0a099096279a",
|
||||
"upstreamAppSha256": "7b48282a19b5b0814a0c96ad5e3a125173d792cc55f9525b2effea962f6063c0",
|
||||
"patchedAppSha256": "61f8eebe0c30cc03b311c6818b2acb158a6d16ca58c8bfac5ebd42db095c2679",
|
||||
"messageIdentityContract": "copilot-native-message-id-v1",
|
||||
"ownedDistributionDelivery": "COPILOT_CLI_DIST_DIR:lease-owned-guarded-inner-distribution:v1",
|
||||
"permissionContextContract": "copilot-edit-permission-context-v1",
|
||||
"permissionContextSourceSha256": "de2d38d702b3c574161af0c0c04790fb6f6347916eb3916ce7a131a8c229121b",
|
||||
"permissionAdapterSourceSha256": "ee5929ed2ee647ad0369465dee9d51a00b2dd28e1ff735b43e969ddc9c164668",
|
||||
"permissionLocationsSourceSha256": "f39a81da395b6e23aa2a1a45572a28846e5e81bfd3d764d9a456f74a79c752e9",
|
||||
"permissionRedactionSourceSha256": "ad6770c69269087951790e2e87e22ac088e3d432769adf17ebc865ed512e6c4f",
|
||||
"permissionClassifierSourceSha256": "1161eabd82e26133e3b3db3ab567f65d52808b03f176e93497e02c8330349fb4",
|
||||
"semanticToolReceiptContract": "paperclip.semantic_tool_receipt.v2",
|
||||
"semanticReceiptSourceSha256": "b2795726b2234a663fec1a6ca11f0551ae69882fe9e82aa39686e952d036e791",
|
||||
"semanticBridgeSourceSha256": "8764b8c9032fdc7d1415b01e75a9fc57c550e7a5e11da4bed7d9100082872ae5",
|
||||
"toolEvidenceSourceSha256": "6eef5039afc75bb851eaf9cd82a6f099e4bd398ca2deb59dd66f5b2a81a7a706",
|
||||
"semanticNormalizedInputContract": "validated-forwarded-input-commit-v1",
|
||||
"semanticSidecarSourceSha256": "7d6e948b7cff4df52a9afc916db46ace0f42b4b2d3134ba0c21ee0a928857e62",
|
||||
"semanticDirectDriverSourceSha256": "d683429427dd8a1a5efe50952018ea486f808bdbf0a92fc5946ee267fe2c72ee",
|
||||
"semanticValidationSourceSha256": "02fbb92681c78c5de5d2f1aae25aabc25a0e5df6b0ff4baccac652192a8da975",
|
||||
"semanticNormalizationSourceSha256": "8b628b82e8eacc91cdcc6fdca2210ba4cf282f01e9c6f74e95ff271655b5047e",
|
||||
"semanticCompletionContractSourceSha256": "f49398b682a5623812f5d3c33d6bb9a749008e47cc0ed969072041615f66df59",
|
||||
"semanticValidatorsSourceSha256": "f22d9caf2035b600abc1a6625ae23ca97f1409d7e29ed5b7264bb8f9784c7dc9",
|
||||
"semanticSchemaBundleSourceSha256": "4cae579aac836762fdbf92c5447425d8b756e87a5766bc0c7a1885a90541c8d6",
|
||||
"semanticSidecarProtocolSourceSha256": "26dd0cfbef8b2b401de6b7862a4af7f243fb703e23678a1a5ed8fa68d4784d42",
|
||||
"semanticSidecarReceiptCommitContract": "correlated-tool-resolve-v1",
|
||||
"displayEventSourceSha256": "d72f9a6035c247bc6a42c067c05753076c54322c4b58984e93922f3325dc6877",
|
||||
"displayProjectionSourceSha256": "75952606b26dd93bbc582c1f0a4424487377272ea745fb3a27ceae031fd5dc7e",
|
||||
"configuredEnvironmentSourceSha256": "5c9008d121979a3a8987e6b8a5752172eafdc4a2b5d725a73f3bbb8fb83be8ff",
|
||||
"configuredEnvironmentRustSourceSha256": "85c87fae62b8a9377e4f0a4c00302c7519fae4397b1c48253f8f2b7ba7faf994",
|
||||
"profileActivitySourceSha256": "4fdb6b0f9125fd8372ba6f27945fa5c8a3d3b2ec891df544092e3dc7a75d5282",
|
||||
"profileExtensionsSourceSha256": "a80ddc95eb4505095bfdbbf85c758199949ab20be9c84b34c77f762eb7180571",
|
||||
"profileInstallationSourceSha256": "3e61c4cdd4b78e38fcb16eaadae4f1fd65ce3c7127184ea7a80948c8e5d77f88",
|
||||
"attachmentPolicySourceSha256": "4f7638b7cc64e18f6a4ba33fd46de2b3d49225e32aeab41f5c695b268fa4f8e2",
|
||||
"singleReadEvidenceSourceSha256": "4069393405089bde613cecec04f5123c426594811da4c668bd96f0e7e283550f",
|
||||
"nativeSessionRuntimeSourceSha256": "1fe6fa9e6b96d84d70432b85a57c473f833606d4a521563d5022b4d3c41576ce",
|
||||
"nativeRuntimeContextSourceSha256": "71607f80dbb8dc5cc6c123d0b8f3995d6c5407277695a8c82cbedc90fb8f4842",
|
||||
"nativeRuntimePromptsSourceSha256": "fff5755dba9b7dce8a5f10ff6ac6d5ed06b92ed079ce1e0a44ac72f2ce7869c1",
|
||||
"nativeSessionContractSourceSha256": "22a8c96ce41ba4f03e976fc37f0cc7c5d05cee99fa789941da31ee1dab440b90",
|
||||
"harnessSessionContractSourceSha256": "baba1a210b863518f01e0c875606ed37f9467c433222251438578bd999bc43b5",
|
||||
"harnessBackendSourceSha256": "dc827e281ae6731545b166ee4d709a4f67f594a556dcbe63c70fe8f1aca26249",
|
||||
"harnessSessionSourceSha256": "81361733e86b56dd5a66415aefc6f72e69be24acc8d3417370154ebb7fef6e94",
|
||||
"transportContractSourceSha256": "03fca93d36a89b0cc0917335e293ad097fdf04356d21b307827bb0ea4c13f523",
|
||||
"nativeBackendSourceSha256": "7495d9898d22dca1ebf6336361d332bafefc4498f6e49f1135025fad846c8586",
|
||||
"nativeBackendFactorySourceSha256": "7e431c926b76d53c4c08e3a4105353dcd34bd940f6588a1a68f79631f6feeb44",
|
||||
"nativeInstructionsSourceSha256": "82ac6e5f7275b4ef79fb166c7330efc504e80cab3d7e9081e4e40a8b570bc50b",
|
||||
"providerLaunchSourceSha256": "c744235b3067ea75973523f78f1e13399337bc155f1775af694e34782d5c9bef",
|
||||
"launchPreparationStoreSourceSha256": "ff6025568bbc0aa6ce545772d73dfca2d3da226740bd3a7b386b069e76cff296",
|
||||
"runtimeRequestBridgeSourceSha256": "93a631b8439df1590b0cf442cf84a9b05f004f12bfee90291651ccfc0861effe",
|
||||
"runtimeRequestFacadeSourceSha256": "d0ed28e0c5ddad34db8f437e704c8a755eb0b47f27e08e44185f66d1d2205295",
|
||||
"runtimeRequestNotificationSourceSha256": "6196c6175f11c69295dc00fc773201f4fdeca26c500653870253c43b81e65211",
|
||||
"guardedInstallationSourceSha256": "56a177d3e702914818dca4ca50e061f0d25f988bfc4c0582c36ce23c1696d82f",
|
||||
"nativeExecutionSourceSha256": "d60b8ea63bad975c0144f0702b2749d7db9a7da50680a6147f20d4d11f2d5297",
|
||||
"profileCompatibilitySourceSha256": "0832086e776ae28048f78ce87664bd196b73349899168746833d943e399bed76",
|
||||
"installationSourceSha256": "a1c7c6f103b898216973e77ffbac0ef7572e250aa574d1a4065270e9dfa0dc2d",
|
||||
"assetOwnershipSourceSha256": "1785e3f31e5dad5a13b53e25d8cf9482a9bd89a27b6c127830aed6b81acc605c",
|
||||
"assetInstallerSourceSha256": "d3bd9514e5920d0cc3567aa50487fb534c57a6f66b8da0d3f22c5f6e499c841f",
|
||||
"credentialBindingSourceSha256": "7586d44b47c83395498dc8806287cd3538ef58177ba7c5949f5766ed105a0161",
|
||||
"admissionDiagnosticsSourceSha256": "df8f1aa4f2d1bc63b2635bdd09cb8165c8b7681ddcc2618435c7c08ca90475af",
|
||||
"grokAdmissionSourceSha256": "f1e46cf2e1e36b7704bd797b678e3db8db2003f97bdb9d827cfa3d7662698777",
|
||||
"sidecarErrorSourceSha256": "17948ad74350dc487ab20d24a0fb89daf0b426b98396454fff0e3856e922d82c",
|
||||
"profileSourceSha256": "f5538b3dbefa7634a332b87d5ededcefb56aa7e5790cede1c7a0d948a548a456",
|
||||
"metadataProbeSourceSha256": "be4c8416edd27061109bc1f33d0c26071b4facbb3f651beaae6b3c0275cce727",
|
||||
"permissionToolIdentitySourceSha256": "770b47305e571a81f344883057d0e4a482a1cd59ac77d045836593a8e739deb1",
|
||||
"semanticContinuationSourceSha256": "c9cc0fd516b3df92a6655f56ee9bef37615a889c371e2e137d8ac5c1176de811",
|
||||
"runtimeHostSourceSha256": "f12712a06c9d25ba78f61883d6582237de405e79f38586e20419522e5a7059f2",
|
||||
"runtimeAdapterSourceSha256": "7c47c05306ebe7d1ca6b5d046a96f5726a48adec4d27e7c16788f505f25b5db2",
|
||||
"runtimeSandboxSourceSha256": "981449a4c6d10f682ecf86d834eed07faca30a7d9b419fb8db4973a442a343ec",
|
||||
"cancellationSourceSha256": "a07d1a9e982dec0ae130c1ad1efa5bc75c6a39e013b730ba3ee45256f09ceeca",
|
||||
"agentFilesSourceSha256": "fb32f6badc13dfa22f231479509b631b2f0eba0c99b1ab9f3cd5c0c601aa03ba",
|
||||
"nativeDistributionSourceSha256": "aed327c389e957483a503cb1bb8b247ee7cd7ff4b528fb4567c39bcb4577690b"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user