Skip to content

fix(bos_build): isolate BrowserClaw user-data dir from BrowserOS#1531

Merged
Nikhil (shadowfax92) merged 5 commits into
mainfrom
fix/browserclaw-profile-isolation
Jul 2, 2026
Merged

fix(bos_build): isolate BrowserClaw user-data dir from BrowserOS#1531
Nikhil (shadowfax92) merged 5 commits into
mainfrom
fix/browserclaw-profile-isolation

Conversation

@shadowfax92

Copy link
Copy Markdown
Contributor

Summary

  • BrowserOS and BrowserClaw both shipped with CrProductDirName = BrowserOS, sharing ~/Library/Application Support/BrowserOS and its SingletonLock — launching one blocked the other. Same hardcoding existed for Linux (browser-os) and Windows (kProductPathName = L"BrowserOS").
  • ProductDescriptor now models the user-data directory identity per platform: mac product_dir_name (BrowserOS / BrowserClaw), linux user_data_dir_name (browser-os / browser-claw), windows product_path_name (BrowserOS / BrowserClaw).
  • New product_identity prep step runs right after patches and stamps those values into the three patched Chromium files; wired into release, debug, and universal presets plus phase-flag mode.

Design

The chromium patches stay product-neutral (they carry the default BrowserOS values); per-product deviation happens in bos_build, same as the chromium_files/products/<id>/ overlays. The step rewrites via structural anchors (the CrProductDirName key, the #else-guarded data_dir_basename assignment, the kProductPathName variable) — never the current value — so it is idempotent, and each anchor must match exactly once or the build dies (a stale patch can never silently ship a shared profile root). For --product browseros the stamp is a byte-level no-op, so default trees stay identical to the patch stack and BrowserOS artifacts are unchanged. Buildflag conditionals inside the patches were rejected because chrome/common/chrome/install_static can't depend on chrome/browser/browseros:buildflags (GN layering) and the plist is static text.

Test plan

  • uv run python -m unittest discover -s bos_build -t . -p "*_test.py" — 601 tests green (goldens for both descriptors, stamp/no-op/idempotence/anchor-failure step tests, planner + phase ordering)
  • uv run ruff check bos_build — clean
  • Anchors validated against the real patch stack content (exactly one match per file)
  • uv run browseros build --preset release --product browserclaw --show-plan lists product_identity right after patches
  • Next claw build: confirm BrowserClaw.app/Contents/Info.plist has CrProductDirName = BrowserClaw and both browsers run side by side

Follow-ups (out of scope)

  • Windows registration identity (ProgIDs/CLSIDs/app GUID in chromium_install_modes.h) is still shared — needed for side-by-side Windows installs, not for running two profiles.
  • resources/entitlements/Info.plist.additions is dead (referenced nowhere) and still says BrowserOS — candidate for deletion.
  • A patch-stack lint could assert the three patches keep carrying the default product's values, guarding the extract workflow.

🤖 Generated with Claude Code

@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 2m 39s —— View job


Code Review

  • Gather context and read changed files
  • Review product_identity.py (core logic)
  • Review product_identity_test.py
  • Review products.py, planner.py, and wiring changes
  • Review test files for planner/step/products
  • Post final review

Overall: This is a clean, well-reasoned fix. The structural-anchor approach (substituting on key/variable names rather than current values) makes stamping genuinely idempotent, and the exactly-one-match guard turns patch drift into an immediate build failure rather than a silent profile collision. Test coverage is thorough. A few observations below.


steps/patches/product_identity.py

_PATHS_LINUX_ANCHOR — subtle regex backtracking dependency

_PATHS_LINUX_ANCHOR = re.compile(
    r'(#else\s*\n\s*std::string data_dir_basename = ")[^"]*(";)'
)

\s* matches \n, so #else\s*\n is theoretically ambiguous: the greedy \s* wants to consume the newline, forcing the literal \n to backtrack. It resolves correctly in practice (Python's re backtracks), but the intent is clearer as #else[ \t]*\n\s* — using [ \t]* to match only horizontal whitespace after #else, then \n explicitly. Also guards against an edge case where someone adds a trailing space on the #else line.

Fix this →

Lambda substitution with value — safe but worth a note

stamped = anchor.sub(lambda m: f"{m.group(1)}{value}{m.group(2)}", content)

The lambda form avoids the string-template substitution issue (a value containing \1 would be treated literally), so this is safe. It's a non-obvious choice that a reader might question, though — a short comment would save that mental check.

validate() only checks chromium_src.exists()

Individual target files are checked in execute() rather than validate(). This is intentional (the files don't exist until after patches runs), but the validate() docstring could note this so reviewers don't wonder if the file-not-found error should be surfaced earlier.


steps/patches/product_identity_test.py

Missing anchor-miss tests for PATHS_LINUX and INSTALL_MODES

test_missing_anchor_raises_with_path only tests the PLIST anchor being corrupted. The same "exactly one anchor" invariant applies to PATHS_LINUX_FILE and INSTALL_MODES_FILE, but those paths have no anchor-miss coverage. Worth adding, especially since PATHS_LINUX_ANCHOR is the most structurally complex of the three.

Fix this →

test_browseros_is_a_byte_level_noop — mtime check is a strong property

Checking st_mtime_ns proves the files were not opened for writing. This is a good property to assert; it rules out any accidental "write identical content back" regressions.


core/products.py

_kebab_case behavior on consecutive uppercase

For the current products ("BrowserOS" → "browser-os", "BrowserClaw" → "browser-claw") this works correctly. The derivation test ("AcmeFox""acme-fox") covers the common case. A product with consecutive uppercase letters (e.g., "BrowserHTTP") would produce "browser-h-t-t-p" rather than "browser-http" — worth a note in the docstring if a third product is ever added.

Field documentation comments are good

The # CrProductDirName: profile root under ~/Library/Application Support comments on each identity field are well placed — they tie the Python model to the Chromium source symbol in one place.


core/planner.py + cli/build.py

product_identity is correctly inserted after patches in all three plan paths (_plan_release, _plan_debug, _plan_universal_runs). The --prep help string update in build.py is accurate.

One observation: _plan_debug omits bundled_extensions and series_patches. Both are pre-existing omissions, not introduced here — just confirming this is intentional for debug builds.


products/products_test.py

UserDataIsolationTest.test_products_have_disjoint_user_data_identities is an excellent regression guard — it will catch any future change that accidentally re-shares a profile root across the three platforms. Keeping it prominent makes the intent clear to future contributors.


Summary

Category Finding
Minor _PATHS_LINUX_ANCHOR: use [ \t]* instead of \s* before \n for clarity
Minor Missing anchor-miss tests for PATHS_LINUX and INSTALL_MODES in the test file
Nit _kebab_case behavior on consecutive-uppercase not documented
Idempotency via structural anchors — solid design
Exactly-one-match guard — build fails on drift, not silently
mtime preservation for BrowserOS no-op path
UserDataIsolationTest regression guard
Golden tests for both descriptors

The core fix and design are sound. The two minor findings above are quality improvements rather than blockers.

@shadowfax92

Copy link
Copy Markdown
Contributor Author

Note on the red bos_build / unittest + ruff check: the 3 failures (test_help_documents_repeatable, test_help_documents_flags_and_read_only_guarantee, test_list_help_shows_bounding_options) are pre-existing help-text assertions that fail on every PR since ~03:00Z today (7 consecutive unrelated branches) — rich/typer renders ANSI codes inside flag names under Actions, so plain-substring asserts like '--product' in output miss. The identical command (uv run python -m unittest discover -s bos_build -t . -p '*_test.py') is green locally at this exact merged tree: 605/605 + ruff clean. Trunk CI needs a follow-up (e.g. NO_COLOR: 1 in the workflow env or ANSI-stripping in the help tests).

@shadowfax92 Nikhil (shadowfax92) merged commit 730e36b into main Jul 2, 2026
2 of 4 checks passed
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a SingletonLock collision between BrowserOS and BrowserClaw caused by both products sharing the same user-data directory names across all three platforms. It introduces a product_identity build step that stamps per-product values into three patched Chromium files immediately after patches runs, keeping the patch stack product-neutral while giving each product its own profile root.

  • Adds product_dir_name (mac), user_data_dir_name (linux), and product_path_name (windows) to the platform identity dataclasses; a _kebab_case helper derives the linux value from the CamelCase product name (e.g. "BrowserClaw" → "browser-claw").
  • New ProductIdentityModule uses structural regex anchors (never the current value) so stamping is idempotent; it enforces exactly one anchor match per file or the build fails, preventing silent patch drift from silently shipping a shared profile root.
  • product_identity is wired into all plan variants (release, debug, universal, CI) directly after patches; for --product browseros the step is a byte-level no-op, keeping default source trees identical to the patch stack.

Confidence Score: 4/5

Safe to merge; the fix is well-tested and the idempotent, fail-loud design prevents silent regressions from patch drift.

The implementation is solid and the test suite is thorough (stamp, no-op, idempotence, missing-file, missing-anchor, duplicate-anchor cases all covered). The two observations are both forward-looking: _kebab_case works correctly for every current product but could silently mis-derive a kebab name for a future product with an acronym-prefixed second word; the Linux anchor is structurally less unique than the other two and would fail loudly (not silently) if a future Chromium version added a second #else/data_dir_basename block. Neither affects the current build.

No files require special attention for this merge. The _kebab_case helper in products.py and the _PATHS_LINUX_ANCHOR pattern in product_identity.py are worth revisiting when onboarding future products or upmerging Chromium versions.

Important Files Changed

Filename Overview
packages/browseros/bos_build/steps/patches/product_identity.py New step that stamps per-product user-data directory identity into three patched Chromium files; idempotent, exactly-one-match invariant is well-designed, lambda substitution avoids regex-escape issues in replacements.
packages/browseros/bos_build/core/products.py Adds product_dir_name, user_data_dir_name, and product_path_name fields to the three platform identity dataclasses; _kebab_case works for current products but is limited for future names with consecutive-uppercase acronym boundaries.
packages/browseros/bos_build/core/planner.py Inserts product_identity immediately after patches in all four plan variants (release, debug, universal, CI); ordering is correct and step runs once per tree in the universal case.
packages/browseros/bos_build/steps/patches/product_identity_test.py Comprehensive tests covering stamp, byte-level no-op (mtime check), idempotence, missing file, missing anchor, and duplicate anchor; golden seeds mirror the real post-patch file content.
packages/browseros/bos_build/products/products_test.py Adds UserDataIsolationTest asserting disjoint identities across all three platforms, plus derivation and override golden checks for the new fields.
packages/browseros/bos_build/core/planner_test.py Golden tests updated with product_identity in all expected plan sequences; covers mac/windows/linux release, CI, debug, and universal presets.
packages/browseros/bos_build/steps/init.py Imports and re-exports ProductIdentityModule; triggers @step decorator registration when the package is loaded.
packages/browseros/bos_build/cli/build.py Help text for --prep flag updated to include product_identity in the listed phase steps; cosmetic/documentation-only change.
packages/browseros/bos_build/core/step_test.py Registry content goldens updated to include product_identity; no new logic, just keeps the step-list assertions green.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[patches step\napply BrowserOS-default values] --> B[product_identity step]
    B --> C{product == browseros?}
    C -- yes --> D[byte-level no-op\nall three files unchanged]
    C -- no, e.g. browserclaw --> E[rewrite mac: CrProductDirName\napp-Info.plist]
    C -- no --> F[rewrite linux: data_dir_basename\nchrome_paths_linux.cc]
    C -- no --> G[rewrite windows: kProductPathName\nchromium_install_modes.h]
    E --> H[exactly 1 anchor match\nor build dies]
    F --> H
    G --> H
    H --> I[configure step]
    D --> I
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[patches step\napply BrowserOS-default values] --> B[product_identity step]
    B --> C{product == browseros?}
    C -- yes --> D[byte-level no-op\nall three files unchanged]
    C -- no, e.g. browserclaw --> E[rewrite mac: CrProductDirName\napp-Info.plist]
    C -- no --> F[rewrite linux: data_dir_basename\nchrome_paths_linux.cc]
    C -- no --> G[rewrite windows: kProductPathName\nchromium_install_modes.h]
    E --> H[exactly 1 anchor match\nor build dies]
    F --> H
    G --> H
    H --> I[configure step]
    D --> I
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/core/products.py:221-223
`_kebab_case` doesn't insert dashes at upper→upper→lower boundaries, so product names with acronym-prefixed words (e.g., "BrowserOSPro") produce "browser-ospro" instead of "browser-os-pro". "BrowserOS" and "BrowserClaw" work correctly today, but a new product named anything like "MyHTTPSProxy" or "BrowserOSPro" would silently get a surprising kebab value that then gets stamped into the user-data path.

### Issue 2 of 2
packages/browseros/bos_build/steps/patches/product_identity.py:31-33
The Linux anchor matches `#else` followed by the `data_dir_basename` assignment, which is structurally less unique than the other two anchors (which use distinct key/variable names like `CrProductDirName` and `kProductPathName`). If the upstream chromium `chrome_paths_linux.cc` ever gains a second `#else` block that assigns `data_dir_basename` for a new branding tier, this would fire the "found 2 anchors" error and block the build. The "exactly one match" invariant will catch this loudly rather than silently, which is the right failure mode — just worth keeping in mind when upmerging chromium versions.

Reviews (1): Last reviewed commit: "chore: merge origin/main into fix/browse..." | Re-trigger Greptile

Comment on lines +221 to +223
def _kebab_case(name: str) -> str:
"""CamelCase → kebab-case ("BrowserOS" → "browser-os")."""
return re.sub(r"(?<=[a-z0-9])(?=[A-Z])", "-", name).lower()

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 _kebab_case doesn't insert dashes at upper→upper→lower boundaries, so product names with acronym-prefixed words (e.g., "BrowserOSPro") produce "browser-ospro" instead of "browser-os-pro". "BrowserOS" and "BrowserClaw" work correctly today, but a new product named anything like "MyHTTPSProxy" or "BrowserOSPro" would silently get a surprising kebab value that then gets stamped into the user-data path.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/browseros/bos_build/core/products.py
Line: 221-223

Comment:
`_kebab_case` doesn't insert dashes at upper→upper→lower boundaries, so product names with acronym-prefixed words (e.g., "BrowserOSPro") produce "browser-ospro" instead of "browser-os-pro". "BrowserOS" and "BrowserClaw" work correctly today, but a new product named anything like "MyHTTPSProxy" or "BrowserOSPro" would silently get a surprising kebab value that then gets stamped into the user-data path.

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 +31 to +33
_PATHS_LINUX_ANCHOR = re.compile(
r'(#else\s*\n\s*std::string data_dir_basename = ")[^"]*(";)'
)

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 The Linux anchor matches #else followed by the data_dir_basename assignment, which is structurally less unique than the other two anchors (which use distinct key/variable names like CrProductDirName and kProductPathName). If the upstream chromium chrome_paths_linux.cc ever gains a second #else block that assigns data_dir_basename for a new branding tier, this would fire the "found 2 anchors" error and block the build. The "exactly one match" invariant will catch this loudly rather than silently, which is the right failure mode — just worth keeping in mind when upmerging chromium versions.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/browseros/bos_build/steps/patches/product_identity.py
Line: 31-33

Comment:
The Linux anchor matches `#else` followed by the `data_dir_basename` assignment, which is structurally less unique than the other two anchors (which use distinct key/variable names like `CrProductDirName` and `kProductPathName`). If the upstream chromium `chrome_paths_linux.cc` ever gains a second `#else` block that assigns `data_dir_basename` for a new branding tier, this would fire the "found 2 anchors" error and block the build. The "exactly one match" invariant will catch this loudly rather than silently, which is the right failure mode — just worth keeping in mind when upmerging chromium versions.

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

@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes the SingletonLock collision between BrowserOS and BrowserClaw by giving each product its own user-data directory identity. Previously both products shared hardcoded values (CrProductDirName = BrowserOS, data_dir_basename = "browser-os", kProductPathName = L"BrowserOS") across macOS, Linux, and Windows, making it impossible to run them simultaneously.

  • Adds product_dir_name, user_data_dir_name, and product_path_name fields to the three platform identity dataclasses in products.py, derived from the product name via ProductDescriptor.define().
  • Introduces ProductIdentityModule (product_identity step, phase prep), which stamps the three per-product values into the corresponding patched Chromium files immediately after patches runs, using structural anchors (key/variable names) rather than current values to guarantee idempotence and catch patch drift at build time.
  • Wires the new step into the release, debug, and universal planners, updates planner golden tests and the --prep help string accordingly.

Confidence Score: 4/5

Safe to merge; the stamping logic is correct, idempotent, and fails loudly on patch drift.

The implementation is well-designed and thoroughly tested — stamp, no-op, idempotency, missing file, and duplicate-anchor cases are all covered. The one item worth a second look is the _PATHS_LINUX_ANCHOR regex, where \s* before the explicit
technically allows the wildcard to consume the newline before backtracking; it works today but the intent would be clearer with [^]*. The end-to-end test confirming BrowserClaw.app ships with the correct CrProductDirName and both browsers run side by side is still pending, which is the remaining gap.

packages/browseros/bos_build/steps/patches/product_identity.py — specifically the _PATHS_LINUX_ANCHOR regex.

Important Files Changed

Filename Overview
packages/browseros/bos_build/steps/patches/product_identity.py New stamping module: reads three Chromium source files, validates exactly one anchor match per file, and rewrites the user-data identity value; idempotent (skips unchanged files). _PATHS_LINUX_ANCHOR uses \s* before the explicit \n, which includes newlines in the wildcard — works via backtracking but could be tightened.
packages/browseros/bos_build/core/products.py Adds product_dir_name, user_data_dir_name, and product_path_name to the three platform identity dataclasses and derives them in define(). New _kebab_case helper correctly converts CamelCase product names to kebab-case for Linux paths.
packages/browseros/bos_build/core/planner.py Adds product_identity after patches in release, debug, and universal planners. Ordering and placement are consistent across all three paths.
packages/browseros/bos_build/steps/patches/product_identity_test.py Comprehensive tests against mock checkout: stamp, no-op for BrowserOS, idempotency, missing file, missing anchor, and duplicate anchor (patch drift) are all covered.
packages/browseros/bos_build/products/products_test.py Golden descriptors for both products updated with the new identity fields; new UserDataIsolationTest asserts the two products always have disjoint user-data roots, guarding against future regressions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[git_setup / clean / provision] --> B[download_resources]
    B --> C[bundled_extensions]
    C --> D[chromium_replace]
    D --> E[string_replaces]
    E --> F[series_patches]
    F --> G[patches\napply BrowserOS-default values]
    G --> H[product_identity NEW\nstamp per-product user-data identity]
    H --> I[configure]
    I --> J[compile]

    subgraph stamp [product_identity stamps 3 files]
        P1[chrome/app/app-Info.plist\nCrProductDirName = BrowserOS to BrowserClaw]
        P2[chrome/common/chrome_paths_linux.cc\ndata_dir_basename = browser-os to browser-claw]
        P3[chrome/install_static/chromium_install_modes.h\nkProductPathName = BrowserOS to BrowserClaw]
    end

    H -.-> P1
    H -.-> P2
    H -.-> P3

    style H fill:#d4edda,stroke:#28a745
    style stamp fill:#f8f9fa,stroke:#6c757d
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[git_setup / clean / provision] --> B[download_resources]
    B --> C[bundled_extensions]
    C --> D[chromium_replace]
    D --> E[string_replaces]
    E --> F[series_patches]
    F --> G[patches\napply BrowserOS-default values]
    G --> H[product_identity NEW\nstamp per-product user-data identity]
    H --> I[configure]
    I --> J[compile]

    subgraph stamp [product_identity stamps 3 files]
        P1[chrome/app/app-Info.plist\nCrProductDirName = BrowserOS to BrowserClaw]
        P2[chrome/common/chrome_paths_linux.cc\ndata_dir_basename = browser-os to browser-claw]
        P3[chrome/install_static/chromium_install_modes.h\nkProductPathName = BrowserOS to BrowserClaw]
    end

    H -.-> P1
    H -.-> P2
    H -.-> P3

    style H fill:#d4edda,stroke:#28a745
    style stamp fill:#f8f9fa,stroke:#6c757d
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/browseros/bos_build/steps/patches/product_identity.py:31-33
The `\s*` before the explicit `
` in this pattern includes `
` itself (Python's `\s` matches `[ 	

\f\v]`), so the greedy quantifier will first consume the newline before backtracking to let the explicit `
` match. This works correctly in practice, but using `[^\S
]*` ("any whitespace that is not a newline") makes the intent explicit and avoids the unnecessary backtracking step.

Reviews (2): Last reviewed commit: "chore: merge origin/main into fix/browse..." | Re-trigger Greptile

Nikhil (shadowfax92) added a commit that referenced this pull request Jul 2, 2026
* feat(patches): per-product user-data dir via browseros_product buildflag

BrowserOS and BrowserClaw shared one profile root (CrProductDirName,
linux data_dir_basename, win kProductPathName all said BrowserOS), so
the second product to launch hit the first one's SingletonLock instead
of starting its own instance. The identity now derives from the
browseros_product GN arg inside the patch stack: macOS substitutes
BROWSEROS_PRODUCT_DIR_NAME into app-Info.plist, Linux and Windows
branch on BUILDFLAG(BROWSEROS_PRODUCT_BROWSERCLAW).

* revert(bos_build): drop product_identity source stamping (#1531)

The stamping step regex-rewrote patched chromium files after apply —
app-Info.plist is itself a patch file, so the stamp fought the patch
stack and re-extraction would silently undo it. The user-data identity
now lives in the patch stack keyed off the browseros_product GN arg
(which bos_build already passes per product), so the step, the model
fields, and their tests go away.

This reverts commit 730e36b.
Nikhil (shadowfax92) added a commit that referenced this pull request Jul 2, 2026
## Summary
- removed stale product identity residue left after #1536 superseded #1531's Python stamping step
- deleted the unreferenced Info.plist additions file that hardcoded BrowserOS as the product directory
- added patch-stack regression coverage for macOS, Linux, and Windows product user-data roots
- stabilized colored CLI help assertions in bos_build tests

## Tests
- uv run python -m unittest discover -s bos_build -t . -p '*_test.py'
- uv run ruff check bos_build
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