Skip to content

test: harden cross-platform CI and packaged desktop E2E - #130

Closed
slashdevcorpse wants to merge 10 commits into
mainfrom
codex/safe-port-integration
Closed

test: harden cross-platform CI and packaged desktop E2E#130
slashdevcorpse wants to merge 10 commits into
mainfrom
codex/safe-port-integration

Conversation

@slashdevcorpse

@slashdevcorpse slashdevcorpse commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • run the full unit suite across Linux, Windows, and macOS with explicit platform quality lanes
  • make the stable browser suite blocking while keeping only registered quarantine cases non-blocking, including a Windows browser lane
  • build same-platform packaged desktop artifacts and run seven offline Electron journeys on Linux and Windows
  • add identity-verified process-tree teardown, failure-only artifacts, and diagnostic secret redaction
  • preserve the managed browser target during transient adopted-webview loads and harden the E2E-only renderer readiness probe across deferred reconnects

Scope boundary

This intentionally does not bring back legacy provider lifecycle or broad process-ownership changes. Production behavior changes are limited to the adopted-webview target preservation fix; reconnect waiting is isolated to the desktop E2E harness.

Verification

  • TURBO_CONCURRENCY=1 bun turbo test on Windows: 9/9 package tasks green
  • bun run build:desktop: passed
  • bun run test:e2e: 7/7 passed twice on the packaged Windows artifact (6.9m and 6.4m)
  • workflow/quarantine tests: 34/34 passed
  • workflow verifier: 7 allowed and 4 disabled paths passed
  • focused desktop tests: 45/45 passed
  • focused renderer transport tests: 44/44 passed
  • Windows launcher source contract: 4/4 passed
  • targeted formatting check and git diff --check: passed

Hosted CI remains the authoritative fmt, lint, typecheck, cross-platform unit, browser, packaged E2E, release smoke, dependency review, and CodeQL gate.


Summary by cubic

Hardened CI and E2E: added cross-platform unit and browser lanes with a reviewed quarantine gate, plus packaged Electron journeys on Linux and Windows. Also fixed a desktop navigation edge case to prevent transient target loss during adopted webview loads.

  • New Features

    • CI: run full unit suite on Linux, Windows, and macOS with explicit lanes.
    • CI: add stable blocking browser suite and a Windows browser lane; quarantine-only lane is non-blocking.
    • Quarantine: machine-readable registry at .github/quarantine.yml with validation and summaries; Vitest configs select tests via registered [quarantine:<id>] markers.
    • Desktop E2E: run seven offline, packaged Electron journeys on Linux and Windows using Playwright; builds artifacts per platform and uploads failure-only reports.
    • Desktop E2E hardening: fake Codex CLI with isolated PATH, strict network guards, identity-verified process-tree teardown, and diagnostic secret redaction.
    • Renderer readiness: install a narrow window.__synaraE2e probe that requires a stable, open transport session and waits through reconnect windows.
    • Misc: enforce LF line endings cross-platform, cap test workers to avoid saturation, and ignore desktop Playwright outputs.
    • Dependencies: add @playwright/test.
  • Bug Fixes

    • Desktop: preserve the managed browser target while an adopted inert webview begins loading it to avoid aborts caused by transient about:blank.

Written for commit 84cdefe. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Improved embedded browser tab loading state and URL handling during navigation.
    • Enhanced desktop process cleanup to prevent stale processes after closing the app.
    • Added diagnostic redaction to protect credentials and access tokens in persisted logs.
  • Quality Improvements

    • Added comprehensive desktop end-to-end coverage for chat, approvals, terminal use, previews, browser navigation, and restart persistence.
    • Strengthened cross-platform browser and desktop test validation across Linux and Windows.
    • Improved test stability by controlling concurrency and accommodating slower test environments.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

slashdevcorpse has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds registry-driven browser quarantine management, restructures CI across Linux and Windows, introduces packaged Electron desktop E2E coverage with isolated fixtures and process cleanup, preserves adopted webview URLs during loading, and adjusts test runtime configuration.

Changes

