-
Notifications
You must be signed in to change notification settings - Fork 328
feat(skip): enable proven static layout transport skips #1437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f933043
6bbc788
370e5d8
58dfd28
deff83f
e7ba059
d9e8205
60f57f0
1e5d1e6
b04d9b7
e1aef58
7bbf954
7702c68
6de6236
d0004bd
1863f07
61bd846
26ae459
8b4713b
fcaac5d
668dc7a
a90d4cf
e539ec0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| import type { ArtifactCompatibilityEnvelope } from "./artifact-compatibility.js"; | ||
| import { | ||
| buildCacheVariantWithRouteBudget, | ||
| DEFAULT_CACHE_VARIANT_BUDGET, | ||
| type StaticLayoutCacheProofOutputScope, | ||
| } from "./cache-proof.js"; | ||
| import { | ||
| CLIENT_REUSE_MANIFEST_SKIP_VERIFICATION_ENTRY_BUDGET, | ||
| countUtf8Bytes, | ||
| DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS, | ||
| serializeClientReuseManifest, | ||
| } from "./client-reuse-manifest.js"; | ||
| import { AppElementsWire, type AppElements } from "./app-elements.js"; | ||
| import { | ||
| createStaticLayoutClientReuseArtifactCompatibility, | ||
| createStaticLayoutClientReusePayloadHash, | ||
| createStaticLayoutClientReuseRouteId, | ||
| } from "./static-layout-client-reuse-proof.js"; | ||
| import type { AppRouterState } from "./app-browser-state.js"; | ||
|
|
||
| type ClientReuseManifestLimits = typeof DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS; | ||
|
|
||
| type VisibleAppState = Pick<AppRouterState, "elements" | "visibleCommitVersion">; | ||
|
|
||
| type BrowserClientReuseManifestEntry = Readonly<{ | ||
| artifactCompatibility: ArtifactCompatibilityEnvelope; | ||
| id: string; | ||
| payloadHash: string; | ||
| privacy: "public"; | ||
| variantCacheKey: string; | ||
| }>; | ||
|
|
||
| type CreateClientReuseManifestHeaderOptions = Readonly<{ | ||
| limits?: ClientReuseManifestLimits; | ||
| }>; | ||
|
|
||
| function capClientReuseManifestProducerLimits( | ||
| limits: ClientReuseManifestLimits, | ||
| ): ClientReuseManifestLimits { | ||
| return { | ||
| ...limits, | ||
| maxEntryCount: Math.min( | ||
| limits.maxEntryCount, | ||
| CLIENT_REUSE_MANIFEST_SKIP_VERIFICATION_ENTRY_BUDGET, | ||
| ), | ||
| }; | ||
| } | ||
|
|
||
| function serializeBoundedClientReuseManifest(input: { | ||
| entries: readonly BrowserClientReuseManifestEntry[]; | ||
| limits: ClientReuseManifestLimits; | ||
| visibleCommitVersion: number; | ||
| }): string | null { | ||
| const entries = input.entries.slice(0, input.limits.maxEntryCount); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The binary search for bounded serialization is clean. One edge case worth noting: if Non-blocking — just documenting the contract. |
||
| // Binary search for the largest prefix that fits. JSON array serialization | ||
| // is monotonic here: adding an entry cannot reduce the byte count. | ||
| let low = 1; | ||
|
NathanDrake2406 marked this conversation as resolved.
|
||
| let high = entries.length; | ||
| let best: string | null = null; | ||
|
|
||
| while (low <= high) { | ||
| const size = Math.floor((low + high) / 2); | ||
| const serialized = serializeClientReuseManifest({ | ||
| entries: entries.slice(0, size), | ||
| replayWindow: { | ||
| validFromVisibleCommitVersion: input.visibleCommitVersion, | ||
| validUntilVisibleCommitVersion: input.visibleCommitVersion, | ||
| }, | ||
| visibleCommitVersion: input.visibleCommitVersion, | ||
| }); | ||
| if (countUtf8Bytes(serialized) <= input.limits.maxManifestBytes) { | ||
| best = serialized; | ||
| low = size + 1; | ||
| } else { | ||
| high = size - 1; | ||
| } | ||
| } | ||
|
|
||
| return best; | ||
| } | ||
|
|
||
| function hasRetainedElement(elements: AppElements, elementId: string): boolean { | ||
| return Object.hasOwn(elements, elementId); | ||
| } | ||
|
|
||
| function createStaticLayoutEntry(input: { | ||
| artifactCompatibility: ArtifactCompatibilityEnvelope; | ||
| layoutId: string; | ||
| }): BrowserClientReuseManifestEntry | null { | ||
| const routeId = createStaticLayoutClientReuseRouteId(input.layoutId); | ||
| const output: StaticLayoutCacheProofOutputScope = { | ||
| kind: "layout", | ||
| layoutId: input.layoutId, | ||
| rootBoundaryId: input.artifactCompatibility.rootBoundaryId, | ||
| routeId, | ||
| }; | ||
| const candidateVariant = buildCacheVariantWithRouteBudget({ | ||
| budget: DEFAULT_CACHE_VARIANT_BUDGET, | ||
| dimensions: [], | ||
| output, | ||
| routeBudget: { | ||
| routeId: output.routeId, | ||
| variantCacheKeys: [], | ||
| }, | ||
| }); | ||
| if (candidateVariant.kind !== "variant") { | ||
| return null; | ||
| } | ||
|
|
||
| const artifactCompatibility = createStaticLayoutClientReuseArtifactCompatibility({ | ||
| artifactCompatibility: input.artifactCompatibility, | ||
| layoutId: input.layoutId, | ||
| rootBoundaryId: output.rootBoundaryId, | ||
| routeId: output.routeId, | ||
| variantCacheKey: candidateVariant.variant.cacheKey, | ||
| }); | ||
|
|
||
| return { | ||
| artifactCompatibility, | ||
| id: input.layoutId, | ||
| payloadHash: createStaticLayoutClientReusePayloadHash({ | ||
| artifactCompatibility, | ||
| layoutId: input.layoutId, | ||
| rootBoundaryId: output.rootBoundaryId, | ||
| routeId: output.routeId, | ||
| variantCacheKey: candidateVariant.variant.cacheKey, | ||
| }), | ||
| privacy: "public", | ||
| variantCacheKey: candidateVariant.variant.cacheKey, | ||
| }; | ||
| } | ||
|
|
||
| export function createClientReuseManifestHeaderFromVisibleAppState( | ||
| state: VisibleAppState, | ||
| options: CreateClientReuseManifestHeaderOptions = {}, | ||
| ): string | null { | ||
| const limits = capClientReuseManifestProducerLimits( | ||
| options.limits ?? DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS, | ||
| ); | ||
| const metadata = AppElementsWire.readMetadata(state.elements); | ||
| const entries: BrowserClientReuseManifestEntry[] = []; | ||
|
|
||
| for (const layoutId of metadata.layoutIds) { | ||
| if (entries.length >= limits.maxEntryCount) break; | ||
|
NathanDrake2406 marked this conversation as resolved.
|
||
| if (layoutId.length > limits.maxEntryIdLength) continue; | ||
| if (metadata.layoutFlags[layoutId] !== "s") continue; | ||
| if (!hasRetainedElement(state.elements, layoutId)) continue; | ||
|
|
||
| const parsedKey = AppElementsWire.parseElementKey(layoutId); | ||
| if (parsedKey?.kind !== "layout") continue; | ||
|
|
||
| const entry = createStaticLayoutEntry({ | ||
| artifactCompatibility: metadata.artifactCompatibility, | ||
| layoutId, | ||
| }); | ||
| if (entry) { | ||
| entries.push(entry); | ||
| } | ||
| } | ||
|
|
||
| if (entries.length === 0) { | ||
| return null; | ||
| } | ||
|
|
||
| return serializeBoundedClientReuseManifest({ | ||
| entries, | ||
| limits, | ||
| visibleCommitVersion: state.visibleCommitVersion, | ||
| }); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good design:
capClientReuseManifestProducerLimitsensures the browser never produces more entries than the server's verification budget (CLIENT_REUSE_MANIFEST_SKIP_VERIFICATION_ENTRY_BUDGET = 8). This prevents the guaranteedSKIP_ENTRY_COUNT_EXCEEDEDrejection that Codex P2 identified.The limit is applied as
Math.min(limits.maxEntryCount, budget)— this means if the default limit (64) is larger than the budget (8), the budget wins. If someone configures a custom limit below 8, that custom limit wins. Both directions are correct.