fix: forward every documented Studio query filter and pin canonicalInputIdentity
Two review Minor findings against the brief itself, both closed: - tests/mocks/handlers/tech-log-studio.ts silently dropped documented query filters instead of mirroring the mock gateway it wraps: listStudioDocuments forwarded only q/limit (dropping kind, publicationStatus, nextAction, projectId, sort, cursor), listStudioCatalog forwarded only type (dropping q/cursor/limit), and listStudioPublications ignored all four of its parameters outright. Added a shared queryParams() helper and forward every field each operation's projectRequest actually emits, plus a regression test that narrows the fixture set by kind through the real HTTP gateway (confirmed it fails without the fix). - canonicalInputIdentity (on the idempotency-safety path, reused by Task 6) had no test. Added three tests against mutationIntent(): a large Korean payload stays within the byte bound, the same input retried twice yields an identical identity, and a mid-codepoint truncation cut leaves no replacement character (confirmed the third fails without the strip). The known collision limitation of any bounded-length identity scheme is documented in the test file rather than solved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1d01a522de
commit
7424ed4594
@@ -23,6 +23,30 @@ async function json(work: () => Promise<unknown>, status = 200) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards every query parameter a `projectRequest` puts on the wire, not
|
||||
* just the ones a first pass happened to reach for. A handler that silently
|
||||
* drops a documented filter lets a later filter test pass for the wrong
|
||||
* reason — it would observe the *unfiltered* mock result and never learn the
|
||||
* parameter never left the URL.
|
||||
*/
|
||||
function queryParams(
|
||||
url: URL,
|
||||
stringNames: readonly string[],
|
||||
numberNames: readonly string[] = [],
|
||||
): Record<string, string | number> {
|
||||
const result: Record<string, string | number> = {};
|
||||
for (const name of stringNames) {
|
||||
const value = url.searchParams.get(name);
|
||||
if (value !== null) result[name] = value;
|
||||
}
|
||||
for (const name of numberNames) {
|
||||
const value = url.searchParams.get(name);
|
||||
if (value !== null) result[name] = Number(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function createTechLogStudioHandlers(
|
||||
gateway = createMockStudioGateway(),
|
||||
baseUrl = BASE,
|
||||
@@ -47,12 +71,14 @@ export function createTechLogStudioHandlers(
|
||||
),
|
||||
http.get(`${baseUrl}/api/v1/studio/documents`, ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
const limit = url.searchParams.get("limit");
|
||||
return json(() =>
|
||||
gateway.listDocuments({
|
||||
...(url.searchParams.get("q") ? { q: url.searchParams.get("q")! } : {}),
|
||||
...(limit ? { limit: Number(limit) } : {}),
|
||||
} as never),
|
||||
gateway.listDocuments(
|
||||
queryParams(
|
||||
url,
|
||||
["q", "kind", "publicationStatus", "nextAction", "projectId", "sort", "cursor"],
|
||||
["limit"],
|
||||
) as never,
|
||||
),
|
||||
);
|
||||
}),
|
||||
http.post(`${baseUrl}/api/v1/studio/documents`, async ({ request }) =>
|
||||
@@ -117,9 +143,14 @@ export function createTechLogStudioHandlers(
|
||||
),
|
||||
),
|
||||
),
|
||||
http.get(`${baseUrl}/api/v1/studio/publications`, () =>
|
||||
json(() => gateway.listPublications({})),
|
||||
),
|
||||
http.get(`${baseUrl}/api/v1/studio/publications`, ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
return json(() =>
|
||||
gateway.listPublications(
|
||||
queryParams(url, ["q", "type", "cursor"], ["limit"]) as never,
|
||||
),
|
||||
);
|
||||
}),
|
||||
http.post(
|
||||
`${baseUrl}/api/v1/studio/publications/:publicationId/unpublish`,
|
||||
async ({ request, params }) =>
|
||||
@@ -139,7 +170,9 @@ export function createTechLogStudioHandlers(
|
||||
http.get(`${baseUrl}/api/v1/studio/catalog`, ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
return json(() =>
|
||||
gateway.getCatalog({ type: url.searchParams.get("type") as never }),
|
||||
gateway.getCatalog(
|
||||
queryParams(url, ["type", "q", "cursor"], ["limit"]) as never,
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user