Quarantine registry and CI

Layer / File(s) Summary
Registry, selectors, and CLI
.github/quarantine.yml, scripts/lib/quarantine-registry.ts, scripts/quarantine-registry.ts, scripts/lib/quarantine-registry.test.ts
Adds strict quarantine registry validation, platform-specific selectors, summaries, baseline handling, and CLI validation/run/summary commands.
Browser selection
apps/web/vitest.browser*.ts, apps/web/src/components/ChatView.browser.tsx, apps/web/BROWSER_TEST_QUARANTINE.md
Replaces hardcoded geometry markers with registry-backed quarantine markers and stable-test selection.
CI workflow and contracts
.github/workflows/ci.yml, scripts/lib/workflow-contracts.ts, scripts/lib/workflow-contracts.test.ts
Splits quality jobs, adds Windows and packaged desktop E2E lanes, validates artifact flow and quarantine gating, and adds fail-closed aggregate checks.

Desktop E2E harness

Layer / File(s) Summary
Isolated Electron fixture
apps/desktop/e2e/desktop.fixture.ts, apps/desktop/e2e/fixtures/*
Adds fake Codex execution, sanitized environments, network guards, redacted diagnostics, renderer readiness checks, and lifecycle teardown.
Process-tree teardown
apps/desktop/e2e/support/processTree.ts, apps/desktop/e2e/support/processTree.test.ts
Adds cross-platform process discovery, identity verification, descendant collection, termination, and cleanup tests.
Desktop workflows
apps/desktop/e2e/desktop.e2e.ts, apps/desktop/e2e/playwright.config.ts, apps/desktop/e2e/global-setup.ts
Adds packaged Electron tests for chat, approvals, interrupts, terminals, markdown, browser navigation, and restart persistence.

Adopted webview handling

Layer / File(s) Summary
Managed URL preservation
apps/desktop/src/browserManager.ts, apps/desktop/src/browserManager.test.ts
Ignores transient about:blank during adopted-webview loading and retains the managed target URL while reporting loading state.

Test stability and platform fixtures

Layer / File(s) Summary
Runtime and platform test updates
apps/web/package.json, packages/*/package.json, scripts/package.json, scripts/benchmark-windows-command-discovery.test.ts, apps/server/src/provider/windowsJobLauncherSourceContract.test.ts
Constrains Vitest workers, extends selected timeouts, types Windows Store fixture lookup, and normalizes launcher source line endings.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: emanuele-web04

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: cross-platform CI hardening plus packaged desktop E2E coverage.
Description check ✅ Passed It covers what changed, why, and verification, though the headings differ from the template and the checklist is omitted.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
scripts/lib/quarantine-registry.test.ts (1)

50-157: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Solid coverage of the happy paths; a few validation branches remain untested.

Duplicate id, sorted-id-order violations, path escaping the repo root, non-existent/non-file paths, and a marker missing from its declared file are all handled in validateQuarantineRegistry but have no corresponding test case here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/lib/quarantine-registry.test.ts` around lines 50 - 157, Extend the
“quarantine registry” tests to cover the remaining validateQuarantineRegistry
validation branches: duplicate ids, ids not in sorted order, paths escaping
repositoryRoot, missing or directory paths, and markers absent from their
declared source file. For each case, construct a minimal invalid registry
fixture and assert the corresponding validation error.
apps/web/vitest.browser.quarantine.ts (1)

23-25: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Avoid rescanning the repository on browser-config load
browserQuarantineTestNamePattern() is used by both browser configs, so this walks apps/, packages/, and scripts/ twice during browser-suite startup. CI already validates the registry separately, so validateSources: false here would keep the registry/schema checks without the redundant traversal.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/vitest.browser.quarantine.ts` around lines 23 - 25, Update the
validateQuarantineRegistry call in the browser configuration load to pass
validateSources: false alongside repositoryRoot, preserving registry and schema
validation while avoiding the redundant repository scan.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 657-678: Update the quality aggregate gate to explicitly include
the macos_arm64 job if macOS is intended to be required for merging: add it to
needs and require its result to equal success alongside the existing
dependencies. If macos_arm64 is intentionally non-blocking, leave the workflow
unchanged and document or confirm that intent.

