fix: complete state-contract naming cleanup
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-companion-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:07cfe53bfdd700cad76d00695a031255ffa76a6062110a05596fa8b64ae372c4)
|
||||
// Input contract: 0.1.0 (sha256:fc25104c077ab8c5c43f77611f505171585d2d40fd54c6538774ac17aae6cce3)
|
||||
// Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/companion-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check
|
||||
|
||||
@@ -63,7 +63,6 @@ export type WorkspaceDeletionState =
|
||||
|
||||
export type WorkspaceDeletionBlockerKind =
|
||||
| "last_accessible_workspace"
|
||||
| "revision_conflict"
|
||||
| "dirty_workdir"
|
||||
| "worker_removal_blocked"
|
||||
| "workdir_removal_blocked"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:07cfe53bfdd700cad76d00695a031255ffa76a6062110a05596fa8b64ae372c4)
|
||||
// Input contract: 0.1.0 (sha256:fc25104c077ab8c5c43f77611f505171585d2d40fd54c6538774ac17aae6cce3)
|
||||
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/repository-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-runtime-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:07cfe53bfdd700cad76d00695a031255ffa76a6062110a05596fa8b64ae372c4)
|
||||
// Input contract: 0.1.0 (sha256:fc25104c077ab8c5c43f77611f505171585d2d40fd54c6538774ac17aae6cce3)
|
||||
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/runtime-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-ticket-browser-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:07cfe53bfdd700cad76d00695a031255ffa76a6062110a05596fa8b64ae372c4)
|
||||
// Input contract: 0.1.0 (sha256:fc25104c077ab8c5c43f77611f505171585d2d40fd54c6538774ac17aae6cce3)
|
||||
// Options: ticket-objective-merge-request-browser-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/ticket-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_ticket_api_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-workdir-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:07cfe53bfdd700cad76d00695a031255ffa76a6062110a05596fa8b64ae372c4)
|
||||
// Input contract: 0.1.0 (sha256:fc25104c077ab8c5c43f77611f505171585d2d40fd54c6538774ac17aae6cce3)
|
||||
// Options: workdir-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/workdir-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_workdir_api_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-worker-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:07cfe53bfdd700cad76d00695a031255ffa76a6062110a05596fa8b64ae372c4)
|
||||
// Input contract: 0.1.0 (sha256:fc25104c077ab8c5c43f77611f505171585d2d40fd54c6538774ac17aae6cce3)
|
||||
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/worker-launch-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check
|
||||
|
||||
@@ -135,7 +135,7 @@ function repositoryArray(value: unknown, path: string): unknown[] {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function repositorySourceRevision(value: unknown, path: string): number {
|
||||
function nonnegativeSafeInteger(value: unknown, path: string): number {
|
||||
const parsed = integer(value, path);
|
||||
if (parsed < 0) {
|
||||
throw new Error(`${path} must be between 0 and Number.MAX_SAFE_INTEGER`);
|
||||
@@ -833,7 +833,7 @@ export function parseRepositorySshConnectionProbeResponse(
|
||||
}
|
||||
|
||||
const WORKSPACE_DELETION_MAX_OPERATION_ID_BYTES = 128;
|
||||
const WORKSPACE_DELETION_MAX_REVISION_BYTES = 128;
|
||||
const WORKSPACE_DELETION_MAX_UPDATED_AT_BYTES = 128;
|
||||
const WORKSPACE_DELETION_MAX_BLOCKERS = 1024;
|
||||
const WORKSPACE_DELETION_MAX_CHILD_OPERATION_IDS = 4096;
|
||||
const WORKSPACE_DELETION_MAX_RESOURCE_VALUE_BYTES = 128;
|
||||
@@ -872,7 +872,6 @@ const deletionStates = new Set<WorkspaceDeletionState>([
|
||||
]);
|
||||
const deletionBlockerKinds = new Set<WorkspaceDeletionBlockerKind>([
|
||||
"last_accessible_workspace",
|
||||
"revision_conflict",
|
||||
"dirty_workdir",
|
||||
"worker_removal_blocked",
|
||||
"workdir_removal_blocked",
|
||||
@@ -981,7 +980,7 @@ export function parseWorkspaceDeletionPreflightResponse(
|
||||
expected_workspace_updated_at: deletionBoundedString(
|
||||
item.expected_workspace_updated_at,
|
||||
"Workspace deletion preflight.expected_workspace_updated_at",
|
||||
WORKSPACE_DELETION_MAX_REVISION_BYTES,
|
||||
WORKSPACE_DELETION_MAX_UPDATED_AT_BYTES,
|
||||
),
|
||||
can_delete: boolean(
|
||||
item.can_delete,
|
||||
@@ -1089,7 +1088,7 @@ export function parseHostListResponse(value: unknown): HostListResponse {
|
||||
["workspace_id", "limit", "items", "source", "diagnostics"],
|
||||
"host list response",
|
||||
);
|
||||
const limit = repositorySourceRevision(
|
||||
const limit = nonnegativeSafeInteger(
|
||||
response.limit,
|
||||
"host list response.limit",
|
||||
);
|
||||
|
||||
@@ -1278,7 +1278,6 @@ Deno.test("Worker Console route resolves logical Worker authority before Runtime
|
||||
consolePage.includes('sendWorkerControl("cancel")') &&
|
||||
consolePage.includes("lifecycleMethod(command)") &&
|
||||
consolePage.includes("command_id: commandId") &&
|
||||
!consolePage.includes("expected_worker_state_revision") &&
|
||||
!consolePage.includes("expected_execution_generation") &&
|
||||
consolePage.includes("onsubmit={handleComposerSubmit}") &&
|
||||
consolePage.includes("disabled={!composerEditable}") &&
|
||||
|
||||
@@ -177,7 +177,7 @@ Deno.test("Merge Request routes distinguish recorded approval from live source o
|
||||
),
|
||||
);
|
||||
assertEquals(detail.includes("Recorded integration approval"), true);
|
||||
assertEquals(detail.includes("Live source revision"), true);
|
||||
assertEquals(detail.includes("Live source ref"), true);
|
||||
assertEquals(detail.includes("Source observation error"), true);
|
||||
});
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ export function sourceReviewFreshness(
|
||||
return `Fresh source review required: no effective verdict exists for ${source}.`;
|
||||
}
|
||||
|
||||
// Source/integration approval can survive rescope; only this exact revision
|
||||
// Source/integration approval can survive rescope; only this exact item snapshot
|
||||
// and linked-result attestation approves the current Ticket requirements.
|
||||
export function currentRequirementApprovalStatus(
|
||||
evidence: TicketEvidenceSummary,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { DriveEntryRef } from "#lib/generated/drive-api.ts";
|
||||
|
||||
/** Human-facing latest-only link: name, path, revision and bearer tokens are absent. */
|
||||
/** Human-facing latest-only link: name, path, content digest and bearer tokens are absent. */
|
||||
export function driveHref(entry: DriveEntryRef): string {
|
||||
if (
|
||||
!/^[1-9][0-9]{0,18}$/.test(entry.node_id) ||
|
||||
|
||||
@@ -97,7 +97,7 @@ function optionalBoundedString(
|
||||
return boundedStringValue(value, context, maxBytes);
|
||||
}
|
||||
|
||||
function optionalRevision(
|
||||
function optionalByteCount(
|
||||
value: unknown,
|
||||
context: string,
|
||||
): number | null | undefined {
|
||||
@@ -250,7 +250,7 @@ function parseWorkspaceProfileSourceSummary(
|
||||
502,
|
||||
);
|
||||
}
|
||||
const sizeBytes = optionalRevision(item.size_bytes, "Profile source catalog");
|
||||
const sizeBytes = optionalByteCount(item.size_bytes, "Profile source catalog");
|
||||
if (sizeBytes === undefined || sizeBytes === null) {
|
||||
throw new ProfileApiError(
|
||||
"Profile source catalog returned an invalid response.",
|
||||
|
||||
@@ -53,9 +53,9 @@ Deno.test("Git Workdir with a selector shows selector at current ref", () => {
|
||||
Deno.test("non-Git Workdir does not receive Git hash formatting", () => {
|
||||
assertEquals(
|
||||
formatCurrentWorkdirCheckout(
|
||||
workdir("snapshot", "revision-value"),
|
||||
workdir("snapshot", "snapshot-id"),
|
||||
"archive",
|
||||
),
|
||||
"snapshot · revision-value",
|
||||
"snapshot · snapshot-id",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -47,7 +47,7 @@ function attachment(
|
||||
};
|
||||
}
|
||||
|
||||
Deno.test("logical config sidebar label is not fabricated as a repository revision", () => {
|
||||
Deno.test("logical config sidebar label is not fabricated as a repository checkout", () => {
|
||||
const meta = sidebarWorkdirMeta([attachment("workspace-config", {
|
||||
display_name: "Workspace configuration",
|
||||
source: { kind: "workspace_config", access: "read_write", content_path: "/workspace-config", purpose: "Configuration" },
|
||||
@@ -87,6 +87,17 @@ Deno.test("Worker sidebar Workdir label uses the creation branch before observat
|
||||
assertEquals(meta.text, "main:develop");
|
||||
});
|
||||
|
||||
Deno.test("Worker sidebar Workdir label shows the creation ref before a current checkout is observed", () => {
|
||||
const meta = sidebarWorkdirMeta([
|
||||
attachment("checkout", {
|
||||
creation_selector: "refs/tags/release",
|
||||
creation_ref: "0123456789abcdef0123456789abcdef01234567",
|
||||
}),
|
||||
]);
|
||||
|
||||
assertEquals(meta.text, "main:creation-ref@0123456789ab");
|
||||
});
|
||||
|
||||
Deno.test("Worker sidebar Workdir label marks detached HEAD instead of reusing creation branch", () => {
|
||||
const meta = sidebarWorkdirMeta([
|
||||
attachment("checkout", {
|
||||
|
||||
@@ -38,10 +38,10 @@ function attachmentLabel(attachment: SidebarWorkdirAttachment): string {
|
||||
const repository = workdir?.source.kind === "repository"
|
||||
? clean(workdir.source.repository_key)
|
||||
: clean(attachment.repository_key);
|
||||
return `${repository ?? "unknown-repo"}:${revisionLabel(attachment)}`;
|
||||
return `${repository ?? "unknown-repo"}:${checkoutLabel(attachment)}`;
|
||||
}
|
||||
|
||||
function revisionLabel(attachment: SidebarWorkdirAttachment): string {
|
||||
function checkoutLabel(attachment: SidebarWorkdirAttachment): string {
|
||||
const workdir = attachment.working_directory;
|
||||
if (!workdir) {
|
||||
return `unknown@${shortReference(attachment.working_directory_id)}`;
|
||||
@@ -66,7 +66,7 @@ function revisionLabel(attachment: SidebarWorkdirAttachment): string {
|
||||
const creationReference = clean(workdir.creation_ref);
|
||||
if (creationSelector || creationReference) {
|
||||
return explicitReferenceFallback(
|
||||
"revision",
|
||||
"creation-ref",
|
||||
creationReference ?? creationSelector,
|
||||
);
|
||||
}
|
||||
@@ -84,7 +84,7 @@ function branchName(selector: string | null): string | null {
|
||||
}
|
||||
|
||||
function explicitReferenceFallback(
|
||||
kind: "detached" | "revision",
|
||||
kind: "detached" | "creation-ref",
|
||||
reference: string | null,
|
||||
): string {
|
||||
return reference ? `${kind}@${shortReference(reference)}` : kind;
|
||||
|
||||
@@ -75,7 +75,7 @@ test("renders the subject index as the Memory product entry", () => {
|
||||
.toBeNull();
|
||||
expect(screen.getByText("subject-1")).not.toBeNull();
|
||||
expect(screen.getByText("Not connected")).not.toBeNull();
|
||||
expect(screen.queryByText("Store revision", { exact: true })).toBeNull();
|
||||
expect(screen.queryByText("Memory fingerprint", { exact: true })).toBeNull();
|
||||
expect(screen.getByText("1 shown · more available")).not.toBeNull();
|
||||
expect(screen.getByRole("link", { name: "First page" }).getAttribute("href"))
|
||||
.toBe("/w/workspace-1/memory");
|
||||
|
||||
@@ -114,7 +114,6 @@ test("saved settings have no editable form, badges or raw data expanded; each te
|
||||
);
|
||||
expect(document.querySelectorAll("details[open]")).toHaveLength(0);
|
||||
expect(document.querySelector(".badge")).toBeNull();
|
||||
expect(screen.queryByText("Revision", { exact: true })).toBeNull();
|
||||
expect(
|
||||
screen.getByText(identityFixture().public_bundle!.public_key_fingerprint),
|
||||
).toBeTruthy();
|
||||
|
||||
@@ -197,12 +197,12 @@ Deno.test("config source API rejects mismatched entry map paths", async () => {
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("config source API rejects removed snapshot revision fields and oversized entry content", () => {
|
||||
Deno.test("config source API rejects unknown snapshot fields and oversized entry content", () => {
|
||||
assertThrows(
|
||||
() =>
|
||||
parseWorkspaceConfigTreeResponse({
|
||||
...tree,
|
||||
snapshot: { ...snapshot, revision: 7 },
|
||||
snapshot: { ...snapshot, unexpected_field: true },
|
||||
}),
|
||||
ConfigSourceApiError,
|
||||
"invalid response",
|
||||
|
||||
@@ -169,7 +169,6 @@ Deno.test("generated WASM diagnostics carry snapshot provenance", () => {
|
||||
}>;
|
||||
assertEquals(diagnostics[0].path, "workspace.dcdl");
|
||||
assertEquals(diagnostics[0].tree_digest, fixtureSnapshot(snapshot).digest);
|
||||
assertEquals("revision" in diagnostics[0], false);
|
||||
assertEquals(diagnostics[0].kind, "syntax");
|
||||
});
|
||||
|
||||
@@ -938,7 +937,6 @@ Deno.test("generated WASM returns to the same content digest and enforces entry
|
||||
content: "{ broken = ; }",
|
||||
}]) as ConfigTreeSnapshot;
|
||||
assertEquals(changed.digest === base.digest, false);
|
||||
assertEquals("revision" in changed, false);
|
||||
const diagnostics = analyze_snapshot(changed, "main.dcdl", undefined) as Array<{ tree_digest: string }>;
|
||||
assertEquals(diagnostics.length > 0, true);
|
||||
assertEquals(diagnostics.every((diagnostic) => diagnostic.tree_digest === changed.digest), true);
|
||||
|
||||
@@ -74,7 +74,7 @@ Deno.test("Repository Access distinguishes permission, conflict, field, and miss
|
||||
repositoryAccessRequestError(409, "rotate the key").message.includes(
|
||||
"Reload",
|
||||
),
|
||||
"409 should explain revision recovery",
|
||||
"409 should explain conflict recovery",
|
||||
);
|
||||
assert(
|
||||
repositoryAccessRequestError(422, "rotate the key").message.includes(
|
||||
|
||||
@@ -43,7 +43,7 @@ capture error is expected. To repeat dark captures, use a scenario copy with
|
||||
|
||||
## Implementer-owned visual review
|
||||
|
||||
- Baseline revision: `e939cd4e4b1f6b63b81411fd7766062f2d69ad0d`.
|
||||
- Baseline commit: `e939cd4e4b1f6b63b81411fd7766062f2d69ad0d`.
|
||||
- Before: `.svelte-kit/t717/visual/before-final-light` and `before-dark`.
|
||||
These use an isolated build under `.svelte-kit/t717/baseline-source`, with the
|
||||
changed production form, catalog API, model, and CSS restored from baseline
|
||||
|
||||
@@ -700,15 +700,14 @@ Deno.test("Memory changes preserve server order without interpreting opaque iden
|
||||
assertEquals(parseSubjektivMemoryReadResponse({ ...detailFixture(), change_id: "z/earlier", current_change_id: "a/current" }).change_id, "z/earlier");
|
||||
});
|
||||
|
||||
Deno.test("Memory identities reject numeric counters, empty and oversized strings, and legacy fields", () => {
|
||||
Deno.test("Memory identities reject numeric counters, empty and oversized strings, and unknown fields", () => {
|
||||
for (const value of [3, "", "x".repeat(513)]) {
|
||||
assertThrows(() => parseSubjektivMemoryReadResponse({ ...detailFixture(), change_id: value }), "bounded identifier");
|
||||
assertThrows(() => parseSubjektivMemoryReadResponse({ ...detailFixture(), current_change_id: value }), "bounded identifier");
|
||||
assertThrows(() => parseSubjektivSubjectResponse({ ...subject(), memory_fingerprint: value }), "bounded identifier");
|
||||
}
|
||||
assertThrows(() => parseSubjektivMemoryReadResponse({ ...detailFixture(), revision: 2 }), "unknown field");
|
||||
assertThrows(() => parseSubjektivSubjectResponse({ ...subject(), behavior_revision: 2 }), "unknown field");
|
||||
assertThrows(() => parseSubjektivSubjectResponse({ ...subject(), store_revision: 12 }), "unknown field");
|
||||
assertThrows(() => parseSubjektivMemoryReadResponse({ ...detailFixture(), unexpected_field: true }), "unknown field");
|
||||
assertThrows(() => parseSubjektivSubjectResponse({ ...subject(), unexpected_field: true }), "unknown field");
|
||||
});
|
||||
|
||||
Deno.test("Behavior CAS sends the observed text byte-for-byte including empty content", async () => {
|
||||
|
||||
@@ -93,6 +93,19 @@ Deno.test("profile settings requests use scoped API and strictly validate respon
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("profile source byte counts accept nonnegative safe integers and reject missing or malformed values", () => {
|
||||
for (const sizeBytes of [0, 128, Number.MAX_SAFE_INTEGER]) {
|
||||
const value = profileSettingsFixture();
|
||||
(value.sources as Record<string, unknown>[])[0].size_bytes = sizeBytes;
|
||||
assertEquals(parseProfileSettingsResponse(value).sources[0].size_bytes, sizeBytes);
|
||||
}
|
||||
for (const sizeBytes of [undefined, null, -1, 1.5, Number.MAX_SAFE_INTEGER + 1, "128"]) {
|
||||
const value = profileSettingsFixture();
|
||||
(value.sources as Record<string, unknown>[])[0].size_bytes = sizeBytes;
|
||||
assertThrows(() => parseProfileSettingsResponse(value), ProfileApiError);
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("workspace metadata requests use generated DTO shapes", async () => {
|
||||
const originalFetch = globalThis.fetch;
|
||||
const requests: Array<{ url: string; init?: RequestInit }> = [];
|
||||
@@ -247,8 +260,7 @@ Deno.test("Workspace signing identity parser validates active and pending public
|
||||
value.private_material_ref = "must-not-be-accepted";
|
||||
},
|
||||
(value: Record<string, unknown>) => {
|
||||
(value.identity as Record<string, unknown>).revision =
|
||||
Number.MAX_SAFE_INTEGER + 1;
|
||||
(value.identity as Record<string, unknown>).unexpected_field = true;
|
||||
},
|
||||
(value: Record<string, unknown>) => {
|
||||
(value.identity as Record<string, unknown>).public_key = "x".repeat(
|
||||
@@ -287,7 +299,7 @@ Deno.test("workspace metadata parser rejects incomplete or stale response fields
|
||||
workspace_id: "workspace-test",
|
||||
display_name: "Workspace",
|
||||
created_at: "2026-01-01T00:00:00Z",
|
||||
revision: "sha256:metadata",
|
||||
updated_at: "2026-01-02T00:00:00Z",
|
||||
source: "workspace-config",
|
||||
diagnostics: [],
|
||||
workspace_path: "/legacy/path",
|
||||
|
||||
@@ -199,10 +199,10 @@ Deno.test("Runtime validators reject unknown object keys and enum variants", ()
|
||||
});
|
||||
|
||||
Deno.test("Runtime validators reject invalid binding identities and bounded collection overflow", () => {
|
||||
const unsafeRevision = structuredClone(detail());
|
||||
Object.assign(unsafeRevision.trust_key, { binding_id: 1 });
|
||||
const invalidBinding = structuredClone(detail());
|
||||
Object.assign(invalidBinding.trust_key, { binding_id: 1 });
|
||||
assertThrows(
|
||||
() => parseWorkspaceRuntimeDetail(unsafeRevision),
|
||||
() => parseWorkspaceRuntimeDetail(invalidBinding),
|
||||
"must be a string",
|
||||
);
|
||||
|
||||
@@ -506,11 +506,11 @@ Deno.test("Runtime trust replacement preserves binding conflicts without retryin
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Runtime trust replacement rejects legacy counter conflict responses", async () => {
|
||||
Deno.test("Runtime trust replacement rejects unknown fields and missing binding identity in conflict responses", async () => {
|
||||
const fetchImpl = (() => Promise.resolve(Response.json({
|
||||
error: "stale_binding",
|
||||
message: "Stale trust",
|
||||
current_revision: 3,
|
||||
unexpected_field: true,
|
||||
}, { status: 409 }))) as typeof fetch;
|
||||
try {
|
||||
await createRemoteRuntime("workspace-a", {
|
||||
|
||||
@@ -161,11 +161,11 @@ Deno.test("Skill parser fails closed on unknown fields and newer enum values", (
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Skill parser rejects removed revision fields and oversized collections or strings", () => {
|
||||
const legacyRevision = catalogFixture();
|
||||
(legacyRevision.projection as Record<string, unknown>).config_revision = 1;
|
||||
Deno.test("Skill parser rejects unknown projection fields and oversized collections or strings", () => {
|
||||
const legacyCounter = catalogFixture();
|
||||
(legacyCounter.projection as Record<string, unknown>).unexpected_field = 1;
|
||||
assertContractError(
|
||||
() => parseSkillCatalogResponse(legacyRevision),
|
||||
() => parseSkillCatalogResponse(legacyCounter),
|
||||
"unknown fields",
|
||||
);
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ Deno.test("workspace creation rejects missing and malformed repository response
|
||||
for (
|
||||
const value of [undefined, false, {}, {
|
||||
...currentInitialRepository,
|
||||
source_revision: -1,
|
||||
source_fingerprint: -1,
|
||||
}]
|
||||
) {
|
||||
assertThrows(
|
||||
@@ -152,13 +152,13 @@ Deno.test("stale repository aliases fail closed at the JSON boundary", () => {
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("repository JSON rejects removed source revision counters", () => {
|
||||
Deno.test("repository JSON rejects unknown fields", () => {
|
||||
const stale = structuredClone(repositoryList) as Record<string, unknown>;
|
||||
const items = stale.items as Array<Record<string, unknown>>;
|
||||
items[0].source_revision = 1;
|
||||
items[0].unexpected_field = 1;
|
||||
assertThrows(
|
||||
() => parseRepositoryListResponse(stale),
|
||||
".source_revision is not part of the wire contract",
|
||||
".unexpected_field is not part of the wire contract",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -322,6 +322,21 @@ Deno.test("Workspace deletion DTOs fail closed and preserve durable operation st
|
||||
}),
|
||||
"unexpected is not part",
|
||||
);
|
||||
assertThrows(
|
||||
() =>
|
||||
parseWorkspaceDeletionPreflightResponse({
|
||||
...preflight,
|
||||
expected_workspace_updated_at: "x".repeat(129),
|
||||
}),
|
||||
".expected_workspace_updated_at is too long",
|
||||
);
|
||||
for (const parse of [parseWorkspaceDeletionPreflightResponse, parseWorkspaceDeletionOperationResponse]) {
|
||||
const value = parse === parseWorkspaceDeletionPreflightResponse ? preflight : operation;
|
||||
assertThrows(
|
||||
() => parse({ ...value, blockers: [{ ...operation.blockers[0], kind: "unknown_blocker" }] }),
|
||||
".kind is invalid",
|
||||
);
|
||||
}
|
||||
assertThrows(
|
||||
() =>
|
||||
parseWorkspaceDeletionOperationResponse({
|
||||
|
||||
Reference in New Issue
Block a user