From fff5e6f59eea28542f4b69cc340a3c64ef4926d8 Mon Sep 17 00:00:00 2001 From: DongHyeonka Date: Wed, 19 Aug 2026 16:34:31 +0900 Subject: [PATCH] fix: gate Studio routes behind a session and repair the broken main build Three defects found while running the release checklist against a live backend, all on main. 1. Every TechLog route registered `access: "public"`, including the whole Studio surface. `decideRouteAccessForDefinition` was therefore a no-op for Studio: a signed-out visitor who typed /studio, /studio/documents, or /studio/assets got the Studio shell rendered, and the page went on to issue Studio API calls. Access is now derived from the spec's own `layoutGroup`, so a newly added Studio route is gated by construction rather than by remembering to restate it. Verified against a production-profile build: /studio* now renders the sign-in surface, / and /explore are unchanged, and after signing in the router returns to the originally requested Studio screen. 2. `public/release-manifest.json` still declared the contract set at 2.0.0 while the vendored contract had moved to 3.0.0 (eb86708). Boot verification fails closed on that mismatch, so `pnpm dev` served a blank screen. Regenerated from the same producer `dist/` uses. 3. `release-manifest.test.ts` asserted the same stale 2.0.0. The literal is deliberately independent of `EXPECTED_CONTRACT_SET_PACKAGES` (see the comment above it), so it is updated in place, not derived. Also drops a dead `= null` initializer that failed `no-useless-assignment`. check:types, lint, check:architecture, check:tech-log-contract and check:dev-release-manifest all pass. test:all is 1818 passed with one pre-existing load-dependent flake (provider-guardian-transaction, passes in isolation, untouched by this change). Co-Authored-By: Claude Opus 5 (1M context) --- public/release-manifest.json | 8 ++++---- .../tech-log/adapters/http/asset-upload-transport.ts | 2 +- .../tech-log/contracts/tech-log-route-contract.ts | 8 +++++++- tests/runtime-schema/release-manifest.test.ts | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/public/release-manifest.json b/public/release-manifest.json index e10a2e4..d4dc30e 100644 --- a/public/release-manifest.json +++ b/public/release-manifest.json @@ -38,14 +38,14 @@ }, "contractSet": { "setAlgorithm": "CA_CONTRACT_SET_V1", - "setDigest": "sha256:e0da77655f51592ece583826d5fc6b092f57dd2bf63307e45e7e77283e6bf437", + "setDigest": "sha256:261ac63030fcbcef8bd0b7087d29120996a9f580f455739dad245141860c1fe5", "packages": [ { "packageId": "@tech-log/studio-contract", - "version": "2.0.0", - "digest": "sha256:99f54f56ea0c582eafdbdf9be5653e3384bef0a1b08bff67f3147ee0292019ea", + "version": "3.0.0", + "digest": "sha256:6cae9924403d0761f401643a022980b8e04183eea0d890c143c9fbbbbc7431e4", "runtimeProtocolVersion": 1, - "sourceRevision": "ce2e748" + "sourceRevision": "b20d7a2" } ] } diff --git a/src/features/tech-log/adapters/http/asset-upload-transport.ts b/src/features/tech-log/adapters/http/asset-upload-transport.ts index 85a6540..f13ef0f 100644 --- a/src/features/tech-log/adapters/http/asset-upload-transport.ts +++ b/src/features/tech-log/adapters/http/asset-upload-transport.ts @@ -114,7 +114,7 @@ export function createAssetUploadTransport( return parsed.data; } - let problemBody: unknown = null; + let problemBody: unknown; try { problemBody = await response.json(); } catch { diff --git a/src/features/tech-log/contracts/tech-log-route-contract.ts b/src/features/tech-log/contracts/tech-log-route-contract.ts index 077e6b1..a4b8ec7 100644 --- a/src/features/tech-log/contracts/tech-log-route-contract.ts +++ b/src/features/tech-log/contracts/tech-log-route-contract.ts @@ -139,7 +139,13 @@ export const TECH_LOG_ROUTE_REGISTRY = Object.freeze( spec.routeId, Object.freeze({ ...spec, - access: "public", + // Studio routes are the authenticated surface. Deriving this from the + // spec's own `layoutGroup` -- rather than restating it per route -- + // keeps a newly added Studio route gated by construction. Registering + // every TechLog route as "public" made `decideRouteAccessForDefinition` + // a no-op for Studio: a signed-out visitor who typed /studio got the + // Studio shell rendered instead of the sign-in surface. + access: spec.layoutGroup === "STUDIO" ? "session-required" : "public", loadingSurface: spec.path.endsWith("*") ? "none" : "app-shell", errorSurface: spec.path.endsWith("*") ? "not-found" diff --git a/tests/runtime-schema/release-manifest.test.ts b/tests/runtime-schema/release-manifest.test.ts index 365f61e..750ef1e 100644 --- a/tests/runtime-schema/release-manifest.test.ts +++ b/tests/runtime-schema/release-manifest.test.ts @@ -113,7 +113,7 @@ describe("expected contract set composition", () => { (entry) => entry.packageId === "@tech-log/studio-contract", ); expect(techLog).toBeTruthy(); - expect(techLog?.version).toBe("2.0.0"); + expect(techLog?.version).toBe("3.0.0"); }); });