Skip to content

Release harness v2: app-status readiness, scripted smoke, evidence export - #497

Merged
100yenadmin merged 2 commits into
mainfrom
codex/worldos-release-harness-v2
Jun 1, 2026
Merged

Release harness v2: app-status readiness, scripted smoke, evidence export#497
100yenadmin merged 2 commits into
mainfrom
codex/worldos-release-harness-v2

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented May 31, 2026

Copy link
Copy Markdown
Member

Summary

  • adds shared app failure bucket classification and wires qa/ui_playtest_app.sh through it while keeping the public ten-bucket contract stable
  • extends /app-status with read-only readiness/health fields and retires stale root/legacy viewer routes to /openworlds/
  • adds deterministic multi-beat scripted smoke with same-port /app-status, screenshots/a11y/status/surface/move logs, and scripted-provider summary/trace
  • extends qa/export_app_evidence.py --run-dir and preserves live --app-status-url export

Closes #483.
Closes #485.
Closes #486.
Refs #480, #481, #484, #479, #466.

Evidence

  • bash -n qa/ui_playtest_app.sh scripts/play_scripted_dm.sh
  • python3 -m py_compile qa/app_smoke_scripted.py qa/export_app_evidence.py qa/app_failure_buckets.py
  • python3 -m pytest viewer/tests/test_openworlds_static.py qa/test_macos_app_static.py qa/test_export_app_evidence.py qa/test_release_readiness.py qa/test_app_failure_buckets.py qa/test_app_smoke_scripted.py qa/test_ui_playtest_app_buckets.py -q -> 77 passed, 6 subtests passed
  • deterministic scripted smoke: /Volumes/LEXAR/Codex/worldos-agent-grade-app-testability/scripted-smoke-v2-20260531T233335Z-080497e/
    • status passed, 5/5 beats, same-port http://127.0.0.1:8899/app-status, ready_for_smoke=true, ready_for_play=true, private art probe ok, actor Abby seated, 5 enabled actions, 11 chat lines, 7 PNG screenshots, zero evidence gaps
  • exporter copy: /Volumes/LEXAR/Codex/worldos-agent-grade-app-testability/scripted-smoke-v2-20260531T233335Z-080497e-export/manifest.json copied 36 files with zero gaps

Notes

Summary by CodeRabbit

  • New Features

    • Enhanced /app-status with nested readiness and health diagnostics; readiness now reports smoke/play readiness and granular failure buckets.
    • Evidence exporter can bundle local run-directory artifacts and derive failure info when present.
  • Refactor

    • Centralized failure-bucket classification and deterministic scripted smoke tooling with richer per-beat evidence.
  • Chores

    • Deprecated legacy viewer pages redirect to OpenWorlds; stabilized test accessibility hooks and test IDs.

@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 790f1499-96a4-4a15-89b7-058680ccb96d

📥 Commits

Reviewing files that changed from the base of the PR and between 0198c51 and e4bfb96.

📒 Files selected for processing (5)
  • docs/AGENT_GRADE_APP_TESTABILITY.md
  • qa/app_smoke_scripted.py
  • scripts/play_scripted_dm.sh
  • viewer/server.py
  • viewer/tests/test_openworlds_static.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • docs/AGENT_GRADE_APP_TESTABILITY.md
  • viewer/server.py
  • scripts/play_scripted_dm.sh
  • qa/app_smoke_scripted.py

📝 Walkthrough

Walkthrough

Adds a centralized failure-bucketing CLI, a deterministic scripted-provider multi-beat smoke runner, server-side app-status readiness/health diagnostics, run-dir evidence export, structured scripted-provider telemetry, UI/test/docs updates, and tests coordinating those pieces.

Changes

Scripted Smoke Testing & Failure Routing

