fix(gcp-cloud-run): include all workspace build dependencies#2608
Conversation
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
First-look adversarial review at HEAD cdca11bcee962864ba647ddc2fa90ff31a9b17cd. Small, focused Dockerfile fix (3 files, +61/-3) closing #2601 — the release-tag fresh-clone docker build fails because 5 workspace manifests + their sources aren't COPY'd. Reviewed against the class-of-drift lens (the reporter's core insight) and Cloud Run adapter runtime path.
Findings
Blockers: none.
Concerns: 3 — one on the coverage test's static source list, one on it not being wired into CI, one on Dockerfile build-order divergence from the root build script (inline C1/C2/C3).
Nits: 2 (inline N1/N2).
Green surface (verified)
- All 14 workspace manifests copied. Enumerated
packages/*at HEAD (aws-lambda, cli, core, engine, gcp-cloud-run, lint, parsers, player, producer, sdk, sdk-playground, shader-transitions, studio, studio-server) — every one has a matchingCOPY packages/<name>/package.jsonline. Manifest-drift is now dynamically detected on next workspace addition (C1 caveat notwithstanding). - Cross-package imports verified. Every
@hyperframes/{parsers,lint,studio-server}and@hyperframes/{sdk,sdk-playground}import frompackages/{core,producer,gcp-cloud-run}/src/*matches a source-tree COPY line — no obvious import that would still resolve to an absent tree at build time. - Build order works despite reversing root's topo-order —
parsers/package.jsonexportsmapbun/import/typesconditions to./src/*.ts(source), sobun run --cwd packages/core build(which invokestsc) can resolve@hyperframes/parserstypes from source without parsers'dist/being built first. Same forlint/studio-server. See C3 for the divergence. --frozen-lockfileinstall now succeeds — all 14 workspace symlinks resolvable.- Font-data generation and adapter build preserved — the
bunx tsx scripts/generate-font-data.tsstep andbun run --cwd packages/gcp-cloud-run buildtail are unchanged. - Small, focused diff — no scope creep beyond the reported bug.
What I didn't verify
- Runtime footprint impact. Copying 5 additional full source trees increases image size + Docker layer cache invalidation on any of those packages' source changes. Might be worth a
.dockerignoresweep onpackages/{lint,parsers,sdk,sdk-playground,studio-server}/test/ test-fixtures / node_modules if not already excluded. Not blocking; the fix is correct. - Whether the built
gcp-cloud-run/dist/server.jsbundle actually references any of the newly-copied source trees at RUNTIME — if the adapter bundle is self-contained (esbuild bundles workspace deps), the source COPYs are only needed at BUILD time and could theoretically be dropped in a later multi-stage refinement. Out of scope for this fix. - Layer 2 exhaustiveness on future imports. I sampled cross-package imports for the render path but didn't audit every symbol in the transitive graph.
- CI green post-merge — statusChecks are IN_PROGRESS at review time; the CI's own
bun run buildstep should catch import-resolution divergence between root and Dockerfile if the resolution ever regresses.
Merge gate
Correct closure of #2601 with a clean, minimal Dockerfile fix. C1/C2 are the most substantive — the coverage check is a nice belt-and-suspenders addition but only actually catches drift if it fires on future PRs; wiring it into CI (or into an existing check:* runner in the root package.json) locks in the value. C3 is a divergence smell worth aligning even if functionally correct today.
LGTM on the fix approach; holding C1/C2 as substantive follow-ups worth Miguel's decision before ship. Leaving as COMMENTED.
vanceingalls
left a comment
There was a problem hiding this comment.
Adversarial R1 at cdca11bce. Read the Dockerfile diff, the coverage-check .mjs, root package.json build script, sibling Dockerfile.test, packages/core/package.json scripts, issue #2601 body + reporter's follow-up comment, and enumerated 14 packages/*/package.json on master.
Right on the reported failure mode — 5 missing manifests copied, 5 new source trees copied, workspace deps built before producer/adapter, deterministic coverage check added. Mechanism addresses issue body's Layer 1 + Layer 2 and reporter's Layer 3 (all three layers). Coverage check is real static parse (not aspirational): regex-extracts COPY lines from the actual Dockerfile and diffs against readdirSync('packages/').
Three concerns, one blocking + two follow-ups.
1. build:hyperframes-runtime:modular was dropped entirely — is the modular artifact still needed at runtime? (P1, please clarify or restore)
The OLD Dockerfile's only core build step was bun run --filter @hyperframes/core build:hyperframes-runtime:modular — invoking SANDBOX_RUNTIME_VARIANT=modular tsx scripts/build-hyperframes-runtime-artifact.ts per packages/core/package.json. The NEW Dockerfile replaces this with bun run --cwd packages/core build, whose script chain is build:hyperframes-runtime && build:position-edits-render && tsc && rewrite-esm-extensions — NOT the :modular variant. The modular variant produces a distinct artifact (different env var → different output). Verification docker build ... success proves the image assembles but doesn't exercise the runtime; if the producer bundle or the Cloud Run server loads the modular runtime artifact at request time, this is a silent runtime regression that CI won't catch. Either (a) explain in the PR body why the modular variant is no longer needed here (and consider a note in the Dockerfile comment), or (b) add bun run --cwd packages/core build:hyperframes-runtime:modular back to the RUN chain after the packages/core build step.
2. Build order diverges from root package.json and sibling Dockerfile.test (P2, cross-scaffold drift)
Canonical order in root package.json build: {parsers,lint,studio-server} → core → the rest. Dockerfile.test (sibling scaffold) encodes exactly this: bun run --filter '@hyperframes/{parsers,lint,studio-server}' build && bun run --cwd packages/core build. Reporter's follow-up on #2601 also proposed this order. This PR builds core FIRST, then parsers/lint/sdk/sdk-playground/studio-server, then engine. It empirically builds (thanks to workspace-source resolution during core's own build), but diverges from three sources of truth. Suggest aligning with the canonical order — cheap cross-scaffold drift-safety, and future maintainers grepping either sibling won't be surprised.
3. Coverage check's source side is hardcoded; build-step layer isn't tested (P2, follow-up)
Manifest side is dynamic (readdirSync('packages/') → catches every new workspace). Sources side is a fixed 9-name literal (requiredSourcePackages); adding a new package that also needs its source in the Dockerfile won't be caught. And the reporter's Layer 3 (build-step order/completeness) isn't validated at all — the test locks copy state but not RUN state. Consider (a) deriving requiredSourcePackages from a parse of the RUN chain, or (b) adding an assertion that each package in the build-order chain has an earlier source COPY line. Not blocking on its own — the current check is a meaningful step up from the pre-PR state.
CI: Format + Preflight (lint + format) already FAILURE at head; several other checks still in progress. Held-until-green regardless of the above.
Reporter follow-up read: reporter's Layer 3 diagnosis IS addressed in spirit (all workspace deps get built before producer). Not refuted. Not blocking on follow-ups.
— Via
4bb21bf to
41e46f6
Compare
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
R2 delta review at HEAD 41e46f65656ceba90df6e0fb8eecf36a6c2dced3. Delta vs R1 SHA cdca11bcee:
Delta
Dockerfile:116— added&& bun run --cwd packages/core build:hyperframes-runtime:modular \between thecore buildstep and the parsers step. Restores theSANDBOX_RUNTIME_VARIANT=modularruntime artifact that R1'score builddidn't emit (R1'sbun run --cwd packages/core buildinvokesbuild:hyperframes-runtime— the non-modular variant — via the compositebuildscript). The old pre-PR command was--filter @hyperframes/core build:hyperframes-runtime:modular, so this restores byte-parity with what shipped atv0.7.60for the modular artifact consumers.check-dockerfile-workspaces.mjs— prettier line-wrapping on the two long output lines. No semantic change.
R1 concern verdict
| ID | Status | Notes |
|---|---|---|
C1 hardcoded requiredSourcePackages |
🟡 unchanged | List still 9 hardcoded entries. Future source-tree drift not detected. Explicit follow-up material. |
| C2 coverage test not wired into CI | 🟡 unchanged | Still no CI invocation of test:dockerfile-workspaces. Silent drift risk on future PRs. Explicit follow-up material. |
| C3 Dockerfile build order diverges from root | 🟡 unchanged | Still core → parsers → …; root builds parsers → core → …. Works via source-conditional exports; divergence remains. |
N1/N2 regex rigidity + readdirSync guard |
🟡 unchanged | Cosmetic; not addressed. |
Delta trace
build:hyperframes-runtime:modularscript definition inpackages/core/package.json:12—SANDBOX_RUNTIME_VARIANT=modular tsx scripts/build-hyperframes-runtime-artifact.ts. Distinct artifact from the defaultbuild:hyperframes-runtimeinvoked bycore build. Confirmed by re-readingpackages/core/package.jsonscripts.- The two build invocations write different artifact files under
packages/core/dist/hyperframes-runtime/(default +.modular.jsvariant), so no wasted work — both are required for downstream consumers. - Prettier formatting is a no-op on the runtime behavior of the coverage script.
Green surface
- Modular runtime restoration is byte-safe (net additive step; nothing removed).
- Prettier formatting reads clean.
- No new failure modes introduced by this delta.
- Verification claim ("Prior Docker/static verification remains valid; CI will rerun") is consistent with the shape of the delta.
Merge gate
Correct disposition of a subtle R1 oversight (modular runtime variant would have silently gone missing from the image otherwise). C1/C2/C3 still stand as pre-merge follow-ups worth Miguel's decision, but nothing regressed in this delta.
LGTM on the delta — leaving as COMMENTED.
vanceingalls
left a comment
There was a problem hiding this comment.
R2 verification at head 41e46f65656ceba90df6e0fb8eecf36a6c2dced3. Prior R1 CHANGES_REQUESTED at cdca11bce.
Delta since R1
Single-line addition at packages/gcp-cloud-run/Dockerfile:118:
&& bun run --cwd packages/core build:hyperframes-runtime:modular \
Chained after bun run --cwd packages/core build, before parsers/lint/sdk. Also: prettier formatting on check-dockerfile-workspaces.mjs (no semantic change).
R1 P1 blocker — resolved
Confirmed via packages/core/package.json at new SHA: build:hyperframes-runtime:modular = SANDBOX_RUNTIME_VARIANT=modular tsx scripts/build-hyperframes-runtime-artifact.ts — byte-parity with the pre-PR command. Composite build script invokes build:hyperframes-runtime (non-modular) + tsc + rewrites, so the new line is additive: both artifacts (default + .modular variant) land in the image. Modular runtime consumers at request time no longer silently regress. Order is safe — tsx + the artifact script are already resolvable after the full core build completes.
R1 P2 nits — status
| ID | Status |
|---|---|
C1 hardcoded requiredSourcePackages list |
🟡 unchanged, follow-up |
C2 test:dockerfile-workspaces not wired into CI |
🟡 unchanged, follow-up |
C3 build-order divergence vs Dockerfile.test |
🟡 unchanged, follow-up |
Deferred per follow-up track; not blocking.
CI state at head
Format: SUCCESS ✓ (was FAILURE at R1). Preflight (lint + format): SUCCESS. Remainder of CI still in-progress but unrelated to this scope. mergeStateStatus=BLOCKED reflects reviewer + in-progress checks, not code health.
Peer state at new head
Rames posted COMMENTED LGTM on the delta — convergent read on additive/byte-parity nature; same C1/C2/C3 follow-up disposition.
Verdict
RIGHT + no residual blocker. Approving the delta.
— Via
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
R3 delta review at HEAD 8bd3038bb. Delta vs R2 SHA 41e46f65:
Delta
Two files, all targeted at R1 concerns:
package.json:27-28— newcheck:gcp-cloud-run-dockerfilescript (bun run --cwd packages/gcp-cloud-run test:dockerfile-workspaces), chained into rootlintbetweencheck:workspace-contractsandoxlint. Every futurebun run lintinvocation — including.github/workflows/ci.yml:105(bun run lint) — will fire the coverage test.packages/gcp-cloud-run/Dockerfile:117-124— build-step reordering. New order:parsers → lint → studio-server → core → core:modular → sdk → sdk-playground → engine → producer → gcp-cloud-run. Matches rootbuild's topo order (parsers,lint,studio-server → core → engine,producer,player,studio,shader-transitions,aws-lambda,gcp-cloud-run,sdk → cli → sdk-playground) for the packages relevant to the render path.
R1 concern verdict
| ID | Status | Notes |
|---|---|---|
C1 hardcoded requiredSourcePackages |
🟡 unchanged | Still 9 hardcoded entries. Not addressed; explicit follow-up material. |
| C2 coverage test not wired into CI | 🟢 addressed | check:gcp-cloud-run-dockerfile chained into root lint. .github/workflows/ci.yml:105 runs bun run lint, so the drift check now fires on every PR. Correct wiring shape — matches the existing check:tracked-artifacts / check:workspace-contracts pattern rather than inventing a new one. |
| C3 Dockerfile build order diverges from root | 🟢 addressed | Reordered to parsers → lint → studio-server → core → core:modular → sdk → sdk-playground → engine → producer → gcp-cloud-run. parsers/lint/studio-server now precede core, matching root build. The sdk/sdk-playground/engine insertion after core:modular differs from root (root builds them in the core,engine,…,sdk group after core), but only for packages whose exports also expose bun/import source conditionals — safe and consistent with the divergence's original justification. |
| N1 source-COPY regex rigidity | 🟡 unchanged | Cosmetic; not addressed. |
N2 readdirSync guard style |
🟡 unchanged | Cosmetic; not addressed. |
Delta trace
- Root
lintchaining: verifiedcheck:gcp-cloud-run-dockerfileruns aftercheck:workspace-contractsand beforeoxlint .; standard&&short-circuit means a Dockerfile drift fails the lint step immediately, before the (slower) oxlint sweep. Correct ordering — cheap check first. - CI wiring path:
ci.yml'slintjob runsbun run lint; that root script now includescheck:gcp-cloud-run-dockerfile. Static verification of the wiring holds; the drift check will run on every push/PR that triggers CI's lint job. - Build-order correctness on the new sequence:
parsersbuild has no@hyperframes/*deps in its own source imports — safe first.lintimports from@hyperframes/parsers(verified viapackages/lint/src/*— same pattern as before) — parsers now precedes lint. ✓studio-serverimports from@hyperframes/parsersand@hyperframes/core. Root builds studio-server BEFORE core (root's topo order). Dockerfile also builds studio-server before core in the new order. Works becausestudio-server/package.jsonexportsalso exposebun/importsource conditionals — same mechanism as before. ✓corebuilds against source-resolved parsers/lint/studio-server; thencore:modularvariant emits the additional runtime artifact.sdk/sdk-playground/enginebuild against a builtcore— correct.
- No regressions on the other files — coverage script unchanged in this delta, so C1 remains as-was.
Green surface
- Wiring shape is idiomatic: matches the existing
check:*runners already chained intolint. No new CI job needed; existing infrastructure covers it. - Build order now maintainable — reads left-to-right in dependency order, easier to keep aligned with root.
- Modular runtime artifact still emitted — the
core:modularstep preserved from R2 delta, correctly slotted right after core. - No new failure modes introduced by the reordering.
What I didn't verify
- Whether
check:gcp-cloud-run-dockerfileruns on every CI job matrix — spot-check confirmslintjob runsbun run lint; other jobs (test,typecheck, etc.) don't need to run it since the check is idempotent and one CI job firing is sufficient to gate merges. - Whether the reordering has any measurable impact on Docker layer cache hit rate. Likely marginal; not a blocker.
Merge gate
Clean disposition of C2 and C3 with the exact wiring shape suggested (check:* in root lint) and root-aligned build order. C1 remains as an explicit follow-up worth Miguel's future attention — the hardcoded requiredSourcePackages is still a class-of-drift risk, but the R3 wiring at least means a manifest drift will now be caught automatically. Progress on the reporter's core insight.
LGTM on the delta — leaving as COMMENTED.
8bd3038 to
66c0fa7
Compare
vanceingalls
left a comment
There was a problem hiding this comment.
R3 delta review at HEAD 8bd3038bb. Delta vs R2 SHA 41e46f65.
Prior R2 APPROVED.
Delta (2 files, +6 / -5)
package.json— newcheck:gcp-cloud-run-dockerfilescript chained into rootlintbetweencheck:workspace-contractsandoxlint.bun run lint(incl. CI's lint job) now fires the drift check.packages/gcp-cloud-run/Dockerfile— build-step reorder:parsers → lint → studio-server → core → core:modular → sdk → sdk-playground → engine → producer → gcp-cloud-run.
R2 P2 verdict
| P2 | Status |
|---|---|
Build-order divergence from root build |
✅ resolved. parsers/lint/studio-server now precede core, matching root's canonical topo order. Modular-runtime step preserved (core build:hyperframes-runtime:modular), slotted after core build — my R2 concern still intact. |
| Coverage-test wiring into CI | ✅ resolved. check:gcp-cloud-run-dockerfile chained into root lint — same shape as sibling check:tracked-artifacts / check:workspace-contracts. No new CI job surface required; existing lint job covers it. |
Hardcoded requiredSourcePackages list |
🟡 unchanged — explicit follow-up. Manifest drift now auto-caught (from workspace enumeration); source-tree drift still needs a manual list bump. Progress, not full-resolution. |
Adversarial
- Reordering preserves render-path correctness:
sdk/sdk-playgroundstill built beforeengine(fine — neither depends on engine);studio-serverbeforecorecontinues to work via the existingexports.bun/exports.importsource-conditional plumbing that the pre-R3 order relied on. No new failure mode introduced. check:gcp-cloud-run-dockerfilein rootlintfires on every PR (not gcp-cloud-run-scoped) — desirable, catches cross-scaffold drift (someone addspackages/foowithout touching the Dockerfile). Cost is onereaddirSync+ regex over ~140-line Dockerfile; negligible.- Merge state
DIRTY(base drift, not R3-introduced) — needs rebase before merge, not a review blocker.
Peer
Rames (COMMENTED, 03:56:19Z): same verdict shape — C2/C3 addressed, C1 follow-up, "LGTM on the delta."
Verdict
APPROVE. R3 tightens wiring + aligns to canonical build order; R2 approval intact.
— Via
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
R4 rebase-only review at HEAD 66c0fa739. git patch-id --stable on the top commit matches R3's 8bd3038b — the PR-scoped diff is byte-content-identical. Main-side commits (e.g. 75eedf5c fix(cli): time out stalled model downloads (#2415)) are the delta.
Verification
- Patch-id equivalence: R3 top-commit patch-id
b27c63195d5eb0fa4a623d3c7f14e2dac7fce8b0== R4 top-commit patch-idb27c63195d5eb0fa4a623d3c7f14e2dac7fce8b0. - PR-scope
git diff 8bd3038b 66c0fa739 -- packages/gcp-cloud-run/ package.jsonis empty. - Commit reorganization noted: R3 was a single squashed commit; R4 is now two commits (
fix: include all workspace build dependencies+test: enforce Dockerfile workspace coverage). Structural cleanliness, no content change.
R1 concern verdict (carried forward from R3)
| ID | Status |
|---|---|
C1 hardcoded requiredSourcePackages |
🟡 unchanged — explicit follow-up material |
| C2 coverage test not wired into CI | 🟢 addressed (R3) — root lint invokes check:gcp-cloud-run-dockerfile |
| C3 Dockerfile build order diverges from root | 🟢 addressed (R3) — reordered to parsers → lint → studio-server → core → … |
| N1 source-COPY regex rigidity | 🟡 unchanged — cosmetic |
N2 readdirSync guard style |
🟡 unchanged — cosmetic |
Merge gate
Rebase-only; no new content to review. Prior R3 verdict stands. LGTM — leaving as COMMENTED.
66c0fa7 to
356fba0
Compare
356fba0 to
5a2df8e
Compare
5a2df8e to
9ee94bb
Compare
# Conflicts: # packages/gcp-cloud-run/check-dockerfile-workspaces.mjs
# Conflicts: # package.json
Fixes #2601.
Reproduced v0.7.60 from the tag: Docker frozen install failed because five workspace manifests were omitted; after adding manifests, a fresh build failed because dependency dist artifacts were absent.
Changes:
Verification:
bun run --cwd packages/gcp-cloud-run test:dockerfile-workspacesdocker build --progress=plain -f packages/gcp-cloud-run/Dockerfile -t hf-2601-fixed3 .(success; image built).Source issue: #2601