In `@scripts/lib/quarantine-registry.ts`:
- Around line 145-240: Refactor the validation loop around the entry field
checks to record the error count before validating each entry, then append the
constructed entry only when no new errors were added. Remove the duplicated
conjunctive predicate guarding entries.push, while preserving all existing
validations, including rejecting future lastFlaked dates. Use the existing
parsed field values and error collection to construct the valid entry.

---

Nitpick comments:
In `@apps/web/vitest.browser.quarantine.ts`:
- Around line 23-25: Update the validateQuarantineRegistry call in the browser
configuration load to pass validateSources: false alongside repositoryRoot,
preserving registry and schema validation while avoiding the redundant
repository scan.

In `@scripts/lib/quarantine-registry.test.ts`:
- Around line 50-157: Extend the “quarantine registry” tests to cover the
remaining validateQuarantineRegistry validation branches: duplicate ids, ids not
in sorted order, paths escaping repositoryRoot, missing or directory paths, and
markers absent from their declared source file. For each case, construct a
minimal invalid registry fixture and assert the corresponding validation error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 016a58ed-7a74-4274-8f8d-ac843395e42d

📥 Commits

Reviewing files that changed from the base of the PR and between c19f103 and 84cdefe.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (46)
  • .gitattributes
  • .github/quarantine.yml
  • .github/workflows/ci.yml
  • .gitignore
  • apps/desktop/e2e/desktop.e2e.ts
  • apps/desktop/e2e/desktop.fixture.test.ts
  • apps/desktop/e2e/desktop.fixture.ts
  • apps/desktop/e2e/fixtures/diagnostic-redaction.cjs
  • apps/desktop/e2e/fixtures/electron-bootstrap.cjs
  • apps/desktop/e2e/fixtures/fake-codex.ts
  • apps/desktop/e2e/fixtures/network-guard.cjs
  • apps/desktop/e2e/global-setup.ts
  • apps/desktop/e2e/playwright.config.ts
  • apps/desktop/e2e/support/processTree.test.ts
  • apps/desktop/e2e/support/processTree.ts
  • apps/desktop/e2e/tsconfig.json
  • apps/desktop/package.json
  • apps/desktop/src/browserManager.test.ts
  • apps/desktop/src/browserManager.ts
  • apps/desktop/src/preload.ts
  • apps/server/src/provider/windowsJobLauncherSourceContract.test.ts
  • apps/web/BROWSER_TEST_QUARANTINE.md
  • apps/web/package.json
  • apps/web/src/components/ChatMarkdown.test.tsx
  • apps/web/src/components/ChatView.browser.tsx
  • apps/web/src/components/Sidebar.import.test.ts
  • apps/web/src/components/chat/MessagesTimeline.test.tsx
  • apps/web/src/vite-env.d.ts
  • apps/web/src/wsNativeApi.test.ts
  • apps/web/src/wsNativeApi.ts
  • apps/web/src/wsTransport.ts
  • apps/web/vitest.browser.geometry.config.ts
  • apps/web/vitest.browser.quarantine.ts
  • apps/web/vitest.browser.stable.config.ts
  • package.json
  • packages/contracts/package.json
  • packages/contracts/src/ipc.ts
  • packages/shared/package.json
  • scripts/benchmark-windows-command-discovery.test.ts
  • scripts/lib/quarantine-registry.test.ts
  • scripts/lib/quarantine-registry.ts
  • scripts/lib/release-worktree-cleanliness.test.ts
  • scripts/lib/workflow-contracts.test.ts
  • scripts/lib/workflow-contracts.ts
  • scripts/package.json
  • scripts/quarantine-registry.ts

