diff --git a/docs/reports/library-reading-continuity-20261026/README.md b/docs/reports/library-reading-continuity-20261026/README.md new file mode 100644 index 000000000..6b3b71dbf --- /dev/null +++ b/docs/reports/library-reading-continuity-20261026/README.md @@ -0,0 +1,31 @@ +# Keep the Library reader’s place + +Main c447d102 rebuilt every saved row when another tab saved an item or source-result attachment finished. That removed focused source/reference/identity controls and closed open Saved identity disclosures. The bounded repair reuses rows by the existing literal entryKey, refreshes changed validated metadata/reference fields, and supplies a reachable focus fallback when an item disappears. It preserves the reading-list schema, sources, classifications and all mathematical content. + +Root OpenAI Codex authored this engineering repair; actual GPT-6 family, finer variant not independently attested, organizational independence0. Separate engineering review may use the same family. Scientific review requires a different actual family; this release supplies no scientific review or theorem certification. + +## Actual verification + +- Initial39 browser controls against unchanged Main:33 focus/disclosure failures and6 existing controls passed; zero page errors. Original independent exact-Main audit also reproduced6 failures with2 outside-focus controls. +- Final49 focused browser cases passed at1440/light,390/dark,320/light: saved control roles, source identity after earlier-row removal, open/closed disclosures, validated metadata enrichment, duplicate import, actual removals/clear, queued-write/newer-focus, closed list and tab-only result reattachment. Native same-origin peer-tab storage events and the product UI were exercised. Fixture SHA metadata tests formatting, not authenticated source custody. +- Original reading-list13 and saved-source→Cite3 browser cases passed on final product bytes; zero page errors across these runs. All12 prescribed/focused command groups exited0: configured Node313tests/311pass/2expected museum fixture skips; reading-list/citation30; geometry10; Python12+46+77+14+5+5; integrated public-shop and museum checks passed. +- Canonical asset release/check: `fc8dff7ea5337eeb443c963d07e6c52cc4454f7f3ac6e217862ae6496edb38fd`. Workspace edit is solely the derived reader-module import key; generated observation bytes are unchanged. + +`SOURCE.json` pins candidate product files. Browser reports retain actual Git checkout HEAD plus measured working-tree product hashes; the base HEAD is not a claim that modified product bytes equal unchanged Main. Original complete39-case RED and final49-case GREEN have different counts because additional controls were added before implementation. The extended baseline also observed the added duplicate-import/tab-only failures, with3 subsequently corrected singular-count harness errors retained in the private evidence package. One initial repetitive polling run was intentionally interrupted; it is not a complete result. No hidden product exception made the tests pass. + +Browser was sandboxed headless Chrome156.0.8078.47 on Linux, SHA25695dc9473b4f904cb3ab0800fc7206081fcae12abc094a088bd741a13f1747b72. Local hash-pinned catalog fixtures replayed; unrelated remote requests refused. Viewport/keyboard checks are not physical touch, Safari, spoken assistive technology, full WCAG or high-node performance qualification. No public deployment or independent review is asserted by these local results; those have their own subsequent receipts. + +## Replay + +```bash +python3 -m pip install playwright +python3 -B tools/research_desk_continuity_browser_check.py --browser /path/to/chrome --output reading-continuity-evidence +python3 -B tools/research_desk_browser_check.py --browser /path/to/chrome --output reading-list-evidence +python3 -B tools/reading_list_citation_browser_check.py --browser /path/to/chrome --output citation-evidence +node --test tests/test_research_desk.mjs tests/test_reading_list_citation.mjs +python3 -B tools/site_asset_release.py --check +``` + +Use an installed sandbox-capable Chromium/Chrome executable; no browser binary is bundled. Complete prescribed reader checks are in docs/site/README.md. Exact preimages remain in the independently downloaded full Main #636 Drive archive1UV4f0z71WK1sztMGpAYd5Ko3AxzpXMYe, whole SHA2563479838a82a32c2c40f77f8d928b7859a301cdc274bfdc399c3702944d5e53f5. No Drive file was deleted, replaced or shared differently. + +The broader interface still lacks an admitted public worker-service/authentication/ID-mapping contract. This repair advances reliable find→save→inspect→cite reading independently of that specific integration gap. diff --git a/docs/reports/library-reading-continuity-20261026/SOURCE.json b/docs/reports/library-reading-continuity-20261026/SOURCE.json new file mode 100644 index 000000000..4369cd04f --- /dev/null +++ b/docs/reports/library-reading-continuity-20261026/SOURCE.json @@ -0,0 +1,11 @@ +{ + "base_commit": "c447d1029aebd44ea7bf278f691ec713633551bf", + "candidate_files": { + "docs/site/research-desk.mjs": "6942601577cf6741ea792b33c366ab06379a2798ad822f020176f7c81ffe884d", + "docs/site/workspace.html": "754b305bbe533f1f3353a8cd7ee9c39a3208f3143d31859e07d0789f600f840c", + "docs/site/README.md": "9bdf09526f7e0a138698a7aab5064cba991710818e9bfa078f467d542108d2ea", + "tools/research_desk_continuity_browser_check.py": "f76679193dd4035476aa4b35afeebd05d9c12d4d8cc28ce7f3332dda981e099b" + }, + "asset_release": "fc8dff7ea5337eeb443c963d07e6c52cc4454f7f3ac6e217862ae6496edb38fd", + "scope": "Engineering-only modified working tree over base; product fingerprints bind browser results. No scientific or spoken-AT verdict." +} diff --git a/docs/reports/library-reading-continuity-20261026/baseline-regression.json b/docs/reports/library-reading-continuity-20261026/baseline-regression.json new file mode 100644 index 000000000..f35627695 --- /dev/null +++ b/docs/reports/library-reading-continuity-20261026/baseline-regression.json @@ -0,0 +1,204 @@ +{ + "started_utc": "2026-10-26T03:01:09.670321+00:00", + "source_commit": "c447d1029aebd44ea7bf278f691ec713633551bf", + "product_sha256": "0f52f187ec6d4db251b0c47c06aa2f6ca77e7c8c46b0e967b8509d923601190d", + "sandbox": true, + "browser_sha256": "95dc9473b4f904cb3ab0800fc7206081fcae12abc094a088bd741a13f1747b72", + "cases": [ + { + "case": "peer-add-retains-source-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 70, in peer_add\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-reference-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 70, in peer_add\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-identity-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 70, in peer_add\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-remove-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 71, in peer_add\n assert detail.evaluate('(e)=>e.open'), 'Open identity collapsed'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Open identity collapsed\n" + }, + { + "case": "peer-add-retains-search-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 76, in saved_search\n control.focus(); add_peer(); focused(control)\n ^^^^^^^^^^^^^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "closed-identity-stays-closed-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 83, in closed\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "outside-focus-and-scroll-1440-light", + "passed": true + }, + { + "case": "earlier-removal-retains-literal-source-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 96, in earlier_removal\n focused(a.locator('#desk-entries > li').first.locator('.desk-cite-source'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "validated-enrichment-refreshes-reference-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 111, in enrichment\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-removal-focus-fallback-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 121, in removed\n focused(a.locator('#reading-list > summary'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-clear-focus-fallback-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 128, in peer_clear\n focused(a.locator('#reading-list > summary'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "local-last-remove-fallback-1440-light", + "passed": true + }, + { + "case": "local-clear-fallback-1440-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 144, in local_clear\n focused(a.locator('#reading-list > summary'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-source-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 70, in peer_add\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-reference-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 70, in peer_add\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-identity-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 70, in peer_add\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-remove-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 71, in peer_add\n assert detail.evaluate('(e)=>e.open'), 'Open identity collapsed'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Open identity collapsed\n" + }, + { + "case": "peer-add-retains-search-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 76, in saved_search\n control.focus(); add_peer(); focused(control)\n ^^^^^^^^^^^^^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "closed-identity-stays-closed-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 83, in closed\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "outside-focus-and-scroll-390-dark", + "passed": true + }, + { + "case": "earlier-removal-retains-literal-source-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 96, in earlier_removal\n focused(a.locator('#desk-entries > li').first.locator('.desk-cite-source'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "validated-enrichment-refreshes-reference-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 111, in enrichment\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-removal-focus-fallback-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 121, in removed\n focused(a.locator('#reading-list > summary'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-clear-focus-fallback-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 128, in peer_clear\n focused(a.locator('#reading-list > summary'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "local-last-remove-fallback-390-dark", + "passed": true + }, + { + "case": "local-clear-fallback-390-dark", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 144, in local_clear\n focused(a.locator('#reading-list > summary'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-source-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 70, in peer_add\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-reference-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 70, in peer_add\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-identity-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 70, in peer_add\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-add-retains-remove-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 71, in peer_add\n assert detail.evaluate('(e)=>e.open'), 'Open identity collapsed'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Open identity collapsed\n" + }, + { + "case": "peer-add-retains-search-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 76, in saved_search\n control.focus(); add_peer(); focused(control)\n ^^^^^^^^^^^^^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "closed-identity-stays-closed-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 83, in closed\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "outside-focus-and-scroll-320-light", + "passed": true + }, + { + "case": "earlier-removal-retains-literal-source-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 96, in earlier_removal\n focused(a.locator('#desk-entries > li').first.locator('.desk-cite-source'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "validated-enrichment-refreshes-reference-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 111, in enrichment\n focused(control)\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-removal-focus-fallback-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 121, in removed\n focused(a.locator('#reading-list > summary'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "peer-clear-focus-fallback-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 128, in peer_clear\n focused(a.locator('#reading-list > summary'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + }, + { + "case": "local-last-remove-fallback-320-light", + "passed": true + }, + { + "case": "local-clear-fallback-320-light", + "passed": false, + "error": "Traceback (most recent call last):\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 28, in case\n try: fn(); row['passed'] = True\n ^^^^\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 144, in local_clear\n focused(a.locator('#reading-list > summary'))\n File \"/workspace/universal-law/library-reading-continuity-20261026/tools/research_desk_continuity_browser_check.py\", line 24, in focused\n assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost'\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: Focused control was lost\n" + } + ], + "page_errors": [], + "limits": "Headless Chromium/Linux, emulated viewport; no physical touch, Safari, spoken AT or scientific qualification.", + "browser_version": "156.0.8078.47", + "origin": "http://127.0.0.1:34419/site/", + "passed": false, + "finished_utc": "2026-10-26T03:02:25.457342+00:00" +} diff --git a/docs/reports/library-reading-continuity-20261026/checks.json b/docs/reports/library-reading-continuity-20261026/checks.json new file mode 100644 index 000000000..0b88647f1 --- /dev/null +++ b/docs/reports/library-reading-continuity-20261026/checks.json @@ -0,0 +1,166 @@ +[ + { + "command": [ + "python", + "-B", + "tools/site_asset_release.py", + "--check" + ], + "exit_code": 0, + "seconds": 3.204, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/00.log" + }, + { + "command": [ + "python", + "-B", + "-m", + "unittest", + "discover", + "-s", + "tests", + "-p", + "test_public_shop_data.py" + ], + "exit_code": 0, + "seconds": 0.23, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/01.log" + }, + { + "command": [ + "python", + "-B", + "-m", + "unittest", + "tests.test_site_asset_release" + ], + "exit_code": 0, + "seconds": 18.619, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/02.log" + }, + { + "command": [ + "node", + "--test", + "tests/test_public_shop_frontend.mjs", + "tests/test_explore_models.mjs", + "tests/test_curvature_export.mjs", + "tests/test_teaching_export.mjs", + "tests/test_pin_export.mjs", + "tests/test_palette_export.mjs", + "tests/test_figure_png.mjs", + "tests/test_reading_list_citation.mjs", + "tests/test_reader_navigation.mjs", + "tests/test_source_reference.mjs", + "tests/test_measurement_model.mjs", + "tests/test_dependency_viewer.mjs", + "tests/test_museum_frontend.mjs", + "tests/test_workspace_navigation.mjs" + ], + "exit_code": 0, + "seconds": 8.318, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/03.log" + }, + { + "command": [ + "python", + "-B", + "-S", + "-m", + "unittest", + "discover", + "-s", + "tests", + "-p", + "test_reader_links.py", + "-v" + ], + "exit_code": 0, + "seconds": 5.065, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/04.log" + }, + { + "command": [ + "python", + "-B", + "-m", + "unittest", + "discover", + "-s", + "tests", + "-p", + "test_museum_data.py" + ], + "exit_code": 0, + "seconds": 0.335, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/05.log" + }, + { + "command": [ + "python", + "-B", + "tools/museum_check.py" + ], + "exit_code": 0, + "seconds": 1.866, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/06.log" + }, + { + "command": [ + "node", + "--test", + "tests/test_museum_geometry.mjs" + ], + "exit_code": 0, + "seconds": 0.219, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/07.log" + }, + { + "command": [ + "python", + "-B", + "-E", + "-S", + "tests/test_public_shop_check_identity_control.py", + "-v" + ], + "exit_code": 0, + "seconds": 0.146, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/08.log" + }, + { + "command": [ + "python", + "-B", + "-E", + "-O", + "-S", + "tests/test_public_shop_check_identity_control.py", + "-v" + ], + "exit_code": 0, + "seconds": 0.492, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/09.log" + }, + { + "command": [ + "python", + "-B", + "tools/public_shop_check.py" + ], + "exit_code": 0, + "seconds": 1.443, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/10.log" + }, + { + "command": [ + "node", + "--test", + "tests/test_research_desk.mjs", + "tests/test_reading_list_citation.mjs" + ], + "exit_code": 0, + "seconds": 0.258, + "log": "/workspace/research/next-reader-stage-20261026/final-checks/11.log" + } +] diff --git a/docs/reports/library-reading-continuity-20261026/citation-browser.json b/docs/reports/library-reading-continuity-20261026/citation-browser.json new file mode 100644 index 000000000..9b0ed0317 --- /dev/null +++ b/docs/reports/library-reading-continuity-20261026/citation-browser.json @@ -0,0 +1,263 @@ +{ + "started_utc": "2026-10-26T03:09:49.545784+00:00", + "cases": [ + { + "case": "home-library-save-keyboard-reference-back-390-light", + "passed": true + }, + { + "case": "home-library-save-keyboard-reference-back-1440-dark", + "passed": true + }, + { + "case": "imported-literal-paths-optional-sha-blob-refusals-export-remove", + "passed": true + } + ], + "page_errors": [], + "local_product_sha256": { + "reading-list-citation.mjs": "7e957e9adff0d0197dfee6817002c7f45e2ea77f1303256477fbb70ba58c5ce5", + "research-desk.mjs": "6942601577cf6741ea792b33c366ab06379a2798ad822f020176f7c81ffe884d", + "source-reference.mjs": "734364565a62772205d7e953c7441e7b5c66cb00f2bb956b378fcbb0bbdd4422" + }, + "local_product_sha256_scope": "Local checkout comparison context only; these hashes do not establish actual served asset identity.", + "browser_sha256": "95dc9473b4f904cb3ab0800fc7206081fcae12abc094a088bd741a13f1747b72", + "sandbox": true, + "limits": "Headless Chromium/Linux viewport emulation; no physical-device, Safari, spoken AT or scientific verdict.", + "browser_version": "156.0.8078.47", + "origin": "http://127.0.0.1:35227/site/", + "journeys": [ + { + "width": 390, + "scheme": "light", + "saved": { + "kind": "source", + "collection": "current", + "repository": "d6g8k5htny-coder/main", + "commit": "b7deb198722582df191006e4f47238f92e6e543d", + "path": "docs/research-translation/20260930/cap-assumption-ablation/PROOF.md", + "savedAt": "2026-10-26T03:09:52.209Z", + "observedAt": "2026-10-13T14:56:55Z", + "blob": "7158f3788ad9c158bf798451e6c36fedf9d7251d", + "bytes": 12287 + }, + "requests_before_cite": [ + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json" + ], + "external_requests": [ + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json" + ] + }, + { + "width": 1440, + "scheme": "dark", + "saved": { + "kind": "source", + "collection": "current", + "repository": "d6g8k5htny-coder/main", + "commit": "b7deb198722582df191006e4f47238f92e6e543d", + "path": "docs/research-translation/20260930/cap-assumption-ablation/PROOF.md", + "savedAt": "2026-10-26T03:09:55.848Z", + "observedAt": "2026-10-13T14:56:55Z", + "blob": "7158f3788ad9c158bf798451e6c36fedf9d7251d", + "bytes": 12287 + }, + "requests_before_cite": [ + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md" + ], + "external_requests": [ + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md" + ] + } + ], + "imported_external_requests": [ + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/coefficients/side24_v1/ENCLOSURE.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/Math-/9d7b6802424fb4715b31999066aafca8ee2f3cca/imports/hardening_ebedb780/MANIFEST.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/query-/c88768bb11efd1f7d6bda188f13064bedec54a06/portable/CANDIDATE_DOWNSTREAM_GATE_STUBS.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/STATUS.md", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-01.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-02.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-03.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-04.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-05.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-06.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-07.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-08.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-09.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-10.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-11.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-12.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-13.json", + "https://raw.githubusercontent.com/d6g8k5htny-coder/main/f2e432ea5c86742e480c66624775bc9103343314/docs/public-math/sources-14.json" + ], + "passed": true, + "finished_utc": "2026-10-26T03:10:06.142704+00:00" +} diff --git a/docs/reports/library-reading-continuity-20261026/continuity-browser.json b/docs/reports/library-reading-continuity-20261026/continuity-browser.json new file mode 100644 index 000000000..fa043cc1a --- /dev/null +++ b/docs/reports/library-reading-continuity-20261026/continuity-browser.json @@ -0,0 +1,211 @@ +{ + "started_utc": "2026-10-26T03:08:28.028140+00:00", + "source_commit": "c447d1029aebd44ea7bf278f691ec713633551bf", + "product_sha256": "6942601577cf6741ea792b33c366ab06379a2798ad822f020176f7c81ffe884d", + "sandbox": true, + "browser_sha256": "95dc9473b4f904cb3ab0800fc7206081fcae12abc094a088bd741a13f1747b72", + "cases": [ + { + "case": "peer-add-retains-source-1440-light", + "passed": true + }, + { + "case": "peer-add-retains-reference-1440-light", + "passed": true + }, + { + "case": "peer-add-retains-identity-1440-light", + "passed": true + }, + { + "case": "peer-add-retains-remove-1440-light", + "passed": true + }, + { + "case": "peer-add-retains-search-1440-light", + "passed": true + }, + { + "case": "closed-identity-stays-closed-1440-light", + "passed": true + }, + { + "case": "outside-focus-and-scroll-1440-light", + "passed": true + }, + { + "case": "earlier-removal-retains-literal-source-1440-light", + "passed": true + }, + { + "case": "validated-enrichment-refreshes-reference-1440-light", + "passed": true + }, + { + "case": "duplicate-import-keeps-reading-state-1440-light", + "passed": true + }, + { + "case": "peer-removal-focus-fallback-1440-light", + "passed": true + }, + { + "case": "peer-clear-focus-fallback-1440-light", + "passed": true + }, + { + "case": "local-last-remove-fallback-1440-light", + "passed": true + }, + { + "case": "local-clear-fallback-1440-light", + "passed": true + }, + { + "case": "queued-removal-keeps-newer-focus-1440-light", + "passed": true + }, + { + "case": "closed-list-background-update-1440-light", + "passed": true + }, + { + "case": "peer-add-retains-source-390-dark", + "passed": true + }, + { + "case": "peer-add-retains-reference-390-dark", + "passed": true + }, + { + "case": "peer-add-retains-identity-390-dark", + "passed": true + }, + { + "case": "peer-add-retains-remove-390-dark", + "passed": true + }, + { + "case": "peer-add-retains-search-390-dark", + "passed": true + }, + { + "case": "closed-identity-stays-closed-390-dark", + "passed": true + }, + { + "case": "outside-focus-and-scroll-390-dark", + "passed": true + }, + { + "case": "earlier-removal-retains-literal-source-390-dark", + "passed": true + }, + { + "case": "validated-enrichment-refreshes-reference-390-dark", + "passed": true + }, + { + "case": "duplicate-import-keeps-reading-state-390-dark", + "passed": true + }, + { + "case": "peer-removal-focus-fallback-390-dark", + "passed": true + }, + { + "case": "peer-clear-focus-fallback-390-dark", + "passed": true + }, + { + "case": "local-last-remove-fallback-390-dark", + "passed": true + }, + { + "case": "local-clear-fallback-390-dark", + "passed": true + }, + { + "case": "queued-removal-keeps-newer-focus-390-dark", + "passed": true + }, + { + "case": "closed-list-background-update-390-dark", + "passed": true + }, + { + "case": "peer-add-retains-source-320-light", + "passed": true + }, + { + "case": "peer-add-retains-reference-320-light", + "passed": true + }, + { + "case": "peer-add-retains-identity-320-light", + "passed": true + }, + { + "case": "peer-add-retains-remove-320-light", + "passed": true + }, + { + "case": "peer-add-retains-search-320-light", + "passed": true + }, + { + "case": "closed-identity-stays-closed-320-light", + "passed": true + }, + { + "case": "outside-focus-and-scroll-320-light", + "passed": true + }, + { + "case": "earlier-removal-retains-literal-source-320-light", + "passed": true + }, + { + "case": "validated-enrichment-refreshes-reference-320-light", + "passed": true + }, + { + "case": "duplicate-import-keeps-reading-state-320-light", + "passed": true + }, + { + "case": "peer-removal-focus-fallback-320-light", + "passed": true + }, + { + "case": "peer-clear-focus-fallback-320-light", + "passed": true + }, + { + "case": "local-last-remove-fallback-320-light", + "passed": true + }, + { + "case": "local-clear-fallback-320-light", + "passed": true + }, + { + "case": "queued-removal-keeps-newer-focus-320-light", + "passed": true + }, + { + "case": "closed-list-background-update-320-light", + "passed": true + }, + { + "case": "tab-only-result-update-and-last-removal", + "passed": true + } + ], + "page_errors": [], + "limits": "Headless Chromium/Linux, emulated viewport; no physical touch, Safari, spoken AT or scientific qualification.", + "browser_version": "156.0.8078.47", + "origin": "http://127.0.0.1:33803/site/", + "passed": true, + "finished_utc": "2026-10-26T03:09:58.310723+00:00" +} diff --git a/docs/reports/library-reading-continuity-20261026/reading-list-browser.json b/docs/reports/library-reading-continuity-20261026/reading-list-browser.json new file mode 100644 index 000000000..3a153f694 --- /dev/null +++ b/docs/reports/library-reading-continuity-20261026/reading-list-browser.json @@ -0,0 +1,73 @@ +{ + "started_utc": "2026-10-26T03:09:49.533797+00:00", + "cases": [ + { + "case": "current-search-save-persist-export-import-1440-light", + "passed": true + }, + { + "case": "current-search-save-persist-export-import-390-light", + "passed": true + }, + { + "case": "current-search-save-persist-export-import-320-dark", + "passed": true + }, + { + "case": "dated-catalog-isolated-query-and-source", + "passed": true + }, + { + "case": "invalid-imports-atomic", + "passed": true + }, + { + "case": "unavailable-storage-session-and-export", + "passed": true + }, + { + "case": "refused-current-data-never-save-static-rows", + "passed": true + }, + { + "case": "no-javascript-static-source-path", + "passed": true + }, + { + "case": "late-readiness-preserves-newer-focus", + "passed": true + }, + { + "case": "corrupt-quota-and-lock-refusal-preserve-session-use", + "passed": true + }, + { + "case": "two-tabs-queued-locks-preserve-both-explicit-saves", + "passed": true + }, + { + "case": "oversize-query-refused-without-page-error", + "passed": true + }, + { + "case": "home-library-opens-collection-choice", + "passed": true + } + ], + "page_errors": [], + "source": "c447d1029aebd44ea7bf278f691ec713633551bf", + "local_product_sha256": { + "workspace.html": "754b305bbe533f1f3353a8cd7ee9c39a3208f3143d31859e07d0789f600f840c", + "research-desk.mjs": "6942601577cf6741ea792b33c366ab06379a2798ad822f020176f7c81ffe884d", + "research-desk-store.mjs": "b677d6e9f7061fc15bb766a6bcfcff08b44792abd31c2308948d48d28199885a", + "research-desk.css": "0704122b2adf2d668a0f6aa90f9b2a5ca77fdb8c2e22b2cb550c93fede4dca51" + }, + "sandbox": true, + "browser_path": "/workspace/research/site-vision-audit-20261025/final-browser-qualification/chrome-package/opt/google/chrome/chrome", + "browser_sha256": "95dc9473b4f904cb3ab0800fc7206081fcae12abc094a088bd741a13f1747b72", + "limits": "Headless Chromium/Linux; viewport emulation, not physical touch, Safari, spoken AT or scientific verification.", + "browser_version": "156.0.8078.47", + "origin": "http://127.0.0.1:37039/site/", + "passed": true, + "finished_utc": "2026-10-26T03:10:09.390577+00:00" +} diff --git a/docs/site/README.md b/docs/site/README.md index 7a7c38134..b150c0dec 100644 --- a/docs/site/README.md +++ b/docs/site/README.md @@ -179,6 +179,18 @@ Rules for future cards, not a retrofit of pinned cuts: each card carries one vis ## Keep or share a Library search +Saved reading-list rows keep their focused source/reference control and open +**Saved identity** disclosure when another tab updates the list. Validated +metadata changes refresh the displayed identity and reference. If the focused +item is removed, focus returns to the reading-list summary; a local Remove +button uses the neighboring Remove button when one remains. No new data is saved +automatically. These browser checks exercise that continuity and its tab-only, +queued-write and outside-focus controls: + +```bash +python3 -B tools/research_desk_continuity_browser_check.py --output reading-continuity-evidence +``` + The Library's search, repository and path filters are saved in the current URL without adding a browser-history entry for every keystroke. Refreshing or returning with Back/Forward restores the filters. **Link to this search** gives a diff --git a/docs/site/research-desk.mjs b/docs/site/research-desk.mjs index c1b8ca8e8..52dc38738 100644 --- a/docs/site/research-desk.mjs +++ b/docs/site/research-desk.mjs @@ -33,46 +33,77 @@ export function startResearchDesk(doc=document,win=window,snapshot=currentSnapsh }catch {storedProblem='Stored reading data is unavailable or unreadable; existing data is preserved. ';} say(storedProblem+'Only items you choose to save enter this list.'); - const currentSources=new Map(); + const currentSources=new Map(),renderedRows=new Map(); const now=()=>new Date().toISOString(); const sourceButtons=()=>doc.querySelectorAll('button.desk-save-source'); function render() { - const focused=doc.activeElement,oldButtons=[...list.querySelectorAll('button')],focusIndex=oldButtons.indexOf(focused); - list.replaceChildren(); + const focused=doc.activeElement,oldRows=[...list.children]; + const focusIndex=oldRows.findIndex(row=>row.contains(focused)); + const keys=new Set(entries.map(entryKey)); + // Keep surviving controls and disclosures in place. A background source + // update must not discard the DOM context of an unrelated saved item. + for(const [key,saved] of renderedRows)if(!keys.has(key)){ + saved.row.remove();renderedRows.delete(key); + } + let cursor=list.firstElementChild; for(const entry of entries) { - const row=make('li'),content=make('div'),a=make('a'); - if(entry.kind==='source') { - a.textContent=entry.repository.split('/')[1]+' · '+entry.path;a.href=sourceHref(entry); - content.append(make('small','Pinned source link','desk-kind'),a); - const details=make('details');details.append(make('summary','Saved identity')); - const identity=make('dl'); - for(const [label,value] of [['Commit',entry.commit],['Git blob',entry.blob],['SHA-256',entry.sha256],['Bytes',entry.bytes],['Source observation',entry.observedAt],['Saved',entry.savedAt]]) { - if(value===undefined)continue;identity.append(make('dt',label),make('dd',String(value))); + const key=entryKey(entry),signature=JSON.stringify(entry); + let saved=renderedRows.get(key); + if(!saved){ + const row=make('li'),content=make('div'),a=make('a'); + let identity=null,citation=null; + if(entry.kind==='source') { + a.textContent=entry.repository.split('/')[1]+' · '+entry.path;a.href=sourceHref(entry); + content.append(make('small','Pinned source link','desk-kind'),a); + const details=make('details');details.append(make('summary','Saved identity')); + identity=make('dl'); + details.append(identity);content.append(details); + const citationHref=readingListCitationHref(entry,win.location.href); + if(citationHref){ + citation=make('a','Make a source reference','button secondary desk-cite-source'); + citation.href=citationHref;content.append(citation); + }else content.append(make('p','Reference builder unavailable for this literal path.','desk-citation-unavailable')); + }else { + a.textContent=(entry.collection==='current'?'Current source search':'Dated catalog search')+': '+(entry.query||'All files'); + a.href=searchHref(entry,win.location.href); + content.append(make('small',entry.collection==='current'?'Reopens against the next admitted observation':'Reopens the dated catalog','desk-kind'),a); + if(entry.repository||entry.path)content.append(make('p',[entry.repository&&'Repository: '+entry.repository,entry.path&&'Path: '+entry.path].filter(Boolean).join(' · '))); + } + const remove=make('button','Remove','desk-remove');remove.type='button';remove.setAttribute('aria-label','Remove '+a.textContent); + remove.addEventListener('click',()=>mutate(items=>items.filter(item=>entryKey(item)!==key),'Item removed.')); + row.append(content,remove); + saved={row,identity,citation,signature:null};renderedRows.set(key,saved); + } + if(saved.signature!==signature){ + if(saved.identity){ + saved.identity.replaceChildren(); + for(const [label,value] of [['Commit',entry.commit],['Git blob',entry.blob],['SHA-256',entry.sha256],['Bytes',entry.bytes],['Source observation',entry.observedAt],['Saved',entry.savedAt]]){ + if(value!==undefined)saved.identity.append(make('dt',label),make('dd',String(value))); + } } - details.append(identity);content.append(details); - const citationHref=readingListCitationHref(entry,win.location.href); - if(citationHref){ - const citation=make('a','Make a source reference','button secondary desk-cite-source'); - citation.href=citationHref;content.append(citation); - }else content.append(make('p','Reference builder unavailable for this literal path.','desk-citation-unavailable')); - }else { - a.textContent=(entry.collection==='current'?'Current source search':'Dated catalog search')+': '+(entry.query||'All files'); - a.href=searchHref(entry,win.location.href); - content.append(make('small',entry.collection==='current'?'Reopens against the next admitted observation':'Reopens the dated catalog','desk-kind'),a); - if(entry.repository||entry.path)content.append(make('p',[entry.repository&&'Repository: '+entry.repository,entry.path&&'Path: '+entry.path].filter(Boolean).join(' · '))); + if(saved.citation)saved.citation.href=readingListCitationHref(entry,win.location.href); + saved.signature=signature; } - const remove=make('button','Remove','desk-remove');remove.type='button';remove.setAttribute('aria-label','Remove '+a.textContent); - remove.addEventListener('click',()=>mutate(items=>items.filter(item=>entryKey(item)!==entryKey(entry)),'Item removed.')); - row.append(content,remove);list.append(row); + if(saved.row!==cursor)list.insertBefore(saved.row,cursor); + cursor=saved.row.nextElementSibling; } byId('desk-count').textContent=entries.length+' saved item'+(entries.length===1?'':'s'); byId('desk-empty').hidden=entries.length>0; byId('desk-export').disabled=!entries.length;byId('desk-clear').disabled=!entries.length; - const keys=new Set(entries.map(entryKey)); for(const button of sourceButtons()){ const saved=keys.has(button.dataset.deskKey);button.disabled=saved;button.textContent=saved?'Saved':'Save source'; } - if(focusIndex>=0){const buttons=list.querySelectorAll('button');(buttons[Math.min(focusIndex,buttons.length-1)]||reading.querySelector('summary')).focus({preventScroll:true});} + if(focusIndex>=0){ + if(list.contains(focused)){ + // Native node moves may blur a retained control on older browsers. + if(doc.activeElement!==focused)focused.focus({preventScroll:true}); + }else{ + const next=focused.matches('.desk-remove')&&list.children[Math.min(focusIndex,list.children.length-1)]?.querySelector('.desk-remove'); + (next||reading.querySelector('summary')).focus({preventScroll:true}); + } + }else if([byId('desk-clear'),byId('desk-export')].includes(focused)&&focused.disabled){ + reading.querySelector('summary').focus({preventScroll:true}); + } } function mutate(operation,success,refusal='Could not update reading list: ') { queue=queue.then(async()=>{ diff --git a/docs/site/workspace.html b/docs/site/workspace.html index 5be6da082..6b6ed6759 100644 --- a/docs/site/workspace.html +++ b/docs/site/workspace.html @@ -14,7 +14,7 @@ - +
Skip to content diff --git a/docs/superpowers/plans/2026-10-26-library-reading-continuity.md b/docs/superpowers/plans/2026-10-26-library-reading-continuity.md new file mode 100644 index 000000000..576abf386 --- /dev/null +++ b/docs/superpowers/plans/2026-10-26-library-reading-continuity.md @@ -0,0 +1,39 @@ +# Library reading continuity implementation plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Keep focus and source-identity disclosures stable while reading-list data updates. + +**Architecture:** Reconcile saved rows with existing entryKey(). Retain surviving control DOM, update changed source metadata and citation href, remove missing rows and make only necessary moves. Capture focus at render time and use a reachable fallback only if its control disappears or becomes disabled. + +**Tech Stack:** Existing dependency-free JavaScript and Python/Playwright browser runner. + +**Spec:** docs/superpowers/specs/2026-10-26-library-reading-continuity.md + +## Global constraints + +- Same bounded schema and literal source identities; no new storage or backend. +- No current/Atlas/math/source/admission changes; workspace change is derived reader-module key only. +- Engineering only; same-family separate reviewer allowed, scientific review needs different actual family. +- Preserve prior evidence and Drive releases; no deletion or sharing changes. + +## Review focus + +- Same-key metadata enrichment must update citation SHA and displayed identity. +- Removing an earlier entry must not switch focus by row index. +- Peer removal/clear must leave reachable focus, with closed-list/outside-focus preserved. +- Queued writes capture current focus at completion, not old click-time focus. +- Local-only storage failure must retain the same reading behavior without overwriting storage. + +### Task 1: Reproduce, repair and qualify reading continuity + +**Files:** Modify docs/site/research-desk.mjs and derived docs/site/workspace.html; create tools/research_desk_continuity_browser_check.py and scoped report. + +**Interfaces:** Consumes existing startResearchDesk(), entryKey(), validated entries and native storage events. Produces unchanged public API and data schema, with stable surviving reading controls. + +- [x] Write real-browser controls for peer add, all saved control roles, saved search, closed/open disclosure, earlier-row removal, same-key enrichment, focused-row removal, clear and outside/late focus. +- [x] Run against untouched Main bytes; retain expected focus/disclosure failures, outside controls and source/browser identity. +- [x] Implement keyed rows and changed metadata refresh; preserve actual-removal fallback without moving unrelated focus. +- [x] Run targeted controls, original reading-list and citation browser journeys; use actual local-only/queued-lock negative controls. +- [x] Stage additions, generate/check canonical asset keys, run prescribed public-shop tests and preserve reports/source identities. +- [ ] Commit, obtain separate engineering review, resolve actual findings, then hand off ordinary protected integration to a separate eligible integrator. Publish/archive only after actual results. diff --git a/docs/superpowers/specs/2026-10-26-library-reading-continuity.md b/docs/superpowers/specs/2026-10-26-library-reading-continuity.md new file mode 100644 index 000000000..dd7a57a59 --- /dev/null +++ b/docs/superpowers/specs/2026-10-26-library-reading-continuity.md @@ -0,0 +1,9 @@ +# Keep the reader's place in the Library + +Dylan's continuing UI/UX instruction authorizes this bounded engineering repair. Main c447d102's reading list replaces every saved row on a peer-tab or result-attachment update. Actual sandboxed Chrome reproduction lost source/reference/summary focus and closed Saved identity in six probes; two outside-focus controls passed. Root's audit is source-exposed engineering, not scientific or spoken-AT evidence. + +Preserve surviving literal entry identities, their focused controls and open/closed Saved identity disclosures. When validated same-key metadata changes, show the new metadata/reference without collapsing its disclosure. When a focused row disappears, local Remove retains its neighboring Remove fallback; other lost row controls return to the reading-list summary. A disabled Clear/Export control also returns to that summary. A reader who has moved focus outside an invalidated control keeps it. Retain the bounded 50-item schema, exact identities, save/import/export/conflict/refusal and coordinated/local-only storage semantics. + +Approaches considered: restoring role and disclosure state after rebuilding is small but still destroys all DOM reading context; keyed reconciliation retains surviving rows and controls and is selected by Root under delegated implementation discretion. A general UI framework or Undo introduces unrelated state and is excluded. Keep existing entryKey authority; no new identity or data registry. Reuse current brand and markup; no decorative redesign. + +Scope: research-desk.mjs, its derived workspace import key, a real-browser regression, and scoped documentation. No current importer/model/app/Atlas/source/mathematics/backend changes. Required site verification, separate engineering reviewer and separate protected integration remain. Same-family engineering review is allowed; scientific review requires a different actual family. Scientific effect NONE. diff --git a/tools/research_desk_continuity_browser_check.py b/tools/research_desk_continuity_browser_check.py new file mode 100644 index 000000000..632beb9c7 --- /dev/null +++ b/tools/research_desk_continuity_browser_check.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +"""Real two-tab reading continuity; no mathematical or spoken-AT verdict.""" +from __future__ import annotations +import argparse +from datetime import datetime, timezone +from hashlib import sha256 +import json +import re +from pathlib import Path +import subprocess +import traceback +from research_desk_browser_check import ROOT, KEY, serve + + +def run(origin, browser, out, report, local): + from playwright.sync_api import expect + config = json.loads((ROOT / 'docs/site/config.json').read_text()) + fixtures = {config['inventory']['url']: ROOT / 'docs/public-math/sources.json', + config['status']['url']: ROOT / 'tests/fixtures/status_f2e432e.md'} + fixtures.update({pin['url']: ROOT / pin['path'] for pin in config['inventory']['pages']}) + + def focused(control): + # Data/count assertions above synchronize the synchronous render. + assert control.evaluate('(e)=>e===document.activeElement'), 'Focused control was lost' + + def case(name, fn): + row = {'case': name}; report['cases'].append(row) + try: fn(); row['passed'] = True + except Exception: row['passed'] = False; row['error'] = traceback.format_exc() + print(json.dumps({'case': name, 'passed': row['passed']}), flush=True) + + for width, scheme in [(1440, 'light'), (390, 'dark'), (320, 'light')]: + c = browser.new_context(viewport={'width': width, 'height': 900}, + color_scheme=scheme, reduced_motion='reduce') + if local: + def fixture(route): + path = fixtures.get(route.request.url) + route.fulfill(status=200 if path else 503, + headers={'Access-Control-Allow-Origin': '*'}, + body=path.read_bytes() if path else b'') + c.route('https://raw.githubusercontent.com/**', fixture) + a, b = c.new_page(), c.new_page() + for p in (a, b): + p.set_default_timeout(10000) + p.on('pageerror', lambda error: report['page_errors'].append(str(error))) + a.goto(origin + 'workspace.html?source-q=PROOF.md#library-current') + expect(a.locator('#desk-save-current')).to_be_enabled() + a.locator('#desk-save-current').click() # Earlier query precedes target source. + a.locator('.current-results .desk-save-source').first.click() + expect(a.locator('#desk-count')).to_have_text('2 saved items') + a.locator('#reading-list > summary').click() + b.goto(origin + 'workspace.html?source-q=README.md#library-current') + expect(b.locator('#desk-save-current')).to_be_enabled() + b.locator('#reading-list > summary').click() + source = a.locator('#desk-entries > li').nth(1) + + def add_peer(): + count = int(a.locator('#desk-count').inner_text().split()[0]) + b.locator('.current-search').fill('continuity ' + str(count)) + b.locator('#desk-save-current').click() + expect(a.locator('#desk-count')).to_have_text(f'{count + 1} saved item' + ('s' if count else '')) + + for role, selector in [('source', ':scope > div > a:first-of-type'), + ('reference', '.desk-cite-source'), + ('identity', 'details > summary'), ('remove', '.desk-remove')]: + def peer_add(selector=selector): + detail = source.locator('details') + if not detail.evaluate('(e)=>e.open'): detail.locator('summary').click() + control = source.locator(selector); control.focus() + add_peer() + focused(control) + assert detail.evaluate('(e)=>e.open'), 'Open identity collapsed' + case(f'peer-add-retains-{role}-{width}-{scheme}', peer_add) + + def saved_search(): + control = a.locator('#desk-entries > li').first.locator('a').first + control.focus(); add_peer(); focused(control) + case(f'peer-add-retains-search-{width}-{scheme}', saved_search) + + def closed(): + detail = source.locator('details') + if detail.evaluate('(e)=>e.open'): detail.locator('summary').click() + control = source.locator('.desk-cite-source'); control.focus(); add_peer() + focused(control) + assert not detail.evaluate('(e)=>e.open'), 'Closed identity reopened' + case(f'closed-identity-stays-closed-{width}-{scheme}', closed) + + def outside(): + control = a.locator('#library-current-link'); control.focus() + before = a.evaluate('scrollY'); add_peer(); focused(control) + assert a.evaluate('scrollY') == before, 'Background update moved scroll' + case(f'outside-focus-and-scroll-{width}-{scheme}', outside) + + def earlier_removal(): + control = source.locator('.desk-cite-source'); control.focus() + b.locator('#desk-entries > li').first.locator('.desk-remove').click() + focused(a.locator('#desk-entries > li').first.locator('.desk-cite-source')) + case(f'earlier-removal-retains-literal-source-{width}-{scheme}', earlier_removal) + source = a.locator('#desk-entries > li').first + + def enrichment(): + detail = source.locator('details') + if not detail.evaluate('(e)=>e.open'): detail.locator('summary').click() + control = source.locator('.desk-cite-source'); control.focus() + entries = json.loads(b.evaluate('(key)=>localStorage.getItem(key)', KEY)) + entry = next(e for e in entries['entries'] if e['kind'] == 'source') + entry['sha256'] = 'a' * 64 # Fixture metadata, never authenticated source bytes. + payload = json.dumps({'schema': KEY, 'entries': [entry]}) + b.locator('#desk-import').set_input_files({'name': 'enrich.json', + 'mimeType': 'application/json', 'buffer': payload.encode()}) + expect(control).to_have_attribute('href', re.compile('sha256=' + 'a' * 64)) + focused(control) + expect(detail).to_contain_text('SHA-256') + expect(detail).to_contain_text('a' * 64) + assert detail.evaluate('(e)=>e.open') + a.locator('#reading-list').screenshot(path=str(out / f'identity-{width}-{scheme}.png')) + case(f'validated-enrichment-refreshes-reference-{width}-{scheme}', enrichment) + + def duplicate_import(): + control = source.locator('.desk-cite-source'); control.focus() + payload = a.evaluate('(key)=>localStorage.getItem(key)', KEY) + a.locator('#desk-import').set_input_files({'name': 'duplicate.json', + 'mimeType': 'application/json', 'buffer': payload.encode()}) + expect(a.locator('#desk-message')).to_contain_text('Reading list imported') + focused(control) + assert source.locator('details').evaluate('(e)=>e.open') + case(f'duplicate-import-keeps-reading-state-{width}-{scheme}', duplicate_import) + + def removed(): + source.locator('.desk-cite-source').focus() + b.locator('#desk-entries > li').first.locator('.desk-remove').click() + expect(a.locator('#desk-entries .desk-cite-source')).to_have_count(0) + focused(a.locator('#reading-list > summary')) + case(f'peer-removal-focus-fallback-{width}-{scheme}', removed) + + def peer_clear(): + a.locator('#desk-entries > li').first.locator('a').first.focus() + b.locator('#desk-clear').click() + expect(a.locator('#desk-count')).to_have_text('0 saved items') + focused(a.locator('#reading-list > summary')) + case(f'peer-clear-focus-fallback-{width}-{scheme}', peer_clear) + + def local_remove(): + a.locator('#desk-save-current').click() + expect(a.locator('#desk-count')).to_have_text('1 saved item') + a.locator('#desk-entries .desk-remove').focus(); a.keyboard.press('Enter') + expect(a.locator('#desk-count')).to_have_text('0 saved items') + focused(a.locator('#reading-list > summary')) + case(f'local-last-remove-fallback-{width}-{scheme}', local_remove) + + def local_clear(): + a.locator('#desk-save-current').click() + expect(a.locator('#desk-count')).to_have_text('1 saved item') + a.locator('#desk-clear').focus(); a.keyboard.press('Enter') + expect(a.locator('#desk-count')).to_have_text('0 saved items') + focused(a.locator('#reading-list > summary')) + case(f'local-clear-fallback-{width}-{scheme}', local_clear) + + def queued_remove(): + a.locator('#desk-save-current').click() + expect(a.locator('#desk-count')).to_have_text('1 saved item') + a.evaluate('''key=>{navigator.locks.request(key,()=>new Promise(resolve=>{ + window.releaseContinuityLock=resolve}));}''', KEY) + a.wait_for_function("typeof window.releaseContinuityLock==='function'") + a.locator('#desk-entries .desk-remove').click() + outside = a.locator('#library-current-link'); outside.focus() + a.evaluate('window.releaseContinuityLock()') + expect(a.locator('#desk-count')).to_have_text('0 saved items') + focused(outside) + case(f'queued-removal-keeps-newer-focus-{width}-{scheme}', queued_remove) + + def closed_list(): + a.locator('#reading-list > summary').click() + control = a.locator('#reading-list > summary'); control.focus() + add_peer(); focused(control) + assert not a.locator('#reading-list').evaluate('(e)=>e.open') + control.click() + case(f'closed-list-background-update-{width}-{scheme}', closed_list) + assert a.evaluate('document.documentElement.scrollWidth <= innerWidth') + a.locator('#reading-list').screenshot(path=str(out / f'list-{width}-{scheme}.png')) + c.unroute_all(behavior='wait'); c.close() + + def local_only(): + c = browser.new_context(viewport={'width': 390, 'height': 900}, color_scheme='dark') + c.add_init_script("Object.defineProperty(window,'localStorage',{get(){throw new Error('fixture storage unavailable')}})") + if local: c.route('https://raw.githubusercontent.com/**', fixture) + p = c.new_page(); p.on('pageerror', lambda error: report['page_errors'].append(str(error))) + p.goto(origin + 'workspace.html?source-q=PROOF.md#library-current') + expect(p.locator('.current-results .desk-save-source').first).to_be_enabled() + p.locator('.current-results .desk-save-source').first.click() + p.locator('#reading-list > summary').click() + detail = p.locator('#desk-entries details'); detail.locator('summary').click() + control = p.locator('#desk-entries .desk-cite-source'); control.focus() + # A result-attachment update uses the same renderer even in tab-only mode. + p.locator('.current-search').evaluate("e=>{e.value='README.md';e.dispatchEvent(new Event('input',{bubbles:true}))}") + expect(p.locator('.current-results > li > a').first).to_contain_text('README.md') + # MutationObserver attachment finishes before the next browser task. + p.wait_for_function("document.querySelector('.current-results .desk-save-source')!==null") + focused(control); assert detail.evaluate('(e)=>e.open') + expect(p.locator('#desk-status')).to_contain_text('this tab only') + control = p.locator('#desk-entries .desk-remove'); control.focus(); p.keyboard.press('Enter') + expect(p.locator('#desk-count')).to_have_text('0 saved items') + focused(p.locator('#reading-list > summary')) + c.unroute_all(behavior='wait'); c.close() + case('tab-only-result-update-and-last-removal', local_only) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--output', type=Path, required=True) + parser.add_argument('--browser', type=Path, default=Path('/opt/google/chrome/chrome')) + parser.add_argument('--origin', help='Actual site origin ending /site/; no local fixtures') + args = parser.parse_args(); args.output.mkdir(parents=True, exist_ok=True) + try: commit = subprocess.check_output(['git', 'rev-parse', 'HEAD'], cwd=ROOT, text=True).strip() + except (subprocess.CalledProcessError, FileNotFoundError): commit = 'No Git metadata' + report = {'started_utc': datetime.now(timezone.utc).isoformat(), 'git_head': commit, + 'local_product_sha256': sha256((ROOT / 'docs/site/research-desk.mjs').read_bytes()).hexdigest(), + 'sandbox': True, 'browser_sha256': sha256(args.browser.read_bytes()).hexdigest(), + 'cases': [], 'page_errors': [], + 'limits': 'Headless Chromium/Linux, emulated viewport; no physical touch, Safari, spoken AT or scientific qualification.'} + from playwright.sync_api import sync_playwright + try: + with sync_playwright() as p: + browser = p.chromium.launch(executable_path=str(args.browser), chromium_sandbox=True) + report['browser_version'] = browser.version + if args.origin: report['origin'] = args.origin; run(args.origin, browser, args.output, report, False) + else: + with serve() as origin: report['origin'] = origin; run(origin, browser, args.output, report, True) + browser.close() + except Exception: report['error'] = traceback.format_exc() + report['passed'] = (not report.get('error') and not report['page_errors'] and + bool(report['cases']) and all(row['passed'] for row in report['cases'])) + report['finished_utc'] = datetime.now(timezone.utc).isoformat() + (args.output / 'report.json').write_text(json.dumps(report, indent=2) + '\n') + print(json.dumps({'passed': report['passed'], 'cases': len(report['cases']), 'output': str(args.output)})) + return 0 if report['passed'] else 1 + + +if __name__ == '__main__': raise SystemExit(main())