fix: 将工作区契约漂移降级为告警
This commit is contained in:
+21
-13
@@ -53,11 +53,11 @@ export function validateCreateRun(input: unknown): CreateRunInput {
|
||||
validateBackendSecretScope(backendProfile, executionPolicy);
|
||||
const workspaceRef = validateWorkspaceRef(requiredRecord(record, "workspaceRef"));
|
||||
const resourceBundleRef = validateResourceBundleRef(record.resourceBundleRef);
|
||||
validatePrimaryWorkspaceContract(workspaceRef, resourceBundleRef);
|
||||
const normalizedWorkspaceRef = validatePrimaryWorkspaceContract(workspaceRef, resourceBundleRef);
|
||||
return {
|
||||
tenantId,
|
||||
projectId: requiredString(record, "projectId"),
|
||||
workspaceRef,
|
||||
workspaceRef: normalizedWorkspaceRef,
|
||||
sessionRef: validateSessionRef(record.sessionRef),
|
||||
resourceBundleRef,
|
||||
providerId: requiredString(record, "providerId"),
|
||||
@@ -152,19 +152,27 @@ export function validateWorkspaceRef(record: JsonRecord): WorkspaceRef {
|
||||
return record as WorkspaceRef;
|
||||
}
|
||||
|
||||
export function validatePrimaryWorkspaceContract(workspaceRef: WorkspaceRef | null, resourceBundleRef: ResourceBundleRef | null): void {
|
||||
if (!resourceBundleRef) return;
|
||||
if (!workspaceRef) throw new AgentRunError("schema-invalid", "resourceBundleRef requires workspaceRef", { httpStatus: 400 });
|
||||
if (workspaceRef.kind !== "opaque") {
|
||||
throw new AgentRunError("schema-invalid", "gitbundle primary workspace requires workspaceRef.kind=opaque so the resource bundle remains the only source authority", { httpStatus: 400 });
|
||||
export function validatePrimaryWorkspaceContract(workspaceRef: WorkspaceRef | null, resourceBundleRef: ResourceBundleRef | null): WorkspaceRef {
|
||||
if (!resourceBundleRef) {
|
||||
if (!workspaceRef) throw new AgentRunError("schema-invalid", "workspaceRef is required", { httpStatus: 400 });
|
||||
return workspaceRef;
|
||||
}
|
||||
if (workspaceRef.path !== ".") {
|
||||
throw new AgentRunError("schema-invalid", "gitbundle primary workspace requires workspaceRef.path=. as its declared targetPath", { httpStatus: 400 });
|
||||
}
|
||||
const rejectedKeys = Object.keys(workspaceRef).filter((key) => key !== "kind" && key !== "path");
|
||||
if (rejectedKeys.length > 0) {
|
||||
throw new AgentRunError("schema-invalid", "gitbundle primary workspaceRef only supports kind and path; resourceBundleRef is the source authority", { httpStatus: 400, details: { rejectedKeys: rejectedKeys.sort(), valuesPrinted: false } });
|
||||
const normalized: WorkspaceRef = { kind: "opaque", path: "." };
|
||||
const received = workspaceRef ?? ({} as WorkspaceRef);
|
||||
const ignoredKeys = Object.keys(received).filter((key) => key !== "kind" && key !== "path").sort();
|
||||
if (received.kind !== normalized.kind || received.path !== normalized.path || ignoredKeys.length > 0) {
|
||||
console.warn(JSON.stringify({
|
||||
event: "agentrun.contract.warning",
|
||||
code: "gitbundle-workspace-ref-normalized",
|
||||
receivedKind: typeof received.kind === "string" ? received.kind : null,
|
||||
receivedPath: typeof received.path === "string" ? received.path : null,
|
||||
ignoredKeys,
|
||||
action: "continue-with-canonical-workspace-ref",
|
||||
blocking: false,
|
||||
valuesPrinted: false,
|
||||
}));
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function validateCommitId(commitId: string, fieldName: string): void {
|
||||
|
||||
@@ -187,8 +187,8 @@ const selfTest: SelfTestCase = async (context) => {
|
||||
const primaryContractBundle = validateResourceBundleRef({ kind: "gitbundle", repoUrl: "git@github.com:pikasTech/unidesk.git", ref: "master", bundles: [{ subpath: "tools", targetPath: "tools" }] });
|
||||
assert.ok(primaryContractBundle);
|
||||
assert.doesNotThrow(() => validatePrimaryWorkspaceContract({ kind: "opaque", path: "." }, primaryContractBundle));
|
||||
assert.throws(() => validatePrimaryWorkspaceContract({ kind: "opaque", path: ".", repo: "pikasTech/unidesk" }, primaryContractBundle), /only supports kind and path/u);
|
||||
assert.throws(() => validatePrimaryWorkspaceContract({ kind: "opaque", path: ".", branch: "master" }, primaryContractBundle), /only supports kind and path/u);
|
||||
assert.deepEqual(validatePrimaryWorkspaceContract({ kind: "opaque", path: ".", repo: "pikasTech/unidesk" }, primaryContractBundle), { kind: "opaque", path: "." });
|
||||
assert.deepEqual(validatePrimaryWorkspaceContract({ kind: "opaque", branch: "master" }, primaryContractBundle), { kind: "opaque", path: "." });
|
||||
|
||||
const submitPlan = await runCliJson(context, server.baseUrl, ["queue", "submit", "--aipod", "Artificer", "--prompt", "处理 pikasTech/unidesk#245", "--model", "gpt-5.4", "--reasoning-effort", "high", "--idempotency-key", "selftest-aipod-cli", "--dry-run"]);
|
||||
assert.equal(submitPlan.ok, true);
|
||||
|
||||
Reference in New Issue
Block a user