Objective
Make the stock Vexa Zoom Web lane reliably join as an unsigned guest without disguising Zoom policy denials, force-clicking disabled controls, leaking browser contexts, or claiming teardown before the bot has actually left.
This issue is the prepared successor to #345. It is scoped to the meet-join brick plus the browser runtime-shape and service adapters required to carry that brick in bot, Lite, Compose, and Helm. Post-admission audio/consent work in #515 is a parked dependency, not part of this issue.
Where we are — evidence, then reading
External platform facts
Research observations
| Probe |
Browser/session |
Actual |
Verdict |
| One protected legacy room, 6 fresh profiles |
stock Chromium 141 |
6/6 rendered the conjunction “detected a bot” + “automated bots are not allowed” + “use Zoom RTMS” before host admission |
deterministic failure for that room/browser cohort; not a universal Zoom claim |
| Same protected room |
current Chrome/Chromium 149 |
reached guest prejoin/waiting-room; one macOS run was admitted and visually left |
browser generation/product affects classification; not stock-image proof |
| Zoom-owned official test meetings, 3 fresh profiles |
stock Chromium 141 |
Clara Khan, Sofia Patel, and Sofia Khan were admitted |
ordinary test rooms are a negative control only; they do not exercise the protected policy cohort |
| Zoom-owned official test meeting |
current browser, Elena Costa |
admitted; browser teardown completed |
one observation, not the protected-room sequence |
| Old/current binary × old/current UA |
four crossover combinations |
all reached ordinary prejoin |
UA-only is not demonstrated as the policy fix |
https://zoom.us/test, disposable current Firefox container |
Playwright 1.61.1 + Firefox 151 rev 1532 |
page title loaded; webdriver=true; mediaDevices=true |
ordinary page compatibility only; no participant joined |
| Same probe under amd64 emulation |
Firefox 151 |
exceeded the 120-second bound and was terminated |
no amd64 verdict; native amd64 proof is owed |
The current reading is that the RTMS wording is a terminal Zoom policy wall, not evidence that the meeting requires RTMS. Classification must require all three clauses so an isolated title/chat string cannot trigger it. The defect is introduced at the browser/runtime contract: the stock image carries a browser generation Zoom can classify differently. The join consumer must not spoof around its own runtime mismatch.
A second independent defect is React-controlled guest-name entry: Zoom may replace/reset the input after a write, leaving Join disabled although an earlier read appeared correct. The prepared behavior is bounded entry attempts, post-settle double verification, node-replacement handling, at most one repair, and a typed terminal result—never a forced click on a disabled button.
Selected browser/driver fork
Use Playwright 1.61.1 with its matched, unmodified Firefox 151.0 revision 1532, only for unsigned Zoom guests.
Preserve the existing Playwright 1.56/Chromium lane for authenticated profiles and every non-Zoom platform. Preserve an operator-supplied executable path as an explicit advanced override; it cannot prove the stock image works.
Upstream identity:
P17 / MPL / LGPL / SBOM contract
The selected fork is admissible only when all of these are true:
- Final bot/Lite images copy only the matched Firefox artifact (
/ms-playwright/firefox-1532) from the current Playwright source image; they do not adopt that whole image as the final base.
THIRD_PARTY_LICENSES.md identifies Firefox, its exact version/revision, source, images, and in-image notice paths.
- The complete MPL 2.0 and embedded Firefox third-party notice inventory travels with the artifact. The source-retrieval reference is retained as required by MPL executable-form distribution.
license-exceptions.json logs the Category-B allowance for clearly demarcated, unmodified, separately shipped/dynamically loaded LGPL components. Static bundling is not accepted.
scripts/sbom.mjs emits a root CONTAINS relationship to Firefox and Firefox CONTAINS relationships to separately identified LGPL runtime components. The Apache-licensed npm package is not used as a proxy for browser bytes.
- Final-image gates prove Firefox rev 1532 and the notices exist and prove current Chrome-for-Testing revision 1228 paths/bytes are absent.
- Both native release architectures are inventoried and hashed. Emulation is not release evidence.
Rejected forks:
- Whole-base Playwright 1.61.1 or Chrome-for-Testing as Vexa's stock browser: rejected because the manifest's current
chromium is Google Chrome for Testing 149/rev 1228, and npm's Apache licence does not cover those browser bytes.
- Debian Chromium 150: rejected under current P17 because the disposable runtime exposed LGPL FFmpeg code without the required clean separate-link boundary.
- Raw Chromium snapshot: rejected because its
chrome://credits was a sample placeholder (generate_about_credits absent), so it lacked a redistributable notice/source inventory.
- Meeting SDK/RTMS: valid only as a separate authorized product contract, not as proof that the unsigned Web guest lane works.
Source and custody
Repository: Vexa-ai/vexa
Milestone: v0.12.20 — meeting lifecycle and operator truth
Module: pkg:meet-join
Human bar: protected solo meeting, host-visible admission and leave
Preferred validator: Dmitriy Grankin as meeting host plus a fresh non-author agent validating the immutable source/image tuple
Research provenance:
- Research base:
6a50a2320b797919f54af9a434ae8ecdf35973fe
- Research branch/worktree:
codex/zoom-robust-join at /Users/dmitriygrankin/dev/vexa-zoom-robust
- Codex task:
019f9070-de4b-7002-bc4b-ca698f5488b8
- Draft state: 42 dirty paths (32 modified, 10 untracked), no commit, push, or PR
Current provisional source candidate
Draft PR: #957
Fresh non-author review: CLEAN on the exact P1/P2 repair head; no findings
Review candidate head: 2235a2c8cc61409c613b6c4f21f26bbd5203d9fb
Tree: 5e4ae0e7b5c20dbe618a633bf3923914b1256773
Provisional base: 72ecb679761fc49668b8d48d54062868832ac1c9
Branch/worktree: codex/938-zoom-firefox-source at /Users/dmitriygrankin/dev/vexa-938-zoom-firefox-source
Exact nine-file base→head manifest:
core/meetings/modules/join/package.json
core/meetings/modules/join/src/__fixtures__/README.md
core/meetings/modules/join/src/__fixtures__/browser-product.contract.v1.json
core/meetings/modules/join/src/browser-product-custody.test.ts
core/meetings/modules/join/src/browser-product.test.ts
core/meetings/modules/join/src/browser-product.ts
core/meetings/modules/join/src/index.ts
core/meetings/modules/join/src/zoom/__fixtures__/README.md
core/meetings/modules/join/src/zoom/__fixtures__/official-test-page.v1.json
Commit 588c689682f2b5cfefa123970c07f7791389cebe remains historical P12-failure evidence. Head 26914ea8219f9c00b6a5df4715faaf3d00c21748 is superseded because review found P1/P2. All current review, PR, and further evidence bind only to 2235a2c8… / 5e4ae0e7….
That dirty tree is evidence, not an implementation candidate. No patch is to be copied wholesale from it.
Provisional source-car implementation base: exact immutable staged assembly 72ecb679761fc49668b8d48d54062868832ac1c9 (tree 627cfb4625ca802e3f377100c135837da1320a46). The 2026-07-24 yard ruling authorizes offline development from this base so #938 does not idle behind the separate causal-speaker-attribution car. This is not a delivered-base or shipping claim. Before composition, the source car must rebase onto the exact public delivered v0.12.19 ref/SHA, recompute collisions, and rerun every gate invalidated by that rebase.
Collision map
Fresh active-car audit at 72ecb679761fc49668b8d48d54062868832ac1c9 (2026-07-24T14:10Z):
| Active owner |
Exact active/reserved paths relevant to the audit |
Intersection with #938 first offline RED |
| #956 telemetry/binder car |
current worktree has only core/meetings/services/bot/src/telemetry-custody.red.test.ts; future custody/binder scope remains telemetry, captured-signal corpus, and mixed-pipeline |
none |
| #839 lifecycle handshake car |
clean provisional worktree at this same base; reserved/PR #944 scope is join-driver.ts, orchestrator.ts, lifecycle HTTP/contracts, meeting-api stop/cascade, seals/docs |
none |
| #938 first source slice |
new core/meetings/modules/join/src/browser-product.ts, its test, one offline official-test-page fixture, and only the package-local test registration if required |
self-owned |
Future #938 service/runtime propagation may approach @vexa/bot package/config and deployment files. Those are excluded from the first RED and must be re-audited after #839/#956 advance; shared hot files are sequenced rather than edited in parallel.
The provisional local v0.12.19 planning ref is 102 commits ahead of the research base and intersects the dirty research paths at nine exact files:
| Overlap |
Incoming behavior that must win/be re-localized |
core/meetings/modules/join/package.json |
#600/#846/#852/#856/#915 tests/deps and locale/redirect behavior |
core/meetings/modules/join/src/index.ts |
typed Teams auth-redirect export (#915) |
core/meetings/modules/remote-browser/package.json |
hot-bot browser runtime A/B (#164958f6) |
core/meetings/modules/remote-browser/src/browser.test.ts |
runtime A/B browser contract tests |
core/meetings/modules/remote-browser/src/browser.ts |
locale pin + runtime A/B behavior |
core/meetings/services/bot/package.json |
mixed-lane attribution/capture changes |
core/meetings/services/bot/src/capture-bridge.ts |
#852 watcher/injection work, capture-time work, runtime A/B, and #934 bounded teardown |
deploy/compose/docker-compose.yml |
current recorder/front-door deployment wiring |
deploy/helm/charts/vexa/values.yaml |
current recorder configuration |
The public rc/0.12.18 already overlaps four of these (join/package.json, join/src/index.ts, remote-browser/src/browser.ts, compose/docker-compose.yml). deploy/lite/Dockerfile.lite, release/SBOM surfaces, and Helm tests are mandatory logical rebase points even where they are not dirty-path intersections.
When v0.12.19 is delivered, recompute this table against its peeled SHA before the ready stamp. Create a fresh worktree from that SHA, re-derive each change at its point of introduction, and preserve all incoming tests/behavior. #515 must revalidate its exact image/DOM fixtures only after this browser fork freezes.
Live-resource custody
- Never publish a meeting URL/passcode, participant screenshot, or meeting content. Public evidence is redacted counts, states, timestamps, hashes, and image digests only.
- Use one newly created protected meeting; never reuse the earlier user rooms.
- Every attempt uses a fresh ephemeral profile and a new random human name.
- Record source SHA, image digest, architecture, egress/region, participant name, start/end time, outcome, and cleanup verdict for each attempt.
- Any temporary VM/browser builder records provider resource ID, owner, purpose, region, hourly price, creation time, and a deletion deadline of at most one hour. Shutdown is not deletion; billing custody ends only after provider-side deletion is verified.
- Stop at first failure or after the exact accepted count. No retry-as-flake. Confirm no participant, bot process, browser context, profile directory, or billable temporary resource remains.
Components / implementation waypoints
@vexa/join: unsigned-Zoom-only browser-product contract; bounded React name entry; exact three-clause wall; route-aware admission and verified leave.
@vexa/remote-browser: matched engine dispatch, Firefox fake-media preferences, persistent-context ownership, and cleanup on initial-page/launch failure.
@vexa/bot capture bridge: select/log browser product + exact version/platform without changing authenticated/non-Zoom lanes.
- Runtime shape:
core/meetings/modules/join/Dockerfile.env, bot image, and Lite/Compose/Helm propagation; one declared brick shape consumed by services.
- Packaging governance:
THIRD_PARTY_LICENSES.md, licenses/, license-exceptions.json, scripts/sbom.mjs, release SBOM sanity, and final-image artifact assertions.
- Docs: join/remote-browser READMEs, operator configuration/troubleshooting, and one
docs/changelog.d/ fragment.
No wire-contract or architecture graph change is expected. If implementation changes a module/data-flow boundary, stop and update the prepared scope before coding further.
Rehearsal / bounded harness
Offline first
Run on the clean delivered base before any live traffic:
pnpm --filter @vexa/join test
pnpm --filter @vexa/join build
pnpm --filter @vexa/join check:isolation
pnpm --filter @vexa/remote-browser test
pnpm --filter @vexa/remote-browser build
pnpm --filter @vexa/remote-browser check:isolation
pnpm --filter @vexa/bot test
pnpm --filter @vexa/bot build
node scripts/sbom.mjs --version v0.12.20 --output /tmp/vexa-938.spdx.json
node scripts/gates.mjs licenses
The focused research draft previously reported 36/36 Zoom tests, green join/remote-browser builds and isolation, green bot capture-launch tests, 23 runtime config/profile tests, Helm render, Lite environment hygiene, Compose config, config-contract gate, and git diff --check. Those are research evidence only and must be re-earned on the clean delivered base.
Native stock-image negative controls
Build the actual bot linux/amd64 image and Lite linux/amd64 + linux/arm64 images. For each native artifact:
- prove source SHA, image digest, Firefox rev 1532, full notice/SBOM inventory, and absence of CfT rev 1228;
- start with a fresh profile and random name;
- reach
https://zoom.us/test guest prejoin with media APIs available;
- leave/close and prove process/profile cleanup.
This phase never targets the protected meeting.
Protected-room witness
Only after every offline and native-image row is green:
- Human host creates one fresh protected Zoom meeting and keeps it open.
- Run exactly three consecutive unsigned guest attempts from the same immutable stock candidate image, each with a fresh profile and new random human name.
- Each attempt must show host-visible admission, then verified leave confirmation, recording drain, terminal
about:blank or closed context, no bot process, and profile cleanup.
- Stop immediately after 3/3 or on the first failure. Preserve the first failure privately; do not retry it as a flake.
Acceptance table
| ID |
Expected |
Required observation / oracle |
Negative control / rejection |
Status at preparation |
| A1 Browser selection |
only unsigned Zoom selects Firefox 151/rev 1532 |
unit matrix: unsigned Zoom → Firefox; authenticated Zoom + Meet/Teams/Jitsi → existing Chromium; operator override is explicit |
any default change outside unsigned Zoom |
open |
| A2 Browser ownership |
fresh Firefox profile launches with fake media and is closed/removed on every failure path |
launch, initial-page-failure, normal-close tests; product/version/platform log |
leaked context/profile or reuse of Chromium auth profile |
open |
| A3 React name entry |
settled DOM value equals requested random name before Join becomes actionable |
replacement-node fixture + delayed-reset fixture; bounded attempt/repair counts |
force-click disabled Join or unbounded fill loop |
open |
| A4 Policy wall |
denial requires all three Zoom clauses and returns a typed terminal outcome |
conjunction fixture; route/page/wall logs |
isolated RTMS/bot text in title/chat must not block |
open |
| A5 Admission/leave |
polling is bounded and route-aware; success means host-visible admission and terminal exit |
admission fixtures + leave confirmation → recording drain → about:blank/closed context |
route loss, popup, or button click alone cannot mean success |
open |
| A6 P17/browser bytes |
final images contain governed Firefox/notices/SBOM and no CfT 1228 |
licence gate, SBOM relationships, per-arch hashes, final-image file assertions |
npm licence green alone; static LGPL; CfT path/bytes present |
open |
| A7 Native negative control |
every native stock image reaches ordinary Zoom test prejoin and cleans up |
amd64 bot + amd64/arm64 Lite evidence bound to source/image digest |
emulation or operator browser is not product proof |
open |
| A8 Protected reliability |
3/3 consecutive fresh-profile admissions and 3/3 verified leaves |
host ledger + machine states + zero remaining process/profile |
stop on first failure; no retries; no earlier rooms |
open |
| A9 Docs/operator truth |
governed default, override, denial semantics, limits, and cleanup are documented |
README/config/troubleshooting + changelog fragment |
any CAPTCHA-bypass or universal-admission claim |
open |
Explicitly unclaimed
Ready and composition predicates
Source-car readiness: satisfied on 2026-07-24. The exact provisional base is 72ecb679761fc49668b8d48d54062868832ac1c9; the active #956/#839 collision audit is file-safe for the bounded first slice; the selected Playwright 1.61.1 + unmodified Firefox 151 rev 1532 P17 contract is unchanged; and the quarantined 42-path research tree remains evidence only.
One public claim may begin from fresh worktree /Users/dmitriygrankin/dev/vexa-938-zoom-firefox-source, branch codex/938-zoom-firefox-source, at that exact base. Initial authority is limited to the offline native browser/profile-selection RED, no-CfT/artifact-custody contract, and the offline official Zoom test-page fixture. No protected-room participant traffic, image publication, stage, or prod mutation is authorized until the offline and native-stock-image rows select a candidate.
Composition remains blocked until public delivered v0.12.19 exists, this source car rebases onto its peeled SHA, the collision map is recomputed against then-active owners, and all invalidated acceptance/gate rows are rerun. The provisional base must never be described as delivered or shippable.
Objective
Make the stock Vexa Zoom Web lane reliably join as an unsigned guest without disguising Zoom policy denials, force-clicking disabled controls, leaking browser contexts, or claiming teardown before the bot has actually left.
This issue is the prepared successor to #345. It is scoped to the
meet-joinbrick plus the browser runtime-shape and service adapters required to carry that brick in bot, Lite, Compose, and Helm. Post-admission audio/consent work in #515 is a parked dependency, not part of this issue.Where we are — evidence, then reading
External platform facts
Research observations
https://zoom.us/test, disposable current Firefox containerwebdriver=true;mediaDevices=trueThe current reading is that the RTMS wording is a terminal Zoom policy wall, not evidence that the meeting requires RTMS. Classification must require all three clauses so an isolated title/chat string cannot trigger it. The defect is introduced at the browser/runtime contract: the stock image carries a browser generation Zoom can classify differently. The join consumer must not spoof around its own runtime mismatch.
A second independent defect is React-controlled guest-name entry: Zoom may replace/reset the input after a write, leaving Join disabled although an earlier read appeared correct. The prepared behavior is bounded entry attempts, post-settle double verification, node-replacement handling, at most one repair, and a typed terminal result—never a forced click on a disabled button.
Selected browser/driver fork
Use Playwright 1.61.1 with its matched, unmodified Firefox 151.0 revision 1532, only for unsigned Zoom guests.
Preserve the existing Playwright 1.56/Chromium lane for authenticated profiles and every non-Zoom platform. Preserve an operator-supplied executable path as an explicit advanced override; it cannot prove the stock image works.
Upstream identity:
1.61.1, Apache-2.0: https://raw.githubusercontent.com/microsoft/playwright/v1.61.1/LICENSE151.0, revision1532: https://raw.githubusercontent.com/microsoft/playwright/v1.61.1/packages/playwright-core/browsers.jsonmcr.microsoft.com/playwright@sha256:7b86926fff94374389e8e1f4fdc5c76d050d4a06a7886bb537bf412b20e2b71eapplication.iniBuildID:20260611122632omni.ja!/chrome/toolkit/content/global/license.html, 308,060 bytes, SHA-256276c0a63176234c8aa3108e415a9e336c590ecf600bc24af7d6809d5af75436edependentlibs.list:liblgpllibs.so; probed arm64 SHA-256e09a057e89519b24f1dd8c26b29df9175c3233b86d8102ad9e13c2e9041acc66P17 / MPL / LGPL / SBOM contract
The selected fork is admissible only when all of these are true:
/ms-playwright/firefox-1532) from the current Playwright source image; they do not adopt that whole image as the final base.THIRD_PARTY_LICENSES.mdidentifies Firefox, its exact version/revision, source, images, and in-image notice paths.license-exceptions.jsonlogs the Category-B allowance for clearly demarcated, unmodified, separately shipped/dynamically loaded LGPL components. Static bundling is not accepted.scripts/sbom.mjsemits a rootCONTAINSrelationship to Firefox and FirefoxCONTAINSrelationships to separately identified LGPL runtime components. The Apache-licensed npm package is not used as a proxy for browser bytes.Rejected forks:
chromiumis Google Chrome for Testing 149/rev 1228, and npm's Apache licence does not cover those browser bytes.chrome://creditswas a sample placeholder (generate_about_creditsabsent), so it lacked a redistributable notice/source inventory.Source and custody
Repository:
Vexa-ai/vexaMilestone:
v0.12.20 — meeting lifecycle and operator truthModule:
pkg:meet-joinHuman bar: protected solo meeting, host-visible admission and leave
Preferred validator: Dmitriy Grankin as meeting host plus a fresh non-author agent validating the immutable source/image tuple
Research provenance:
6a50a2320b797919f54af9a434ae8ecdf35973fecodex/zoom-robust-joinat/Users/dmitriygrankin/dev/vexa-zoom-robust019f9070-de4b-7002-bc4b-ca698f5488b8Current provisional source candidate
Draft PR: #957
Fresh non-author review: CLEAN on the exact P1/P2 repair head; no findings
Review candidate head:
2235a2c8cc61409c613b6c4f21f26bbd5203d9fbTree:
5e4ae0e7b5c20dbe618a633bf3923914b1256773Provisional base:
72ecb679761fc49668b8d48d54062868832ac1c9Branch/worktree:
codex/938-zoom-firefox-sourceat/Users/dmitriygrankin/dev/vexa-938-zoom-firefox-sourceExact nine-file base→head manifest:
core/meetings/modules/join/package.jsoncore/meetings/modules/join/src/__fixtures__/README.mdcore/meetings/modules/join/src/__fixtures__/browser-product.contract.v1.jsoncore/meetings/modules/join/src/browser-product-custody.test.tscore/meetings/modules/join/src/browser-product.test.tscore/meetings/modules/join/src/browser-product.tscore/meetings/modules/join/src/index.tscore/meetings/modules/join/src/zoom/__fixtures__/README.mdcore/meetings/modules/join/src/zoom/__fixtures__/official-test-page.v1.jsonCommit
588c689682f2b5cfefa123970c07f7791389ceberemains historical P12-failure evidence. Head26914ea8219f9c00b6a5df4715faaf3d00c21748is superseded because review found P1/P2. All current review, PR, and further evidence bind only to2235a2c8…/5e4ae0e7….That dirty tree is evidence, not an implementation candidate. No patch is to be copied wholesale from it.
Provisional source-car implementation base: exact immutable staged assembly
72ecb679761fc49668b8d48d54062868832ac1c9(tree627cfb4625ca802e3f377100c135837da1320a46). The 2026-07-24 yard ruling authorizes offline development from this base so #938 does not idle behind the separate causal-speaker-attribution car. This is not a delivered-base or shipping claim. Before composition, the source car must rebase onto the exact public deliveredv0.12.19ref/SHA, recompute collisions, and rerun every gate invalidated by that rebase.Collision map
Fresh active-car audit at
72ecb679761fc49668b8d48d54062868832ac1c9(2026-07-24T14:10Z):core/meetings/services/bot/src/telemetry-custody.red.test.ts; future custody/binder scope remains telemetry, captured-signal corpus, and mixed-pipelinejoin-driver.ts,orchestrator.ts, lifecycle HTTP/contracts, meeting-api stop/cascade, seals/docscore/meetings/modules/join/src/browser-product.ts, its test, one offline official-test-page fixture, and only the package-local test registration if requiredFuture #938 service/runtime propagation may approach
@vexa/botpackage/config and deployment files. Those are excluded from the first RED and must be re-audited after #839/#956 advance; shared hot files are sequenced rather than edited in parallel.The provisional local v0.12.19 planning ref is 102 commits ahead of the research base and intersects the dirty research paths at nine exact files:
core/meetings/modules/join/package.jsoncore/meetings/modules/join/src/index.tscore/meetings/modules/remote-browser/package.jsoncore/meetings/modules/remote-browser/src/browser.test.tscore/meetings/modules/remote-browser/src/browser.tscore/meetings/services/bot/package.jsoncore/meetings/services/bot/src/capture-bridge.tsdeploy/compose/docker-compose.ymldeploy/helm/charts/vexa/values.yamlThe public
rc/0.12.18already overlaps four of these (join/package.json,join/src/index.ts,remote-browser/src/browser.ts,compose/docker-compose.yml).deploy/lite/Dockerfile.lite, release/SBOM surfaces, and Helm tests are mandatory logical rebase points even where they are not dirty-path intersections.When
v0.12.19is delivered, recompute this table against its peeled SHA before the ready stamp. Create a fresh worktree from that SHA, re-derive each change at its point of introduction, and preserve all incoming tests/behavior. #515 must revalidate its exact image/DOM fixtures only after this browser fork freezes.Live-resource custody
Components / implementation waypoints
@vexa/join: unsigned-Zoom-only browser-product contract; bounded React name entry; exact three-clause wall; route-aware admission and verified leave.@vexa/remote-browser: matched engine dispatch, Firefox fake-media preferences, persistent-context ownership, and cleanup on initial-page/launch failure.@vexa/botcapture bridge: select/log browser product + exact version/platform without changing authenticated/non-Zoom lanes.core/meetings/modules/join/Dockerfile.env, bot image, and Lite/Compose/Helm propagation; one declared brick shape consumed by services.THIRD_PARTY_LICENSES.md,licenses/,license-exceptions.json,scripts/sbom.mjs, release SBOM sanity, and final-image artifact assertions.docs/changelog.d/fragment.No wire-contract or architecture graph change is expected. If implementation changes a module/data-flow boundary, stop and update the prepared scope before coding further.
Rehearsal / bounded harness
Offline first
Run on the clean delivered base before any live traffic:
The focused research draft previously reported 36/36 Zoom tests, green join/remote-browser builds and isolation, green bot capture-launch tests, 23 runtime config/profile tests, Helm render, Lite environment hygiene, Compose config, config-contract gate, and
git diff --check. Those are research evidence only and must be re-earned on the clean delivered base.Native stock-image negative controls
Build the actual bot
linux/amd64image and Litelinux/amd64+linux/arm64images. For each native artifact:https://zoom.us/testguest prejoin with media APIs available;This phase never targets the protected meeting.
Protected-room witness
Only after every offline and native-image row is green:
about:blankor closed context, no bot process, and profile cleanup.Acceptance table
about:blank/closed contextExplicitly unclaimed
Ready and composition predicates
Source-car readiness: satisfied on 2026-07-24. The exact provisional base is
72ecb679761fc49668b8d48d54062868832ac1c9; the active #956/#839 collision audit is file-safe for the bounded first slice; the selected Playwright 1.61.1 + unmodified Firefox 151 rev 1532 P17 contract is unchanged; and the quarantined 42-path research tree remains evidence only.One public claim may begin from fresh worktree
/Users/dmitriygrankin/dev/vexa-938-zoom-firefox-source, branchcodex/938-zoom-firefox-source, at that exact base. Initial authority is limited to the offline native browser/profile-selection RED, no-CfT/artifact-custody contract, and the offline official Zoom test-page fixture. No protected-room participant traffic, image publication, stage, or prod mutation is authorized until the offline and native-stock-image rows select a candidate.Composition remains blocked until public delivered
v0.12.19exists, this source car rebases onto its peeled SHA, the collision map is recomputed against then-active owners, and all invalidated acceptance/gate rows are rerun. The provisional base must never be described as delivered or shippable.