Skip to content

fix: bake product identity buildflags for browseros/browserclaw release#1526

Merged
Nikhil (shadowfax92) merged 3 commits into
mainfrom
fix/release-product-buildflags
Jul 2, 2026
Merged

fix: bake product identity buildflags for browseros/browserclaw release#1526
Nikhil (shadowfax92) merged 3 commits into
mainfrom
fix/release-product-buildflags

Conversation

@shadowfax92

Copy link
Copy Markdown
Contributor

Summary

  • Restores safe buildflags.gni defaults: browseros_allow_runtime_product_override = false, browseros_package_all_server_resources follows the override — resolving the pre-claw-release TODO from c840d95. Content is byte-identical to the pre-flip version (blob 0a4b34ea72336), verified to apply cleanly.
  • get_product_gn_args() now couples browseros_package_all_server_resources to the runtime override: debug builds get true/true (one debug binary can actually run as either product — previously the override was on but the other product's server resources were missing), release builds bake browseros_product with both flags false. Release args.gn output is unchanged from current main.
  • Configure now warns per missing server-resource bundle on debug builds, so an unstaged tree fails with an actionable message at configure time instead of a cryptic ninja missing-input error.

Design

Release safety lives in two layers on purpose: bos_build states managed-build policy explicitly in args.gn (auditable, belt-and-suspenders for shipped artifacts), while the .gni default protects anything built outside bos_build. The Jun 30 testing need (run either product from one build) is preserved through the managed debug path instead of unsafe global defaults.

Notes for dev workflows

  • Hand-managed args.gn (not written by browseros build configure) must add browseros_allow_runtime_product_override = true to keep the --browseros-product switch; the flipped default compiles it out otherwise. This is the intended pre-claw-release behavior.
  • Existing debug out dirs pick up the corrected flags on their next configure run; plans that skip configure keep their frozen args.gn (true of every GN arg).
  • Review triage: declined adding a GN assert against override && !package_all (legitimate for browser-only cross-product testing without server resources) and declined dropping the explicit package_all arg from args.gn (see Design).

Test plan

  • uv run python -m unittest discover -s bos_build -t . -p "*_test.py" — 596 tests OK (new: release golden args for both products, debug wiring test, configure warning tests)
  • uv run ruff check bos_build — clean
  • Edited patch applies cleanly in a scratch repo; git hash-object of the result matches the embedded index hash
  • Next nightly debug build: confirm both BrowserOSServer and BrowserClawServer resources land in the output and --browseros-product=browserclaw works end to end

Return browseros_allow_runtime_product_override to false and make
browseros_package_all_server_resources follow it, resolving the
pre-claw-release TODO from c840d95. Managed builds are unaffected:
bos_build configure writes all three product args explicitly, and the
debug preset keeps the runtime override for cross-product testing.
get_product_gn_args hardcoded browseros_package_all_server_resources
to false, so a debug build with the runtime product override enabled
was missing the other product's server resources and the override was
half-broken. Debug now sets override and package-all together; release
still bakes identity with both off.
…taged

Review follow-ups: early configure-time warning instead of a late
ninja missing-input error when a product's server resources aren't
staged for a debug (package-all) build; derive the debug configure
test's expected args from get_product_gn_args instead of a third
literal copy; one-line docstring.
@shadowfax92

Copy link
Copy Markdown
Contributor Author

Greptile (@greptileai) review

@shadowfax92

Copy link
Copy Markdown
Contributor Author

Claude (@claude) review

@github-actions github-actions Bot added the fix label Jul 2, 2026
@claude

claude Bot commented Jul 2, 2026

Copy link
Copy Markdown

Claude finished Nikhil (@shadowfax92)'s task in 1m 51s —— View job


Code Review

  • Gather context and understand the request
  • Read changed files
  • Review buildflags.gni
  • Review context.py and context_test.py
  • Review configure.py and configure_test.py
  • Post final review

This PR cleanly resolves the pre-claw-release TODO by restoring safe .gni defaults, coupling package_all to allow_override in both GN and Python, and adding a configure-time early warning for the debug case. No correctness bugs found. Notes below are a mix of minor observations and nits.

buildflags.gni (patch)

Clean. Using two declare_args() blocks to let package_all derive from allow_runtime_product_override is idiomatic GN — the second block can reference identifiers from the first. The blob hash update (8c87fe61ab7380a4b34ea72336) looks correct and the PR verifies it applies cleanly.

One thing to keep in mind: the .gni file is a patch file, not a live GN file. The browseros_package_all_server_resources = browseros_allow_runtime_product_override default in the patch is the correct pattern, but reviewers should confirm the patched Chromium tree's buildflags.gni actually reflects this (the PR description says this was manually verified via git hash-object).

context.pyget_product_gn_args()

Good change. Renaming runtime_overridedev_build better signals intent (build-mode flag, not mechanism), and the updated docstring is much more informative about why debug needs both resource sets.

Observation — package_all=true / override=false use case: The PR notes "can be forced on for packaging tests" as a legitimate configuration. Currently get_product_gn_args() can't express it — users must pass --gn-arg browseros_package_all_server_resources=true. The CLI flag path works (extra_gn_args appended last → GN last-write-wins), but the dev note mentions this only for hand-managed args.gn. Worth clarifying in dev docs or a --help message if this is a common need.

context_test.py

Improvement: Upgrading from assertIn to assertEqual over the full list is a materially stricter assertion — it catches ordering bugs, extra args, and missing args. Good call.

test_release_gn_args_bake_product_identity with subTest over both products is the right pattern.

Minor gap: test_debug_gn_args_allow_override_and_package_all only covers the default browseros product in debug mode. Consider adding a browserclaw debug sub-case to confirm browseros_product = "browserclaw" appears correctly when build_type="debug". Not a blocker since the logic path is identical, but it'd close the coverage gap.

# suggested addition to test_debug_gn_args_allow_override_and_package_all
def test_debug_gn_args_allow_override_and_package_all(self):
    for product in ("browseros", "browserclaw"):
        with self.subTest(product=product):
            ctx = Context(
                chromium_src=Path("/nonexistent-src"),
                architecture="x64",
                build_type="debug",
                product=get_product_descriptor(product),
            )
            self.assertEqual(
                ctx.get_product_gn_args(),
                [
                    f'browseros_product = "{product}"',
                    "browseros_allow_runtime_product_override = true",
                    "browseros_package_all_server_resources = true",
                ],
            )

configure.py_warn_missing_server_resources()

Correct placement: Called after args_file.write_text(...) but before gn gen, so the user sees the warning before a slow compile-time failure. Using log_warning (not ValidationError) is the right choice given the PR explicitly notes that missing resources can be intentional for cross-product testing.

Observation — warning vs. error: A developer who ignores the warning will still hit the cryptic ninja missing-input error. You might consider making this a ValidationError with an opt-out flag (e.g. --allow-missing-server-resources), but that's clearly scope creep from this PR's intent. The current non-blocking approach is reasonable for now.

Nit — _warn_missing_server_resources is an implementation detail but the method name uses the public underscore convention correctly. The configure.py import of all_server_bundles is the right coupling — it avoids hardcoding product IDs and stays in sync with the product registry.

configure_test.py

Good coverage of new paths.

test_debug_warns_when_server_resources_not_staged relies on the fresh temp dir not having any staged resources — a sound implicit assumption given _execute creates a bare MockChromium. The any("server resources" in m ...) check is loose but not too loose: it would catch a message refactor that loses the key phrase.

test_release_does_not_warn_about_server_resources using assert_not_called() is clean.

test_debug_args_append_product_args_verbatim references ctx.get_product_gn_args() in the expected string rather than hardcoding — slightly circular (a broken get_product_gn_args() could make both sides wrong), but context_test.py tests that function directly, so the division of test responsibility is fine.


Summary

Approve. Changes are correct, well-motivated, and well-tested. The one non-trivial observation is the missing browserclaw coverage in the debug GN args test (Fix this →), but it's not blocking. The design rationale (two-layer release safety, non-fatal warning for debug, extra_gn_args escape hatch for packaging tests) is sound.

@shadowfax92 Nikhil (shadowfax92) merged commit 6c21378 into main Jul 2, 2026
6 of 7 checks passed
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR resolves a pre-claw-release TODO by flipping the buildflags.gni default for browseros_allow_runtime_product_override back to false (safe for shipped artifacts) and coupling browseros_package_all_server_resources to it. get_product_gn_args() is updated so debug builds explicitly set both to true (enabling the runtime product switch and packaging all server resource sets), while release builds bake both to false.

  • buildflags.gni patch: Safe defaults restored — override is false, and browseros_package_all_server_resources derives from the override flag in a second declare_args() block, following the standard GNI pattern for derived defaults.
  • context.py / configure.py: Debug builds write true for both flags; release builds bake false. A new _warn_missing_server_resources() helper emits per-bundle warnings at configure time when debug resources aren't staged, surfacing the issue before the ninja missing-input error.
  • Tests: New tests cover debug and release GN arg golden values, the configure warning path, and the no-warning-on-release invariant.

Confidence Score: 5/5

Safe to merge — changes are narrow, well-tested, and resolve a known pre-release TODO without introducing new runtime risk.

The three-file logic change (GNI patch, GN args generation, configure warning) is tightly scoped and fully covered by new tests. Debug and release golden args are verified explicitly. No pre-existing release-path logic is altered in ways that could affect shipped artifacts.

No files require special attention. The configure_test.py warning test relies on all_server_bundles() returning at least one bundle from the real product registry, which is reasonable but worth keeping in mind if the registry changes shape.

Important Files Changed

Filename Overview
packages/browseros/chromium_patches/chrome/browser/browseros/buildflags.gni Patch content updated: flips override default to false and derives package_all from it via a second declare_args() block — standard GNI pattern, byte-identical to the pre-flip version per PR description.
packages/browseros/bos_build/core/context.py get_product_gn_args() now sets both browseros_allow_runtime_product_override and browseros_package_all_server_resources symmetrically based on build type; clean change with no edge cases left unhandled.
packages/browseros/bos_build/steps/setup/configure.py Adds _warn_missing_server_resources() called only on debug builds; iterates all_server_bundles() and logs an actionable warning per missing resource root before gn gen runs.
packages/browseros/bos_build/core/context_test.py Replaces a weaker assertIn check with equality assertions covering both debug (true/true) and release (false/false) golden values for both products via subTest.
packages/browseros/bos_build/steps/setup/configure_test.py Adds three new tests: debug args verbatim content, warning fires when resources are missing, and no-warning on release.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[bos_build configure step] --> B{build_type?}
    B -- debug --> C["get_product_gn_args()\noverride = true\npackage_all = true"]
    B -- release --> D["get_product_gn_args()\noverride = false\npackage_all = false"]
    C --> E[Write args.gn]
    D --> E
    E --> F{debug build?}
    F -- yes --> G[_warn_missing_server_resources]
    G --> H{bundle resources exist?}
    H -- missing --> I[log_warning: actionable message]
    H -- present --> J[no warning]
    I --> K[gn gen]
    J --> K
    F -- no --> K
    K --> L[Build with ninja]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[bos_build configure step] --> B{build_type?}
    B -- debug --> C["get_product_gn_args()\noverride = true\npackage_all = true"]
    B -- release --> D["get_product_gn_args()\noverride = false\npackage_all = false"]
    C --> E[Write args.gn]
    D --> E
    E --> F{debug build?}
    F -- yes --> G[_warn_missing_server_resources]
    G --> H{bundle resources exist?}
    H -- missing --> I[log_warning: actionable message]
    H -- present --> J[no warning]
    I --> K[gn gen]
    J --> K
    F -- no --> K
    K --> L[Build with ninja]
Loading

Reviews (1): Last reviewed commit: "fix(browseros): warn at configure when d..." | Re-trigger Greptile

@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR resolves a pre-claw-release TODO by restoring browseros_allow_runtime_product_override = false in buildflags.gni and coupling browseros_package_all_server_resources to that flag; it then propagates those semantics into the managed build path (get_product_gn_args) and adds an early configure-time warning for debug builds when server resource directories are missing.

  • buildflags.gni: Default flipped back to false for both flags; the second flag now derives from the first via GN's multi-block declare_args() ordering, removing the pre-claw TODO comment.
  • context.py: get_product_gn_args() emits true for both override flags on debug builds and false for release builds, baking product identity at compile time.
  • configure.py: New _warn_missing_server_resources helper fires once per missing bundle directory during debug configure, surfacing the problem before the opaque ninja missing-input failure.

Confidence Score: 4/5

The logic is sound and the release path is unchanged; the only gaps are in test robustness, not in production code.

The production code changes are clean: the .gni default flip is byte-identical to the verified pre-flip blob, get_product_gn_args() correctly gates both flags on build type, and the warning helper reads a directory check that cannot affect the build outcome. The two test gaps could mask future regressions but do not affect current correctness.

configure_test.py — the new debug arg test constructs its expected value from the same function under test, and the warning test relies on the server bundle registry being non-empty without asserting it.

Important Files Changed

Filename Overview
packages/browseros/chromium_patches/chrome/browser/browseros/buildflags.gni Restores safe defaults: browseros_allow_runtime_product_override = false and ties browseros_package_all_server_resources to that flag; removes the pre-claw TODO comment.
packages/browseros/bos_build/core/context.py Couples browseros_package_all_server_resources to browseros_allow_runtime_product_override in managed builds; debug → both true, release → both false.
packages/browseros/bos_build/steps/setup/configure.py Adds _warn_missing_server_resources that emits a per-bundle actionable warning on debug configure when server resource directories aren't staged.
packages/browseros/bos_build/core/context_test.py Replaces the partial assertIn check with exact assertEqual on the full arg list; adds a release golden test covering both browseros and browserclaw products.
packages/browseros/bos_build/steps/setup/configure_test.py New tests for debug arg format, missing-resource warning, and release-no-warn; the debug args test constructs expected values from get_product_gn_args() itself, reducing its bug-catching power.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[configure.execute] --> B{build_type == debug?}
    B -- Yes --> C["get_product_gn_args()\nallow_runtime_override = true\npackage_all_server_resources = true"]
    B -- No --> D["get_product_gn_args()\nallow_runtime_override = false\npackage_all_server_resources = false\nbrowseros_product baked in"]
    C --> E[Write args.gn]
    D --> E
    E --> F{build_type == debug?}
    F -- Yes --> G[_warn_missing_server_resources]
    G --> H{for each bundle\nresources_dir.exists?}
    H -- No --> I[log_warning: run resources step first]
    H -- Yes --> J[OK]
    I --> K[gn gen out_dir]
    J --> K
    F -- No --> L[gn gen out_dir --fail-on-unused-args]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[configure.execute] --> B{build_type == debug?}
    B -- Yes --> C["get_product_gn_args()\nallow_runtime_override = true\npackage_all_server_resources = true"]
    B -- No --> D["get_product_gn_args()\nallow_runtime_override = false\npackage_all_server_resources = false\nbrowseros_product baked in"]
    C --> E[Write args.gn]
    D --> E
    E --> F{build_type == debug?}
    F -- Yes --> G[_warn_missing_server_resources]
    G --> H{for each bundle\nresources_dir.exists?}
    H -- No --> I[log_warning: run resources step first]
    H -- Yes --> J[OK]
    I --> K[gn gen out_dir]
    J --> K
    F -- No --> L[gn gen out_dir --fail-on-unused-args]
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
packages/browseros/bos_build/steps/setup/configure_test.py:98-109
**Circular expected-value construction in debug args test**

`ctx.get_product_gn_args()` is called to build the expected string, so the test validates that "the file contains what `get_product_gn_args()` returns" rather than a concrete known value. If `get_product_gn_args()` had a bug — e.g., emitting `"false"` for debug builds — both sides of the `assertEqual` would reflect that bug and the test would still pass. The release counterpart (`test_writes_args_gn_with_target_cpu`) hard-codes its expected lines; this debug test should do the same.

### Issue 2 of 2
packages/browseros/bos_build/steps/setup/configure_test.py:157-162
**Warning test has an implicit dependency on a non-empty server bundle registry**

`test_debug_warns_when_server_resources_not_staged` does not mock `all_server_bundles()`, so the assertion (`assertTrue(any(...))`) silently passes vacuously if the registry ever returns an empty tuple — no warning would be fired, but the test would also never fail. A guard like `self.assertTrue(len(all_server_bundles()) > 0, "registry is empty")` at the top of the test, or mocking `all_server_bundles` with a known stub, would make the dependency explicit.

Reviews (2): Last reviewed commit: "fix(browseros): warn at configure when d..." | Re-trigger Greptile

Comment on lines +98 to +109
def test_debug_args_append_product_args_verbatim(self):
ctx, chromium, _ = self._execute(
"debug", architecture="arm64", flags="is_debug = true\n"
)

args_gn = (chromium.src / ctx.out_dir / "args.gn").read_text()
self.assertEqual(
args_gn,
'is_debug = true\n\ntarget_cpu = "arm64"\n'
+ "\n".join(ctx.get_product_gn_args())
+ "\n",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Circular expected-value construction in debug args test

ctx.get_product_gn_args() is called to build the expected string, so the test validates that "the file contains what get_product_gn_args() returns" rather than a concrete known value. If get_product_gn_args() had a bug — e.g., emitting "false" for debug builds — both sides of the assertEqual would reflect that bug and the test would still pass. The release counterpart (test_writes_args_gn_with_target_cpu) hard-codes its expected lines; this debug test should do the same.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/browseros/bos_build/steps/setup/configure_test.py
Line: 98-109

Comment:
**Circular expected-value construction in debug args test**

`ctx.get_product_gn_args()` is called to build the expected string, so the test validates that "the file contains what `get_product_gn_args()` returns" rather than a concrete known value. If `get_product_gn_args()` had a bug — e.g., emitting `"false"` for debug builds — both sides of the `assertEqual` would reflect that bug and the test would still pass. The release counterpart (`test_writes_args_gn_with_target_cpu`) hard-codes its expected lines; this debug test should do the same.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +157 to +162
def test_debug_warns_when_server_resources_not_staged(self):
with mock.patch.object(configure, "log_warning") as log_warning:
self._execute("debug")

messages = [call.args[0] for call in log_warning.call_args_list]
self.assertTrue(any("server resources" in m for m in messages), messages)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Warning test has an implicit dependency on a non-empty server bundle registry

test_debug_warns_when_server_resources_not_staged does not mock all_server_bundles(), so the assertion (assertTrue(any(...))) silently passes vacuously if the registry ever returns an empty tuple — no warning would be fired, but the test would also never fail. A guard like self.assertTrue(len(all_server_bundles()) > 0, "registry is empty") at the top of the test, or mocking all_server_bundles with a known stub, would make the dependency explicit.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/browseros/bos_build/steps/setup/configure_test.py
Line: 157-162

Comment:
**Warning test has an implicit dependency on a non-empty server bundle registry**

`test_debug_warns_when_server_resources_not_staged` does not mock `all_server_bundles()`, so the assertion (`assertTrue(any(...))`) silently passes vacuously if the registry ever returns an empty tuple — no warning would be fired, but the test would also never fail. A guard like `self.assertTrue(len(all_server_bundles()) > 0, "registry is empty")` at the top of the test, or mocking `all_server_bundles` with a known stub, would make the dependency explicit.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant