From 50077c9bea01fa43a4676af69d1995134b2f6cd2 Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 13 Oct 2026 20:48:05 +0200 Subject: [PATCH] Fix short-intent discovery and publish verified browser provider guidance Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a13690-1c84-77a2-aeee-7f517ec60f5d --- .custodian-brief.md | 10 +- WORK-RECORDS.md | 4 + docs/CapabilityCatalog.md | 7 +- docs/catalog/index.html | 4 +- docs/catalog/registry.json | 9 +- docs/evidence/2026-10-13-browser-discovery.md | 84 ++++++++ .../artifact-checks.json | 30 +++ .../desktop-final.png | Bin 0 -> 26622 bytes .../narrow-final.png | Bin 0 -> 24280 bytes .../preflight.json | 22 ++ .../2026-10-13-browser-discovery/receipt.json | 184 ++++++++++++++++ docs/graph/capability-graph.mmd | 2 +- docs/graph/index.html | 2 +- .../capability.infotech.headless-browser.md | 202 ++++++++++++++---- registry/indexes/capabilities.yaml | 21 +- registry/indexes/federated.yaml | 20 +- reuse_surface/plan_check.py | 11 +- specs/PlanCheck.md | 16 +- tests/test_hosted_plan_check.py | 25 +++ tests/test_plan_check.py | 57 +++++ tests/test_stats.py | 37 +++- ...browser-discovery-and-provider-evidence.md | 76 +++++++ 22 files changed, 736 insertions(+), 87 deletions(-) create mode 100644 docs/evidence/2026-10-13-browser-discovery.md create mode 100644 docs/evidence/2026-10-13-browser-discovery/artifact-checks.json create mode 100644 docs/evidence/2026-10-13-browser-discovery/desktop-final.png create mode 100644 docs/evidence/2026-10-13-browser-discovery/narrow-final.png create mode 100644 docs/evidence/2026-10-13-browser-discovery/preflight.json create mode 100644 docs/evidence/2026-10-13-browser-discovery/receipt.json create mode 100644 workplans/REUSE-WP-0024-browser-discovery-and-provider-evidence.md diff --git a/.custodian-brief.md b/.custodian-brief.md index 96418f7..acae414 100644 --- a/.custodian-brief.md +++ b/.custodian-brief.md @@ -2,12 +2,18 @@ # Custodian Brief — reuse-surface **Domain:** infotech -**Last synced:** 2026-10-13 11:59 UTC +**Last synced:** 2026-10-13 18:43 UTC **State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)* ## Active Workstreams -*(none — repo may need first-session setup)* +### Resolve browser discovery relevance and publish verified provider consumption +Progress: 0/3 done | workplan_id: `3d62d0af-5deb-55b5-b570-e62f05a43666` + +**Open tasks:** +- ► Publish the verified provider path `dd75f033` +- · Fix short-intent relevance `a689bc2a` +- · Validate, publish and synchronize `0be283ba` ## Inbox Hygiene diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index 2746b8e..2b2c7aa 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -10,8 +10,12 @@ | --- | --- | --- | --- | --- | | workplan | ADHOC-2026-10-13 | finished | — | workplans/ADHOC-2026-10-13.md | | workplan | REUSE-WP-0023 | finished | — | workplans/REUSE-WP-0023-access-engine-source-rename.md | +| workplan | REUSE-WP-0024 | active | — | workplans/REUSE-WP-0024-browser-discovery-and-provider-evidence.md | | task | ADHOC-2026-10-13-T01 | done | — | workplans/ADHOC-2026-10-13.md | | task | ADHOC-2026-10-13-T02 | done | — | workplans/ADHOC-2026-10-13.md | | task | REUSE-WP-0023-T01 | done | — | workplans/REUSE-WP-0023-access-engine-source-rename.md | | task | REUSE-WP-0023-T02 | done | — | workplans/REUSE-WP-0023-access-engine-source-rename.md | +| task | REUSE-WP-0024-T01 | progress | — | workplans/REUSE-WP-0024-browser-discovery-and-provider-evidence.md | +| task | REUSE-WP-0024-T02 | todo | — | workplans/REUSE-WP-0024-browser-discovery-and-provider-evidence.md | +| task | REUSE-WP-0024-T03 | todo | — | workplans/REUSE-WP-0024-browser-discovery-and-provider-evidence.md | | intake | REUSE-IN-0001 | open | green | intakes/REUSE-IN-0001-headless-browser-runnable-answer.md | diff --git a/docs/CapabilityCatalog.md b/docs/CapabilityCatalog.md index 504b0b2..fbc72ee 100644 --- a/docs/CapabilityCatalog.md +++ b/docs/CapabilityCatalog.md @@ -36,13 +36,14 @@ Generated by `reuse-surface catalog`. Do not edit manually. ### Headless Browser Automation - **ID:** `capability.infotech.headless-browser` -- **Vector:** D3 / A2 / C2 / R2 +- **Vector:** D3 / A5 / C2 / R2 - **Owner:** reuse-surface - **Path:** `registry/capabilities/capability.infotech.headless-browser.md` -- **Summary:** Headless browser automation with Playwright and Chromium for UI testing, screenshots and page extraction; recommended default based on existing whynot-design, coulomb-social, core-hub and frontend-patterns implementations. A rapp-playwright-provided service will be available shortly (announced 2026-10-13; planned, not yet verified available). +- **Summary:** Headless browser automation, screenshots and keyboard trials through rapp-playwright 0.1.0 (Playwright 1.64.0, Chromium 156.0.8078.4). Published A5 local container; managed Railiance admission is pending. Download the Python 3.10+ standalone client from https://forgejo.coulomb.social/coulomb/rapp-playwright/raw/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/client/rapp_playwright.py and run `python3 rapp_playwright.py --url http://127.0.0.1:18083 preflight`, then `python3 rapp_playwright.py --url http://127.0.0.1:18083 trial --out trial-01` with a fresh output directory. This endpoint was verified locally on 2026-10-13 and is ephemeral; it installs no browser for the caller. If unreachable, follow the local container setup in the capability card or adapt its A2 source examples; this is an availability gap on the existing capability. Contract: https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/consumer-contract.md. **Known limitations:** - This is a dated source inspection; run the target-repo trial before claiming adoption success. - Firefox is evidenced in frontend-patterns; WebKit is supported upstream but unverified in this inspection. - Selenium is an optional testdrive-jsui dependency, not verified execution; Puppeteer has no verified example here. -- The forthcoming rapp-playwright service has no verified endpoint or launch receipt in this record yet. +- Local provider availability is verified but ephemeral; managed admission and platform operation remain pending. +- Provider fixture success does not establish consumer target reachability or application acceptance. diff --git a/docs/catalog/index.html b/docs/catalog/index.html index 386e802..99328ac 100644 --- a/docs/catalog/index.html +++ b/docs/catalog/index.html @@ -32,8 +32,8 @@

infotech

Headless Browser Automation

-

capability.infotech.headless-browser · D3 / A2 / C2 / R2

-

Headless browser automation with Playwright and Chromium for UI testing, screenshots and page extraction; recommended default based on existing whynot-design, coulomb-social, core-hub and frontend-patterns implementations. A rapp-playwright-provided service will be available shortly (announced 2026-10-13; planned, not yet verified available).