Layer / File(s) Summary
Failure bucket taxonomy and classifiers
qa/app_failure_buckets.py, qa/test_app_failure_buckets.py
Defines stable bucket names and implements classifiers (native, readiness, artifacts, score, browser-probe) with a CLI and unit tests.
App-status readiness and health diagnostics
viewer/server.py, viewer/tests/test_openworlds_static.py
Server computes readiness and health dicts (ready_for_smoke/ready_for_play, failure_bucket/detail, console/network counts) and exposes them in /openworlds/app-status; legacy routes redirect to /openworlds/.
Scripted provider structured telemetry
scripts/play_scripted_dm.sh
Emits structured NDJSON trace events, writes worldos.scripted-provider-summary.v1 summary.json with resolved move counts, sets provider env to scripted, and tracks per-beat resolution events.
Deterministic scripted smoke test runner
qa/app_smoke_scripted.py, qa/test_app_smoke_scripted.py
Runs gated scripted provider, polls /app-status, posts deterministic /move beats, captures per-beat app-status/surface/HTML/screenshots/NDJSON logs, synthesizes provider summary, writes smoke.json verdict, copies play-state artifacts, and exposes CLI.
Evidence export with run-directory support
qa/export_app_evidence.py, qa/test_export_app_evidence.py
Adds --run-dir mode with allowlisted RUN_DIR_PATTERNS, helpers to copy/validate artifacts into bundle, derives failure bucket/detail from copied files, and makes --app-status-url optional.
Documentation and contract updates
docs/AGENT_GRADE_APP_TESTABILITY.md
Documents app-status V2 readiness/health schema, scripted provider id=scripted + WORLDOS_ENABLE_SCRIPTED_PROVIDER gate, required scripted-provider summary output, stable data-worldos-testid guidance, revised minimum hook set, evidence-export usage, and deterministic smoke gate (same-port ready_for_smoke + 5–8 narration-advancing beats).
UI hook markers and deprecated viewer redirect
viewer/openworlds/screen-table.jsx, viewer/index.html
Replaces full viewer index with minimal redirect to /openworlds/; status banner now uses data-worldos-testid="app-status-banner" and data-worldos-status-scope="session-surface".
Release readiness part_a failure tracking
qa/release_readiness.py, qa/test_release_readiness.py
Includes part_a result and failure bucket/detail in harness failures and persona outputs when score.json is missing; appends native_detail into native gate/evidence-gap diagnostics.
Centralize failure classification in shell harness
qa/ui_playtest_app.sh, qa/test_macos_app_static.py, qa/test_ui_playtest_app_buckets.py
Removes inline bash/Python bucketing, delegates classification to qa/app_failure_buckets.py, removes score_failed bucket, and updates tests to match new bucket outputs.

Sequence Diagram(s)

sequenceDiagram
  participant Test as qa/app_smoke_scripted.py
  participant Provider as scripts/play_scripted_dm.sh
  participant Status as viewer/server.py (/app-status)
  participant UI as OpenWorlds UI
  participant Trace as play-state trace files
  Test->>Provider: Start with WORLDOS_ENABLE_SCRIPTED_PROVIDER=1
  Provider->>Trace: Emit init events and per-move trace.ndjson
  Test->>Status: Poll /openworlds/app-status until readiness.ready_for_smoke
  Status->>Status: Compute readiness/health from provider/actor/narration/console
  loop For each beat (5–8)
    Test->>UI: POST /move deterministic intent
    Provider->>Trace: Append move_resolved with beat detail
    Test->>Status: Poll for narration advancement
    Test->>Test: Capture app-status, surface HTML, screenshot, NDJSON logs
  end
  Provider->>Trace: Write summary.json with resolved_move_count
  Test->>Test: Write smoke.json verdict and copy play-state artifacts
  Test->>CLI: qa/export_app_evidence.py --run-dir <dir> --out <bundle> (optional)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • electricsheephq/WorldOS#496: Both PRs update qa/ui_playtest_app.sh to change built-app failure classification and related tests; this PR centralizes classifiers in Python.
  • electricsheephq/WorldOS#494: Related scripted-provider plumbing; this PR's smoke runner and script telemetry align with that work.
  • electricsheephq/WorldOS#374: Earlier changes to playtest harness/scores that intersect with the classifier and bucketing updates here.

Poem

🐰 A rabbit hops the smoke-test trail,

Five beats measured, scripts set sail,
Buckets tidy reasons when things fail,
Traces saved in tidy tale,
Evidence bundled — hop, prevail!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.38% 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
Title check ✅ Passed The PR title 'Release harness v2: app-status readiness, scripted smoke, evidence export' clearly and concisely summarizes the main changes across the changeset: extending app-status, adding scripted smoke tests, and improving evidence export.
Description check ✅ Passed The PR description includes a summary of changes, identifies closed/referenced issues (#483, #485, #486, #480, #481, #484, #479, #466), and provides concrete validation evidence (syntax checks, pytest results, manual smoke runs), though the CLA/licensing checkbox is incomplete.
Linked Issues check ✅ Passed The changeset addresses all three primary linked issues: #483 (failure bucket classification via app_failure_buckets.py), #485 (evidence export with run-dir support), and #486 (deterministic smoke vs. full RRI split in docs/harness).
Out of Scope Changes check ✅ Passed All changes align with the stated objectives: failure bucket classification, app-status readiness/health, scripted smoke, evidence export, and viewer route redirects are all within scope of the three linked issues.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/AGENT_GRADE_APP_TESTABILITY.md (1)

87-117: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

blocked status referenced but not in the readiness enum.

The readiness.status enum lists only ready|degraded (line 88), but the behavioral rules describe a blocked status (line 117). Either add blocked to the enum or drop it from the prose so the documented contract is self-consistent.

🤖 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 `@docs/AGENT_GRADE_APP_TESTABILITY.md` around lines 87 - 117, The documentation
currently lists readiness.status as "ready|degraded" but the behavioral rules
mention a third status "blocked"; update the contract to be consistent by adding
"blocked" to the readiness.status enum (e.g., change the literal set for
readiness.status to "ready|degraded|blocked") and, if needed, add a brief line
in the readiness section describing when readiness.status should be set to
blocked to match the prose in the behavioral rules (reference readiness.status
and the behavioral rules mentioning blocked).
🧹 Nitpick comments (2)
qa/ui_playtest_app.sh (1)

95-97: 💤 Low value

Consider documenting or removing unused variable.

APP_FAILURE_BUCKETS_JSON is no longer used in this script (all classification delegates to qa/app_failure_buckets.py). If it's part of the public contract for external scripts that source this file, add a comment explaining its purpose. Otherwise, consider removing it along with the bucket_pair bash function.

🤖 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 `@qa/ui_playtest_app.sh` around lines 95 - 97, APP_FAILURE_BUCKETS_JSON and the
bucket_pair() function are unused in qa/ui_playtest_app.sh; either remove both
to avoid dead code or document them if they're part of an external sourcing
contract: if removing, delete the APP_FAILURE_BUCKETS_JSON declaration and the
bucket_pair() function; if keeping for backward compatibility, add a clear
comment above APP_FAILURE_BUCKETS_JSON explaining its purpose and that
qa/app_failure_buckets.py now handles classification, and mark bucket_pair() as
deprecated with a short usage note referencing qa/app_failure_buckets.py.
qa/app_failure_buckets.py (1)

247-251: 💤 Low value

Clarify browser-probe fallback message.

When classify_browser_probe returns None (indicating app_status is OK), the fallback at line 251 returns "no_provider|browser probe passed". This pairs a failure bucket (no_provider) with a success message (passed), which could confuse callers. Consider either:

  • Returning "ok|browser probe passed" (though "ok" isn't in APP_FAILURE_BUCKETS)
  • Documenting that callers should not invoke browser-probe unless they already know there's a failure
  • Exiting with a different code or empty output when the probe passes
🤖 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 `@qa/app_failure_buckets.py` around lines 247 - 251, The current fallback
coerces a successful browser probe (classify_browser_probe returning None) into
a failure bucket by using bucket_pair("no_provider", "browser probe passed");
change this so a successful probe returns None (or an explicit success sentinel)
instead of a failure pair: remove the "or bucket_pair(...)" fallback and let
result be the direct return value of classify_browser_probe (or return a
documented "success" sentinel), updating callers to handle None/sentinel
accordingly; references: classify_browser_probe and bucket_pair.
🤖 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 `@qa/app_smoke_scripted.py`:
- Around line 357-383: The in-beat polling and final status/surface fetches
(calls to wait_for_status, fetch_json and surface_url inside the beat loop and
before finalization) are unguarded and can raise
RuntimeError/URLError/ValueError; wrap the polling body and the final
wait_for_status/fetch_json blocks in try/except to catch those exceptions, set
verdict.update(...) with an appropriate failure_bucket (e.g. "no_app" or
"console_error") and failure_detail describing the exception, json_dump the
smoke.json via the existing json_dump(out / "smoke.json", verdict) call, and
return 1 — specifically add exception handling around the loop that uses
wait_for_status/fetch_json (referencing wait_for_status, fetch_json,
surface_url, provider_summary, json_dump, write_text_snapshot,
capture_openworlds_screenshot) so any transient provider/viewer drop produces a
bucketed smoke.json and a clean return instead of an unhandled traceback.

In `@viewer/server.py`:
- Around line 5402-5403: The readiness counters network_failures and
console_errors are incorrectly hardcoded to 0; replace those assignments with
computed aggregates from the runtime event data (e.g., count entries in the
console/log buffer and network request records) so the readiness model can
reflect real failures — for example, set console_errors = sum(1 for e in
console_events if e.level in ("error","fatal") or matches error patterns) and
network_failures = sum(1 for r in network_requests if r.failed or r.status_code
>= 400); update the same logic at the other occurrence that mirrors lines
5425-5428 so both readiness checks use these computed counts and not fixed
zeros, and ensure the code refers to the actual event collections used elsewhere
in this module (console_events, network_requests, or their local equivalents).

---

Outside diff comments:
In `@docs/AGENT_GRADE_APP_TESTABILITY.md`:
- Around line 87-117: The documentation currently lists readiness.status as
"ready|degraded" but the behavioral rules mention a third status "blocked";
update the contract to be consistent by adding "blocked" to the readiness.status
enum (e.g., change the literal set for readiness.status to
"ready|degraded|blocked") and, if needed, add a brief line in the readiness
section describing when readiness.status should be set to blocked to match the
prose in the behavioral rules (reference readiness.status and the behavioral
rules mentioning blocked).

---

Nitpick comments:
In `@qa/app_failure_buckets.py`:
- Around line 247-251: The current fallback coerces a successful browser probe
(classify_browser_probe returning None) into a failure bucket by using
bucket_pair("no_provider", "browser probe passed"); change this so a successful
probe returns None (or an explicit success sentinel) instead of a failure pair:
remove the "or bucket_pair(...)" fallback and let result be the direct return
value of classify_browser_probe (or return a documented "success" sentinel),
updating callers to handle None/sentinel accordingly; references:
classify_browser_probe and bucket_pair.

In `@qa/ui_playtest_app.sh`:
- Around line 95-97: APP_FAILURE_BUCKETS_JSON and the bucket_pair() function are
unused in qa/ui_playtest_app.sh; either remove both to avoid dead code or
document them if they're part of an external sourcing contract: if removing,
delete the APP_FAILURE_BUCKETS_JSON declaration and the bucket_pair() function;
if keeping for backward compatibility, add a clear comment above
APP_FAILURE_BUCKETS_JSON explaining its purpose and that
qa/app_failure_buckets.py now handles classification, and mark bucket_pair() as
deprecated with a short usage note referencing qa/app_failure_buckets.py.
🪄 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: 7af3cce7-f89c-4e0a-9b90-006189b66c79

📥 Commits

Reviewing files that changed from the base of the PR and between 080497e and 0198c51.

📒 Files selected for processing (17)
  • docs/AGENT_GRADE_APP_TESTABILITY.md
  • qa/app_failure_buckets.py
  • qa/app_smoke_scripted.py
  • qa/export_app_evidence.py
  • qa/release_readiness.py
  • qa/test_app_failure_buckets.py
  • qa/test_app_smoke_scripted.py
  • qa/test_export_app_evidence.py
  • qa/test_macos_app_static.py
  • qa/test_release_readiness.py
  • qa/test_ui_playtest_app_buckets.py
  • qa/ui_playtest_app.sh
  • scripts/play_scripted_dm.sh
  • viewer/index.html
  • viewer/openworlds/screen-table.jsx
  • viewer/server.py
  • viewer/tests/test_openworlds_static.py

Comment thread qa/app_smoke_scripted.py
Comment thread viewer/server.py Outdated
@100yenadmin

Copy link
Copy Markdown
Member Author

Manual in-app browser smoke on top of #497:

  • Proved stale-tab guard first: current http://127.0.0.1:8899/openworlds/ was stale until same-port /app-status was restarted.
  • Started scripted provider on 8899 from this branch (0198c51) with private art. /app-status reported ready_for_smoke=true, ready_for_play=true, failure_bucket=none, actor Abby, 5 enabled actions, image probe ok.
  • In the in-app browser, drove launcher Continue → Play into the table via stable hooks.
  • Verified visible table: private art, Abby active, 5 enabled action buttons, move-input, move-submit, no alerts.
  • Submitted a free-text move through move-input/move-submit; chat lines advanced 1 → 3 and narration accepted the move.
  • Clicked palette continue; chat lines advanced 3 → 5 and readiness stayed green.

Evidence bundle: /Volumes/LEXAR/Codex/worldos-agent-grade-app-testability/browser-manual-browser-test-20260601T043614Z-0198c51/
Screenshot: screenshots/after-two-browser-moves.png

UX note for follow-up triage, not blocking this harness PR: the Chronicle can show the player echo after the scripted DM response for the palette action, and the opening narration appeared duplicated in the live log. The harness still correctly proves same-port status + accepted moves + narration advancement.

@100yenadmin

Copy link
Copy Markdown
Member Author

Follow-up after CodeRabbit:

  • Fixed unguarded mid-run smoke status/surface fetches in e4bfb96; failures now write smoke.json with a stable bucket instead of tracebacking.
  • Fixed app-status health counters to read optional browser/palette console/network NDJSON logs instead of fixed zeros.
  • Fixed the doc enum mismatch around blocked.

Validation after the fix:

  • bash -n scripts/play_scripted_dm.sh qa/ui_playtest_app.sh
  • python3 -m py_compile qa/app_smoke_scripted.py qa/export_app_evidence.py qa/app_failure_buckets.py viewer/server.py
  • python3 -m pytest viewer/tests/test_openworlds_static.py qa/test_macos_app_static.py qa/test_export_app_evidence.py qa/test_release_readiness.py qa/test_app_failure_buckets.py qa/test_app_smoke_scripted.py qa/test_ui_playtest_app_buckets.py -q -> 78 passed, 6 subtests
  • post-fix 5-beat scripted smoke passed with zero evidence gaps: /Volumes/LEXAR/Codex/worldos-agent-grade-app-testability/scripted-smoke-crfix-20260601T044652Z-0198c51/

@100yenadmin
100yenadmin merged commit ec96832 into main Jun 1, 2026
10 checks passed
@100yenadmin
100yenadmin deleted the codex/worldos-release-harness-v2 branch June 1, 2026 05:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant