mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-06 06:52:20 +02:00
feat(runtime): bind browser resources to authority
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"starting_sha": "bc5e1ee6922000a290371f8c2aa18802a03ffcad",
|
||||
"starting_tree": "8e09cc2560f50a3472e06ec614d6ada028b7eb18",
|
||||
"resource_focused": {
|
||||
"passed": 1425
|
||||
},
|
||||
"integrated": {
|
||||
"files": 149,
|
||||
"passed": 3776,
|
||||
"skipped": 7,
|
||||
"xfailed": 2
|
||||
},
|
||||
"index_schema_config_focused": {
|
||||
"passed": 40
|
||||
},
|
||||
"release_docker_live": {
|
||||
"passed": 4,
|
||||
"version": "0.35.0",
|
||||
"architecture": "linux-x64",
|
||||
"page_execution_enabled": false,
|
||||
"pin_contract_proven": false
|
||||
},
|
||||
"full": {
|
||||
"passed": 12310,
|
||||
"failed": 76,
|
||||
"skipped": 65,
|
||||
"xfailed": 2,
|
||||
"subtests_passed": 6,
|
||||
"seconds": 403.66
|
||||
},
|
||||
"failure_classification": {
|
||||
"initial_failing_cases": 82,
|
||||
"frozen_a_replay_failed": 79,
|
||||
"frozen_a_replay_passed": 3,
|
||||
"corrected_browser_regressions": [
|
||||
"tests/test_execution_bridge.py::test_registry_dispatch_preserves_session_id_for_native_handlers",
|
||||
"tests/test_tool_index_schema_parity.py::test_every_schema_tool_has_an_index_description"
|
||||
],
|
||||
"remaining_order_failure_reproduced_on_frozen_a": {
|
||||
"command": "python -m pytest -q tests/test_scheduler_restart_doublefire.py tests/test_tool_approvals.py::test_dispatcher_rejects_approved_document_action_without_target",
|
||||
"passed": 4,
|
||||
"failed": 1
|
||||
},
|
||||
"all_final_failed_nodes_reproduced_on_frozen_a": true,
|
||||
"final_failed_nodes": [
|
||||
"tests/test_agent_bash_tmux_env.py::test_direct_bash_subprocess_has_closed_stdin",
|
||||
"tests/test_agent_bash_tmux_env.py::test_bash_rejects_unicode_ffmpeg_drawtext_without_explicit_font",
|
||||
"tests/test_agent_bash_tmux_env.py::test_bash_allows_unicode_ffmpeg_drawtext_with_explicit_fontfile",
|
||||
"tests/test_agent_bash_windows.py::test_windows_bash_tool_passes_ctx_env_through_to_the_child",
|
||||
"tests/test_agent_bash_windows.py::test_bash_tool_returns_install_hint_when_git_bash_is_missing",
|
||||
"tests/test_agent_bash_windows.py::test_windows_bash_does_not_use_a_stray_tmux_executable",
|
||||
"tests/test_agent_external_tool_schemas.py::test_known_native_tool_reaches_scoped_bridge_without_redeclared_schema",
|
||||
"tests/test_client_tool_routing.py::test_no_bridge_falls_back_to_backend_execution",
|
||||
"tests/test_client_tool_routing.py::test_host_shell_requires_bridge_context",
|
||||
"tests/test_doc_library_open_orphaned.py::test_mobile_explicit_load_restores_full_editor_from_bottom_dock",
|
||||
"tests/test_document_history_controls.py::test_mobile_rich_text_history_state_and_document_switch",
|
||||
"tests/test_document_library_mobile_footer.py::test_mobile_open_in_new_chat_copies_to_materialized_session",
|
||||
"tests/test_document_module_api.py::test_default_export_surface_is_complete_and_callable",
|
||||
"tests/test_document_module_api.py::test_named_exports_survive_and_stay_callable",
|
||||
"tests/test_document_module_api.py::test_window_bridge_is_the_default_export",
|
||||
"tests/test_document_outline.py::test_outline_jumps_in_markdown_and_rich_text_and_fits_mobile",
|
||||
"tests/test_document_rich_checklist_enter.py::test_enter_creates_unchecked_task_and_empty_enter_exits_cleanly",
|
||||
"tests/test_document_rich_color_reset_and_contrast.py::test_rich_colors_follow_theme_and_undo_as_one_edit",
|
||||
"tests/test_document_rich_docx_export.py::test_browser_word_export_contains_native_rich_docx_ooxml",
|
||||
"tests/test_document_rich_docx_export.py::test_browser_markdown_word_export_keeps_heading_and_inline_formatting",
|
||||
"tests/test_document_rich_find_boundaries.py::test_find_rejects_cross_block_matches_but_supports_inline_matches_and_replacement",
|
||||
"tests/test_document_rich_font_color_controls.py::test_numeric_font_size_and_custom_colors_work_on_desktop_and_mobile",
|
||||
"tests/test_document_rich_heading_enter.py::test_mobile_heading_enter_exits_cleanly_and_is_one_step_undoable",
|
||||
"tests/test_document_rich_heading_enter.py::test_heading_enter_preserves_shift_middle_and_empty_heading_semantics",
|
||||
"tests/test_document_rich_image_caption.py::test_mobile_image_caption_survives_resize_history_and_empty_removal",
|
||||
"tests/test_document_rich_input_rules.py::test_typing_markers_converts_blocks_and_preserves_following_text",
|
||||
"tests/test_document_rich_keyboard_shortcuts.py::test_rich_document_shortcuts_work_at_desktop_and_mobile_widths",
|
||||
"tests/test_document_rich_selection_toolbar.py::test_selection_toolbar_formats_and_stays_inside_desktop_and_mobile_viewports",
|
||||
"tests/test_document_rich_slash_menu.py::test_slash_menu_filters_converts_blocks_inserts_tables_and_fits_mobile",
|
||||
"tests/test_document_rich_smart_link_paste.py::test_rich_url_paste_links_selections_and_plain_urls_without_unsafe_autolinks",
|
||||
"tests/test_document_rich_structure_tools.py::test_mobile_headings_page_break_history_and_persistence",
|
||||
"tests/test_document_rich_table_cell_alignment.py::test_mobile_table_cell_alignment_tracks_state_and_native_history",
|
||||
"tests/test_document_rich_table_header_preservation.py::test_mobile_structural_edits_preserve_header_modes_and_history",
|
||||
"tests/test_document_rich_table_headers.py::test_mobile_header_row_and_column_toggle_independently_with_undo",
|
||||
"tests/test_document_rich_table_merge_split.py::test_mobile_merge_split_round_trip_preserves_headers_formatting_and_history",
|
||||
"tests/test_document_rich_table_tab_history.py::test_mobile_table_tab_navigation_row_creation_and_history",
|
||||
"tests/test_document_rich_toolbar_menus.py::test_mobile_toolbar_uses_native_momentum_and_distinct_activation_tokens",
|
||||
"tests/test_document_rich_toolbar_menus.py::test_mobile_toolbar_menu_preserves_selection_and_restores_focus",
|
||||
"tests/test_document_rich_toolbar_menus.py::test_rich_toolbar_menus_track_live_formatting_values",
|
||||
"tests/test_document_save_shortcut.py::test_ctrl_s_saves_rich_text_immediately_once_and_updates_status",
|
||||
"tests/test_document_save_status.py::test_save_status_is_dirty_race_safe_and_reports_failures",
|
||||
"tests/test_document_toolbar_order.py::test_rich_toolbar_rendered_order_is_stable_on_desktop_and_mobile",
|
||||
"tests/test_edit_file.py::test_edit_file_blocked_at_execution_for_non_admin",
|
||||
"tests/test_email_library_module_graph_js.py::test_every_package_module_evaluates_on_its_own_in_a_browser",
|
||||
"tests/test_email_library_module_graph_js.py::test_wrapper_and_entry_module_hand_out_the_same_functions",
|
||||
"tests/test_escape_inner_layers.py::test_rich_escape_closes_toolbar_then_selection_badge",
|
||||
"tests/test_escape_inner_layers.py::test_email_escape_closes_inner_states_without_closing_library",
|
||||
"tests/test_failed_call_correction.py::test_corrected_ids_execute_after_repeated_ambiguous_title_failures[2]",
|
||||
"tests/test_failed_call_correction.py::test_corrected_ids_execute_after_repeated_ambiguous_title_failures[3]",
|
||||
"tests/test_history_resume_rendering_js.py::test_history_resume_rendering_browser_suite",
|
||||
"tests/test_live_fallback_round_attribution.py::test_detached_resume_reconciles_canonical_terminal_failures",
|
||||
"tests/test_live_fallback_round_attribution.py::test_detached_resume_surfaces_fallback_then_provider_alias_without_reload",
|
||||
"tests/test_live_fallback_round_attribution.py::test_detached_resume_renders_preoutput_error_without_empty_reload",
|
||||
"tests/test_manage_tasks_cron.py::test_cron_create_edit_resume_and_invalid_edit_rollback",
|
||||
"tests/test_manage_tasks_cron.py::test_named_weekdays_create_and_edit_preserve_actual_clock",
|
||||
"tests/test_manage_tasks_cron.py::test_time_only_edit_changes_cron_clock_not_calendar_fields[15 9 * * 1,3,5]",
|
||||
"tests/test_manage_tasks_cron.py::test_time_only_edit_changes_cron_clock_not_calendar_fields[15 9 15 * *]",
|
||||
"tests/test_manage_tasks_cron.py::test_time_only_edit_changes_cron_clock_not_calendar_fields[0,30 8-10 * * 2,4]",
|
||||
"tests/test_manage_tasks_cron.py::test_invalid_cron_retime_rolls_back_all_edits",
|
||||
"tests/test_preview_execution_evidence.py::test_failed_shell_retains_exit_status_and_both_streams_for_followup",
|
||||
"tests/test_review_regressions.py::test_host_shell_uses_tui_bridge_context",
|
||||
"tests/test_review_regressions.py::test_host_shell_forwards_detach_and_job_polling",
|
||||
"tests/test_review_regressions.py::test_host_shell_rejects_non_local_bridge_url_before_http",
|
||||
"tests/test_review_regressions.py::test_public_agent_policy_blocks_sensitive_tools",
|
||||
"tests/test_review_regressions.py::test_disabled_qualified_email_tool_blocks_bare_alias",
|
||||
"tests/test_review_regressions.py::test_tool_policy_qualified_email_block_covers_bare_alias",
|
||||
"tests/test_review_regressions.py::test_bare_email_dispatch_rejects_non_object_json_args",
|
||||
"tests/test_review_regressions.py::test_bare_email_dispatch_rejects_invalid_json_body",
|
||||
"tests/test_review_regressions.py::test_write_file_inline_json_args",
|
||||
"tests/test_review_regressions.py::test_plan_mode_blocks_mutating_email_aliases_without_mcp_inventory",
|
||||
"tests/test_review_regressions.py::test_bare_email_dispatch_empty_content_calls_with_empty_args",
|
||||
"tests/test_review_regressions.py::test_email_mcp_non_object_args_fail_before_dispatch",
|
||||
"tests/test_review_regressions.py::test_email_mcp_dispatch_includes_hidden_owner",
|
||||
"tests/test_review_regressions.py::test_bare_email_mcp_dispatch_includes_hidden_owner",
|
||||
"tests/test_tool_approvals.py::test_dispatcher_rejects_approved_document_action_without_target",
|
||||
"tests/test_turn_rendering_js.py::test_turn_rendering_browser_suite"
|
||||
]
|
||||
},
|
||||
"static": {
|
||||
"compileall": "passed",
|
||||
"diff_check": "passed",
|
||||
"conflict_markers": "none",
|
||||
"unmerged_index": "none"
|
||||
},
|
||||
"limitations": [
|
||||
"page/document reads and effects unconditionally unavailable",
|
||||
"arm64 producer execution not live tested",
|
||||
"18-case positive producer enabling gate remains blocked on atomic expected-identity operation support",
|
||||
"full repository suite is not green; failures reproduced on frozen A"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
# Wave 3 browser authority: observations with page execution disabled
|
||||
|
||||
Starting Checkpoint A: `bc5e1ee6922000a290371f8c2aa18802a03ffcad`, tree
|
||||
`8e09cc2560f50a3472e06ec614d6ada028b7eb18`. Branch, cleanliness, both A
|
||||
commits and canonical Wave 5B ancestry were verified before edits. Existing
|
||||
145-file Checkpoint A baseline passed 3369 tests, with 3 platform skips
|
||||
and 2 existing xfails.
|
||||
|
||||
## Producer decision and live evidence
|
||||
|
||||
The actual release Docker image was available locally:
|
||||
`sha256:cc2d47e2327d573af01c6b027f23d2ab0f2ee9b85d658e9eb8065bd02b9c3515`
|
||||
(Linux amd64). Its native binary reports exactly `agent-browser 0.35.0`.
|
||||
|
||||
The isolated local-launch probe performed:
|
||||
|
||||
1. Fresh local browser launch with the first `--pin-tab` request.
|
||||
2. Create a sibling tab; capture and select an exact producer targetId.
|
||||
3. `session info --no-pin-tab`, then `session info --pin-tab`.
|
||||
4. Destroy the captured target using an external **test fixture**.
|
||||
5. `snapshot --pin-tab`.
|
||||
|
||||
Both re-arm calls succeeded. The snapshot also succeeded, a replacement target
|
||||
became active, and there was no `tab_gone`. Lifecycle metadata reported
|
||||
`relaunchedBrowser=false`, `restartedBackground=false`, `launched=false`.
|
||||
The CLI's special `session info` path does not attach the pin fields to its
|
||||
daemon request. Successful flags therefore cannot establish `pin_armed_for`.
|
||||
The producer audit's proposed re-arm sequence is not valid in this mode.
|
||||
|
||||
`tests/test_browser_producer_live_contract.py` reproduces this defect against
|
||||
the actual binary, rather than treating the defect as a passing pin contract.
|
||||
The four live tests also validate target/loader stability, reload/navigation,
|
||||
same-document history change, distinct same-URL pages, and exact target switch
|
||||
responses. Four passed in the actual release image. Raw GUIDs/CDP capability URLs
|
||||
are neither printed nor saved by the tests or production adapter.
|
||||
|
||||
Page/document reads and effects are **unconditionally disabled before producer
|
||||
dispatch**. Observations, matching preconditions, matching postconditions,
|
||||
successful pin flags, exact approval and child scope never override this gate.
|
||||
|
||||
## Identity architecture
|
||||
|
||||
`src/browser_identity.py` owns producer validation, private configuration,
|
||||
registration, observations, metadata execution, resource binding and CDP
|
||||
observation. `src/agent_runtime/resources.py` supplies immutable types:
|
||||
|
||||
- `BrowserSessionObservation`: trusted namespace, version, platform, binary
|
||||
digest, configuration digest, selector-only session key, one nested Wave 5B
|
||||
`ProcessIdentity`, domain-separated browser GUID digest, and deterministic
|
||||
session-incarnation digest. No duplicated start-token abstraction.
|
||||
- `BrowserSessionResource`: the observation plus mandatory owner/thread binding.
|
||||
- `BrowserPageResource`: exact parent session, producer targetId, opaque loaderId,
|
||||
explicit page/document scope, and alias/URL audit metadata. Page authority is
|
||||
session + target; document authority additionally includes loader. Metadata
|
||||
does not participate in the authority key.
|
||||
|
||||
Registration is server-only, checks the installed producer and creates private
|
||||
owned configuration. It does not spawn or adopt a daemon/browser. Model-facing
|
||||
lookup never creates a session. Legacy lifecycle records are not authority.
|
||||
There is currently no model-facing launch/enrolment operation; default/legacy
|
||||
sessions without a registered observation fail closed.
|
||||
|
||||
An explicit trusted observation checks active producer state, captures the
|
||||
daemon incarnation around exact executable observation, obtains the local CDP
|
||||
capability, rejects lifecycle launch/replacement, validates tab schema and the
|
||||
absence of labels, cross-checks CDP target type, captures main-frame loaderId,
|
||||
detaches and rechecks daemon/browser identity. A changed session invalidates
|
||||
every earlier page/document observation. A changed loader invalidates document
|
||||
scope; a same-URL or same-alias replacement never inherits target scope.
|
||||
|
||||
The proposed pin re-arm is **not implemented as an authority-establishing
|
||||
action**. `pin_armed_for` stays unset; even modifying this field cannot enable
|
||||
page execution. No alternate pin workaround or producer fork is introduced.
|
||||
|
||||
## Trusted producer and observation transport
|
||||
|
||||
Only explicit glibc Linux release binaries are allowlisted:
|
||||
|
||||
| Platform | Version | Native binary SHA-256 |
|
||||
| --- | --- | --- |
|
||||
| linux-x64 | 0.35.0 | b7a28c3a43a7008dd02585e2e60c391c08983f7a099149caed63c9f13f57b752 |
|
||||
| linux-arm64 | 0.35.0 | 92cd7d0897837ac648b9a6ab1965c69c5920e0f54df57e4295cdb1143b0541c8 |
|
||||
|
||||
These digests were observed from the release image's installed package. x64 was
|
||||
executed live; arm64 execution remains a separate architecture gate. Selection
|
||||
uses `/usr/local/lib/node_modules/agent-browser/bin/agent-browser-<platform>`.
|
||||
Version, hash, ownership, permissions and schema are checked. No PATH search,
|
||||
npx execution/download, cache glob, mtime selection or replacement download.
|
||||
0.27.0, unknown versions, platforms and hashes fail closed.
|
||||
|
||||
The CDP sidecar accepts only loopback browser websocket capability URLs and
|
||||
only `Target.getTargets`, `Target.getTargetInfo`, `Target.attachToTarget`,
|
||||
`Page.getFrameTree`, `Target.detachFromTarget`. It does not enable domains,
|
||||
evaluate, navigate, close targets or expose arbitrary CDP to tools. Frame identity
|
||||
must equal the captured target and loaderId must be nonempty. Requests have
|
||||
3-second bounds and bounded frame/message sizes. This is producer identity
|
||||
observation, not semantic evidence or trust elevation.
|
||||
|
||||
The capability URL stays in a non-serializable, non-repr memory field. Metadata
|
||||
revalidation connects to that captured browser endpoint, rather than calling
|
||||
`get cdp-url` again: that getter can auto-launch a replacement. Failed or changed
|
||||
daemon/CDP observations invalidate the registered session; no rediscovery/retry.
|
||||
|
||||
Configuration is exactly `{}` in an owned private cwd, with observed inode and
|
||||
permissions checked. Client environment is constructed from an explicit fixed
|
||||
allowlist: owned HOME/TMPDIR/socket directory, system PATH, Chromium path and
|
||||
idle timeout. Ambient AGENT_BROWSER/CDP/provider/profile/state/config/proxy/XDG
|
||||
settings and model subprocess environment are not inherited. Configuration is
|
||||
part of the incarnation digest; credentials are not serialized.
|
||||
|
||||
## Operation and approval boundaries
|
||||
|
||||
| Operation | Binding | Current execution |
|
||||
| --- | --- | --- |
|
||||
| `session_info` | Exact registered session + caller/request | Supported metadata only; no URL/title/content, target selection or launch |
|
||||
| New page, initial open, tab list, whole-session close | Session/creation producer guarantee | Disabled; no trustworthy atomic creation/control contract admitted |
|
||||
| Select/close page, navigate/reload/back/forward, time wait, viewport scroll, page network/console | Exact session + target | Disabled before dispatch |
|
||||
| Click/fill/press/evaluate, selector/ref interactions and waits | Exact session + target + loader | Disabled before dispatch |
|
||||
| Snapshot/read/find/screenshot | Exact page, loader sandwich for any future read | Disabled before dispatch; no replacement-page read |
|
||||
|
||||
Failure is structured: `failure_kind=browser_page_authority_unavailable`,
|
||||
`executed=false`, `retryable=false`, `producer_capability_unavailable=true`.
|
||||
Missing session authority produces a separate session-unavailable failure.
|
||||
No timeout or post-check can authorize execution against a replacement.
|
||||
|
||||
RequestAuthority version 5 carries explicit session/page ceilings. Old snapshots
|
||||
restore empty browser scopes. Exact proposal capture binds normalized operation,
|
||||
request/owner/thread and the exact session/page/document observation. Metadata
|
||||
execution revalidates before one-use claim and at producer entry. Restoration
|
||||
adds no general scope. Unsupported page approvals are never claimed/executed.
|
||||
|
||||
Child scopes validate parent observations before intersection. Session ceilings
|
||||
require exact incarnation; page ceilings require exact parent + target; document
|
||||
ceilings also require loader. A page child cannot acquire session control, and a
|
||||
document child cannot renew a replaced document. Discovery adds no authority.
|
||||
|
||||
Model batches, raw tab/window/frame/connect commands, labels, raw targetIds,
|
||||
configuration/session/CDP/provider/profile/state flags and flag-like positional
|
||||
values are rejected. `page: tN` is strictly validated. The preview's automatic
|
||||
open/snapshot batch rewrite and native read/post-click batches/recovery engine
|
||||
are removed. Raw global Playwright browser control calls fail closed as well;
|
||||
remote backend/stdio identity is not page authority. Other remote/MCP transport
|
||||
mechanics remain unchanged and external.
|
||||
|
||||
Client invocations are bounded at 20 seconds, below the source-verified 30-second
|
||||
read/resend floor, with held-handle kill/wait on timeout/cancellation and no
|
||||
Odysseus retries. Immediate producer EOF/reset retries cannot be eliminated by
|
||||
this wrapper. **No exactly-once claim is made; all effects remain disabled.**
|
||||
|
||||
## Control state and prior unsupported paths
|
||||
|
||||
Private browser runtime/configuration is protected by central control-plane
|
||||
resolution and native launch workspace guards, including actual configured
|
||||
directories. Direct, symlink and hardlink tests cover it. These are pathname/
|
||||
inode observations, not race-freedom claims or a new containment policy.
|
||||
Service-owned Wave 5B cleanup remains independent of model authority; shutdown
|
||||
does not discover/download/run an untrusted producer binary.
|
||||
|
||||
Re-audit of Checkpoint A seams found:
|
||||
|
||||
| Path | Remaining enforcement |
|
||||
| --- | --- |
|
||||
| PTY/native manager routes | `routes/shell_routes.py:setup_shell_routes.shell_exec/shell_stream` call `_require_admin` before `_exec_shell/_generate_pty/_generate_tmux`; internal/anonymous controls denied, authenticated human administration separate |
|
||||
| Additional process producers | `resources.ProcessResource.__post_init__` admits only frozen native producer/role combinations; `process_resources.resolve_process_operation` requires sealed observations |
|
||||
| Raw scheduled SSH | `TaskScheduler._execute_action` → `builtin_actions.action_ssh_command` → `_run_subprocess` refuses SSH without an external workload adapter |
|
||||
| Local Cookbook scheduled auto-stop | `routes/cookbook_routes.py:setup_cookbook_routes.protect_native_control` applies shell admin boundary to local mutation; `tools/cookbook._cookbook_kill_session` refuses registry-less local control; legacy internal shell route cannot gain administration |
|
||||
| Legacy/unscoped tasks | `authority.restore_task_authority` → `process_resources.resolve_process_operation` admits no missing creation scope |
|
||||
| Anonymous administration / generic app_api | `owned_resources.needs_owned_binding` rejects shell/model/Cookbook namespaces; `_require_admin` also rejects unlabelled loopback when anonymous or unauthenticated |
|
||||
|
||||
No model-reachable page producer entry remains in the native/research wrapper.
|
||||
Trusted observation/setup methods are not tools or routes. Native arbitrary
|
||||
program/network effects and remote workload effects retain their existing
|
||||
explicit launch/backend boundaries; this checkpoint adds no general network
|
||||
egress/provenance policy (Wave 4).
|
||||
|
||||
## Validation and remaining release gates
|
||||
|
||||
`wave-3-final-tests.txt` contains 149 files, retaining all 145 Checkpoint A files
|
||||
and the exact prior 88-file selection. Legacy positive page/batch/recovery tests
|
||||
are replaced by explicit unsupported-before-dispatch tests; formatting,
|
||||
filesystem, YouTube, Wave 5B ownership/cleanup and research fallback tests remain.
|
||||
|
||||
Final resource/authority/approval focused run: **1,425 passed**. Final 149-file
|
||||
integrated gate: **3,776 passed, 7 skipped, 2 xfailed**. The exact old 88-file
|
||||
selection and all 145 Checkpoint A files were verified as subsets of this gate.
|
||||
The 7 skips are `/tmp` not being a symlink, applicable RLIMIT_AS already
|
||||
available, the Windows Ollama startup guard, and four explicit Docker-only
|
||||
producer probes. Those four probes ran separately: **4 passed** on the actual
|
||||
release x64 image. Index/schema/configuration checks separately passed 40 tests.
|
||||
|
||||
Full-suite failure classification was performed against an isolated archive of
|
||||
the frozen Checkpoint A (no checkout/rewrite): replay of the initial 82 failing
|
||||
cases reproduced 79. Two browser/schema regressions were corrected. The third
|
||||
case, `test_dispatcher_rejects_approved_document_action_without_target`, passed
|
||||
alone but failed identically on the frozen archive when preceded by
|
||||
`test_scheduler_restart_doublefire.py`. That fixture permanently replaces
|
||||
`core.database.SessionLocal/engine` with a task-only database. This is an
|
||||
existing suite-order issue, not a browser authority regression. Missing Node
|
||||
Playwright dependencies and legacy fixtures that expect unscoped execution
|
||||
also remain explicit full-suite limitations; they are not skipped or counted
|
||||
as passes. New browser test environment documentation also records the existing
|
||||
memory backend owner settings required to regenerate the configuration page.
|
||||
|
||||
Final full repository run: **12,310 passed, 76 failed, 65 skipped, 2 xfailed,
|
||||
6 subtests passed** (403.66 seconds). Every final failed node was reproduced on
|
||||
frozen Checkpoint A, using the scheduler-order reproduction for the document
|
||||
case. This is **not a green full-suite gate**. Exact failed node IDs and totals
|
||||
are in `validation/wave-3-browser-final-results.json`.
|
||||
|
||||
Full-suite skips include smoke/live endpoints without an instance or opt-in,
|
||||
the four separately executed release producer probes, the three platform cases,
|
||||
missing caldav/chromadb/fitz/openpyxl/markitdown/libmagic/Node Playwright,
|
||||
ffmpeg format limitations and missing rsvg-convert. Nothing was silently
|
||||
converted into a pass. The two existing strict xfails remain the inferred single-file deletion and inferred CSV overwrite path cases in `test_runtime_behavior_regressions.py`.
|
||||
|
||||
Compileall, whitespace, conflict-marker and unmerged-index checks pass.
|
||||
The coherent fail-closed implementation is available for independent review;
|
||||
full-suite cleanup remains outstanding and page enabling is not merge-ready.
|
||||
|
||||
## Exact production changes since Checkpoint A
|
||||
|
||||
```text
|
||||
src/browser_identity.py
|
||||
src/agent_runtime/resources.py
|
||||
src/agent_runtime/authority.py
|
||||
src/agent_runtime/process_resources.py
|
||||
src/agent_tools/web_tools.py
|
||||
src/tool_execution.py
|
||||
src/tool_approvals.py
|
||||
src/tool_schemas.py
|
||||
src/tool_index.py
|
||||
src/clean_agent_preview.py
|
||||
src/agent_loop.py
|
||||
src/constants.py
|
||||
scripts/generate_env_reference.py
|
||||
```
|
||||
|
||||
`website/configuration-reference.md` is regenerated documentation. Runtime
|
||||
instructions/schema/index no longer advertise executable page interactions.
|
||||
The agent loop change is only the browser prompt snippet; it is not decomposed.
|
||||
Wave 5B lifecycle mechanics and MCP transport are not modified.
|
||||
|
||||
```sh
|
||||
python3 -m pytest -q -rs $(cat docs/runtime-decomposition/wave-3-final-tests.txt)
|
||||
python3 -m pytest -q -rs
|
||||
python3 -m compileall -q app.py core routes services src tests scripts
|
||||
git diff --check
|
||||
git grep -n -E '^(<<<<<<< |=======$|>>>>>>> )' || true
|
||||
git ls-files -u
|
||||
```
|
||||
|
||||
Live release probe (source checkout mounted read-only, isolated container state):
|
||||
|
||||
```sh
|
||||
docker run --rm --network none \
|
||||
-e ODYSSEUS_BROWSER_LIVE_CONTRACT=1 -e ODYSSEUS_DATA_DIR=/tmp/w3-data \
|
||||
-e DATABASE_URL=sqlite:///:memory: -v "$PWD:/app:ro" \
|
||||
--entrypoint python odysseus-maintainer-preview-odysseus:latest \
|
||||
-m pytest -q -rs -o cache_dir=/tmp/w3-pytest-cache \
|
||||
tests/test_browser_producer_live_contract.py
|
||||
```
|
||||
|
||||
The x64 probes pass by proving observation contracts **and the known defect**.
|
||||
They are not a positive merge gate for enabling page effects. Re-enabling needs
|
||||
a separately audited/allowlisted producer that executes only while expected
|
||||
browser incarnation, targetId and optional loaderId still match, rejects stale
|
||||
state atomically before reading/effect, and does not resend an indeterminate
|
||||
effect. No producer changes are implemented here.
|
||||
|
||||
The original positive 18-case Docker gate remains mandatory before re-enabling:
|
||||
stable/repeated targets; reload; cross-/same-document navigation; identical URLs;
|
||||
close/recreate; browser and daemon replacement; popup races; destroyed targets;
|
||||
local-launch pin/atomic binding; exact target switch; A-F label collision;
|
||||
lifecycle metadata; timeout/duplicate effects; bfcache; prerender/frame invariant;
|
||||
strict schema. It must run per supported release architecture. Pin success and
|
||||
pre/post checking alone can never substitute for atomic binding.
|
||||
|
||||
P1: producer page/document capability unavailable; unregistered sessions and
|
||||
Checkpoint A compatibility paths intentionally denied. P2: private-runtime scan
|
||||
cost/retention, filesystem observation races and architecture-specific live
|
||||
coverage. Wave 4 remains responsible for effects/provenance/egress and truthful
|
||||
completion evidence; no Wave 4 journal or lifecycle redesign is introduced.
|
||||
@@ -0,0 +1,149 @@
|
||||
tests/test_resource_identity.py
|
||||
tests/test_owned_resource_identity.py
|
||||
tests/test_remote_resource_identity.py
|
||||
tests/test_request_authority.py
|
||||
tests/test_tool_approvals.py
|
||||
tests/test_tool_approval_single_action_scope.py
|
||||
tests/test_tool_approval_task_scope.py
|
||||
tests/test_workspace_confine.py
|
||||
tests/test_tool_path_confinement.py
|
||||
tests/test_path_confinement_boundary.py
|
||||
tests/test_filesystem_tool_argument_validation.py
|
||||
tests/test_code_nav_tools.py
|
||||
tests/test_apply_patch_transaction.py
|
||||
tests/test_execution_bridge.py
|
||||
tests/test_production_external_bridge.py
|
||||
tests/test_turn_contract.py
|
||||
tests/test_turn_contract_read_operations.py
|
||||
tests/test_turn_contract_integration.py
|
||||
tests/test_agent_turn_contract_boundaries.py
|
||||
tests/test_explicit_personal_turn_contract.py
|
||||
tests/test_nested_invocation_ownership.py
|
||||
tests/test_containment_contract.py
|
||||
tests/test_containment_enforcement.py
|
||||
tests/test_containment_process_tree.py
|
||||
tests/test_native_execution_containment.py
|
||||
tests/test_background_containment.py
|
||||
tests/test_process_ownership.py
|
||||
tests/test_bg_jobs_store.py
|
||||
tests/test_bg_job_tools.py
|
||||
tests/test_execution_filesystem_boundary.py
|
||||
tests/test_mcp_manager.py
|
||||
tests/test_mcp_reconnect_args.py
|
||||
tests/test_mcp_text_error_normalization.py
|
||||
tests/test_mcp_param_hint_hardening.py
|
||||
tests/test_mcp_tool_params_in_prompt.py
|
||||
tests/test_mcp_memory_owner_scope.py
|
||||
tests/test_mcp_cache_invalidation.py
|
||||
tests/test_multiple_mcp_servers_timeout.py
|
||||
tests/test_mcp_dependency_compatibility.py
|
||||
tests/test_builtin_mcp_bg_tasks.py
|
||||
tests/test_builtin_mcp_pythonpath.py
|
||||
tests/test_builtin_mcp_npx_cache.py
|
||||
tests/test_mcp_add_server_args_validation.py
|
||||
tests/test_manage_mcp_command_allowlist.py
|
||||
tests/test_document_tool_owner_scope.py
|
||||
tests/test_owned_document_query.py
|
||||
tests/test_document_session_owner_scope.py
|
||||
tests/test_active_document_mutation_guard.py
|
||||
tests/test_native_document_stream.py
|
||||
tests/test_document_followup_integrity.py
|
||||
tests/test_document_active_restore.py
|
||||
tests/test_attachment_refs.py
|
||||
tests/test_upload_handler_atomicity.py
|
||||
tests/test_upload_handler_cleanup.py
|
||||
tests/test_upload_handler_rename_owner.py
|
||||
tests/test_upload_routes_owner_scope.py
|
||||
tests/test_resolve_upload_path_nondict.py
|
||||
tests/test_personal_upload_isolation.py
|
||||
tests/test_personal_upload_privilege.py
|
||||
tests/test_extract_text_tool.py
|
||||
tests/test_media_ingress.py
|
||||
tests/test_session_tools_registry.py
|
||||
tests/test_session_owner_attribution.py
|
||||
tests/test_session_list_owner_scope.py
|
||||
tests/test_session_endpoint_owner_scope.py
|
||||
tests/test_session_search.py
|
||||
tests/test_session_search_batch_fetch.py
|
||||
tests/test_history_topics_owner_scope.py
|
||||
tests/test_history_order_by_timestamp_regression.py
|
||||
tests/test_history_db_fallback_hidden.py
|
||||
tests/test_memory_owner_isolation.py
|
||||
tests/test_memory_routes_session_owner.py
|
||||
tests/test_manage_memory_json_contract.py
|
||||
tests/test_manage_memory_list.py
|
||||
tests/test_memory_store_unreadable_no_wipe.py
|
||||
tests/test_manage_notes_search_contract.py
|
||||
tests/test_notes_fail_closed_auth.py
|
||||
tests/test_notes_checklist_state.py
|
||||
tests/test_vault_password_not_in_argv.py
|
||||
tests/test_vault_routes_shim.py
|
||||
tests/test_external_context_tool_gate.py
|
||||
tests/test_chat_route_tool_policy.py
|
||||
tests/test_product_turn_contract_route.py
|
||||
tests/test_native_tool_result_threading.py
|
||||
tests/test_host_shell_polling.py
|
||||
tests/test_integrations_url_join.py
|
||||
tests/test_integration_api_call_ssrf.py
|
||||
tests/test_integrations_api_call_truncation.py
|
||||
tests/test_process_resource_identity.py
|
||||
tests/test_background_resource_identity.py
|
||||
tests/test_runtime_resource_integration.py
|
||||
tests/test_process_lifecycle.py
|
||||
tests/test_browser_lifecycle.py
|
||||
tests/test_private_browser_tool.py
|
||||
tests/test_browser_transport_recovery.py
|
||||
tests/test_shell_routes.py
|
||||
tests/test_agent_tmux_retirement.py
|
||||
tests/test_cookbook_stop_without_procfs.py
|
||||
tests/test_cookbook_serve_lifecycle.py
|
||||
tests/test_task_scheduler_cancel.py
|
||||
tests/test_task_shell_tools.py
|
||||
tests/test_runtime_behavior_regressions.py
|
||||
tests/test_workspace_artifact_tool_floor.py
|
||||
tests/test_bg_monitor_stream.py
|
||||
tests/test_orphan_reaping.py
|
||||
tests/test_cookbook_agent_tool_ssh_validation.py
|
||||
tests/test_codex_cookbook_admin_gate.py
|
||||
tests/test_task_cookbook_admin_gate.py
|
||||
tests/test_builtin_actions_cookbook_serve_state.py
|
||||
tests/test_cookbook_local_serve_pid_winpid.py
|
||||
tests/test_scheduler_restart_doublefire.py
|
||||
tests/test_task_scheduler_session_delivery.py
|
||||
tests/test_cookbook_cache_scan_isolation.py
|
||||
tests/test_cookbook_cached_scan_refresh.py
|
||||
tests/test_cookbook_chat_deeplinks_static.py
|
||||
tests/test_cookbook_cpu_only_serve.py
|
||||
tests/test_cookbook_dead_download_status.py
|
||||
tests/test_cookbook_dependency_completion_regression.py
|
||||
tests/test_cookbook_deps_recipes.py
|
||||
tests/test_cookbook_diagnosis.py
|
||||
tests/test_cookbook_diagnosis_js.py
|
||||
tests/test_cookbook_docker_access.py
|
||||
tests/test_cookbook_download_toast_duration.py
|
||||
tests/test_cookbook_endpoint_registration.py
|
||||
tests/test_cookbook_error_feedback.py
|
||||
tests/test_cookbook_error_tail_lines.py
|
||||
tests/test_cookbook_finished_download_label.py
|
||||
tests/test_cookbook_gemma4_thinking_template.py
|
||||
tests/test_cookbook_helpers.py
|
||||
tests/test_cookbook_hf_token.py
|
||||
tests/test_cookbook_official_trending_filter.py
|
||||
tests/test_cookbook_package_detection.py
|
||||
tests/test_cookbook_port_parsing_js.py
|
||||
tests/test_cookbook_progress_signal_js.py
|
||||
tests/test_cookbook_remote_windows_diffusers.py
|
||||
tests/test_cookbook_same_host_server_profiles_js.py
|
||||
tests/test_cookbook_tool_dry_run.py
|
||||
tests/test_cookbook_windows_stop_tree_js.py
|
||||
tests/test_scheduler_prompt_cache_time.py
|
||||
tests/test_scheduler_scheduled_time_validation.py
|
||||
tests/test_task_scheduler_cache.py
|
||||
tests/test_task_scheduler_fixture_isolation.py
|
||||
tests/test_tool_task_cancelled_on_disconnect.py
|
||||
tests/test_background_tool_jobs.py
|
||||
tests/test_deep_research_browser_fallback.py
|
||||
tests/test_browser_resource_identity.py
|
||||
tests/test_browser_identity_transport.py
|
||||
tests/test_browser_producer_live_contract.py
|
||||
tests/test_clean_agent_preview.py
|
||||
Reference in New Issue
Block a user