Test Framework Documentation
This document describes the unit testing framework setup for the Wegent project.
Pre-push checks run the complete frontend unit suite with two Jest workers by default to prevent concurrent JSDOM instances from causing resource-contention timeouts. Set FRONTEND_PRE_PUSH_TEST_WORKERS to adjust concurrency; this does not change test scope or timeout limits.
Overviewβ
The project includes comprehensive unit testing support across all modules:
- Backend (FastAPI): pytest + pytest-asyncio + pytest-cov + pytest-mock
- Executor (AI Agent Engine): pytest + pytest-mock + pytest-asyncio
- Executor Manager (Task Management): pytest + pytest-mock + pytest-cov
- Shared (Utilities): pytest + pytest-cov
- Frontend (Next.js + React 19): Jest + @testing-library/react
- Wework (Electron + React): Vitest + @testing-library/react and the Node.js test runner
Maintaining Wework Unit Testsβ
Run related tests with pnpm --filter wework test <test-file>. Count expanded parameterized cases when measuring reductions, rather than files or test() declarations. Do not reduce the count by skipping cases, merging tests, or changing discovery rules.
Prioritize behavior coverage for task creation and sending, permissions and resource ownership, persistence, failure recovery, state machines, and upgrade or rollback. Tests with identical inputs, actions, and assertions can be removed; independent checks of colors, spacing, icons, and ordinary display formatting can be trimmed according to maintenance needs. Coverage evidence helps detect omissions but cannot alone establish behavioral equivalence. Run affected tests and review assertions after cleanup, preserving security assertions and distinct critical boundary cases.
Current Test Coverageβ
Backend (backend/)β
- β Core security: Authentication, JWT tokens, password hashing
- β Configuration management
- β Exception handling
- β User service and models
- β GitHub repository provider
- β³ API endpoints (placeholder directory exists)
Executor (executor/)β
- β Agent factory
- β Base agent classes
- β Mocked AI client interactions (Anthropic, OpenAI)
Executor Manager (executor_manager/)β
- β Base executor classes
- β Task dispatcher
- β Docker executor and utilities
- β Docker constants and configuration
Shared (shared/)β
- β Cryptography utilities
- β Sensitive data masking (tokens, API keys, etc.)
Frontend (frontend/)β
- β³ Component tests (basic setup in place)
- β³ Hook tests
- β³ Utility tests
Test Coverage Goalsβ
- Target: 40-60% code coverage initially
- Priority: Core business logic and critical paths
- Strategy: Incremental coverage improvement
Backend Testsβ
Running Testsβ
cd backend
pytest # Run all tests
pytest tests/core/ # Run core tests only
pytest --cov=app # Run with coverage report
pytest -v # Verbose output
pytest -k test_security # Run specific test pattern
pytest -m unit # Run only unit tests
pytest -m integration # Run only integration tests
Test Structureβ
backend/tests/
βββ conftest.py # Global test fixtures
βββ core/ # Core infrastructure tests
β βββ test_security.py # Authentication & JWT tests
β βββ test_config.py # Configuration tests
β βββ test_exceptions.py # Exception handler tests
βββ services/ # Service layer tests
β βββ test_user_service.py # User service tests
βββ models/ # Data model tests
β βββ test_user_model.py # User model tests
βββ repository/ # Repository integration tests
β βββ test_github_provider.py
βββ api/ # API endpoint tests (placeholder)
Test Configurationβ
The backend uses pytest.ini for configuration with the following settings:
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
-v
--strict-markers
--cov=app
--cov-report=term-missing
--cov-report=html
--cov-report=xml
asyncio_mode = auto
markers =
unit: Unit tests
integration: Integration tests
slow: Slow running tests
Key Fixturesβ
test_db: SQLite in-memory database session (function scope)test_settings: Test settings with overridden valuestest_user: Test user instancetest_admin_user: Test admin user instancetest_inactive_user: Inactive test user instancetest_token: Valid JWT token for test usertest_admin_token: Valid JWT token for admin usertest_client: FastAPI test client with database overridemock_redis: Mocked Redis client
Executor Testsβ
Running Testsβ
cd executor
pytest tests/ --cov=agents
Test Structureβ
executor/tests/
βββ conftest.py # Executor-specific fixtures
βββ agents/ # Agent tests
Key Fixturesβ
mock_anthropic_client: Mocked Anthropic API client for testing Claude modelsmock_openai_client: Mocked OpenAI API client for testing GPT modelsmock_callback_client: Mocked callback HTTP client for agent responsessuppress_resource_warnings: Session-scoped fixture to suppress ResourceWarning messagescleanup_logging: Session-scoped fixture to clean up logging handlers and prevent daemon thread errors
Executor Manager Testsβ
Running Testsβ
cd executor_manager
pytest tests/ --cov=executors
Key Fixturesβ
mock_docker_client: Mocked Docker SDK client for container operationsmock_executor_config: Mock executor configuration with image, CPU, memory, and network settings
Test Structureβ
executor_manager/tests/
βββ conftest.py # Executor manager fixtures
βββ executors/ # Executor tests
βββ test_base.py
βββ test_dispatcher.py
βββ test_docker_executor.py
βββ test_docker_utils.py
βββ test_docker_constants.py
Shared Testsβ
Running Testsβ
cd shared
pytest tests/ --cov=utils
Test Structureβ
shared/tests/
βββ utils/
βββ test_crypto.py # Encryption/decryption tests
βββ test_sensitive_data_masker.py # Sensitive data masking tests
Key Features Testedβ
- Cryptography: Encryption and decryption of sensitive data (Git tokens, API keys)
- Data Masking: Automatic masking of sensitive information in logs and outputs
- GitHub tokens (
github_pat_*) - Anthropic API keys (
sk-ant-api03-*) - OpenAI API keys
- Generic API keys and secrets
- File path protection (no false positives)
- URL protection (no false positives)
- GitHub tokens (
Frontend Testsβ
Running Testsβ
cd Wegent
pnpm --dir frontend test # Run all tests
pnpm --dir frontend run test:watch # Watch mode
pnpm --dir frontend run test:coverage # With coverage report
Test Structureβ
frontend/src/__tests__/
βββ utils/ # Utility function tests
βββ hooks/ # React hooks tests
βββ components/ # Component tests
Wework Unit Testsβ
Focus unit coverage on task state and message consistency, account and permission boundaries, persistence, device and runtime routing, input submission, and failure recovery. Do not add standalone cases for CSS classes, icons, copy ordering, source keywords, fixed metadata, or diagnostic log formatting. Keep mixed scenarios focused on business outcomes. Retain telemetry consent, opt-out, redaction, and account isolation coverage rather than separate analytics-label or debug-snapshot tests.
Run the complete Wework unit test suite from the repository root:
pnpm --dir wework test
When debugging one test file, pass its path or file name to the test script. The following forms are equivalent and collect only matching Vitest files:
pnpm --dir wework test runtimePaneMessages.test.ts
pnpm --dir wework test -- runtimePaneMessages.test.ts
For compatibility, the test script removes one standalone leading --, then
passes all remaining file filters and Vitest options through unchanged. For a
focused run, confirm that the reported Test Files count matches the intended
scope so an accidental full-suite run is caught immediately.
Pure logic tests without DOM dependencies should declare // @vitest-environment node
at the top of the file. These tests do not load the browser mocks, storage, or plugin UI
fixtures in src/test/setup.dom.ts. Tests exercising browser behavior keep the default
jsdom environment. Component tests import plugin UI helpers from @/test/setup.dom.
Wework CI runs tests without collecting coverage by default to avoid Istanbul
instrumentation overhead. Collect focused coverage when needed with
pnpm --dir wework exec vitest run <test-file> --coverage.
Full renderer push checks report the current shard's passed file count every 15 seconds;
complete diagnostics remain in the logs.
A running Executor writes to tasks.sqlite concurrently. Desktop E2E fixtures that
write directly to this database must set PRAGMA busy_timeout = 10000 on their
independent connection so normal write transactions can release their locks.
Keep this wait scoped to the fixture connection and preserve business assertions
and global UI timeout budgets.
Async Question Model Fixturesβ
The desktop E2E async question fixture recognizes only an exact expected answer
in a user message after the matching function_call_output acknowledgement,
using the shared parser to remove runtime context wrappers from the reply.
AGENTS.md and environment context can also arrive with role=user; scanning the
whole request or matching an answer substring cannot establish a user reply.
desktop-async-input-fixture.test.mjs covers injected context, historical answers,
tool output, and actual replies. Existing desktop async question scenarios retain
the distracting word Complete in their prompt and assert both the waiting
message before an answer and the completion message afterward.
Wework Desktop Cloud Device Testsβ
Run the cloud-device feature E2E from the repository root:
pnpm --filter wework e2e:desktop:cloud-features
This scenario starts a real backend, Redis, cloud-device executor, and Electron
application. It verifies cloud project tasks, Goal auto-continuation and unread
state, busy-turn Goal handoff, and the local/cloud model protocol matrix. On
failure, use the reported wework/test-results/desktop-e2e/<run-id>/ directory
to correlate frontend, backend, and executor logs before changing behavior.
Continuous Integrationβ
GitHub Actions Workflowβ
The test and cache workflows run automatically as follows:
.github/workflows/test.ymlresponds to PRs targetingmainand merge-queue checks..github/workflows/ci-cache-warmup.ymlprewarms shared caches after related dependencies, source, or CI configuration entermain.
CI first runs .github/scripts/classify-ci-changes.sh to select module jobs from
the changed paths. Dependency relationships are included. For example, a
shared/ change runs the Backend, Executor Manager, Knowledge Engine, Shared,
and CLI suites, while a packages/chat-core/ change runs both Frontend and
Wework checks. Changes to the test workflows or the classifier itself select
every module so CI orchestration changes receive full validation.
Apply the ci:all label to a PR to bypass path classification and force every
module test, the platform E2E suite, Wework browser and desktop E2E, and the
Wework macOS memory gate. This is useful when changed paths might not capture
the full blast radius of a change. All three test workflows respond to label
events; without ci:all, test selection still follows the changed paths.
The Wework macOS memory gate runs only for non-draft PRs carrying ci:all;
Regular PRs, scheduled runs, and manual runs do not trigger memory E2E.
Windows desktop builds share the build-wework-windows-e2e action between PRs
and main-branch cache warmup. Only main writes shared caches. Complete packages
require an exact match of source inputs, Node, Rust, and runner image versions;
prefix matching is not used. A hit validates and uploads the original package,
preserving its producer identity. A miss builds with shared pnpm, Codex, Electron,
Executor, and Backend compilation caches. These are E2E builds, not evidence of
upgrade compatibility.
Windows Core independently balances serial shards using median successful
checkpoint durations in .github/ci/wework-windows-checkpoint-durations.json,
which records the source Actions runs. Linux grouping stays unchanged. Scheduling
preserves the ten-runner budget, two exclusive benchmark shards, and every
checkpoint. A shard containing an unmeasured checkpoint remains intact until
successful logs provide evidence. Failed and cancelled checkpoints are excluded.
Checkpoints sharing CLI, Electron, or object-storage preparation stay together,
preserving the original number of preparation jobs.
Loads also include measured conditional preparation costs with a source job link,
so cold object-storage compilation does not sit on an otherwise full shard.
Cache hits may reduce these costs.
Estimated loads omit runner queues, common setup, and cleanup; validate actual
savings with a complete CI run.
Feature-branch pushes do not run a duplicate CI suite; the pull_request event
validates the branch after a PR is opened. A newer commit to the same PR or to
main cancels the older in-progress run. test-summary and lint-summary
always appear and verify that every selected job actually succeeded. Skipped,
unrelated modules do not make the summary fail.
CI reliability depends on these invariants:
- Desktop E2E element mounting and subsequent value polling each use the shared step budget. Mounting must not consume the entire value loop before its first read; retain actual-value diagnostics and exact-match assertions.
- After routing control commands back from another window, explicitly restore native window focus before checking virtualized content. Control routing does not bring a native window to the foreground.
- Desktop teardown observes both exit events and operating-system liveness and always checks the entire process group. Timeouts retain the PID, exit status, and Linux kernel process state without relaxing cleanup assertions.
- The platform E2E MySQL service must allow enough startup grace for its first
initialization. Its health-check
start-periodshould cover a cold start on a shared runner before the interval and retry count determine failure; reruns must not hide initialization timeouts. - Repository Policy jobs triggered by
pull_request_targetmust run policy scripts from the trusted base checkout, while checking out the scan target by the PR head repository and immutable head SHA. Do not depend onrefs/pull/<number>/merge, which can be replaced or removed while a PR is synchronized, and never execute code supplied by the PR in the policy job. - When final text and related controls render independently in desktop E2E, wait for each target element before reading attributes or asserting state. Visible final text does not imply that associated disclosure controls or timelines have mounted.
- After desktop E2E triggers an asynchronous export, disable, reload, immediate inspection, creation, or archival, do not treat a success notice, request count, re-enabled button, or optimistic DOM update as the final result. Assert at least one independently verifiable outcome from the actual artifact, persisted file, stopped service, completed-state copy, or backend/UI state loaded again. If the test environment exposes no real outcome boundary, do not fabricate coverage with a mocked readback.
- After a page reload, task switch, or injected lifecycle/transcript event, desktop E2E must not wait only for sidebar, composer, or debug state. Before reading a virtualized transcript or asserting text occurrence counts, wait for the expected conversation text to appear in a page snapshot, then retain exact occurrence assertions so fixed delays or reruns cannot hide missing or duplicated messages.
- Wework release-note lookups for GitHub commit authors retry transient API or TLS failures a limited number of times with exponential backoff. The release job must still fail after retries are exhausted instead of silently omitting attribution or publishing incomplete notes.
CI Cache Ownershipβ
Large caches are prewarmed and owned by main. Pull requests and merge-queue
runs may restore the default-branch cache, but they do not save another copy:
- Linux workspace
node_moduleshas one shared cache keyed by the Node version andpnpm-lock.yaml. Tests, Lint, and platform E2E reuse it. - Wework browser and desktop E2E use dependency images published to GHCR. Image tags are derived from the corresponding Dockerfile content hash. The workflow builds and publishes an image only when that tag is missing, then runs downstream jobs directly in the image container instead of installing Node, pnpm, uv, Rust, Playwright browsers, or desktop system packages per job. Local debugging commands do not build these CI images.
- uv caches downloads and build results only, not project
.venvdirectories. Python 3.10, 3.11, and 3.12 each have one shared cache whose key includes the dependency lockfiles, and CI pruning runs before save. - Playwright browsers, the Next.js build cache, local harness CLIs, and desktop
Cargo targets use explicit restore/save steps; only
refs/heads/mainsaves. OpenCode, Claude Code, and Kimi Code share the integrity-locked npm install defined by.github/claude-code-cli/package-lock.json. - Rust unit tests, the Windows check, release and snapshot binaries, and the
macOS memory gate use sccache. The
mainwarmup runs the same Electron desktop build onmacos-14; non-mainjobs access the shared compiler cache in read-only mode. If sccache installation is temporarily unavailable, jobs emit a warning and compile without the cache instead of failing. - Wework Desktop Core E2E retains its
main-owned Cargo target cache because several desktop jobs must reuse the same complete binary output. - Platform E2E, Release, and Snapshot Docker BuildKit caches live in corresponding GHCR build-cache tags instead of consuming GitHub Actions dependency cache storage.
- Outside Wework E2E, Executor and Electron system dependency installers first
check packages already present on the runner. Only
mainwrites the APT download cache; PRs restore it read-only. - The real Electron update-transport probe on Linux isolates both Xvfb and D-Bus sessions so an invalid inherited session-bus address cannot interfere with native startup or exit. Keep its startup count, lifecycle assertions, and timeouts unchanged.
- Before parallel desktop checkpoints launch their Xvfb servers, the parent runner
prepares the shared X11 Unix socket directory to avoid concurrent
EEXISTfailures. Redis readiness failures retain the last output, log-read error, and process state; readiness deadlines are not extended to hide startup defects.
.github/workflows/ci-cache-warmup.yml runs after related source, dependency
lockfile, or cache implementation changes enter main, and rejects manual
warmups from non-main refs. It downloads dependencies or compiles cache
entries without repeating tests already validated by the merge queue. Do not add large automatically saved PR or
merge-group caches. Use actions/cache/restore plus a main-only
actions/cache/save, or reuse the existing shared action.
Writing GitHub Actions Outputsβ
Every line written to $GITHUB_OUTPUT must use the name=value format. Do not
write the substituted output of a command that can emit progress or diagnostic
messages directly to that file. Extract the needed value first, then write the
output. For example, to resolve the Playwright version:
version="$(pnpm exec playwright --version | sed -n 's/^Version //p')"
echo "version=$version" >> "$GITHUB_OUTPUT"
This prevents package-manager supply-chain checks or other auxiliary logs from invalidating the workflow output format.
Workflow Jobsβ
Regular PR checks must cover module tests; E2E jobs do not replace them:
- test-backend runs the Backend suite with Python 3.11 and
uv run pytest. - test-executor runs
cargo fmt --check,cargo test --all-features, and Clippy for the Rust Executor. It placesCARGO_TARGET_DIRunder the runner's temporary directory to avoid shared build contamination and workspace disk pressure. - test-executor-manager, test-shared, and test-knowledge-engine run
their Python suites with
uv run pytest. - test-frontend runs the Chat Core and Frontend unit tests.
- test-wework runs the Wework unit suite with Vitest and generates coverage.
- test-wegent-cli and test-wegent-cli-integration run CLI unit tests and integration tests backed by MySQL, Redis, and a real Backend, respectively.
- test-summary always runs and depends on every job above. It must fail when any module test job fails.
E2E coverage lives in dedicated workflows: .github/workflows/e2e-tests.yml
covers product end-to-end flows, while .github/workflows/wework-e2e.yml covers
Wework flows. They add cross-module verification and do not replace the module
tests in .github/workflows/test.yml. Platform E2E runs only when Backend,
Frontend, Executor, Executor Manager, Shared, Chat Shell, Chat Core, Docker, or
related build configuration changes, so a Wework-only PR no longer starts an
unrelated platform E2E suite. Draft PRs skip expensive E2E and run it after they
become ready for review.
The full platform E2E suite runs daily at 02:00 UTC, and the full Wework E2E suite runs daily at 04:00 UTC. Scheduled runs use a different concurrency group from PR and merge-queue runs, so they do not cancel each other.
Wework Shared Release Regressionβ
.github/workflows/wework-release-e2e.yml runs a real GitHub regression for
related same-repository PRs and supports manual dispatch. Using an Actions token
with only Contents: write, it creates an isolated tag and draft release,
executes the release workflow's actual shared-release provisioning commands,
and verifies that an older RELEASE_SHA does not change an existing release's
target, metadata, or assets. It cleans up test resources on success or failure.
Fork PRs do not run this test because their tokens cannot write repository contents.
The shared wework-updater title and notes are set only when it is first
created. Later releases upload dependencies and update manifests without
resubmitting its target commit. Workflow differences between an old target and
main can otherwise require Workflows: write and cause a 403 response.
Run it with an authenticated GitHub CLI:
GH_REPO=wecode-ai/Wegent bash .github/scripts/test-wework-shared-release.sh
Coverage Reportsβ
Coverage reports are automatically uploaded to Codecov (if configured).
Mocking Strategyβ
External APIsβ
- GitHub/GitLab/Gitee: Mock with
httpx-mockorpytest-mock - Anthropic/OpenAI: Mock SDK clients
- Redis: Use
fakeredisor mock
Databaseβ
- Test DB: SQLite in-memory database
- Isolation: Each test gets a fresh transaction
- Cleanup: Automatic rollback after each test
Dockerβ
- Mock
docker.from_env()and container operations
Best Practicesβ
Writing Testsβ
- One assertion per test: Each test should verify one specific behavior
- Descriptive names: Use clear, descriptive test function names that explain what is being tested
- AAA pattern: Arrange, Act, Assert - structure your tests clearly
- Mock external dependencies: Never call real external services (APIs, databases, etc.)
- Use fixtures: Share common test setup via fixtures to reduce duplication
- Test edge cases: Include tests for error conditions, boundary values, and unusual inputs
- Keep tests independent: Each test should be able to run independently without relying on other tests
Security Testing Best Practicesβ
The project includes comprehensive security testing examples in backend/tests/core/test_security.py:
- Password hashing and verification (bcrypt)
- JWT token creation and validation
- Token expiration handling
- User authentication with valid/invalid credentials
- Inactive user detection
- Role-based access control (admin vs regular users)
Example test pattern for security features:
@pytest.mark.unit
class TestPasswordHashing:
"""Test password hashing and verification functions"""
def test_verify_password_with_correct_password(self):
"""Test password verification with correct password"""
password = "testpassword123"
hashed = get_password_hash(password)
assert verify_password(password, hashed) is True
def test_verify_password_with_incorrect_password(self):
"""Test password verification with incorrect password"""
password = "testpassword123"
hashed = get_password_hash(password)
assert verify_password("wrongpassword", hashed) is False
Test Organizationβ
@pytest.mark.unit
class TestFeatureName:
"""Test feature description"""
def test_success_case(self):
"""Test successful operation"""
# Arrange
data = {"key": "value"}
# Act
result = function_under_test(data)
# Assert
assert result == expected_value
def test_error_case(self):
"""Test error handling"""
with pytest.raises(ExpectedException):
function_under_test(invalid_data)
Using Test Markersβ
Test markers help categorize and selectively run tests:
# Run only unit tests
pytest -m unit
# Run only integration tests
pytest -m integration
# Run slow tests
pytest -m slow
# Skip slow tests
pytest -m "not slow"
Async Testsβ
@pytest.mark.asyncio
async def test_async_function():
"""Test asynchronous function"""
result = await async_function()
assert result is not None
The backend's pytest.ini has asyncio_mode = auto which automatically detects and runs async tests.
Adding New Testsβ
Backendβ
- Create test file in appropriate
tests/subdirectory (e.g.,tests/services/test_new_service.py) - Import necessary fixtures from
conftest.py - Use
@pytest.mark.unitor@pytest.mark.integrationto categorize tests - Follow the AAA (Arrange-Act-Assert) pattern
- Write test classes and methods with descriptive names
- Run tests locally before committing:
pytest tests/ -v - Ensure coverage is maintained or improved:
pytest --cov=app --cov-report=term-missing
Frontendβ
- Create test file in
src/__tests__/matching source structure - Use
@testing-library/reactfor component tests - Mock API calls and external dependencies
- Ensure tests pass with
pnpm --filter wecode-ai-assistant test
Debugging Testsβ
Backendβ
# Run specific test with verbose output
pytest tests/core/test_security.py::TestPasswordHashing::test_verify_password_with_correct_password -v
# Drop into debugger on failure
pytest --pdb
# Show print statements
pytest -s
Frontendβ
# Run tests in watch mode
pnpm --dir frontend run test:watch
# Debug specific test file
pnpm --dir frontend test -- src/__tests__/utils/test_example.test.ts
Configuration Filesβ
Backendβ
backend/pytest.ini: pytest configuration with coverage settings and test markers- Enables verbose output, strict markers, and automatic async mode
- Configures coverage reports in terminal, HTML, and XML formats
- Defines custom markers:
unit,integration,slow
Executor/Executor Manager/Sharedβ
pytest.ini: Module-specific pytest configuration- Similar setup to backend but with module-specific coverage targets
Frontendβ
frontend/jest.config.ts: Jest configurationfrontend/jest.setup.js: Test environment setup
Future Improvementsβ
- Increase coverage to 70-80%
- Add integration tests for API endpoints (currently placeholder)
- Add E2E tests for critical user flows
- Performance/load testing
- Mutation testing with
mutmut - Add more frontend component tests
- Implement database migration tests
- Add tests for WebSocket connections and real-time features
Troubleshootingβ
Common Issuesβ
Import errors in tests:
- Ensure you're running pytest from the correct directory
- Check that modules are installed:
uv sync
Database errors:
- Tests use SQLite in-memory DB, no setup needed
- Check that fixtures are imported correctly
Frontend test failures:
- Ensure Node.js 20+ is installed
- Run
pnpm install --frozen-lockfilefrom the repository root to install exact dependency versions - Clear Jest cache:
pnpm --dir frontend exec jest --clearCache
Resourcesβ
E2E resource reuse and shard allocationβ
Platform E2E checks its content-addressed GHCR image before starting Buildx, and starts the builder and publishes an image only when that image is missing. A registry hit does not download BuildKit, avoiding an unnecessary Docker Hub dependency. Knowledge tests use the official gcr.io/etcd-development/etcd:v3.5.16 image to avoid the 502 errors observed on the previous Quay download path.
Shard 4's knowledge test entry point owns the on-demand Milvus and etcd containers, reusing the existing network and MinIO; other shards do not start these services. Startup checks etcd /health and MinIO /minio/health/ready before starting Milvus and polling its actual /healthz, within the existing 180-second budget. Container exit fails immediately, test failures preserve their exit code, and every path records container state, health-check configuration/history and complete logs before cleanup. Evidence is uploaded as knowledge-provider-lifecycle-e2e. This addresses the pre-checkout service failure in 40609610685, where subsequent steps could not capture health details. The four runners and both knowledge test entry points remain unchanged.
Platform E2E keeps its four existing shards. S3 uploads reuse shard 2's MySQL, Redis and MinIO; media hosting reuses the same services in shard 3. Test entry points, assertions and evidence artifacts are preserved. Redis uses a separate logical database, and media tools are installed in the shared image. Replication starts its dedicated replica and broker only in shard 3, saves logs and removes the containers on success or failure. The replica health probe authenticates over TCP and executes SELECT 1, so the entrypoint's temporary socket-only server cannot satisfy readiness. Remote knowledge indexing moves to shard 4.
The allocation uses successful runs 40548056927 and 40547828678: shard 1's remote indexing took 149β164 seconds, replication 20β26 seconds, media hosting 24β26 seconds, and S3 uploads about 6 seconds. Extra work moves off shard 1 onto lighter existing shards without adding machines. Reassess using actual test-step duration and cumulative runner time, excluding queue time.
Ordinary label events do not classify Platform E2E changes; only the ci:all label requests full regression. Selected desktop Plugins scenarios run sequentially in one job while retaining independent initialization and failure results. The shared macOS job is named Wework Desktop macOS E2E: Inspector coverage runs for affected paths, while the memory step remains limited to PRs with ci:all. Scheduled and manual runs do not execute the memory step automatically.
In the first integration run 40558717377, the five test jobs consumed 44m20s of cumulative runner execution time, compared with 48m18s and 51m53s for the two seven-job baselines. Timing starts at each job's first step and excludes queues. Provider-native logical shard 1 took 120 seconds while logical shard 3 was effectively empty, so they are assigned to physical shards 3 and 1 respectively. Other provider shards, ordinary browser shards and per-machine user identities remain unchanged. A matrix contract enforces four physical shards and exactly one execution of each provider shard.
While an install or uninstall is in flight, background device repair and explicit refresh reconciliation share the foreground mutation's busy state. Intermediate pending membership must not trigger a second complete capability dispatch. Genuine device gaps remain eligible for repair after the foreground mutation settles. Component coverage holds the install response while publishing pending membership, then verifies repair resumes after settlement; the original multi-Runtime E2E assertions requiring one dispatch per device remain unchanged.
When reinstall overlaps old uninstall cleanup, a newer snapshot may advance the device watermark before the reinstall acknowledgement is persisted. Single-plugin synchronization sends current desired state again only when a successful acknowledgement was fenced by a newer watermark and the device installation is still unconfirmed, with a three-attempt limit. Persistent conflicts return plugin_write_conflict; device failures are not immediately retried. test_plugin_sync_recording.py covers convergence, persistent conflicts, device failures, and already-confirmed newer acknowledgements using real database rows and watermarks. Desktop plugin-write-coordination retains its assertion that the reinstall response contains a confirmed installed device.
Before creating the standard test account, the Windows desktop runner prepares a 1920Γ1080 display and checks for a working area of at least 1440Γ960. This prevents the default 1024Γ768 display from clamping Electron into compact layout. Directory-publication fault injection holds a native directory handle without delete sharing; an open child file does not guarantee that renaming its parent fails. Regression run 42033008185 retains evidence for both compact-layout failures and the incorrect directory-lock assumption. Claude configuration publication also covers isolated paths exceeding Windows MAX_PATH. History-search component coverage verifies that the virtualizer receives the new search offset before native scroll events arrive.
Stand-in list and standalone-preview approval scenarios share shell-command-response.mjs. Direct calls and code_mode must preserve identical one-time escalation arguments. The preview fixture in 42048584579 recognized only direct shell tools; a protocol test reproduces its exact exception with code_mode input. Shared call generation now covers both scenarios. Unknown tools remain fatal and retain tool schemas, request types, and input-role diagnostics without request text or authentication headers.
The same Windows run exposed two later issues. A project lookup finishing after a switch to a task updates its owning board tab's title and route, replacing the URL only while that tab is active; closed tabs stay closed. Component coverage checks background completion, reselection, and late callbacks after closure, while notification E2E retains exact route assertions. Cached-history search captures its baseline from the same settled snapshot after bottom layout and pagination complete. An intermediate loadingMoreBefore=true state cannot be compared with pagination completed during search; all message and pagination equality assertions remain intact.
Executor restart logs in 42061132998 show a history-loss event arriving before RPC negotiation completes, causing the sole recovery request to fail. After authenticating the event connection, the HTTP entry point checks RPC readiness and returns 503 while unavailable. Existing SSE reconnection retains its cursor and rereads the executor journal without prematurely consuming the recovery event. Protocol coverage verifies withholding events until readiness and replaying from the original cursor. Human-interaction evidence also shows that reloading after the dismissal marker but before archive persistence loses history. Dismissal now commits the archive under its history lock before saving the handled marker; component coverage blocks that lock and verifies that the question remains unsuppressed until commit. The Windows directory-holder fixture constructs its extended path prefix with native PowerShell formatting to avoid String.Concat overload binding failures.
Async project callbacks must read current tab state when invoked rather than the tab list and selection captured when the request started. Regression coverage retains the old callback across selection and closure, checking that it neither changes the current task URL nor recreates a closed tab. If redispatch throws after a superseded successful plugin acknowledgement, synchronization returns an explicit failed response and stops the loop instead of reusing stale success. Database coverage verifies exactly two calls and the plugin_device_sync_failed result.
Assignment-control and activity receipt timestamps must be compared in one DOM read. Windows logs in 42072191562 place the separate reads at 17:42:02.912 and .977. An intervening Issue status update reloaded the version-scoped control receipt, leaving the second read empty; the subsequent page snapshot shows matching timestamps. The assertion now waits for both receipts to load in one snapshot before comparing their exact text. Protocol tests cover the intervening refresh and genuinely different timestamps, which must still fail.
The public stand-in Beta button leaves project headers using their existing
width-based tab or compact-select navigation. Cloud shard 1 in
CI 42196630424
recorded missing collaboration-tab-manage controls in both
plugin-source-continuation-evidence.json and
plugin-detail-resilience-evidence.json. The
plugin-detail-resilience-healthy-before-fault.png capture shows the real
execution-environment page with a Project settings select in its header.
ProjectViewSwitcher renders only collaboration-project-view-select in compact
mode. Both plugin scenarios therefore reuse selectCollaborationProjectView
instead of assuming an inline Manage tab. Healthy baselines, persistent plugin
bindings, fault injection, permission and recovery assertions remain intact;
timeouts and scenario coverage are unchanged.
Long-conversation switching retains its original assertions and wait budgets.
CI 42199573796
timed out before the initial body following 520 progress messages. The executor
history already contained that body. Mapping conversation-switching-initial.cpuprofile
through the matching build's source maps identified repeated shared-footer height
reads from MessageList layout callbacks, accounting for about 1.9 seconds of
synchronous layout. Footer measurement now runs on controller commits and observed
resizes; virtual rows retain their existing positioning logic. Component coverage
checks that 520 row updates do not remeasure the footer, while size changes,
unmounting and remounting still update its height.