Comment thread .github/workflows/ci.yml
Comment on lines +657 to +678
quality:
name: quality
if: always()
needs:
- quality_linux
- quality_windows
- unit
- browser_windows
- e2e_linux
- e2e_windows
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Require every quality dependency to succeed
run: |
test "${{ needs.quality_linux.result }}" = success
test "${{ needs.quality_windows.result }}" = success
test "${{ needs.unit.result }}" = success
test "${{ needs.browser_windows.result }}" = success
test "${{ needs.e2e_linux.result }}" = success
test "${{ needs.e2e_windows.result }}" = success

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Confirm macos_arm64 is intentionally excluded from the merge gate.

The aggregate gates quality_linux, quality_windows, unit, browser_windows, e2e_linux, and e2e_windows. windows_x64 is transitively enforced because e2e_windows needs it (a failed producer skips the consumer, which the = success check rejects). However, macos_arm64 has no downstream consumer and is absent from needs, so its failures (native build / packaged smoke) would not block merge. If macOS is meant to be a required lane, add it to the aggregate; otherwise confirm the intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 657 - 678, Update the quality
aggregate gate to explicitly include the macos_arm64 job if macOS is intended to
be required for merging: add it to needs and require its result to equal success
alongside the existing dependencies. If macos_arm64 is intentionally
non-blocking, leave the workflow unchanged and document or confirm that intent.

Comment on lines +145 to +240
for (const [index, value] of document.entries.entries()) {
const label = `Quarantine entry ${index + 1}`;
if (!isRecord(value)) {
errors.push(`${label} must be a mapping.`);
continue;
}
for (const key of Object.keys(value)) {
if (!ENTRY_KEYS.has(key)) errors.push(`${label} has unsupported key \`${key}\`.`);
}

const id = value.id;
const path = value.path;
const marker = value.marker;
const suite = value.suite;
const platforms = value.platform;
const reason = value.reason;
const owner = value.owner;
const lastFlaked = value.lastFlaked;
const cases = value.cases;

if (typeof id !== "string" || !ID_PATTERN.test(id)) errors.push(`${label} id is invalid.`);
if (typeof id === "string") {
if (ids.has(id)) errors.push(`${label} duplicates id \`${id}\`.`);
ids.add(id);
}
if (
typeof path !== "string" ||
path.length === 0 ||
path.includes("\\") ||
path.startsWith("/")
) {
errors.push(`${label} path must be a repository-relative POSIX path.`);
}
if (typeof marker !== "string" || typeof id !== "string" || marker !== `[quarantine:${id}]`) {
errors.push(`${label} marker must exactly match its id.`);
}
if (suite !== "browser-geometry") errors.push(`${label} suite is unsupported.`);
if (!Array.isArray(platforms) || platforms.length === 0 || !platforms.every(isPlatform)) {
errors.push(`${label} platform must contain supported platforms.`);
} else {
if (new Set(platforms).size !== platforms.length) errors.push(`${label} repeats a platform.`);
const sorted = [...platforms].sort(
(left, right) => PLATFORM_ORDER.get(left)! - PLATFORM_ORDER.get(right)!,
);
if (sorted.some((platform, platformIndex) => platform !== platforms[platformIndex])) {
errors.push(`${label} platforms must use linux, windows order.`);
}
}
if (typeof reason !== "string" || reason.trim().length < 12) {
errors.push(`${label} reason must explain the quarantine.`);
}
if (typeof owner !== "string" || owner.trim().length === 0) {
errors.push(`${label} owner must be non-empty.`);
}
const lastFlakedDate = typeof lastFlaked === "string" ? parseIsoDate(lastFlaked) : null;
if (!lastFlakedDate) errors.push(`${label} lastFlaked must be a real YYYY-MM-DD date.`);
else if (lastFlakedDate > today) errors.push(`${label} lastFlaked cannot be in the future.`);
if (!Number.isInteger(cases) || (cases as number) < 1) {
errors.push(`${label} cases must be a positive integer.`);
}

if (
typeof id === "string" &&
ID_PATTERN.test(id) &&
typeof path === "string" &&
path.length > 0 &&
!path.includes("\\") &&
!path.startsWith("/") &&
typeof marker === "string" &&
marker === `[quarantine:${id}]` &&
suite === "browser-geometry" &&
Array.isArray(platforms) &&
platforms.length > 0 &&
platforms.every(isPlatform) &&
typeof reason === "string" &&
reason.trim().length >= 12 &&
typeof owner === "string" &&
owner.trim().length > 0 &&
typeof lastFlaked === "string" &&
lastFlakedDate &&
Number.isInteger(cases) &&
(cases as number) > 0
) {
entries.push({
id,
path,
marker,
suite,
platform: platforms,
reason,
owner,
lastFlaked,
cases: cases as number,
});
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Duplicate validation predicates for id/path/marker/suite/platform/reason/owner/lastFlaked/cases.

Lines 165-204 and 206-227 encode the same set of field checks twice — once to accumulate error messages, once (inverted/conjunctive) to gate the entries.push. They already drifted: the first pass additionally rejects a future lastFlaked (Line 201), but the second pass's gate only checks that the date parsed, not that it isn't in the future (Line 224). It's currently harmless only because the function nulls the whole registry whenever any error exists, but that's an easy invariant to break in a future edit.

Track whether the current entry produced any new errors and build the entry from that, instead of restating every predicate.

As per coding guidelines, **/*.{ts,tsx}: "avoid duplicating logic across files and prefer reusable modules over local shortcuts" — the same principle applies to duplicated logic within a file.

♻️ Proposed refactor to remove the duplicate predicate block
   for (const [index, value] of document.entries.entries()) {
     const label = `Quarantine entry ${index + 1}`;
     if (!isRecord(value)) {
       errors.push(`${label} must be a mapping.`);
       continue;
     }
     for (const key of Object.keys(value)) {
       if (!ENTRY_KEYS.has(key)) errors.push(`${label} has unsupported key \`${key}\`.`);
     }
+    const errorsBeforeEntry = errors.length;

     const id = value.id;
     const path = value.path;
     const marker = value.marker;
     const suite = value.suite;
     const platforms = value.platform;
     const reason = value.reason;
     const owner = value.owner;
     const lastFlaked = value.lastFlaked;
     const cases = value.cases;

     if (typeof id !== "string" || !ID_PATTERN.test(id)) errors.push(`${label} id is invalid.`);
     if (typeof id === "string") {
       if (ids.has(id)) errors.push(`${label} duplicates id \`${id}\`.`);
       ids.add(id);
     }
     // ...unchanged per-field checks (path, marker, suite, platform, reason, owner, lastFlaked, cases)...

-    if (
-      typeof id === "string" &&
-      ID_PATTERN.test(id) &&
-      typeof path === "string" &&
-      path.length > 0 &&
-      !path.includes("\\") &&
-      !path.startsWith("/") &&
-      typeof marker === "string" &&
-      marker === `[quarantine:${id}]` &&
-      suite === "browser-geometry" &&
-      Array.isArray(platforms) &&
-      platforms.length > 0 &&
-      platforms.every(isPlatform) &&
-      typeof reason === "string" &&
-      reason.trim().length >= 12 &&
-      typeof owner === "string" &&
-      owner.trim().length > 0 &&
-      typeof lastFlaked === "string" &&
-      lastFlakedDate &&
-      Number.isInteger(cases) &&
-      (cases as number) > 0
-    ) {
+    if (errors.length === errorsBeforeEntry) {
       entries.push({
-        id,
-        path,
-        marker,
-        suite,
-        platform: platforms,
-        reason,
-        owner,
-        lastFlaked,
+        id: id as string,
+        path: path as string,
+        marker: marker as string,
+        suite: suite as QuarantineEntry["suite"],
+        platform: platforms as readonly QuarantinePlatform[],
+        reason: reason as string,
+        owner: owner as string,
+        lastFlaked: lastFlaked as string,
         cases: cases as number,
       });
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const [index, value] of document.entries.entries()) {
const label = `Quarantine entry ${index + 1}`;
if (!isRecord(value)) {
errors.push(`${label} must be a mapping.`);
continue;
}
for (const key of Object.keys(value)) {
if (!ENTRY_KEYS.has(key)) errors.push(`${label} has unsupported key \`${key}\`.`);
}
const id = value.id;
const path = value.path;
const marker = value.marker;
const suite = value.suite;
const platforms = value.platform;
const reason = value.reason;
const owner = value.owner;
const lastFlaked = value.lastFlaked;
const cases = value.cases;
if (typeof id !== "string" || !ID_PATTERN.test(id)) errors.push(`${label} id is invalid.`);
if (typeof id === "string") {
if (ids.has(id)) errors.push(`${label} duplicates id \`${id}\`.`);
ids.add(id);
}
if (
typeof path !== "string" ||
path.length === 0 ||
path.includes("\\") ||
path.startsWith("/")
) {
errors.push(`${label} path must be a repository-relative POSIX path.`);
}
if (typeof marker !== "string" || typeof id !== "string" || marker !== `[quarantine:${id}]`) {
errors.push(`${label} marker must exactly match its id.`);
}
if (suite !== "browser-geometry") errors.push(`${label} suite is unsupported.`);
if (!Array.isArray(platforms) || platforms.length === 0 || !platforms.every(isPlatform)) {
errors.push(`${label} platform must contain supported platforms.`);
} else {
if (new Set(platforms).size !== platforms.length) errors.push(`${label} repeats a platform.`);
const sorted = [...platforms].sort(
(left, right) => PLATFORM_ORDER.get(left)! - PLATFORM_ORDER.get(right)!,
);
if (sorted.some((platform, platformIndex) => platform !== platforms[platformIndex])) {
errors.push(`${label} platforms must use linux, windows order.`);
}
}
if (typeof reason !== "string" || reason.trim().length < 12) {
errors.push(`${label} reason must explain the quarantine.`);
}
if (typeof owner !== "string" || owner.trim().length === 0) {
errors.push(`${label} owner must be non-empty.`);
}
const lastFlakedDate = typeof lastFlaked === "string" ? parseIsoDate(lastFlaked) : null;
if (!lastFlakedDate) errors.push(`${label} lastFlaked must be a real YYYY-MM-DD date.`);
else if (lastFlakedDate > today) errors.push(`${label} lastFlaked cannot be in the future.`);
if (!Number.isInteger(cases) || (cases as number) < 1) {
errors.push(`${label} cases must be a positive integer.`);
}
if (
typeof id === "string" &&
ID_PATTERN.test(id) &&
typeof path === "string" &&
path.length > 0 &&
!path.includes("\\") &&
!path.startsWith("/") &&
typeof marker === "string" &&
marker === `[quarantine:${id}]` &&
suite === "browser-geometry" &&
Array.isArray(platforms) &&
platforms.length > 0 &&
platforms.every(isPlatform) &&
typeof reason === "string" &&
reason.trim().length >= 12 &&
typeof owner === "string" &&
owner.trim().length > 0 &&
typeof lastFlaked === "string" &&
lastFlakedDate &&
Number.isInteger(cases) &&
(cases as number) > 0
) {
entries.push({
id,
path,
marker,
suite,
platform: platforms,
reason,
owner,
lastFlaked,
cases: cases as number,
});
}
}
for (const [index, value] of document.entries.entries()) {
const label = `Quarantine entry ${index + 1}`;
if (!isRecord(value)) {
errors.push(`${label} must be a mapping.`);
continue;
}
for (const key of Object.keys(value)) {
if (!ENTRY_KEYS.has(key)) errors.push(`${label} has unsupported key \`${key}\`.`);
}
const errorsBeforeEntry = errors.length;
const id = value.id;
const path = value.path;
const marker = value.marker;
const suite = value.suite;
const platforms = value.platform;
const reason = value.reason;
const owner = value.owner;
const lastFlaked = value.lastFlaked;
const cases = value.cases;
if (typeof id !== "string" || !ID_PATTERN.test(id)) errors.push(`${label} id is invalid.`);
if (typeof id === "string") {
if (ids.has(id)) errors.push(`${label} duplicates id \`${id}\`.`);
ids.add(id);
}
if (
typeof path !== "string" ||
path.length === 0 ||
path.includes("\\") ||
path.startsWith("/")
) {
errors.push(`${label} path must be a repository-relative POSIX path.`);
}
if (typeof marker !== "string" || typeof id !== "string" || marker !== `[quarantine:${id}]`) {
errors.push(`${label} marker must exactly match its id.`);
}
if (suite !== "browser-geometry") errors.push(`${label} suite is unsupported.`);
if (!Array.isArray(platforms) || platforms.length === 0 || !platforms.every(isPlatform)) {
errors.push(`${label} platform must contain supported platforms.`);
} else {
if (new Set(platforms).size !== platforms.length) errors.push(`${label} repeats a platform.`);
const sorted = [...platforms].sort(
(left, right) => PLATFORM_ORDER.get(left)! - PLATFORM_ORDER.get(right)!,
);
if (sorted.some((platform, platformIndex) => platform !== platforms[platformIndex])) {
errors.push(`${label} platforms must use linux, windows order.`);
}
}
if (typeof reason !== "string" || reason.trim().length < 12) {
errors.push(`${label} reason must explain the quarantine.`);
}
if (typeof owner !== "string" || owner.trim().length === 0) {
errors.push(`${label} owner must be non-empty.`);
}
const lastFlakedDate = typeof lastFlaked === "string" ? parseIsoDate(lastFlaked) : null;
if (!lastFlakedDate) errors.push(`${label} lastFlaked must be a real YYYY-MM-DD date.`);
else if (lastFlakedDate > today) errors.push(`${label} lastFlaked cannot be in the future.`);
if (!Number.isInteger(cases) || (cases as number) < 1) {
errors.push(`${label} cases must be a positive integer.`);
}
if (errors.length === errorsBeforeEntry) {
entries.push({
id: id as string,
path: path as string,
marker: marker as string,
suite: suite as QuarantineEntry["suite"],
platform: platforms as readonly QuarantinePlatform[],
reason: reason as string,
owner: owner as string,
lastFlaked: lastFlaked as string,
cases: cases as number,
});
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/lib/quarantine-registry.ts` around lines 145 - 240, Refactor the
validation loop around the entry field checks to record the error count before
validating each entry, then append the constructed entry only when no new errors
were added. Remove the duplicated conjunctive predicate guarding entries.push,
while preserving all existing validations, including rejecting future lastFlaked
dates. Use the existing parsed field values and error collection to construct
the valid entry.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 47 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/lib/workflow-contracts.ts">

<violation number="1" location="scripts/lib/workflow-contracts.ts:1667">
P2: An additional failure-masked command can bypass the nonblocking-test policy: `node scripts/quarantine-registry.ts run --platform linux && bun run ...` passes this prefix check, while failure from the appended command is ignored. Restrict this allowance to the two exact registered quarantine commands.</violation>

<violation number="2" location="scripts/lib/workflow-contracts.ts:1728">
P2: Runner validation now accepts `${{ matrix.runner }}` outside the unit job. A new CI job can therefore evade the approved-runner allowlist (or fail at runtime without a matrix) while the contract verifier succeeds; scope this exception to `jobs.unit.runs-on`.</violation>
</file>

<file name="apps/desktop/e2e/fixtures/electron-bootstrap.cjs">

<violation number="1" location="apps/desktop/e2e/fixtures/electron-bootstrap.cjs:67">
P2: The onCompleted handler throws if a completed request has an invalid URL, while the two sibling handlers safely catch that case. Wrap the URL parse in a try-catch consistent with the pattern used in onBeforeRequest and onErrorOccurred.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

for (const runner of runners) {
if (typeof runner !== "string" || !APPROVED_RUNNERS.has(runner)) {
const isCiUnitMatrixRunner =
policy.path === ".github/workflows/ci.yml" && runner === MATRIX_RUNNER_EXPRESSION;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Runner validation now accepts ${{ matrix.runner }} outside the unit job. A new CI job can therefore evade the approved-runner allowlist (or fail at runtime without a matrix) while the contract verifier succeeds; scope this exception to jobs.unit.runs-on.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/lib/workflow-contracts.ts, line 1728:

<comment>Runner validation now accepts `${{ matrix.runner }}` outside the unit job. A new CI job can therefore evade the approved-runner allowlist (or fail at runtime without a matrix) while the contract verifier succeeds; scope this exception to `jobs.unit.runs-on`.</comment>

<file context>
@@ -948,7 +1724,9 @@ function validateAllowedWorkflow(
   for (const runner of runners) {
-    if (typeof runner !== "string" || !APPROVED_RUNNERS.has(runner)) {
+    const isCiUnitMatrixRunner =
+      policy.path === ".github/workflows/ci.yml" && runner === MATRIX_RUNNER_EXPRESSION;
+    if (typeof runner !== "string" || (!APPROVED_RUNNERS.has(runner) && !isCiUnitMatrixRunner)) {
       errors.push(`${policy.path} references unsupported runner ${String(runner)}.`);
</file context>

const allowed =
step["continue-on-error"] === true &&
typeof step.run === "string" &&
normalizeShellCommand(step.run).startsWith("node scripts/quarantine-registry.ts run ");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: An additional failure-masked command can bypass the nonblocking-test policy: node scripts/quarantine-registry.ts run --platform linux && bun run ... passes this prefix check, while failure from the appended command is ignored. Restrict this allowance to the two exact registered quarantine commands.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/lib/workflow-contracts.ts, line 1667:

<comment>An additional failure-masked command can bypass the nonblocking-test policy: `node scripts/quarantine-registry.ts run --platform linux && bun run ...` passes this prefix check, while failure from the appended command is ignored. Restrict this allowance to the two exact registered quarantine commands.</comment>

<file context>
@@ -896,6 +1656,22 @@ function validateCiArchitecture(workflow: UnknownRecord, errors: string[]): void
+      const allowed =
+        step["continue-on-error"] === true &&
+        typeof step.run === "string" &&
+        normalizeShellCommand(step.run).startsWith("node scripts/quarantine-registry.ts run ");
+      if (!allowed && step["continue-on-error"] !== false) {
+        errors.push(
</file context>
Suggested change
normalizeShellCommand(step.run).startsWith("node scripts/quarantine-registry.ts run ");
[
"node scripts/quarantine-registry.ts run --platform linux",
"node scripts/quarantine-registry.ts run --platform windows",
].includes(normalizeShellCommand(step.run));

callback({ cancel: true });
});
guardedSession.webRequest.onCompleted({ urls: ["<all_urls>"] }, (details) => {
const parsed = new URL(details.url);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The onCompleted handler throws if a completed request has an invalid URL, while the two sibling handlers safely catch that case. Wrap the URL parse in a try-catch consistent with the pattern used in onBeforeRequest and onErrorOccurred.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/e2e/fixtures/electron-bootstrap.cjs, line 67:

<comment>The onCompleted handler throws if a completed request has an invalid URL, while the two sibling handlers safely catch that case. Wrap the URL parse in a try-catch consistent with the pattern used in onBeforeRequest and onErrorOccurred.</comment>

<file context>
@@ -0,0 +1,148 @@
+    callback({ cancel: true });
+  });
+  guardedSession.webRequest.onCompleted({ urls: ["<all_urls>"] }, (details) => {
+    const parsed = new URL(details.url);
+    if (NETWORK_PROTOCOLS.has(parsed.protocol) && isLoopbackHost(parsed.hostname)) {
+      recordNetworkEvent({
</file context>
Suggested change
const parsed = new URL(details.url);
let parsed;
try {
parsed = new URL(details.url);
} catch {
return;
}

@slashdevcorpse

Copy link
Copy Markdown
Owner Author

Closing this stale-base prototype without merge so it cannot race the Windows .9 release. The exact head is not qualified (required quality failed; Windows E2E 5/7; Linux E2E 0/7; Windows/macOS unit failures; five unresolved threads). Product browser lifecycle work remains in #123, installed NSIS qualification in #11, production process ownership in #7, and the reusable Windows-first test/CI scope is tracked in #133. The .9 installer timeout is outside this diff.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant