diff --git a/CHANGELOG.md b/CHANGELOG.md index 02c4d8240..a126ace14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ All notable changes to OriginWeave are documented in this file. The format follo - Real loopback rustls integration covering trusted DNS SAN, Common-Name fallback rejection, wrong-name and untrusted-root rejection, fixed-time expiry and not-yet-valid failures, exact IPv4 and IPv6 SANs, TLS 1.2/TLS 1.3, required and optional ALPN, and transport-origin binding. - Cumulative interactive-first RAM, VRAM, batch, local-model, admission, pause, and compositor-pressure mitigation plans, including active-consumer reduction at exact hard limits. - Real pinned-Chrome WebDriver evidence for the controlled Agent Task fixture: the CI lane uses an isolated profile, disables extensions, types and submits synthetic text, observes the same-document post-condition, and proves profile cleanup; this does not claim a shipped OriginWeave browser adapter. +- Active pinned-Chrome Agent Task evidence verifies browser-computed role/name for controlled input and submit targets before action; this remains test-harness semantic evidence and does not claim a product semantic observer or authority. - Universally value-redacted network evidence with explicit path, metadata, and provenance bounds; ambiguous path rejection; validated source URLs; lowercase SHA-256 identifiers; and verification state. - Rust 1.97.1 build contract, strict Clippy and rustdoc gates, and exact production function, line, region, and branch coverage enforcement. - Hourly bounded OpenCode product-development workflow using `NVIDIA_NIM_API_KEY`, an unprivileged disposable workspace, loopback-only model broker, independently verified patches, and publication through a dedicated `OPENCODE_PR_TOKEN` that cannot review or merge. diff --git a/docs/DOCUMENTATION_FITNESS.md b/docs/DOCUMENTATION_FITNESS.md index cd637ae65..f82bd4fe8 100644 --- a/docs/DOCUMENTATION_FITNESS.md +++ b/docs/DOCUMENTATION_FITNESS.md @@ -158,9 +158,9 @@ Active #64 makes a successful action-outcome value require existing verified pro ### 3.19 Controlled Agent Task fixture -Active #65 supplies a deterministic synthetic local web fixture with a labelled semantic input, submit control, same-document post-condition and explicitly hidden/untrusted prompt-injection text. Active #70 executes that fixture through real WebDriver on pinned Chrome with an isolated profile, disabled extensions, synthetic input, same-document post-condition verification and profile cleanup. The fixture contains no credential collection surface and requires no live third-party site. +Active #65 supplies a deterministic synthetic local web fixture with a labelled semantic input, submit control, same-document post-condition and explicitly hidden/untrusted prompt-injection text. Active #70 executes that fixture through real WebDriver on pinned Chrome with an isolated profile, disabled extensions, synthetic input, same-document post-condition verification and profile cleanup. Active #71 verifies browser-computed role/name for the controlled input and submit button before action. The fixture contains no credential collection surface and requires no live third-party site. -**Resolution:** the #65/#70 lane makes controlled browser-level evidence reproducible without turning a third-party site into a test dependency. It is not a browser adapter, semantic extractor, OriginWeave input-dispatch authority, policy engine, trusted clock, process-attribution source or proof of the shipped product runtime. +**Resolution:** the #65/#70/#71 lane makes controlled browser-level and browser-computed role/name evidence reproducible without turning a third-party site into a test dependency. It is not a browser adapter, product semantic extractor, OriginWeave input-dispatch authority, policy engine, trusted clock, process-attribution source or proof of the shipped product runtime. ### 3.20 Bounded browser process-set resource evidence diff --git a/docs/TEST_STRATEGY.md b/docs/TEST_STRATEGY.md index 56dd6f18f..faf7f54b3 100644 --- a/docs/TEST_STRATEGY.md +++ b/docs/TEST_STRATEGY.md @@ -85,6 +85,11 @@ browser-level fixture execution only; it does not replace the OriginWeave BiDi/CDP authority adapter, semantic node contract, policy dispatch or protected-main runtime acceptance required by issue #28. +Active PR #71 additionally verifies browser-computed role/name for the +controlled input and submit target before the real WebDriver action. CSS remains +a fixture-harness locator; this does not establish OriginWeave node authority, +semantic provenance or policy dispatch. + ### 3.5 Buyer acceptance Versioned task packs measure repeatable product outcomes rather than one lucky agent run. The benchmark artifact records browser build, OriginWeave version, model/provider/reasoning configuration, seed where supported, policy profile, hardware profile and source fixtures. diff --git a/docs/traceability/action-postcondition-evidence.md b/docs/traceability/action-postcondition-evidence.md index 3dc12137a..482538394 100644 --- a/docs/traceability/action-postcondition-evidence.md +++ b/docs/traceability/action-postcondition-evidence.md @@ -63,6 +63,14 @@ PR #70 reuses the existing pinned Chrome for Testing workflow and executes the # This is real WebDriver evidence for a controlled local fixture, not a product browser adapter. It does not establish WebDriver BiDi/CDP authority translation, OriginWeave semantic observation or node handles, policy-authorized typed action dispatch, trusted browser-process attribution, or protected-main product runtime completion. +### PR #71 — browser-computed semantic role/name evidence before action + +**Capability maturity:** `IMPLEMENTED_ON_ACTIVE_PR` + +PR #71 extends the pinned-Chrome fixture lane by reading WebDriver's browser-computed role and accessible name for the controlled input and submit button before sending input or clicking. The exact expected values are `textbox` / `Task text` and `button` / `Submit task`; the repeatability gate requires both semantic checks in every successful trial. + +This is bounded browser-computed evidence for a synthetic test target, not the OriginWeave semantic observation adapter. CSS locators remain test-harness selectors, and the lane does not create OriginWeave node handles, source-channel provenance, policy authority, or permission to execute page-advertised actions. + ## 4. Non-transitive success semantics The intended first-slice chain is: @@ -88,7 +96,7 @@ VerifiedActionOutcomeEvidence type existence -/> proof of real Chromium executio controlled fixture success -/> proof of an OriginWeave product browser runtime ``` -PR #64 now rejects a caller-supplied observation timestamp that predates caller-supplied dispatch time, but the type cannot independently prove the clock source, that a real browser actually dispatched the action, that the supplied provenance belongs to the claimed browser target/node, or that the observed state was caused by that action. PR #70 proves real Chromium execution against the controlled fixture, but its test-harness CSS locators and direct WebDriver calls are not the OriginWeave adapter/runtime composition required under issue #28. +PR #64 now rejects a caller-supplied observation timestamp that predates caller-supplied dispatch time, but the type cannot independently prove the clock source, that a real browser actually dispatched the action, that the supplied provenance belongs to the claimed browser target/node, or that the observed state was caused by that action. PR #70 proves real Chromium execution against the controlled fixture and PR #71 adds browser-computed role/name evidence, but their test-harness CSS locators and direct WebDriver calls are not the OriginWeave adapter/runtime composition required under issue #28. ## 5. Active prerequisite graph for issue #28 @@ -102,9 +110,10 @@ The first real Chromium vertical slice remains distributed across bounded active - PR #51 — bounded browser-task telemetry plus one explicitly supplied Linux PID `VmRSS` sampler; Chromium process discovery/process-set attribution remains outside that slice; - PR #64 — verified and caller-timestamp-ordered post-condition action-outcome evidence; and - PR #65 — controlled hostile local Agent Task workflow fixture; and -- PR #70 — real WebDriver execution of that fixture on pinned Chrome, without claiming a product browser adapter. +- PR #70 — real WebDriver execution of that fixture on pinned Chrome, without claiming a product browser adapter; and +- PR #71 — browser-computed role/name evidence before controlled action, without claiming a product semantic observer. -These active PRs are non-shipped evidence. PR #70 proves a bounded browser-level fixture flow, but the active set does not itself compose WebDriver BiDi/CDP transport, OriginWeave authority translation, trusted Chromium process attribution, policy-authorized real input dispatch, causal post-condition observation, or deterministic end-to-end teardown/recovery into one protected-main runtime. +These active PRs are non-shipped evidence. PR #70/#71 prove bounded browser-level and semantic evidence, but the active set does not itself compose WebDriver BiDi/CDP transport, OriginWeave authority translation, trusted Chromium process attribution, policy-authorized real input dispatch, causal post-condition observation, or deterministic end-to-end teardown/recovery into one protected-main runtime. ## 6. Remaining issue #28 boundary @@ -122,4 +131,4 @@ This dossier does **not** close issue #28. Material remaining work includes: ## 7. Documentation fitness consequence -The ADR/PRD/TRD/Architecture/UML/ERD graph remains **DESIGN-SUFFICIENT / PROTECTED-MAIN-PARTIAL**. PR #64 narrows a typed evidence gap, PR #65 supplies the controlled fixture, and PR #70 supplies real WebDriver evidence for that fixture. Neither introduces a new trust domain, deployed component, persistence owner, database schema, or independent architecture decision, so a new ADR or physical ERD entity would overstate the implementation. Detailed real-Chromium dispatch/post-condition sequence diagrams should be reconciled when the executable adapter chain stabilizes rather than manufacturing as-built detail before that runtime exists. +The ADR/PRD/TRD/Architecture/UML/ERD graph remains **DESIGN-SUFFICIENT / PROTECTED-MAIN-PARTIAL**. PR #64 narrows a typed evidence gap, PR #65 supplies the controlled fixture, and PR #70/#71 supply real WebDriver and browser-computed semantic evidence for that fixture. Neither introduces a new trust domain, deployed component, persistence owner, database schema, or independent architecture decision, so a new ADR or physical ERD entity would overstate the implementation. Detailed real-Chromium dispatch/post-condition sequence diagrams should be reconciled when the executable adapter chain stabilizes rather than manufacturing as-built detail before that runtime exists. diff --git a/scripts/ci/run_mv3_compatibility.py b/scripts/ci/run_mv3_compatibility.py old mode 100644 new mode 100755 index 98e4e7605..747fc9b01 --- a/scripts/ci/run_mv3_compatibility.py +++ b/scripts/ci/run_mv3_compatibility.py @@ -7,9 +7,10 @@ content-script, storage, declarative-net-request, tabs, windows, scripting, commands, side-panel, bookmarks, history, real browser-click, and restart-persistence behavior. It also executes the controlled Agent Task fixture -with extensions disabled in a fresh profile, performs real WebDriver input and -click operations, verifies the observable post-condition, and proves profile -cleanup without treating page content as instruction or authority. +with extensions disabled in a fresh profile, verifies browser-computed role/name +for the controlled action targets, performs real WebDriver input and click +operations, verifies the observable post-condition, and proves profile cleanup +without treating page content as instruction or authority. """ from __future__ import annotations @@ -179,6 +180,28 @@ def _element_command_path(session_id: str, element_id: str, suffix: str) -> str: return _webdriver_path(session_id, f"/element/{safe_element}{suffix}") +def _get_element_semantics( + driver_port: int, + session_id: str, + element_id: str, +) -> tuple[str, str]: + """Read one controlled element's browser-computed role and accessible name.""" + + role = _json_request( + driver_port, + "GET", + _element_command_path(session_id, element_id, "/computedrole"), + ).get("value") + label = _json_request( + driver_port, + "GET", + _element_command_path(session_id, element_id, "/computedlabel"), + ).get("value") + if not isinstance(role, str) or not isinstance(label, str): + raise RuntimeError("WebDriver returned malformed element semantics") + return role, label + + def _wait_for_extension_evidence( driver_port: int, session_id: str, @@ -538,6 +561,13 @@ def _run_agent_task_browser_pass( f"Agent Task initial URL mismatch: expected {fixture_url!r}, got {initial_url!r}" ) input_element = _find_element(driver_port, session_id, "#task-text") + input_role, input_name = _get_element_semantics( + driver_port, + session_id, + input_element, + ) + if input_role != "textbox" or input_name != "Task text": + raise RuntimeError("Agent Task input semantic evidence mismatch") _json_request( driver_port, "POST", @@ -555,6 +585,13 @@ def _run_agent_task_browser_pass( session_id, "#agent-task-form button[type=submit]", ) + submit_role, submit_name = _get_element_semantics( + driver_port, + session_id, + submit_element, + ) + if submit_role != "button" or submit_name != "Submit task": + raise RuntimeError("Agent Task submit semantic evidence mismatch") _json_request( driver_port, "POST", @@ -588,6 +625,8 @@ def _run_agent_task_browser_pass( "post_condition": True, "input_echo_verified": True, "url_unchanged": url_unchanged, + "input_semantics_verified": True, + "submit_semantics_verified": True, "extensions_disabled": True, "duration_ms": round((time.monotonic() - started) * 1000), } @@ -635,13 +674,17 @@ def _run_agent_task_trial( "post_condition": result["post_condition"], "input_echo_verified": result["input_echo_verified"], "url_unchanged": result["url_unchanged"], + "input_semantics_verified": result["input_semantics_verified"], + "submit_semantics_verified": result["submit_semantics_verified"], "extensions_disabled": result["extensions_disabled"], "profile_cleaned": profile_cleaned, "duration_ms": round((time.monotonic() - trial_started) * 1000), } -def _start_fixture_server(directory: pathlib.Path) -> tuple[http.server.ThreadingHTTPServer, threading.Thread]: +def _start_fixture_server( + directory: pathlib.Path, +) -> tuple[http.server.ThreadingHTTPServer, threading.Thread]: """Start one loopback-only static fixture server for a bounded browser lane.""" server = http.server.ThreadingHTTPServer( @@ -759,6 +802,8 @@ def main() -> int: trial.get("post_condition") is True and trial.get("input_echo_verified") is True and trial.get("url_unchanged") is True + and trial.get("input_semantics_verified") is True + and trial.get("submit_semantics_verified") is True and trial.get("extensions_disabled") is True and trial.get("profile_cleaned") is True for trial in agent_task_trials diff --git a/tests/test_agent_task_pinned_chrome_contract.py b/tests/test_agent_task_pinned_chrome_contract.py index cf4ef2658..2571cabd4 100644 --- a/tests/test_agent_task_pinned_chrome_contract.py +++ b/tests/test_agent_task_pinned_chrome_contract.py @@ -97,6 +97,25 @@ def test_agent_task_submission_preserves_the_loaded_url(self) -> None: self.assertIn(expected, runner) self.assertIn("Agent Task URL changed during submission", runner) + def test_agent_task_observes_computed_role_and_name_before_action(self) -> None: + """Real-browser evidence must bind the controlled targets to semantic role/name.""" + + namespace = runpy.run_path(str(RUNNER), run_name="agent_task_semantics_contract") + runner = RUNNER.read_text(encoding="utf-8") + self.assertIn("_get_element_semantics", namespace) + for expected in ( + '"/computedrole"', + '"/computedlabel"', + '"textbox"', + '"Task text"', + '"button"', + '"Submit task"', + '"input_semantics_verified"', + '"submit_semantics_verified"', + ): + with self.subTest(expected=expected): + self.assertIn(expected, runner) + def test_agent_task_fixture_runs_under_the_existing_pinned_chrome_job(self) -> None: """No floating browser or second workflow may be introduced for this slice.""" @@ -123,6 +142,10 @@ def test_documentation_separates_active_browser_evidence_from_product_runtime(se self.assertIn("not a product browser adapter", traceability) self.assertIn("pinned Chrome", fitness) self.assertIn("not a browser adapter", fitness) + self.assertIn("browser-computed role/name", changelog) + self.assertIn("PR #71", traceability) + self.assertIn("computed role/name", traceability) + self.assertIn("computed role/name", fitness) if __name__ == "__main__":