+

capability.infotech.headless-browser · D3 / A5 / C2 / R2

+

Headless browser automation, screenshots and keyboard trials through rapp-playwright 0.1.0 (Playwright 1.64.0, Chromium 156.0.8078.4). Published A5 local container; managed Railiance admission is pending. Download the Python 3.10+ standalone client from https://forgejo.coulomb.social/coulomb/rapp-playwright/raw/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/client/rapp_playwright.py and run `python3 rapp_playwright.py --url http://127.0.0.1:18083 preflight`, then `python3 rapp_playwright.py --url http://127.0.0.1:18083 trial --out trial-01` with a fresh output directory. This endpoint was verified locally on 2026-10-13 and is ephemeral; it installs no browser for the caller. If unreachable, follow the local container setup in the capability card or adapt its A2 source examples; this is an availability gap on the existing capability. Contract: https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/consumer-contract.md.

registry/capabilities/capability.infotech.headless-browser.md

diff --git a/docs/catalog/registry.json b/docs/catalog/registry.json index 895f28f..f9642fb 100644 --- a/docs/catalog/registry.json +++ b/docs/catalog/registry.json @@ -5,8 +5,8 @@ { "id": "capability.infotech.headless-browser", "name": "Headless Browser Automation", - "summary": "Headless browser automation with Playwright and Chromium for UI testing, screenshots and page extraction; recommended default based on existing whynot-design, coulomb-social, core-hub and frontend-patterns implementations. A rapp-playwright-provided service will be available shortly (announced 2026-10-13; planned, not yet verified available).", - "vector": "D3 / A2 / C2 / R2", + "summary": "Headless browser automation, screenshots and keyboard trials through rapp-playwright 0.1.0 (Playwright 1.64.0, Chromium 156.0.8078.4). Published A5 local container; managed Railiance admission is pending. Download the Python 3.10+ standalone client from https://forgejo.coulomb.social/coulomb/rapp-playwright/raw/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/client/rapp_playwright.py and run `python3 rapp_playwright.py --url http://127.0.0.1:18083 preflight`, then `python3 rapp_playwright.py --url http://127.0.0.1:18083 trial --out trial-01` with a fresh output directory. This endpoint was verified locally on 2026-10-13 and is ephemeral; it installs no browser for the caller. If unreachable, follow the local container setup in the capability card or adapt its A2 source examples; this is an availability gap on the existing capability. Contract: https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/consumer-contract.md.", + "vector": "D3 / A5 / C2 / R2", "domain": "infotech", "status": "reviewed", "owner": "reuse-surface", @@ -29,7 +29,10 @@ "informational", "source adaptation", "JavaScript library", - "Python library" + "Python library", + "cli", + "service API", + "container" ] }, { diff --git a/docs/evidence/2026-10-13-browser-discovery.md b/docs/evidence/2026-10-13-browser-discovery.md new file mode 100644 index 0000000..d2c3287 --- /dev/null +++ b/docs/evidence/2026-10-13-browser-discovery.md @@ -0,0 +1,84 @@ +# Browser discovery review — 2026-10-13 + +REUSE-WP-0024 resolves the registry-owned portion of REUSE-IN-0001 on the +existing `capability.infotech.headless-browser` record. Provider implementation +and managed lifecycle remain with rapp-playwright and railiance-platform; +CONTENT-WP-0000-T04 remains the consumer's acceptance task. + +## Published provider evidence + +Fetched the raw client, consumer contract, independent-consumer report and +release manifest at provider commit +`8831a05aeba5ce588f3b395ade676dde2a151c5d`. All four matched `git show` at that +revision byte for byte. The single-file Python client SHA-256 is +`9967a0831ed04e27fde419098af707722d5c81c993e4c294b3677ffb75729c12`. +Pinned public links are retained in the +[capability card](../../registry/capabilities/capability.infotech.headless-browser.md). + +The published image is +`forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441` +for linux/amd64. Provider publication evidence includes immutable registry +verification and railiance01 pull. This review did not redeploy the provider. + +## Fresh client-only local trial + +Executed the downloaded client, without installing Playwright or Chromium: + +```sh +python3 /tmp/reuse-browser-review/rapp_playwright.py --url http://127.0.0.1:18083 preflight +python3 /tmp/reuse-browser-review/rapp_playwright.py --url http://127.0.0.1:18083 trial --out /tmp/reuse-browser-review/trial-01 +``` + +Both exited 0. Run `6c710b36-319b-45b8-b062-ac2065f5e81b` completed at +**18:42:58 UTC** with **14 passed steps**: visibility, counter checks, Tab, +focused-button assertion, Enter and screenshot in two viewports. The provider +reported service 0.1.0, Playwright 1.64.0, Chromium 156.0.8078.4, +`workstation-release-check`, and the published digest above. Preflight permitted +no external origins; only the synthetic fixture was exercised. + +Independently parsed all four PNG headers and recomputed hashes against the +client receipt. Desktop screenshots are 1280×800 and narrow screenshots are +390×844. This validates dimensions and integrity, not visual-baseline quality. + +- [Preflight](2026-10-13-browser-discovery/preflight.json) +- [Receipt](2026-10-13-browser-discovery/receipt.json) +- [Independent artifact checks](2026-10-13-browser-discovery/artifact-checks.json) +- [Desktop fixture](2026-10-13-browser-discovery/desktop-final.png) +- [Narrow fixture](2026-10-13-browser-discovery/narrow-final.png) + +Private run handles are excluded. The endpoint is ephemeral and was available +on this workstation at trial time; it is not a managed service or a promise of +future availability. The source examples remain a fallback when a provider is +unavailable. No consumer app, remote target or managed browser was tested. + +## Assessment and matching + +Promoted availability **A2 → A5** under the standard's deployable-container +definition. **A6 managed platform capability remains pending**. D3/C2/R2 stay +conservative; fixture execution does not prove broader target compatibility or +platform operation. Decision recorded in State Hub as +`b8ef28c1-9164-4678-8a61-1652e0f07407`. + +Before this fix, `plan-check --intent "headless browser" --no-llm` returned +`new`, with an unrelated context engine first at 0.0476 and the browser third. +After scoring names independently from summaries/tags, the same query returns +`reuse`, with the browser first at **0.6667** and unrelated matches at **0.2 or +less**. Long command/evidence summaries no longer dilute direct name matches. +The output includes the standalone client link, preflight/trial commands, +ephemeral endpoint warning, managed-admission condition and availability-gap +fallback. Reuse advice now describes relevance rather than asserting readiness. + +Regressions cover short-name relevance despite long summaries and higher-maturity +unrelated services, summary-only matching, equal-relevance maturity ties, and +hosted CLI output carrying conditional provider instructions. Stats tests now +use a fixed temporary registry rather than assuming the live repo always has +two capabilities. + +## Validation + +- `.venv/bin/python -m pytest -q`: **212 passed**. One existing Starlette + TestClient/httpx deprecation warning remains. +- `validate --relations --fail-on-warnings`: **3 entries valid**. +- `catalog`, `graph --check`, and `federation compose`: generated successfully; + **66 federated capabilities**, preserving one browser capability. +- `git diff --check`: clean. diff --git a/docs/evidence/2026-10-13-browser-discovery/artifact-checks.json b/docs/evidence/2026-10-13-browser-discovery/artifact-checks.json new file mode 100644 index 0000000..c7e6c95 --- /dev/null +++ b/docs/evidence/2026-10-13-browser-discovery/artifact-checks.json @@ -0,0 +1,30 @@ +[ + { + "name": "desktop-6-keyboard-result.png", + "bytes": 26622, + "sha256": "b15998824256b86c74f2bbb75f061061be65db0b4f3bb5444529ac69a723cdad", + "width": 1280, + "height": 800 + }, + { + "name": "desktop-final.png", + "bytes": 26622, + "sha256": "b15998824256b86c74f2bbb75f061061be65db0b4f3bb5444529ac69a723cdad", + "width": 1280, + "height": 800 + }, + { + "name": "narrow-6-keyboard-result.png", + "bytes": 24280, + "sha256": "49d27cb169b8e180ce93969c6d2b8619a7684cf035bb9dcae9cd91d8bd9952e8", + "width": 390, + "height": 844 + }, + { + "name": "narrow-final.png", + "bytes": 24280, + "sha256": "49d27cb169b8e180ce93969c6d2b8619a7684cf035bb9dcae9cd91d8bd9952e8", + "width": 390, + "height": 844 + } +] diff --git a/docs/evidence/2026-10-13-browser-discovery/desktop-final.png b/docs/evidence/2026-10-13-browser-discovery/desktop-final.png new file mode 100644 index 0000000000000000000000000000000000000000..91a204048b0770305733f1a80622eaeace4f4d74 GIT binary patch literal 26622 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 literal 0 HcmV?d00001 diff --git a/docs/evidence/2026-10-13-browser-discovery/preflight.json b/docs/evidence/2026-10-13-browser-discovery/preflight.json new file mode 100644 index 0000000..0a0f4fd --- /dev/null +++ b/docs/evidence/2026-10-13-browser-discovery/preflight.json @@ -0,0 +1,22 @@ +{ + "available": true, + "error": null, + "checked_at": "2026-10-13T18:42:18.136Z", + "browser_version": "156.0.8078.4", + "api_version": "1", + "service_version": "0.1.0", + "playwright_version": "1.64.0", + "execution_location": "workstation-release-check", + "release": "sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441", + "allowed_origins": [], + "fixture": true, + "active": 0, + "queued": 0, + "limits": { + "concurrency": 1, + "max_queue": 4, + "max_timeout_ms": 120000, + "retention_ms": 3600000, + "max_runs": 64 + } +} diff --git a/docs/evidence/2026-10-13-browser-discovery/receipt.json b/docs/evidence/2026-10-13-browser-discovery/receipt.json new file mode 100644 index 0000000..c30efdf --- /dev/null +++ b/docs/evidence/2026-10-13-browser-discovery/receipt.json @@ -0,0 +1,184 @@ +{ + "id": "6c710b36-319b-45b8-b062-ac2065f5e81b", + "api_version": "1", + "status": "passed", + "error": null, + "label": "independent-browser-trial", + "target": "fixture", + "viewports": [ + { + "name": "desktop", + "width": 1280, + "height": 800 + }, + { + "name": "narrow", + "width": 390, + "height": 844 + } + ], + "timeout_ms": 60000, + "created_at": "2026-10-13T18:42:41.545Z", + "expires_at": "2026-10-13T19:42:41.545Z", + "service_version": "0.1.0", + "playwright_version": "1.64.0", + "release": "sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441", + "execution_location": "workstation-release-check", + "browser_version": "156.0.8078.4", + "completed_steps": 14, + "steps": [ + { + "viewport": "desktop", + "index": 0, + "action": "visible", + "status": "passed", + "at": "2026-10-13T18:42:52.067Z", + "selector": "h1" + }, + { + "viewport": "desktop", + "index": 1, + "action": "text", + "status": "passed", + "at": "2026-10-13T18:42:52.461Z", + "selector": "#count" + }, + { + "viewport": "desktop", + "index": 2, + "action": "press", + "status": "passed", + "at": "2026-10-13T18:42:52.576Z", + "key": "Tab" + }, + { + "viewport": "desktop", + "index": 3, + "action": "focused", + "status": "passed", + "at": "2026-10-13T18:42:52.660Z", + "selector": "#increment" + }, + { + "viewport": "desktop", + "index": 4, + "action": "press", + "status": "passed", + "at": "2026-10-13T18:42:52.674Z", + "key": "Enter" + }, + { + "viewport": "desktop", + "index": 5, + "action": "text", + "status": "passed", + "at": "2026-10-13T18:42:52.754Z", + "selector": "#count" + }, + { + "viewport": "desktop", + "index": 6, + "action": "screenshot", + "status": "passed", + "at": "2026-10-13T18:42:52.764Z" + }, + { + "viewport": "narrow", + "index": 0, + "action": "visible", + "status": "passed", + "at": "2026-10-13T18:42:55.566Z", + "selector": "h1" + }, + { + "viewport": "narrow", + "index": 1, + "action": "text", + "status": "passed", + "at": "2026-10-13T18:42:55.959Z", + "selector": "#count" + }, + { + "viewport": "narrow", + "index": 2, + "action": "press", + "status": "passed", + "at": "2026-10-13T18:42:56.177Z", + "key": "Tab" + }, + { + "viewport": "narrow", + "index": 3, + "action": "focused", + "status": "passed", + "at": "2026-10-13T18:42:56.253Z", + "selector": "#increment" + }, + { + "viewport": "narrow", + "index": 4, + "action": "press", + "status": "passed", + "at": "2026-10-13T18:42:56.265Z", + "key": "Enter" + }, + { + "viewport": "narrow", + "index": 5, + "action": "text", + "status": "passed", + "at": "2026-10-13T18:42:56.275Z", + "selector": "#count" + }, + { + "viewport": "narrow", + "index": 6, + "action": "screenshot", + "status": "passed", + "at": "2026-10-13T18:42:56.359Z" + } + ], + "artifacts": [ + { + "name": "desktop-6-keyboard-result.png", + "bytes": 26622 + }, + { + "name": "desktop-final.png", + "bytes": 26622 + }, + { + "name": "narrow-6-keyboard-result.png", + "bytes": 24280 + }, + { + "name": "narrow-final.png", + "bytes": 24280 + } + ], + "started_at": "2026-10-13T18:42:41.550Z", + "blocked_requests": 13, + "finished_at": "2026-10-13T18:42:58.107Z", + "downloads": [ + { + "name": "desktop-6-keyboard-result.png", + "bytes": 26622, + "sha256": "b15998824256b86c74f2bbb75f061061be65db0b4f3bb5444529ac69a723cdad" + }, + { + "name": "desktop-final.png", + "bytes": 26622, + "sha256": "b15998824256b86c74f2bbb75f061061be65db0b4f3bb5444529ac69a723cdad" + }, + { + "name": "narrow-6-keyboard-result.png", + "bytes": 24280, + "sha256": "49d27cb169b8e180ce93969c6d2b8619a7684cf035bb9dcae9cd91d8bd9952e8" + }, + { + "name": "narrow-final.png", + "bytes": 24280, + "sha256": "49d27cb169b8e180ce93969c6d2b8619a7684cf035bb9dcae9cd91d8bd9952e8" + } + ] +} diff --git a/docs/graph/capability-graph.mmd b/docs/graph/capability-graph.mmd index 907f454..b66c008 100644 --- a/docs/graph/capability-graph.mmd +++ b/docs/graph/capability-graph.mmd @@ -1,5 +1,5 @@ graph LR - capability_infotech_headless_browser["capability.infotech.headless-browser
D3 / A2 / C2 / R2"] + capability_infotech_headless_browser["capability.infotech.headless-browser
D3 / A5 / C2 / R2"] capability_registry_register["capability.registry.register
D3 / A4 / C2 / R3"] capability_registry_validate["capability.registry.validate
D4 / A3 / C3 / R3"] capability_registry_register -->|supports| capability_feature_control_evaluate diff --git a/docs/graph/index.html b/docs/graph/index.html index fbf84b7..19366f8 100644 --- a/docs/graph/index.html +++ b/docs/graph/index.html @@ -17,7 +17,7 @@

Generated from entry relations fields. Regenerate with reuse-surface graph.


   
 
 
diff --git a/registry/capabilities/capability.infotech.headless-browser.md b/registry/capabilities/capability.infotech.headless-browser.md
index f13af73..3adb61d 100644
--- a/registry/capabilities/capability.infotech.headless-browser.md
+++ b/registry/capabilities/capability.infotech.headless-browser.md
@@ -2,11 +2,18 @@
 id: capability.infotech.headless-browser
 name: Headless Browser Automation
 summary: >-
-  Headless browser automation with Playwright and Chromium for UI testing,
-  screenshots and page extraction; recommended default based on existing
-  whynot-design, coulomb-social, core-hub and frontend-patterns implementations.
-  A rapp-playwright-provided service will be available shortly (announced
-  2026-10-13; planned, not yet verified available).
+  Headless browser automation, screenshots and keyboard trials through
+  rapp-playwright 0.1.0 (Playwright 1.64.0, Chromium 156.0.8078.4).
+  Published A5 local container; managed Railiance admission is pending.
+  Download the Python 3.10+ standalone client from
+  https://forgejo.coulomb.social/coulomb/rapp-playwright/raw/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/client/rapp_playwright.py
+  and run `python3 rapp_playwright.py --url http://127.0.0.1:18083 preflight`,
+  then `python3 rapp_playwright.py --url http://127.0.0.1:18083 trial --out trial-01`
+  with a fresh output directory. This endpoint was verified locally on 2026-10-13
+  and is ephemeral; it installs no browser for the caller. If unreachable,
+  follow the local container setup in the capability card or adapt its A2 source
+  examples; this is an availability gap on the existing capability.
+  Contract: https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/consumer-contract.md.
 owner: reuse-surface
 status: reviewed
 domain: infotech
@@ -20,14 +27,15 @@ maturity:
       Inspected four implemented Playwright consumers and separated optional
       dependencies and plans from usage. No comprehensive alternatives benchmark.
   availability:
-    current: A2
-    target: A2
+    current: A5
+    target: A6
     confidence: medium
     rationale: >
-      Existing JavaScript and Python source examples can be adapted in a consumer
-      repo. This entry does not deliver a shared wrapper or hosted browser service.
-      The founder announced a forthcoming rapp-playwright service on 2026-10-13;
-      that planned delivery does not change the evidenced current A2 level.
+      rapp-playwright 0.1.0 is a published immutable container with a versioned
+      HTTP contract and standalone Python client, independently trialled locally.
+      A5 describes deployable container availability, not managed operation (A6).
+      Railiance admission is pending. Existing A2 source adaptation remains usable;
+      no endpoint uptime or caller browser installation is implied.
 external_evidence:
   completeness:
     level: C2
@@ -36,8 +44,10 @@ external_evidence:
     satisfied_expectations:
       - Identifies implemented consumers, browser engines and source entry points.
       - Gives a scoped default recommendation and a practical trial procedure.
+      - Published provider client and container have independent fixture screenshots and keyboard receipts.
     broken_expectations:
-      - No shared package, standard configuration or consumer-independent trial receipt.
+      - Managed admission and persistent platform endpoint are still pending.
+      - Consumer application acceptance remains the consuming repo's responsibility.
     out_of_scope_expectations:
       - Exhaustive estate dependency inventory or comparative browser benchmark.
       - Browser service implementation or operation by reuse-surface.
@@ -49,10 +59,13 @@ external_evidence:
     known_reliability_risks:
       - Browser binaries and system libraries must match the selected Playwright version.
       - Existing examples contain application-specific fixtures and assumptions.
-      - Browser launch and target-repo compatibility have not been tested by this registration.
+      - Local fixture receipts do not prove managed operation or arbitrary target compatibility.
+      - Local provider endpoints are ephemeral; check preflight for each trial.
     evidence:
       satisfied_signals:
         - frontend-patterns navigation-history records a completed Chromium/Firefox experiment.
+        - rapp-playwright independent final-release trial passed 14 steps across desktop and narrow viewports.
+        - Independent provider evidence includes wrong-token, failed assertion and unavailable-service checks.
 discovery:
   intent: >
     Help a worker select and reuse existing headless browser tooling instead of
@@ -61,19 +74,24 @@ discovery:
     - Playwright automation with headless Chromium as the default starting point.
     - JavaScript UI tests, screenshots and page extraction examples.
     - Python visual-check example and Firefox experiment evidence.
+    - Published rapp-playwright container, Python client and bounded HTTP fixture trials.
   excludes:
     - Browser hosting or workstation provisioning by reuse-surface.
     - Credential provisioning and permission to automate external targets.
     - Claims that a dependency declaration or a workplan proves executed browser usage.
   assumptions:
-    - The consumer chooses a version compatible with its runtime and installs matching browsers.
+    - Source-adaptation consumers install matching browsers; provider clients need only Python 3.10+.
+    - Provider consumers establish an available endpoint and run preflight before a trial.
   use_cases:
     - Find which working repos already use a headless browser and where to start reusing it.
     - Run a local UI assertion and screenshot in a target repo before adopting the tooling.
 availability:
-  current_level: A2
-  target_level: A2
+  current_level: A5
+  target_level: A6
   current_artifacts:
+    - forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441
+    - https://forgejo.coulomb.social/coulomb/rapp-playwright/raw/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/client/rapp_playwright.py
+    - https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/releases/0.1.0.json
     - ../whynot-design/playwright.config.mjs
     - ../whynot-design/tests/visual/ui-kit.spec.mjs
     - ../coulomb-social/scripts/test-usecase-browser.mjs
@@ -81,10 +99,9 @@ availability:
     - ../frontend-patterns/research/experiments/navigation-history/experiment.mjs
   target_artifacts:
     - >-
-      Planned rapp-playwright-provided service, announced by the founder on
-      2026-10-13 as available shortly; endpoint, consumption contract and readiness
-      evidence have not yet been verified by reuse-surface.
-  consumption_modes: [informational, source adaptation, JavaScript library, Python library]
+      Managed Railiance deployment after platform admission, with consumer
+      access and live recovery/rollback evidence; not currently available.
+  consumption_modes: [informational, source adaptation, JavaScript library, Python library, cli, service API, container]
 relations:
   depends_on: []
   supports: []
@@ -95,9 +112,12 @@ evidence:
     - ../frontend-patterns/research/experiments/navigation-history/README.md
     - ../test-driver/SCOPE.md
     - ../testdrive-jsui/pyproject.toml
-    - ../rapp-playwright/README.md
+    - https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/consumer-contract.md
+    - https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/evidence/2026-10-13-publication.md
     - intakes/REUSE-IN-0001-headless-browser-runnable-answer.md
   tests:
+    - https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/evidence/2026-10-13-independent-local-consumer.md
+    - docs/evidence/2026-10-13-browser-discovery.md
     - ../whynot-design/tests/visual/ui-kit.spec.mjs
     - ../coulomb-social/scripts/test-usecase-browser.mjs
     - ../core-hub/scripts/check_console_visual.py
@@ -114,9 +134,10 @@ consumer_guidance:
     - Reuse whynot-design for JavaScript visual tests and core-hub for Python visual checks.
     - Reuse coulomb-social for JavaScript browser scripts and frontend-patterns for multi-engine experiments.
     - >-
-      For service consumption, rapp-playwright is the announced provider and its
-      service will be available shortly. Use its published contract and readiness
-      evidence when delivered; current availability remains source reuse only.
+      For bounded screenshot and keyboard jobs, use the published rapp-playwright
+      Python client against an available local provider and run preflight first.
+      Use the immutable container to reproduce the provider; managed Railiance
+      access requires admission and a working tunnel before consumption.
   not_recommended_for:
     - Treating this recommendation as an approved mandatory estate standard.
     - Selecting test-driver as an implemented JavaScript-capable browser engine.
@@ -125,8 +146,19 @@ consumer_guidance:
     - This is a dated source inspection; run the target-repo trial before claiming adoption success.
     - Firefox is evidenced in frontend-patterns; WebKit is supported upstream but unverified in this inspection.
     - Selenium is an optional testdrive-jsui dependency, not verified execution; Puppeteer has no verified example here.
-    - The forthcoming rapp-playwright service has no verified endpoint or launch receipt in this record yet.
-promotion_history: []
+    - Local provider availability is verified but ephemeral; managed admission and platform operation remain pending.
+    - Provider fixture success does not establish consumer target reachability or application acceptance.
+promotion_history:
+  - date: "2026-10-13"
+    dimension: availability
+    from: A2
+    to: A5
+    rationale: >-
+      Published immutable rapp-playwright 0.1.0 container, versioned client/contract
+      and independent local release receipts satisfy deployable-container availability.
+      This is not an A6 managed-platform claim. D3, C2 and R2 remain conservative
+      assessments pending broader target and operational evidence.
+    author: codex
 ---
 
 # Headless Browser Automation
@@ -147,24 +179,101 @@ implementations and the upstream Playwright project maintains the library.
 
 ## Service provider and delivery status
 
-**A `rapp-playwright`-provided service will be available shortly**, as announced by
-the founder on 2026-10-13. Its [repository description](../../../rapp-playwright/README.md)
-identifies a Railiance wrapper for a Playwright and headless Chromium environment
-supporting use-case testing. Service availability is **planned**, not verified:
-this record has no confirmed endpoint, consumption contract or launch receipt yet.
-The current **D3 / A2 / C2 / R2** vector continues to describe evidenced source reuse.
+**rapp-playwright 0.1.0 is published and verified as a local container provider.**
+The current vector is **D3 / A5 / C2 / R2**. A5 means a deployable container under
+[the maturity standard](../../specs/CapabilityMaturityStandard.md); managed
+platform operation is A6 and remains **pending Railiance admission**. Source
+examples remain available at A2. No browser is installed on the caller's machine
+by discovery or by running the Python client.
 
-`rapp-playwright` owns the forthcoming browser service. `reuse-surface` owns
-discovery, consumption guidance, maturity assessment and evidence references; it
-does not implement or operate the browser service or install browsers on behalf
-of consumers. Its `owner` field here denotes the maintainer of this registry record.
+`rapp-playwright` owns the browser service; `railiance-platform` owns managed
+lifecycle admission. `reuse-surface` owns this record, discovery, consumption
+guidance and evidence assessment. The
+[content-explorer intake](../../intakes/REUSE-IN-0001-headless-browser-runnable-answer.md)
+concerns registry relevance and availability clarity; CONTENT-WP-0000-T04
+acceptance remains with the consumer.
 
-The [content-explorer feedback](../../intakes/REUSE-IN-0001-headless-browser-runnable-answer.md)
-is retained as consumer evidence. Browser delivery is assigned to the provider;
-the reported relevance, false-`new` verdict and availability-clarity issues remain
-reuse-surface concerns. A2 means source/library reuse, not proof of a locally
-installed browser. The service announcement does not complete the consumer's
-screenshot and keyboard-walkthrough task.
+### Verified client path
+
+Only Python 3.10+ is needed by the consumer. Download the single revision-pinned
+client into a working directory; a sibling checkout is not required:
+
+```sh
+curl -fL --output rapp_playwright.py https://forgejo.coulomb.social/coulomb/rapp-playwright/raw/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/client/rapp_playwright.py
+python3 rapp_playwright.py --url http://127.0.0.1:18083 preflight
+python3 rapp_playwright.py --url http://127.0.0.1:18083 trial --out trial-01
+```
+
+Use a fresh output directory for each run. Port **18083** was verified on this
+workstation on **2026-10-13**; it is an ephemeral local provider, not a permanent
+or remotely reachable endpoint. Preflight must report `available: true`, API 1,
+service 0.1.0, Playwright **1.64.0**, Chromium **156.0.8078.4**, and the expected
+release/location. Connection failure means the provider or tunnel is unavailable,
+not that another browser capability is needed. Use the local setup below or the
+source-adaptation fallback. Repeat `--url` on later status/download commands.
+
+The fixture trial checks Tab focus, Enter activation and the counter assertion
+across **1280×800** and **390×844** viewports, then downloads screenshots and a
+receipt. It does not inspect or accept the consumer's own UI. `run.json` is a
+private run handle and must not be published. For `trial`/`run`, exit 0 means
+passed, 2 means UI assertion failed, and 3 means infrastructure/setup or another
+unsuccessful result; `status` exit 0 only means retrieval succeeded.
+
+### Reproduce the local provider
+
+The published release targets **linux/amd64**. With Docker and image pull access,
+start the immutable container in one terminal, then point the client at port
+**18081** in another:
+
+```sh
+docker run --rm --name rapp-playwright-local --read-only \
+  --tmpfs /tmp:rw,size=512m --shm-size=256m --memory=1g --cpus=1 \
+  --cap-drop ALL --security-opt no-new-privileges \
+  --mount type=volume,src=rapp-playwright-local-data,dst=/data \
+  -p 127.0.0.1:18081:8080 -e HOST=0.0.0.0 \
+  -e EXECUTION_LOCATION=workstation-container \
+  -e RELEASE_ID=sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441 \
+  forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441
+python3 rapp_playwright.py --url http://127.0.0.1:18081 preflight
+python3 rapp_playwright.py --url http://127.0.0.1:18081 trial --out trial-local-01
+```
+
+This is the provider's documented local setup with the published digest pinned;
+it was not redeployed by this registry review. Existing independent final-release
+receipts and the fresh discovery trial use the same digest. The default fixture
+requires no external target grant. The provider supports trusted/synthetic pages,
+not hostile-page or mutually untrusted tenant execution.
+
+### Conditional managed path
+
+Only **after platform admission, deployment and caller access are confirmed**:
+
+```sh
+kubectl -n playwright port-forward deployment/playwright 18081:8080 --address 127.0.0.1
+# In another terminal, while the tunnel remains running:
+python3 rapp_playwright.py preflight
+python3 rapp_playwright.py trial --out trial-managed-01
+```
+
+No managed deployment or successful managed invocation is claimed here. A remote
+browser's localhost belongs to the provider. Consumer applications need a
+provider-reachable, explicitly allowed origin; the browser API tunnel does not
+forward a workstation app. See the provider contract before running a target
+scenario.
+
+### Pinned delivery evidence
+
+All provider links below are pinned to published commit
+`8831a05aeba5ce588f3b395ade676dde2a151c5d`:
+
+- [Consumer contract](https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/consumer-contract.md).
+- [Release manifest](https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/releases/0.1.0.json)
+  and [publication/pull evidence](https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/evidence/2026-10-13-publication.md).
+- [Independent consumer evidence](https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/evidence/2026-10-13-independent-local-consumer.md),
+  including final-release screenshots, keyboard assertions, wrong-token rejection,
+  UI failure and unavailable-service results. These are retained provider-side
+  reports; this review separately verified the fixture path.
+- [Fresh registry review and trial](../../docs/evidence/2026-10-13-browser-discovery.md).
 
 ## Existing implementations
 
@@ -196,15 +305,14 @@ copy its workstation paths as a portable browser installation recipe.
 - **Firefox/WebKit:** Playwright supports both upstream. Firefox has retained
   experiment evidence here; WebKit has no verified local example in this record.
 
-## Practical trial for the consuming worker
+## Source-adaptation fallback for the consuming worker
 
 1. Query this checkout with `python3 -m reuse_surface.cli query --keyword browser`
    from the reuse-surface root, then open this entry. If the CLI is installed,
    `reuse-surface query --keyword browser` is equivalent.
-   `plan-check --intent "headless browser" --no-llm` also includes this candidate,
-   but its token-overlap thresholds and maturity tie-breaking currently return
-   `new` for this short query. That verdict does not establish absence of reuse;
-   use the explicit keyword query and read the evidence for this trial.
+   `plan-check --intent "headless browser" --no-llm` ranks this entry first.
+   Its reuse verdict describes relevance; provider preflight determines current
+   runtime availability. Use source adaptation when the provider path is unsuitable.
 2. Pick the example matching the target repo's language and task. Inspect its
    fixture/server assumptions before adapting the smallest useful test or script.
 3. Use the target repo's package manager and lockfile. Select a compatible
diff --git a/registry/indexes/capabilities.yaml b/registry/indexes/capabilities.yaml
index 23698cb..21ca35a 100644
--- a/registry/indexes/capabilities.yaml
+++ b/registry/indexes/capabilities.yaml
@@ -6,18 +6,25 @@ capabilities:
   - id: capability.infotech.headless-browser
     name: Headless Browser Automation
     summary: >-
-      Headless browser automation with Playwright and Chromium for UI testing,
-      screenshots and page extraction; recommended default based on existing
-      whynot-design, coulomb-social, core-hub and frontend-patterns implementations.
-      A rapp-playwright-provided service will be available shortly (announced
-      2026-10-13; planned, not yet verified available).
-    vector: D3 / A2 / C2 / R2
+      Headless browser automation, screenshots and keyboard trials through
+      rapp-playwright 0.1.0 (Playwright 1.64.0, Chromium 156.0.8078.4).
+      Published A5 local container; managed Railiance admission is pending.
+      Download the Python 3.10+ standalone client from
+      https://forgejo.coulomb.social/coulomb/rapp-playwright/raw/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/client/rapp_playwright.py
+      and run `python3 rapp_playwright.py --url http://127.0.0.1:18083 preflight`,
+      then `python3 rapp_playwright.py --url http://127.0.0.1:18083 trial --out trial-01`
+      with a fresh output directory. This endpoint was verified locally on 2026-10-13
+      and is ephemeral; it installs no browser for the caller. If unreachable,
+      follow the local container setup in the capability card or adapt its A2 source
+      examples; this is an availability gap on the existing capability.
+      Contract: https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/consumer-contract.md.
+    vector: D3 / A5 / C2 / R2
     domain: infotech
     status: reviewed
     owner: reuse-surface
     path: registry/capabilities/capability.infotech.headless-browser.md
     tags: [headless, browser, automation, playwright, chromium, testing, screenshots, extraction, firefox, webkit, selenium, puppeteer]
-    consumption_modes: [informational, source adaptation, JavaScript library, Python library]
+    consumption_modes: [informational, source adaptation, JavaScript library, Python library, cli, service API, container]
 
   - id: capability.registry.register
     name: Capability Registration
diff --git a/registry/indexes/federated.yaml b/registry/indexes/federated.yaml
index 8672c50..ba26a8e 100644
--- a/registry/indexes/federated.yaml
+++ b/registry/indexes/federated.yaml
@@ -943,12 +943,17 @@ capabilities:
   source_index: registry/federation/cache/email-connect.yaml
 - id: capability.infotech.headless-browser
   name: Headless Browser Automation
-  summary: Headless browser automation with Playwright and Chromium for UI testing,
-    screenshots and page extraction; recommended default based on existing whynot-design,
-    coulomb-social, core-hub and frontend-patterns implementations. A rapp-playwright-provided
-    service will be available shortly (announced 2026-10-13; planned, not yet verified
-    available).
-  vector: D3 / A2 / C2 / R2
+  summary: 'Headless browser automation, screenshots and keyboard trials through rapp-playwright
+    0.1.0 (Playwright 1.64.0, Chromium 156.0.8078.4). Published A5 local container;
+    managed Railiance admission is pending. Download the Python 3.10+ standalone client
+    from https://forgejo.coulomb.social/coulomb/rapp-playwright/raw/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/client/rapp_playwright.py
+    and run `python3 rapp_playwright.py --url http://127.0.0.1:18083 preflight`, then
+    `python3 rapp_playwright.py --url http://127.0.0.1:18083 trial --out trial-01`
+    with a fresh output directory. This endpoint was verified locally on 2026-10-13
+    and is ephemeral; it installs no browser for the caller. If unreachable, follow
+    the local container setup in the capability card or adapt its A2 source examples;
+    this is an availability gap on the existing capability. Contract: https://forgejo.coulomb.social/coulomb/rapp-playwright/src/commit/8831a05aeba5ce588f3b395ade676dde2a151c5d/docs/consumer-contract.md.'
+  vector: D3 / A5 / C2 / R2
   domain: infotech
   status: reviewed
   owner: reuse-surface
@@ -971,6 +976,9 @@ capabilities:
   - source adaptation
   - JavaScript library
   - Python library
+  - cli
+  - service API
+  - container
   source_repo: reuse-surface
   source_index: registry/indexes/capabilities.yaml
 - id: capability.infotech.hub-core-library
diff --git a/reuse_surface/plan_check.py b/reuse_surface/plan_check.py
index 9118bba..7d424b6 100644
--- a/reuse_surface/plan_check.py
+++ b/reuse_surface/plan_check.py
@@ -147,7 +147,14 @@ def match_query(
         tokens = _tokens(blob)
         if not tokens:
             continue
-        score = len(query.tokens & tokens) / len(query.tokens | tokens)
+        # Score the name independently: descriptive summaries must not dilute
+        # a direct short-intent match (e.g. "headless browser"). Keep the full
+        # blob score for longer intents and summary/tag-only matches.
+        name_tokens = _tokens(item.get("name", ""))
+        score = max(
+            len(query.tokens & tokens) / len(query.tokens | tokens),
+            len(query.tokens & name_tokens) / len(query.tokens | name_tokens),
+        )
         if score <= 0:
             continue
         scored.append(
@@ -340,7 +347,7 @@ def format_plan_check_markdown(result: dict[str, Any]) -> str:
 
     verdict = result["verdict"]
     if verdict == "reuse":
-        lines.append("**Verdict: REUSE** — an existing capability already covers this; link it instead of building new.")
+        lines.append("**Verdict: REUSE** — a close lexical match exists; review its consumption contract and availability before adopting it.")
     elif verdict == "extend":
         lines.append("**Verdict: EXTEND** — scope overlaps closely enough that extending the top match is likely cheaper than a new capability.")
     else:
diff --git a/specs/PlanCheck.md b/specs/PlanCheck.md
index 61b71f1..224f01c 100644
--- a/specs/PlanCheck.md
+++ b/specs/PlanCheck.md
@@ -61,9 +61,11 @@ Reuses the token-Jaccard approach already proven in `overlaps.py`
 same codebase:
 
 1. **Tokenize** the query blob with the existing `TOKEN_RE`.
-2. **Score** against every federated capability's blob (`name` + `summary` +
-   `tags` + `discovery.intent` + `discovery.includes`, mirroring
-   `overlaps._entry_blob`) via Jaccard similarity.
+2. **Score** with the maximum of two token-Jaccard similarities: query versus
+   capability `name`, and query versus `name` + `summary` + `tags`.
+   Scoring the name separately prevents detailed summaries and consumption
+   instructions from diluting a short direct query such as "headless browser".
+   Summary/tag matches and longer intents retain the full-blob signal.
 3. **Rank signal, not just tie-break:** among candidates within
    `--tie-window` (default 0.05) of the top score, prefer the entry with the
    higher discovery/availability vector (a more mature capability is a safer
@@ -76,7 +78,7 @@ same codebase:
 
 | Verdict | Condition | Meaning |
 |---|---|---|
-| `reuse` | top score ≥ `--reuse-threshold` (default 0.45) | An existing capability already covers this need — link it, don't rebuild it. |
+| `reuse` | top score ≥ `--reuse-threshold` (default 0.45) | A close lexical match exists; review its consumption contract and availability before adoption. |
 | `extend` | top score in `[--extend-threshold, --reuse-threshold)` (default 0.22–0.45) | Scope overlaps a capability closely enough that extending it is very likely cheaper than a new one — surfaced with an explicit "consider extending" framing. |
 | `new` | top score < `--extend-threshold`, or no federated capabilities exist | No good match. Proceed; optionally file a capability request (T04). |
 
@@ -86,6 +88,12 @@ the same threshold reasoning as `overlaps.py`'s `--threshold 0.28` default,
 shifted since plan-check matches short intent text against short summaries
 rather than long entry-to-entry blobs.
 
+Verdicts describe relevance, not runtime readiness. A source-only candidate or
+an unavailable endpoint is an availability gap on the existing capability, not
+evidence that a second capability should be built. The match summary carries
+provider consumption guidance where published; callers must run its preflight
+and respect any local-only or managed-admission conditions.
+
 ## 6. Output
 
 ### Markdown (TTY default)
diff --git a/tests/test_hosted_plan_check.py b/tests/test_hosted_plan_check.py
index df687a6..35256fc 100644
--- a/tests/test_hosted_plan_check.py
+++ b/tests/test_hosted_plan_check.py
@@ -58,6 +58,31 @@ def test_hosted_only_capability_and_provenance_without_local_fallback(monkeypatc
     assert result["index_source"]["capability_count"] == 1
 
 
+def test_hosted_browser_discovery_includes_conditional_trial_guidance(monkeypatch, capsys):
+    from reuse_surface.registry import load_index
+
+    browser = next(item for item in load_index()["capabilities"]
+                   if item["id"] == "capability.infotech.headless-browser")
+    payload = snapshot()
+    payload["capabilities"] = [
+        {"id": "capability.example.headless", "name": "Headless Knowledge Engine",
+         "summary": "Headless information management", "tags": [],
+         "vector": "D7 / A7 / C6 / R6"},
+        browser,
+    ]
+    serve(monkeypatch, payload)
+    assert main(["plan-check", "--intent", "headless browser", "--hub-url",
+                 "https://registry.example", "--no-llm", "--format", "json"]) == 0
+    result = json.loads(capsys.readouterr().out)
+    assert result["verdict"] == "reuse"
+    assert result["matches"][0]["id"] == browser["id"]
+    summary = result["matches"][0]["summary"]
+    assert "rapp_playwright.py" in summary
+    assert "preflight" in summary and "trial --out" in summary
+    assert "ephemeral" in summary and "admission is pending" in summary
+    assert "availability gap" in summary
+
+
 @pytest.mark.parametrize("change", [
     {"stale": True}, {"stale": None}, {"composed_at": None},
     {"composed_at": "2020-01-01T00:00:00Z"},
diff --git a/tests/test_plan_check.py b/tests/test_plan_check.py
index fd9fccb..6cdaba5 100644
--- a/tests/test_plan_check.py
+++ b/tests/test_plan_check.py
@@ -80,6 +80,63 @@ def test_match_query_no_capabilities():
     assert match_query(query, []) == []
 
 
+def test_short_browser_intent_outranks_mature_headless_services(monkeypatch):
+    browser = {
+        "id": "capability.infotech.headless-browser",
+        "name": "Headless Browser Automation",
+        "summary": "Playwright Chromium screenshots keyboard " + " ".join(
+            f"detail{i}" for i in range(100)
+        ),
+        "vector": "D3 / A2 / C2 / R2",
+        "tags": ["headless", "browser"],
+    }
+    other = {
+        "id": "capability.communication.context-engine",
+        "name": "Context Engine",
+        "summary": "Headless knowledge operations",
+        "vector": "D7 / A7 / C6 / R6",
+    }
+    monkeypatch.setattr(
+        "reuse_surface.plan_check.load_federated_capabilities",
+        lambda: ([other, browser], _recent_date()),
+    )
+    result = run_plan_check(load_query_from_intent("headless browser"), use_llm=False)
+    assert result["verdict"] == "reuse"
+    assert result["matches"][0]["id"] == browser["id"]
+    assert result["matches"][0]["score"] > result["matches"][1]["score"]
+    assert maybe_file_capability_request(
+        result, requesting_domain="infotech", requesting_agent="test"
+    ) is None
+
+    # Extra operational documentation must not turn a direct name match into NEW.
+    original_score = result["top_score"]
+    browser["summary"] += " " + " ".join(f"command{i}" for i in range(100))
+    repeated = run_plan_check(load_query_from_intent("headless browser"), use_llm=False)
+    assert repeated["top_score"] == original_score
+
+
+def test_summary_only_matching_survives_name_scoring():
+    query = load_query_from_intent("responsive screenshots keyboard assertions")
+    matches = match_query(query, [{
+        "id": "capability.infotech.headless-browser",
+        "name": "Browser Automation",
+        "summary": "Responsive screenshots keyboard assertions",
+    }])
+    assert verdict_for_score(matches[0].score) == "reuse"
+
+
+def test_maturity_still_breaks_equally_relevant_name_ties():
+    candidates = [
+        {"id": "capability.example.early", "name": "Browser Automation",
+         "summary": "Early implementation", "vector": "D2 / A2 / C1 / R1"},
+        {"id": "capability.example.mature", "name": "Browser Automation",
+         "summary": "Documented implementation", "vector": "D4 / A5 / C3 / R3"},
+    ]
+    matches = match_query(load_query_from_intent("browser automation"), candidates)
+    assert matches[0].id == "capability.example.mature"
+    assert matches[0].score == matches[1].score
+
+
 def test_load_query_from_workplan(tmp_path):
     workplan = tmp_path / "TEST-WP-0001-thing.md"
     workplan.write_text(
diff --git a/tests/test_stats.py b/tests/test_stats.py
index 339670e..d5f47e0 100644
--- a/tests/test_stats.py
+++ b/tests/test_stats.py
@@ -2,6 +2,8 @@ from __future__ import annotations
 
 from pathlib import Path
 
+import pytest
+
 from reuse_surface.stats import (
     collect_roster_stats,
     collect_stats,
@@ -10,19 +12,36 @@ from reuse_surface.stats import (
 )
 
 
-def test_collect_stats_on_repo_root():
-    root = Path(__file__).resolve().parent.parent
-    stats = collect_stats(root)
+@pytest.fixture
+def stats_repo(tmp_path, monkeypatch):
+    monkeypatch.delenv("REUSE_SURFACE_URL", raising=False)
+    index = tmp_path / "registry/indexes/capabilities.yaml"
+    index.parent.mkdir(parents=True)
+    index.write_text("""version: 1
+domain: infotech
+capabilities:
+  - id: capability.example.source
+    vector: D3 / A2 / C2 / R2
+    path: registry/capabilities/source.md
+  - id: capability.example.service
+    vector: D4 / A5 / C3 / R3
+    path: registry/capabilities/service.md
+""")
+    return tmp_path
+
+
+def test_collect_stats_on_repo_root(stats_repo):
+    stats = collect_stats(stats_repo)
     assert stats["capability_count"] == 2
     assert stats["index_present"] is True
-    assert "discovery" in stats["histograms"]
+    assert stats["histograms"]["discovery"]["D3"] == 1
+    assert stats["histograms"]["discovery"]["D4"] == 1
+    assert stats["reliability"] == {"r0_r2": 1, "r3_plus": 1}
 
 
-def test_format_stats_markdown_contains_count():
-    root = Path(__file__).resolve().parent.parent
-    text = format_stats_markdown(collect_stats(root))
-    assert "Capabilities:" in text
-    assert "2" in text
+def test_format_stats_markdown_contains_count(stats_repo):
+    text = format_stats_markdown(collect_stats(stats_repo))
+    assert "**Capabilities:** 2" in text
 
 
 def test_collect_roster_stats_federation_ready():
diff --git a/workplans/REUSE-WP-0024-browser-discovery-and-provider-evidence.md b/workplans/REUSE-WP-0024-browser-discovery-and-provider-evidence.md
new file mode 100644
index 0000000..cf3decd
--- /dev/null
+++ b/workplans/REUSE-WP-0024-browser-discovery-and-provider-evidence.md
@@ -0,0 +1,76 @@
+---
+id: REUSE-WP-0024
+type: workplan
+title: "Resolve browser discovery relevance and publish verified provider consumption"
+domain: infotech
+repo: reuse-surface
+status: active
+owner: codex
+origin: cross-repo
+origin_ref: REUSE-IN-0001
+created: "2026-10-13"
+updated: "2026-10-13"
+state_hub_workstream_id: "3d62d0af-5deb-55b5-b570-e62f05a43666"
+---
+
+# Browser discovery and provider evidence
+
+Reviewed against the current checkout and rapp-playwright's published 0.1.0
+contract, immutable release and independent consumer receipts. All prior
+workplans are closed. REUSE-IN-0001 and the October 13 provider inbox handoffs
+are the remaining actionable work. User authorized review, implementation,
+commit and synchronization.
+
+## Publish the verified provider path
+
+```task
+id: REUSE-WP-0024-T01
+status: done
+priority: high
+state_hub_task_id: "dd75f033-02f1-521e-b5c3-cddb5dce80df"
+```
+
+Update the existing capability, index and generated views with pinned public
+client/contract/release/evidence links and executable preflight/trial guidance.
+Assess maturity against the standard; distinguish deployable local container
+availability from pending managed platform admission and ephemeral endpoints.
+Retain the source-adaptation fallback. No second browser capability or consumer
+task closure. Verify published sources and the available local fixture path.
+
+## Fix short-intent relevance
+
+```task
+id: REUSE-WP-0024-T02
+status: done
+priority: high
+state_hub_task_id: "a689bc2a-a112-59d4-b00c-f6934665dffb"
+```
+
+Keep deterministic token matching, but score capability names separately so
+long summaries cannot dilute a direct name match. Test browser versus unrelated
+headless services, unrelated queries, long descriptions, and maturity ties.
+Make reuse advice distinguish lexical relevance from runtime availability.
+Verify the same behavior against the hosted snapshot using the local CLI.
+
+## Validate, publish and synchronize
+
+```task
+id: REUSE-WP-0024-T03
+status: progress
+priority: medium
+state_hub_task_id: "0be283ba-12da-52a1-b1af-0c2d6dcb58f1"
+```
+
+Run the appropriate tests and registry/generated-artifact checks. Commit and
+push, refresh hosted federation, retain public readback evidence, reconcile
+REUSE-IN-0001 and workplan statuses, and log progress to State Hub. Browser
+deployment and CONTENT-WP-0000-T04 acceptance remain their owners' work.
+
+## Implementation evidence
+
+See [review and trial receipts](../docs/evidence/2026-10-13-browser-discovery.md).
+The published client passed 14 fixture steps and produced four independently
+checked screenshots. Availability is now A5 for the published local container;
+A6 managed admission remains pending. Name scoring ranks the browser first at
+0.6667 instead of returning false-new. Replaced stale live-registry stats
+assumptions with a controlled fixture after the full suite exposed them.