diff --git a/TREE.md b/TREE.md index 8cbd391..6ca772d 100644 --- a/TREE.md +++ b/TREE.md @@ -353,11 +353,14 @@ research/evolution/context.json research/evolution/cycles/2026-09-27-navigation-effort.json research/evolution/cycles/2026-09-27-navigation-focus-effort.json research/evolution/cycles/2026-09-27-navigation-focus.md +research/evolution/cycles/2026-09-27-navigation-ownership-effort.json +research/evolution/cycles/2026-09-27-navigation-ownership.md research/evolution/cycles/2026-09-27-navigation.md research/evolution/ledger.json research/evolution/profiles.json research/evolution/snapshots/baseline-2026-09-26.json research/evolution/snapshots/cycle-2026-09-27-navigation-focus.json +research/evolution/snapshots/cycle-2026-09-27-navigation-ownership.json research/evolution/snapshots/cycle-2026-09-27-navigation.json research/examples/SchemaEvidence.md research/examples/schema-contract.yaml @@ -407,6 +410,11 @@ research/experiments/navigation-history/focus-policy.js research/experiments/navigation-history/focus-result.json research/experiments/navigation-history/focus.mjs research/experiments/navigation-history/initial-partial.json +research/experiments/navigation-history/ownership-initial-result.json +research/experiments/navigation-history/ownership-initial.mjs +research/experiments/navigation-history/ownership-policy.js +research/experiments/navigation-history/ownership-result.json +research/experiments/navigation-history/ownership.mjs research/experiments/navigation-history/package-lock.json research/experiments/navigation-history/package.json research/experiments/navigation-history/result.json @@ -431,7 +439,9 @@ research/reviews/MatrixRecoveryExperiment.md research/reviews/NavigationCoverage.md research/reviews/NavigationFocusExperiment.md research/reviews/NavigationHistoryExperiment.md +research/reviews/NavigationOwnershipExperiment.md research/reviews/NavigationRenderingEvidence.md +research/reviews/NavigationThreadReview.md research/reviews/NestedDismissalIsolation.md research/reviews/NestedOwnershipRouting.md research/reviews/ObsidianConflictScreen.json diff --git a/research/candidates/FocusReturn.md b/research/candidates/FocusReturn.md index 875de54..dcfe1f0 100644 --- a/research/candidates/FocusReturn.md +++ b/research/candidates/FocusReturn.md @@ -85,3 +85,12 @@ this fixture restores a same-ID link; that behavior alone does not choose the ne task. Preserve this candidate's modal scope instead of treating every route change as a return-to-invoker problem. No general route-focus pattern or AT validation is admitted; delayed history restoration and competing navigation remain open. + +## Completion ownership contrast — 2026-09-27 + +[NO01–NO06](../reviews/NavigationOwnershipExperiment.md) strengthen the route/modal +scope boundary. A still-current history result can restore content without taking +focus from a newer search task; an obsolete navigation result must not supply a +continuation at all. The earlier single-response route policy is insufficient for +competing completions. This contrast does not expand the modal candidate into a +universal routing pattern or prove AT behavior. diff --git a/research/candidates/ProgressiveEnhancement.md b/research/candidates/ProgressiveEnhancement.md index 54dc834..66be540 100644 --- a/research/candidates/ProgressiveEnhancement.md +++ b/research/candidates/ProgressiveEnhancement.md @@ -65,3 +65,18 @@ return to the invoker. Check ownership when the response is applied, not only wh it is requested. Failure feedback need not move focus. Same-ID restoration is not proof of semantic continuity. DOM/ARIA checks here do not establish spoken feedback; AT, delayed history and overlapping-request behavior remain unverified. + +## Separate completion and focus ownership — 2026-09-27 + +[Competing navigation](../reviews/NavigationOwnershipExperiment.md) NO01–NO06 exposes +limits of the preceding single-response policy. Validate ownership before any result +effects, including old errors and history restoration, not only before moving focus. +A current response may update content/title/status while the user has moved focus +to another surviving task; an obsolete response may own none of those effects. +The latest-intent policy tested here does not revive older success when newer intent +fails. Ignoring completion does not abort or undo server work. + +A scoped navigation generation and separate focus-change check meet the tested +obligations. Their history adapter depends on pinned htmx internals; multiple history +misses, nonzero swap delays, redirects, lifecycle teardown and AT validation remain +open. Do not apply this navigation policy indiscriminately to unrelated background work. diff --git a/research/candidates/URLAddressableState.md b/research/candidates/URLAddressableState.md index 1932fed..4b98984 100644 --- a/research/candidates/URLAddressableState.md +++ b/research/candidates/URLAddressableState.md @@ -47,3 +47,19 @@ a fragment served as a full document in Chromium and Firefox; correct selection keeps representations distinct, without promising cache retention or freshness. See [NH01–NH06](../reviews/NavigationHistoryExperiment.md). One authored application with a real package, not independent deployed recurrence. Hypothesis retained. + +## Competing completion ownership — 2026-09-27 + +[NO01–NO06](../reviews/NavigationOwnershipExperiment.md) show a delayed history response +replacing content/title while a newer URL remains selected in the unguarded fixture. +Treat navigation initiation, including Back/Forward, as intent with an explicit +completion owner. Before applying an asynchronous result, check that it still owns +the selected route; include URL, content, title and feedback in that decision. +A response to obsolete intent is not made current by arriving last or succeeding. + +The experiment's latest-intent policy keeps the last committed view and newest error +when a newer request fails; it does not revive older pending navigation implicitly. +Other policies require an explicit contract. Browser history can change the URL before +loading completes: pending-state disclosure/recovery is still unresolved here. +The authored guard supports this obligation only in the tested schedules, not a +portable router or proof of independent application recurrence. diff --git a/research/catalog/SourceCatalog.md b/research/catalog/SourceCatalog.md index fca224d..8d30290 100644 --- a/research/catalog/SourceCatalog.md +++ b/research/catalog/SourceCatalog.md @@ -189,3 +189,10 @@ order and programmatically exposed feedback; no conformance claim from this fixt SRC-0040: [htmx events](https://htmx.org/events/), lifecycle-hook reference accessed 2026-09-27, living revision unknown. Same htmx family as SRC-0018/0019 and SRC-0038. Runtime conclusions use pinned 2.0.11 code and hashed receipts. + +SRC-0038 ownership follow-up, 2026-09-27: [NO01–NO06](../reviews/NavigationOwnershipExperiment.md) +compares the unchanged prior focus policy with an authored generation/focus guard. +24 completed rows, guard 12/12 full obligations versus baseline 0/12, with initial +keyboard-helper failures retained. Same fixture family and pinned htmx package. +SRC-0040 event documentation and pinned loadHistoryFromServer source delimit the +experimental history-XHR adapter; no vendor patch or production claim. diff --git a/research/evolution/EvolutionReport.md b/research/evolution/EvolutionReport.md index d301334..eb7d2e1 100644 --- a/research/evolution/EvolutionReport.md +++ b/research/evolution/EvolutionReport.md @@ -55,9 +55,9 @@ Ten selected retrospective outcomes (not a historical census), followed by prosp | inconclusive | 0 | | merge | 0 | | rejection | 0 | -| revision | 10 | +| revision | 11 | -Cycles with recorded research effort: 2/12. Unknown effort is neither zero nor estimated from commits, tokens or assertion counts. +Cycles with recorded research effort: 3/13. Unknown effort is neither zero nor estimated from commits, tokens or assertion counts. ### Stream B / B-navigation-mechanism-v1 @@ -75,6 +75,14 @@ One bounded question counts at most one consequential outcome. Corroboration and One bounded question counts at most one consequential outcome. Corroboration and inconclusive work remain visible separately. Fewer than three comparable cycles: no trend assessment. +### Stream F / F-navigation-ownership-v1 + +| Cycle | Outcome | Research minutes | Consequential outcome/hour | +| --- | --- | ---: | ---: | +| LEARN-0013 | revision | 13.918 | 4.31 | + +One bounded question counts at most one consequential outcome. Corroboration and inconclusive work remain visible separately. Fewer than three comparable cycles: no trend assessment. + ## Coherence and maintainability Profile hashes and local references passed validation when this report was generated. That checks traceability, not source truth or external URL freshness. @@ -222,8 +230,9 @@ Make a navigable state reconstructible from its URL. | documentary | htmx | History behavior and history-cache misses. | [NavigationRenderingEvidence](../../research/reviews/NavigationRenderingEvidence.md) | | documentary | Web platform | pushState changes history, not server dereferenceability. | [NavigationRenderingEvidence](../../research/reviews/NavigationRenderingEvidence.md) | | runtime | htmx in authored public-catalog fixture | NH01–NH06: native/enhanced routes, history hit/miss, actual browser cache ordering and missing-Vary negative control; explicit Node validator checks separate. | [NavigationHistoryExperiment](../../research/reviews/NavigationHistoryExperiment.md) | +| runtime | htmx in authored public-catalog fixture | NO01–NO06: ordered history/success/error races, prior policy 0/12 full obligations versus guarded 12/12; separate focus ownership. Same fixture family; pinned history-XHR adapter. | [NavigationOwnershipExperiment](../../research/reviews/NavigationOwnershipExperiment.md) | -Open limits: Independent deployed full-contract recurrence remains unverified. Keyboard/focus/announcements, late-script activation, interrupted transport, invalid/deleted routes, offline availability and real intermediary behavior remain open. +Open limits: Independent application recurrence and human/AT validation remain unverified. Pending history disclosure, multiple history misses, redirects, nonzero swap delays, bfcache, lifecycle cleanup, interrupted/late enhancement and offline availability remain open. Superseded by: none recorded. @@ -239,8 +248,9 @@ Keep essential actions usable when enhancement is unavailable. | documentary | SvelteKit | Form actions and rendering/page options. | [NavigationRenderingEvidence](../../research/reviews/NavigationRenderingEvidence.md) | | runtime | htmx in authored public-catalog fixture | NH01–NH06: native/enhanced routes, history hit/miss, actual browser cache ordering and missing-Vary negative control; explicit Node validator checks separate. | [NavigationHistoryExperiment](../../research/reviews/NavigationHistoryExperiment.md) | | runtime | htmx in authored public-catalog fixture | NF01–NF06: Tab/Enter navigation, raw versus authored focus/status policy, held-response ownership and background update; DOM evidence only, not AT speech. | [NavigationFocusExperiment](../../research/reviews/NavigationFocusExperiment.md) | +| runtime | htmx in authored public-catalog fixture | NO01–NO06: ordered history/success/error races, prior policy 0/12 full obligations versus guarded 12/12; separate focus ownership. Same fixture family; pinned history-XHR adapter. | [NavigationOwnershipExperiment](../../research/reviews/NavigationOwnershipExperiment.md) | -Open limits: Independent deployed full-contract recurrence and human/AT validation remain unverified. Focus visibility, delayed history, overlapping requests, late-script activation, interrupted transport, invalid/deleted routes, offline availability and real intermediaries remain open. +Open limits: Independent application recurrence and human/AT validation remain unverified. Pending history disclosure, multiple history misses, redirects, nonzero swap delays, bfcache, lifecycle cleanup, interrupted/late enhancement and offline availability remain open. Superseded by: none recorded. @@ -328,8 +338,9 @@ Restore meaningful focus after a temporary interaction ends. | static-code | Radix | Pinned layer/listener ownership implementation. | [NestedDismissalIsolation](../../research/reviews/NestedDismissalIsolation.md) | | runtime | Radix | Authored fixture: raw 20/24 versus routed 24/24; browser/build limits retained. | [NestedOwnershipRouting](../../research/reviews/NestedOwnershipRouting.md) | | runtime | htmx in authored public-catalog fixture | NF01–NF06: Tab/Enter navigation, raw versus authored focus/status policy, held-response ownership and background update; DOM evidence only, not AT speech. | [NavigationFocusExperiment](../../research/reviews/NavigationFocusExperiment.md) | +| runtime | htmx in authored public-catalog fixture | NO01–NO06: ordered history/success/error races, prior policy 0/12 full obligations versus guarded 12/12; separate focus ownership. Same fixture family; pinned history-XHR adapter. | [NavigationOwnershipExperiment](../../research/reviews/NavigationOwnershipExperiment.md) | -Open limits: One implementation family; repeated trials are not independent uses. Animated exits and competing owners remain untested; no production repair claim. Route continuation is a contrasting context, not independent modal-pattern recurrence; delayed history and AT speech unverified. +Open limits: One implementation family; repeated trials are not independent uses. Animated exits and competing owners remain untested; no production repair claim. Route ownership is a contrast, not independent modal recurrence; AT speech and broader history/lifecycle cases remain unverified. Superseded by: none recorded. @@ -519,3 +530,17 @@ Evidence: [NavigationFocusExperiment](../../research/reviews/NavigationFocusExpe Remaining uncertainty: Author-model DOM evidence, no human/AT validation or independent recurrence. Delayed history focus, competing requests, delayed scripts and interrupted enhancement remain open. Supersedes: none recorded. + +### LEARN-0013 — Can obsolete history/navigation completions affect newer intent, and does separating completion ownership from focus ownership prevent it? + +2026-09-27 · stream F · prospective · revision + +Before: The single-response continuation policy preserved newer search focus but left competing history/success/error completions unresolved; focus-at-swap alone might not be sufficient. + +Conclusion: Revise operational guidance: validate navigation ownership before content/URL/title/feedback effects, including stale errors and newer failure, independently of focus permission. Prior policy misses obligations in 12/12 adversarial rows; authored guard meets 12/12. Pause fixture work for independent source contrast. + +Evidence: [NavigationOwnershipExperiment](../../research/reviews/NavigationOwnershipExperiment.md), [NavigationThreadReview](../../research/reviews/NavigationThreadReview.md), [ownership-result](../../research/experiments/navigation-history/ownership-result.json), [2026-09-27-navigation-ownership-effort](../../research/evolution/cycles/2026-09-27-navigation-ownership-effort.json). + +Remaining uncertainty: One authored htmx family and author-model review, not production recurrence or AT validation. History adapter is pinned implementation-dependent; pending-state, multiple-miss and lifecycle limits remain open. Three distinct protocols are not a comparable diminishing-returns window. + +Supersedes: none recorded. diff --git a/research/evolution/cycles/2026-09-27-navigation-ownership-effort.json b/research/evolution/cycles/2026-09-27-navigation-ownership-effort.json new file mode 100644 index 0000000..fdea88f --- /dev/null +++ b/research/evolution/cycles/2026-09-27-navigation-ownership-effort.json @@ -0,0 +1,42 @@ +{ + "start": 199629.983211976, + "execution_seconds": 74.26050614900305, + "executions": [ + { + "command": [ + "node", + "research/experiments/navigation-history/ownership.mjs" + ], + "seconds": 23.363541921018623, + "exit_code": 1 + }, + { + "command": [ + "node", + "research/experiments/navigation-history/ownership.mjs" + ], + "seconds": 37.19569087898708, + "exit_code": 0 + }, + { + "command": [ + "make", + "evolution-check", + "evolution-test", + "schema-test", + "bench-test" + ], + "seconds": 13.701273348997347, + "exit_code": 0 + } + ], + "status": "complete", + "end_utc": "2026-09-26T22:45:32.069777+00:00", + "start_utc_approx": "2026-09-26T22:30:22.733700+00:00", + "elapsed_seconds": 909.336, + "research_minutes": 13.918, + "execution_minutes": 1.238, + "method": "Monotonic single-agent session minus timed experiment/check subprocess intervals. Initial harness failures and corrected run both retained in execution. Checkpoint inspection assigned to execution, not double-counted.", + "excluded": "Orientation before start and final receipt refresh, commits, snapshot, decision/progress logging and sync after cutoff; unknown model tokens/cost.", + "budget": "Within registered 45 active / 10 execution minute budget; no scope extension." +} diff --git a/research/evolution/cycles/2026-09-27-navigation-ownership.md b/research/evolution/cycles/2026-09-27-navigation-ownership.md new file mode 100644 index 0000000..6722b03 --- /dev/null +++ b/research/evolution/cycles/2026-09-27-navigation-ownership.md @@ -0,0 +1,64 @@ +# LEARN-0013 — Completion ownership under competing navigation + +Status: preregistered before implementation/execution. 2026-09-27 Europe/Berlin. +Codex author-model review; stream F, new comparison group F-navigation-ownership-v1. +The multi-request question differs from the single-response focus protocol; do not +pool rates. CAND-0009 URL-addressable State, CAND-0010 Progressive Enhancement, +CAND-0016 Focus Return. No new candidate presumed. + +## Question and prior + +Can the previous managed focus policy let old history/navigation completions replace +newer selection, steal focus or report obsolete results? Prior single-request evidence +supports continuation but leaves competing completions untested. Proposed guard: +assign an owner/generation to navigation, reject stale completions before effects, +and track focus ownership independently so an otherwise valid response need not +move focus. Test outcome, not a blanket recommendation to cancel HTTP requests. + +Compare the unchanged prior focus-policy.js with an authored guarded policy on one +new controlled fixture. Use stable content target and persistent navigation controls +so requests from different elements can compete. Hold responses at server barriers, +then release in declared order. Browser history uses real Back with htmx snapshot +eviction. Keep default transport alive to distinguish ignored completion from abort. +If htmx prevents a race itself, record that rather than force a failure. A guarded +miss/error or URL/content mismatch is failure, not permission to revise expectations. + +## Registered matrix + +Two policies × two browsers (Chromium/Firefox), six cases = 24 rows. Baseline rows +record the same obligation booleans as guarded rows; distinguish successful recording +from meeting the obligations. Guarded rows assert all registered obligations. One +trial each; preserve failures and any correction. No arbitrary sleeps. Tab/Enter +activate links; browser Back uses history API through Playwright. + +| ID | Ordered scenario | Obligation after completion | +| --- | --- | --- | +| O01 | Back misses history cache; user moves to surviving search; release history | Restore selected article/URL/title but preserve search focus and typed text | +| O02 | Back miss held; newer article navigation completes; release old history | Keep newer article/URL/title/status/focus; old history completion has no UI effect | +| O03 | Older article request held; newer article completes; release older success | Keep newer article/URL/title/status; no late focus theft | +| O04 | Older request held and will fail; newer article completes; release old 503 | Preserve newer result and feedback; no obsolete error replaces completion | +| O05 | Older request held; newer request fails; then release older success | Do not resurrect older intent; retain last committed view with newest failure feedback | +| O06 | Older article held; Back restores cached view; release old success | History is newer intent too: keep restored view/URL/title/status/focus | + +O05 starts from an already committed alpha view; O06 first visits beta to establish +history. Distinguish committed route from pending browser-history URL. Capture +intermediate and final state, actual requests and completion traces. Prefer public +hooks; any history-XHR callback wrapping is explicitly pinned/experimental, not a +portable production fix. No writes, server rollback, AT speech, production recurrence, +nonzero swap delays, view transitions, redirect/error taxonomy or universal race proof. + +## Learning and stopping + +45 active research minutes and 10 execution minutes before scope review. Monotonic +single-agent elapsed session minus experiment/check subprocess durations; checkpoint +inspection belongs to execution, no double count. Orientation and final administration +outside window; tokens/cost unknown. Commit this plan before implementation/execution. +Append one ledger outcome; retain all results and source hashes. If scope/criteria +must change, preserve and disclose the original plan rather than rewriting it. + +After this comparison, pause the navigation-fixture thread. Write a short synthesis: +what changed versus prior claims, what remains unverified, and the next independent +or broader evidence question. Hand residuals to WP-0003 T01/T02 and measurement work +to WP-0006 T03. Do not automatically start another fixture hardening cycle. One cycle +per distinct group cannot demonstrate diminishing returns. Live inference, if needed, +uses llm-connect; none is planned here. diff --git a/research/evolution/ledger.json b/research/evolution/ledger.json index f4e41a4..4078cc0 100644 --- a/research/evolution/ledger.json +++ b/research/evolution/ledger.json @@ -410,6 +410,46 @@ "cost_usd": null }, "supersedes": [] + }, + { + "id": "LEARN-0013", + "date": "2026-09-27", + "recording": "prospective", + "stream": "F", + "comparison_group": "F-navigation-ownership-v1", + "protocol_ref": "research/evolution/cycles/2026-09-27-navigation-ownership.md", + "question": "Can obsolete history/navigation completions affect newer intent, and does separating completion ownership from focus ownership prevent it?", + "previous_belief": "The single-response continuation policy preserved newer search focus but left competing history/success/error completions unresolved; focus-at-swap alone might not be sufficient.", + "conclusion": "Revise operational guidance: validate navigation ownership before content/URL/title/feedback effects, including stale errors and newer failure, independently of focus permission. Prior policy misses obligations in 12/12 adversarial rows; authored guard meets 12/12. Pause fixture work for independent source contrast.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0009", + "CAND-0010", + "CAND-0016" + ], + "evidence": [ + "research/reviews/NavigationOwnershipExperiment.md", + "research/reviews/NavigationThreadReview.md", + "research/experiments/navigation-history/ownership-result.json", + "research/evolution/cycles/2026-09-27-navigation-ownership-effort.json" + ], + "remaining_uncertainty": [ + "One authored htmx family and author-model review, not production recurrence or AT validation.", + "History adapter is pinned implementation-dependent; pending-state, multiple-miss and lifecycle limits remain open.", + "Three distinct protocols are not a comparable diminishing-returns window." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": 13.918, + "execution_minutes": 1.238, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] } ] } diff --git a/research/evolution/profiles.json b/research/evolution/profiles.json index 7dcf782..ac0586a 100644 --- a/research/evolution/profiles.json +++ b/research/evolution/profiles.json @@ -317,7 +317,7 @@ "id": "CAND-0009", "path": "research/candidates/URLAddressableState.md", "title": "URL-addressable State", - "sha256": "3edc087c5b4b0a332dd9097334022cdb138437413b933f271e5cf96096cc63be", + "sha256": "7374180994e13cbca7b1dd4cf4da27c36926e462e844bbc0beb42e5ef6e562f5", "status": "draft", "maturity": "hypothesis", "decision": "Make a navigable state reconstructible from its URL.", @@ -339,6 +339,12 @@ "family": "htmx in authored public-catalog fixture", "ref": "research/reviews/NavigationHistoryExperiment.md", "scope": "NH01–NH06: native/enhanced routes, history hit/miss, actual browser cache ordering and missing-Vary negative control; explicit Node validator checks separate." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationOwnershipExperiment.md", + "scope": "NO01–NO06: ordered history/success/error races, prior policy 0/12 full obligations versus guarded 12/12; separate focus ownership. Same fixture family; pinned history-XHR adapter." } ], "independent_full_contract_uses": null, @@ -350,8 +356,8 @@ "last_substantive_review_date": "2026-09-27" }, "gaps": [ - "Independent deployed full-contract recurrence remains unverified.", - "Keyboard/focus/announcements, late-script activation, interrupted transport, invalid/deleted routes, offline availability and real intermediary behavior remain open." + "Independent application recurrence and human/AT validation remain unverified.", + "Pending history disclosure, multiple history misses, redirects, nonzero swap delays, bfcache, lifecycle cleanup, interrupted/late enhancement and offline availability remain open." ], "superseded_by": [] }, @@ -359,7 +365,7 @@ "id": "CAND-0010", "path": "research/candidates/ProgressiveEnhancement.md", "title": "Progressive Enhancement", - "sha256": "ec3ab16d680308593af4d22fbbcbea737fe46096c5f3e65968d0db3a8befec21", + "sha256": "3eebc18862e1f5cd0221fa72f468a74719e7fbeab407cc81930d9e4ea397b3b5", "status": "draft", "maturity": "hypothesis", "decision": "Keep essential actions usable when enhancement is unavailable.", @@ -387,6 +393,12 @@ "family": "htmx in authored public-catalog fixture", "ref": "research/reviews/NavigationFocusExperiment.md", "scope": "NF01–NF06: Tab/Enter navigation, raw versus authored focus/status policy, held-response ownership and background update; DOM evidence only, not AT speech." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationOwnershipExperiment.md", + "scope": "NO01–NO06: ordered history/success/error races, prior policy 0/12 full obligations versus guarded 12/12; separate focus ownership. Same fixture family; pinned history-XHR adapter." } ], "independent_full_contract_uses": null, @@ -398,8 +410,8 @@ "last_substantive_review_date": "2026-09-27" }, "gaps": [ - "Independent deployed full-contract recurrence and human/AT validation remain unverified.", - "Focus visibility, delayed history, overlapping requests, late-script activation, interrupted transport, invalid/deleted routes, offline availability and real intermediaries remain open." + "Independent application recurrence and human/AT validation remain unverified.", + "Pending history disclosure, multiple history misses, redirects, nonzero swap delays, bfcache, lifecycle cleanup, interrupted/late enhancement and offline availability remain open." ], "superseded_by": [] }, @@ -566,7 +578,7 @@ "id": "CAND-0016", "path": "research/candidates/FocusReturn.md", "title": "Focus Return", - "sha256": "129ef7623d11da91f3f5429686455be16180e5477d1706836f5c1c3617698eae", + "sha256": "a09b79e3b481caab81a7f9ee10d895ba77c6c7eedb71f4313733735eea58a477", "status": "draft", "maturity": "hypothesis", "decision": "Restore meaningful focus after a temporary interaction ends.", @@ -594,6 +606,12 @@ "family": "htmx in authored public-catalog fixture", "ref": "research/reviews/NavigationFocusExperiment.md", "scope": "NF01–NF06: Tab/Enter navigation, raw versus authored focus/status policy, held-response ownership and background update; DOM evidence only, not AT speech." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationOwnershipExperiment.md", + "scope": "NO01–NO06: ordered history/success/error races, prior policy 0/12 full obligations versus guarded 12/12; separate focus ownership. Same fixture family; pinned history-XHR adapter." } ], "independent_full_contract_uses": null, @@ -607,7 +625,7 @@ "gaps": [ "One implementation family; repeated trials are not independent uses.", "Animated exits and competing owners remain untested; no production repair claim.", - "Route continuation is a contrasting context, not independent modal-pattern recurrence; delayed history and AT speech unverified." + "Route ownership is a contrast, not independent modal recurrence; AT speech and broader history/lifecycle cases remain unverified." ], "superseded_by": [] }, diff --git a/research/evolution/snapshots/cycle-2026-09-27-navigation-ownership.json b/research/evolution/snapshots/cycle-2026-09-27-navigation-ownership.json new file mode 100644 index 0000000..f644593 --- /dev/null +++ b/research/evolution/snapshots/cycle-2026-09-27-navigation-ownership.json @@ -0,0 +1,1214 @@ +{ + "schema_version": 1, + "id": "cycle-2026-09-27-navigation-ownership", + "source_revision": "e8ccb73a12b485d9845882134869fc1c5447fc4c", + "assessment": { + "profiles": { + "schema_version": 1, + "assessed_at": "2026-09-27", + "profiles": [ + { + "id": "CAND-0001", + "path": "research/candidates/ConflictCopy.md", + "title": "Conflict Copy", + "sha256": "24f250d89ac17d96df287d67c275b5320b48c8356b57ae126a6c941e92a1c6e9", + "status": "draft", + "maturity": "hypothesis", + "decision": "Preserve competing versions instead of silently losing one.", + "evidence": [ + { + "kind": "documentary", + "family": "Joplin", + "ref": "research/reviews/LocalFirstEvidenceExpansion.md", + "scope": "Documented detected-note conflict copy." + }, + { + "kind": "documentary", + "family": "Obsidian", + "ref": "research/reviews/LocalFirstEvidenceExpansion.md", + "scope": "Optional conflict-file mode, not default behavior." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "Authorized retention and export are separate decisions.", + "Complete contract recurrence and fault-tested deployed behavior remain unverified." + ], + "superseded_by": [] + }, + { + "id": "CAND-0002", + "path": "research/candidates/LocalCommitBoundary.md", + "title": "Local Commit Boundary", + "sha256": "22165fc2979e8f4d8859b34417cb71e7b5ec7a8440ad045aee2383d499648013", + "status": "draft", + "maturity": "hypothesis", + "decision": "Define when a local change is durably accepted.", + "evidence": [ + { + "kind": "documentary", + "family": "Ink & Switch", + "ref": "research/reviews/LocalFirstEvidenceExpansion.md", + "scope": "Local-first motivation." + }, + { + "kind": "documentary", + "family": "Joplin", + "ref": "research/reviews/LocalFirstEvidenceExpansion.md", + "scope": "Local storage and synchronization architecture." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "No executed storage crash or backup test.", + "Local acceptance is not off-device recovery." + ], + "superseded_by": [] + }, + { + "id": "CAND-0003", + "path": "research/candidates/PendingSynchronization.md", + "title": "Pending Synchronization", + "sha256": "9c5cb0f4ea4e6f4406ce55513ca2c252172427a49d8280ae1a9c713f1d11b070", + "status": "draft", + "maturity": "hypothesis", + "decision": "Keep accepted local intent visible until synchronization resolves.", + "evidence": [ + { + "kind": "documentary", + "family": "Joplin", + "ref": "research/reviews/LocalFirstEvidenceExpansion.md", + "scope": "Per-item synchronization metadata." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "Atomic supersession and retry contract proposed, not storage-tested." + ], + "superseded_by": [] + }, + { + "id": "CAND-0004", + "path": "research/candidates/ExplicitReconciliation.md", + "title": "Explicit Reconciliation", + "sha256": "d48a40aab7417b8b8f8406094c84b9e90d0ca8c2f94d6e616d0b80499dc04959", + "status": "draft", + "maturity": "hypothesis", + "decision": "Resolve divergent content while retaining provenance.", + "evidence": [ + { + "kind": "documentary", + "family": "Joplin", + "ref": "research/reviews/LocalFirstEvidenceExpansion.md", + "scope": "Documented manual conflict resolution." + }, + { + "kind": "documentary", + "family": "Obsidian", + "ref": "research/reviews/LocalFirstEvidenceExpansion.md", + "scope": "Conflict comparison workflow." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "Atomic resolution/provenance UI not executed.", + "Overlap with Conflict Copy remains an open merge question." + ], + "superseded_by": [] + }, + { + "id": "CAND-0005", + "path": "research/candidates/LocalDraftState.md", + "title": "Local Draft State", + "sha256": "8e5f427975c76083c80b895bc68b7130b249be5129c2854f3df11cc374b4b240", + "status": "draft", + "maturity": "hypothesis", + "decision": "Separate unfinished intent from refreshed authoritative data.", + "evidence": [ + { + "kind": "documentary", + "family": "Kubernetes / GitLab / React Router", + "ref": "research/reviews/TransactionalEvidenceExpansion.md", + "scope": "Rejection and pending-input mechanisms motivate recovery." + }, + { + "kind": "static-code", + "family": "Zulip", + "ref": "research/reviews/FrontendRecoveryImplementations.md", + "scope": "Pinned composer draft storage; partial lifecycle." + }, + { + "kind": "static-code", + "family": "Element / Matrix", + "ref": "research/reviews/FrontendRecoveryImplementations.md", + "scope": "Pinned composer draft restoration; partial lifecycle." + }, + { + "kind": "runtime", + "family": "authored release fixture", + "ref": "research/reviews/ActivationConflictsAndReload.md", + "scope": "Same-tab preservation/refusal/discard and post-navigation schema check." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "No native-unload, crash, multiple-tab or access-revocation guarantee.", + "Full base/draft/current merge contract is not verified in deployed frontends." + ], + "superseded_by": [] + }, + { + "id": "CAND-0006", + "path": "research/candidates/VersionCheckedMutation.md", + "title": "Version-Checked Mutation", + "sha256": "6a3335ae2fa1de51c95dcbfa8d766d988a3f7a9604fb608b8a0bcf9a10b64198", + "status": "draft", + "maturity": "hypothesis", + "decision": "Reject an operation whose observed base is stale.", + "evidence": [ + { + "kind": "documentary", + "family": "Kubernetes", + "ref": "research/reviews/TransactionalEvidenceExpansion.md", + "scope": "Conditional PUT; precise version mechanism." + }, + { + "kind": "documentary", + "family": "GitLab", + "ref": "research/reviews/TransactionalEvidenceExpansion.md", + "scope": "Optional last_commit_id; different failure surface." + }, + { + "kind": "runtime", + "family": "authored release fixture", + "ref": "research/reviews/ActivationConflictsAndReload.md", + "scope": "Related conditional activation-map mechanism in one process, not the full frontend pattern." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "Distributed atomicity and complete frontend recurrence remain unverified.", + "Refetch does not authorize overwriting conflicting intent." + ], + "superseded_by": [] + }, + { + "id": "CAND-0007", + "path": "research/candidates/MutationOutcomeTracking.md", + "title": "Mutation Outcome Tracking", + "sha256": "e04cb835fd054bfaf88616375bd0262deffb2801ea04105be92543bfa9582179", + "status": "draft", + "maturity": "hypothesis", + "decision": "Retain operation identity when transport outcome is uncertain.", + "evidence": [ + { + "kind": "documentary", + "family": "Stripe", + "ref": "research/reviews/TransactionalEvidenceExpansion.md", + "scope": "Idempotency mechanism." + }, + { + "kind": "documentary", + "family": "React Router", + "ref": "research/reviews/TransactionalEvidenceExpansion.md", + "scope": "Cancellation does not imply server rollback." + }, + { + "kind": "static-code", + "family": "Zulip", + "ref": "research/reviews/FrontendRecoveryImplementations.md", + "scope": "Pinned send/recovery state." + }, + { + "kind": "static-code", + "family": "Element / Matrix", + "ref": "research/reviews/FrontendRecoveryImplementations.md", + "scope": "Pinned client and SDK transaction/echo paths." + }, + { + "kind": "runtime", + "family": "Element / Matrix", + "ref": "research/reviews/MatrixRecoveryExperiment.md", + "scope": "Real SDK with synthetic transport: lost acknowledgement, identity reuse and authoritative echo." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "No production server deduplication or complete retention-window guarantee.", + "Cancelling local UI is not remote compensation." + ], + "superseded_by": [] + }, + { + "id": "CAND-0008", + "path": "research/candidates/InvalidateAndReproject.md", + "title": "Invalidate and Reproject", + "sha256": "47c405adbc3caac2383768ed3d30b6a2e7ff1f44f4954c340049e78944227844", + "status": "draft", + "maturity": "hypothesis", + "decision": "Refresh a projection after mutation without equating acceptance and visibility.", + "evidence": [ + { + "kind": "documentary", + "family": "React Router", + "ref": "research/reviews/TransactionalEvidenceExpansion.md", + "scope": "Concurrency and pending-state guidance." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "Read-your-write and acceptance/refresh distinction still proposed.", + "No independent deployed full-contract observation." + ], + "superseded_by": [] + }, + { + "id": "CAND-0009", + "path": "research/candidates/URLAddressableState.md", + "title": "URL-addressable State", + "sha256": "7374180994e13cbca7b1dd4cf4da27c36926e462e844bbc0beb42e5ef6e562f5", + "status": "draft", + "maturity": "hypothesis", + "decision": "Make a navigable state reconstructible from its URL.", + "evidence": [ + { + "kind": "documentary", + "family": "htmx", + "ref": "research/reviews/NavigationRenderingEvidence.md", + "scope": "History behavior and history-cache misses." + }, + { + "kind": "documentary", + "family": "Web platform", + "ref": "research/reviews/NavigationRenderingEvidence.md", + "scope": "pushState changes history, not server dereferenceability." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationHistoryExperiment.md", + "scope": "NH01–NH06: native/enhanced routes, history hit/miss, actual browser cache ordering and missing-Vary negative control; explicit Node validator checks separate." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationOwnershipExperiment.md", + "scope": "NO01–NO06: ordered history/success/error races, prior policy 0/12 full obligations versus guarded 12/12; separate focus ownership. Same fixture family; pinned history-XHR adapter." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-27", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": "2026-09-27" + }, + "gaps": [ + "Independent application recurrence and human/AT validation remain unverified.", + "Pending history disclosure, multiple history misses, redirects, nonzero swap delays, bfcache, lifecycle cleanup, interrupted/late enhancement and offline availability remain open." + ], + "superseded_by": [] + }, + { + "id": "CAND-0010", + "path": "research/candidates/ProgressiveEnhancement.md", + "title": "Progressive Enhancement", + "sha256": "3eebc18862e1f5cd0221fa72f468a74719e7fbeab407cc81930d9e4ea397b3b5", + "status": "draft", + "maturity": "hypothesis", + "decision": "Keep essential actions usable when enhancement is unavailable.", + "evidence": [ + { + "kind": "documentary", + "family": "htmx", + "ref": "research/reviews/NavigationRenderingEvidence.md", + "scope": "Boosted links and forms." + }, + { + "kind": "documentary", + "family": "SvelteKit", + "ref": "research/reviews/NavigationRenderingEvidence.md", + "scope": "Form actions and rendering/page options." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationHistoryExperiment.md", + "scope": "NH01–NH06: native/enhanced routes, history hit/miss, actual browser cache ordering and missing-Vary negative control; explicit Node validator checks separate." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationFocusExperiment.md", + "scope": "NF01–NF06: Tab/Enter navigation, raw versus authored focus/status policy, held-response ownership and background update; DOM evidence only, not AT speech." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationOwnershipExperiment.md", + "scope": "NO01–NO06: ordered history/success/error races, prior policy 0/12 full obligations versus guarded 12/12; separate focus ownership. Same fixture family; pinned history-XHR adapter." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-27", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": "2026-09-27" + }, + "gaps": [ + "Independent application recurrence and human/AT validation remain unverified.", + "Pending history disclosure, multiple history misses, redirects, nonzero swap delays, bfcache, lifecycle cleanup, interrupted/late enhancement and offline availability remain open." + ], + "superseded_by": [] + }, + { + "id": "CAND-0011", + "path": "research/candidates/PresentationModel.md", + "title": "Presentation Model", + "sha256": "5ff03b5799b0a9e5ec6b54b21034720d89dbc8ffde7c4cdcf71616cdf57baf49", + "status": "draft", + "maturity": "hypothesis", + "decision": "Separate presentation decisions from view mechanisms.", + "evidence": [ + { + "kind": "documentary", + "family": "Fowler", + "ref": "research/reviews/PatternBreadthExpansion.md", + "scope": "Named pattern and illustrative model/view discussion." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "No executed model/view integration or independently reviewed full-contract use." + ], + "superseded_by": [] + }, + { + "id": "CAND-0012", + "path": "research/candidates/DerivedState.md", + "title": "Derived State", + "sha256": "9f29b9f1296a52b83f08dfd97437c4dc16e4949ddac1ff3b3830e3fc9831bd4f", + "status": "draft", + "maturity": "hypothesis", + "decision": "Compute a result from explicit authoritative inputs.", + "evidence": [ + { + "kind": "documentary", + "family": "Redux", + "ref": "research/reviews/PatternBreadthExpansion.md", + "scope": "Selector guidance, not a requirement for a global store." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "Snapshot coherence and changed-locale cache test still planned." + ], + "superseded_by": [] + }, + { + "id": "CAND-0013", + "path": "research/candidates/VerticalFeatureSlice.md", + "title": "Vertical Feature Slice", + "sha256": "d6b332b9c104a079bd4b72512b8ddd1a889199b2e2e531753c411688053e647a", + "status": "draft", + "maturity": "hypothesis", + "decision": "Group a capability across UI, state and behavior with explicit interfaces.", + "evidence": [ + { + "kind": "documentary", + "family": "Feature-Sliced Design", + "ref": "research/reviews/PatternBreadthExpansion.md", + "scope": "Layer/slice and public-interface guidance." + }, + { + "kind": "static-code", + "family": "Feature-Sliced Design", + "ref": "research/reviews/FeatureDeploymentBoundaries.md", + "scope": "Pinned todo-app interfaces coexist with one application build." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "Build/import enforcement not executed.", + "Feature organization does not establish independent activation." + ], + "superseded_by": [] + }, + { + "id": "CAND-0014", + "path": "research/candidates/IslandsOfInteractivity.md", + "title": "Islands of Interactivity", + "sha256": "821a1497da10c02ae11fa6f56cb8e205a4f32c40b39770ab8ca3f907561a260a", + "status": "draft", + "maturity": "hypothesis", + "decision": "Activate selected interactive regions within a document.", + "evidence": [ + { + "kind": "documentary", + "family": "Astro", + "ref": "research/reviews/PatternBreadthExpansion.md", + "scope": "Client-island mechanism and execution placement." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "No executed island fixture, performance comparison or complete recurrence study." + ], + "superseded_by": [] + }, + { + "id": "CAND-0015", + "path": "research/candidates/FailureBoundary.md", + "title": "Failure Boundary", + "sha256": "a6e76ed17a92baade683d5df96fa8ecd066c593661e6a14983a86d046e7d9c2c", + "status": "draft", + "maturity": "hypothesis", + "decision": "Contain specified failure classes while preserving useful neighboring work.", + "evidence": [ + { + "kind": "documentary", + "family": "React", + "ref": "research/reviews/PatternBreadthExpansion.md", + "scope": "Error boundary scope and exclusions." + }, + { + "kind": "runtime", + "family": "React", + "ref": "research/reviews/BoundaryRecoveryExperiment.md", + "scope": "Real package in authored host: render/event/request distinction and fallback escalation." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "Synthetic host, not full application recurrence.", + "Boundary cannot imply containment for all asynchronous failures." + ], + "superseded_by": [] + }, + { + "id": "CAND-0016", + "path": "research/candidates/FocusReturn.md", + "title": "Focus Return", + "sha256": "a09b79e3b481caab81a7f9ee10d895ba77c6c7eedb71f4313733735eea58a477", + "status": "draft", + "maturity": "hypothesis", + "decision": "Restore meaningful focus after a temporary interaction ends.", + "evidence": [ + { + "kind": "documentary", + "family": "WAI-ARIA APG", + "ref": "research/reviews/PatternBreadthExpansion.md", + "scope": "Dialog focus obligations." + }, + { + "kind": "static-code", + "family": "Radix", + "ref": "research/reviews/NestedDismissalIsolation.md", + "scope": "Pinned layer/listener ownership implementation." + }, + { + "kind": "runtime", + "family": "Radix", + "ref": "research/reviews/NestedOwnershipRouting.md", + "scope": "Authored fixture: raw 20/24 versus routed 24/24; browser/build limits retained." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationFocusExperiment.md", + "scope": "NF01–NF06: Tab/Enter navigation, raw versus authored focus/status policy, held-response ownership and background update; DOM evidence only, not AT speech." + }, + { + "kind": "runtime", + "family": "htmx in authored public-catalog fixture", + "ref": "research/reviews/NavigationOwnershipExperiment.md", + "scope": "NO01–NO06: ordered history/success/error races, prior policy 0/12 full obligations versus guarded 12/12; separate focus ownership. Same fixture family; pinned history-XHR adapter." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-27", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": "2026-09-27" + }, + "gaps": [ + "One implementation family; repeated trials are not independent uses.", + "Animated exits and competing owners remain untested; no production repair claim.", + "Route ownership is a contrast, not independent modal recurrence; AT speech and broader history/lifecycle cases remain unverified." + ], + "superseded_by": [] + }, + { + "id": "CAND-0017", + "path": "research/candidates/IndependentFeatureBoundary.md", + "title": "Independent Feature Boundary", + "sha256": "60b78725ed4036681675d4c68244fc25aea6e0dffb09d54a7108e3fcbf527b4f", + "status": "draft", + "maturity": "hypothesis", + "decision": "Separate feature release, activation and session transition contracts.", + "evidence": [ + { + "kind": "documentary", + "family": "single-spa / webpack", + "ref": "research/reviews/FeatureDeploymentBoundaries.md", + "scope": "Mechanism documentation, not deployed independence proof." + }, + { + "kind": "static-code", + "family": "react-microfrontends examples", + "ref": "research/reviews/FeatureDeploymentBoundaries.md", + "scope": "Root config/navbar are one example family with shared startup gating." + }, + { + "kind": "runtime", + "family": "authored release fixture", + "ref": "research/reviews/FeatureReleaseExperiment.md", + "scope": "Publication/activation/rollback across fresh, loaded and lazy sessions." + }, + { + "kind": "runtime", + "family": "authored release fixture", + "ref": "research/reviews/ActivationConflictsAndReload.md", + "scope": "Conditional activation updates and safe reload policies, including negative controls." + } + ], + "independent_full_contract_uses": null, + "review": { + "assessed_at": "2026-09-26", + "reviewer": "Codex", + "role": "author-model", + "independent_human": false, + "last_substantive_review_date": null + }, + "gaps": [ + "No upstream deployment or real team/release-independence validation.", + "Distributed atomicity, retention authorization and native-unload/crash behavior remain open." + ], + "superseded_by": [] + } + ] + }, + "ledger": { + "schema_version": 1, + "coverage": "Ten selected retrospective outcomes (not a historical census), followed by prospectively registered bounded cycles. Retrospective effort remains unknown.", + "events": [ + { + "id": "LEARN-0001", + "date": "2026-09-25", + "recording": "retrospective", + "stream": "D", + "comparison_group": null, + "question": "What do pinned recovery implementations establish?", + "previous_belief": "Documentary motivation did not locate draft/outcome mechanisms in frontend code.", + "conclusion": "Zulip and Element locate partial draft/outcome mechanisms; complete pattern recurrence is still unknown.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0005", + "CAND-0007" + ], + "evidence": [ + "research/reviews/FrontendRecoveryImplementations.md" + ], + "remaining_uncertainty": [ + "Deployed full lifecycle remains unverified." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0002", + "date": "2026-09-25", + "recording": "retrospective", + "stream": "D", + "comparison_group": null, + "question": "Does cancellation or a transport error settle mutation outcome?", + "previous_belief": "Recovery identity and authoritative echo required executable checks.", + "conclusion": "Synthetic transport with the real Matrix SDK distinguishes replay identity, duplicate commits and authoritative echo.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0007" + ], + "evidence": [ + "research/reviews/MatrixRecoveryExperiment.md" + ], + "remaining_uncertainty": [ + "No real server deduplication guarantee." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0003", + "date": "2026-09-26", + "recording": "retrospective", + "stream": "cross-stream", + "comparison_group": null, + "question": "Does naming patterns improve the frozen pilot decisions?", + "previous_belief": "Initial editorial scores were 21/24 named and 19/24 prose.", + "conclusion": "Submitted model review adjudication yields 18/24 in each condition; this does not establish equivalence or a presentation benefit.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0005", + "CAND-0007", + "CAND-0001", + "CAND-0002" + ], + "evidence": [ + "research/evaluations/language-pilot-01/submitted-review-01/adjudication.md" + ], + "remaining_uncertainty": [ + "Independent human validation pending.", + "Historical effort unknown; this entry does not allocate whole-pilot telemetry." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0004", + "date": "2026-09-26", + "recording": "retrospective", + "stream": "D", + "comparison_group": null, + "question": "Which recovery recommendations overstate their guarantees?", + "previous_belief": "Shared guidance left retention/export policy, cancellation and local backup boundaries insufficiently explicit.", + "conclusion": "Guidance now separates authorization, remote compensation, atomic supersession and off-device backup.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0001", + "CAND-0002", + "CAND-0003", + "CAND-0005", + "CAND-0007" + ], + "evidence": [ + "research/reviews/SharedGuidanceRevision.md" + ], + "remaining_uncertainty": [ + "Editorial correction is not new production evidence." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0005", + "date": "2026-09-26", + "recording": "retrospective", + "stream": "B", + "comparison_group": null, + "question": "What does URL/history and enhancement documentation actually promise?", + "previous_belief": "Navigation and rendering seeds lacked explicit dereferenceability and fallback distinctions.", + "conclusion": "Developed two hypotheses separating address-bar updates from direct loads, and HTML delivery from usable no-script actions.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0009", + "CAND-0010" + ], + "evidence": [ + "research/reviews/NavigationRenderingEvidence.md" + ], + "remaining_uncertainty": [ + "Navigation/history/cache runtime checks remain pending." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0006", + "date": "2026-09-26", + "recording": "retrospective", + "stream": "F", + "comparison_group": null, + "question": "Why can immediate nested dismissal close the outer task?", + "previous_belief": "The first fixture exposed a timing failure with unresolved ownership.", + "conclusion": "Trace locates stale Escape listener ownership despite inner registration/focus; a guard can lose input.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0016", + "CAND-0015" + ], + "evidence": [ + "research/reviews/BoundaryRecoveryExperiment.md", + "research/reviews/NestedDismissalIsolation.md" + ], + "remaining_uncertainty": [ + "Readiness waits are not a public product repair." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0007", + "date": "2026-09-26", + "recording": "retrospective", + "stream": "F", + "comparison_group": null, + "question": "Can event-time ownership route dismissal without a settling delay?", + "previous_belief": "Isolation supplied a mechanism but no lifecycle-safe candidate routing experiment.", + "conclusion": "Controlled fixture routed 24/24 versus raw 20/24; initial measurement error and corrected results retained.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0016" + ], + "evidence": [ + "research/reviews/NestedOwnershipRouting.md" + ], + "remaining_uncertainty": [ + "Animated exit and competing-owner coverage remain open." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0008", + "date": "2026-09-26", + "recording": "retrospective", + "stream": "E", + "comparison_group": null, + "question": "Are feature organization and independent activation the same boundary?", + "previous_belief": "The feature-slice hypothesis needed a source-layout/release contrast.", + "conclusion": "Pinned examples distinguish organizational slicing from activation contracts; added Independent Feature Boundary.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0013", + "CAND-0017" + ], + "evidence": [ + "research/reviews/FeatureDeploymentBoundaries.md" + ], + "remaining_uncertainty": [ + "Shared startup dependencies still couple nominally separate features." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0009", + "date": "2026-09-26", + "recording": "retrospective", + "stream": "E", + "comparison_group": null, + "question": "Does publication or rollback update every session?", + "previous_belief": "Static source review could not establish loaded/lazy-session behavior.", + "conclusion": "Native-module experiment distinguishes publication, activation and already-bound sessions; artifact retirement breaks old lazy sessions.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0017" + ], + "evidence": [ + "research/reviews/FeatureReleaseExperiment.md" + ], + "remaining_uncertainty": [ + "No CDN or upstream deployment validation." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0010", + "date": "2026-09-26", + "recording": "retrospective", + "stream": "E", + "comparison_group": null, + "question": "How do stale activation writers and unfinished drafts constrain updates?", + "previous_belief": "Release experiment left activation conflicts and reload policy unexecuted.", + "conclusion": "Conditional replacement rejects stale writers; explicit reload policies preserve or refuse transition, with schema recheck after navigation.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0017", + "CAND-0005", + "CAND-0006" + ], + "evidence": [ + "research/reviews/ActivationConflictsAndReload.md" + ], + "remaining_uncertainty": [ + "One-process atomicity; no native unload, crash or real remote-outcome coverage." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": null, + "execution_minutes": null, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0011", + "date": "2026-09-27", + "recording": "prospective", + "stream": "B", + "comparison_group": "B-navigation-mechanism-v1", + "protocol_ref": "research/evolution/cycles/2026-09-27-navigation.md", + "question": "Can a public route preserve selection and complete-document availability across native/enhanced entry, history and HTTP caching?", + "previous_belief": "Native href/GET contracts plus representation-aware routing and cache selection should satisfy this narrow obligation; documentary support lacked runtime checks.", + "conclusion": "Corroborated in pinned htmx fixture: native and history paths work; missing Vary reproduces fragment-as-document reuse in both browsers. Existing obligations stand; no new pattern or promotion.", + "disposition": "corroboration", + "affected_patterns": [ + "CAND-0009", + "CAND-0010" + ], + "evidence": [ + "research/reviews/NavigationHistoryExperiment.md", + "research/experiments/navigation-history/result.json", + "research/evolution/cycles/2026-09-27-navigation-effort.json" + ], + "remaining_uncertainty": [ + "One authored application, no independent recurrence or usefulness gain.", + "Accessibility, delayed scripts, interrupted transport, real intermediaries and offline availability remain open." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": 6.177, + "execution_minutes": 1.021, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0012", + "date": "2026-09-27", + "recording": "prospective", + "stream": "F", + "comparison_group": "F-navigation-focus-v1", + "protocol_ref": "research/evolution/cycles/2026-09-27-navigation-focus.md", + "question": "Does enhanced route replacement need explicit continuation and feedback policy that respects changed focus ownership?", + "previous_belief": "Native controls alone do not establish enhanced focus/feedback semantics; delayed responses should respect focus moved to another surviving task. Modal return is not automatically route continuation.", + "conclusion": "Corroborated in 22 cases: raw same-ID link focus survives but this fragment contract leaves stale title and silent failure; authored heading/status policy works and preserves newer search focus. No AT speech or universal heading policy established.", + "disposition": "corroboration", + "affected_patterns": [ + "CAND-0010", + "CAND-0016" + ], + "evidence": [ + "research/reviews/NavigationFocusExperiment.md", + "research/experiments/navigation-history/focus-result.json", + "research/evolution/cycles/2026-09-27-navigation-focus-effort.json" + ], + "remaining_uncertainty": [ + "Author-model DOM evidence, no human/AT validation or independent recurrence.", + "Delayed history focus, competing requests, delayed scripts and interrupted enhancement remain open." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": 5.138, + "execution_minutes": 0.525, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + }, + { + "id": "LEARN-0013", + "date": "2026-09-27", + "recording": "prospective", + "stream": "F", + "comparison_group": "F-navigation-ownership-v1", + "protocol_ref": "research/evolution/cycles/2026-09-27-navigation-ownership.md", + "question": "Can obsolete history/navigation completions affect newer intent, and does separating completion ownership from focus ownership prevent it?", + "previous_belief": "The single-response continuation policy preserved newer search focus but left competing history/success/error completions unresolved; focus-at-swap alone might not be sufficient.", + "conclusion": "Revise operational guidance: validate navigation ownership before content/URL/title/feedback effects, including stale errors and newer failure, independently of focus permission. Prior policy misses obligations in 12/12 adversarial rows; authored guard meets 12/12. Pause fixture work for independent source contrast.", + "disposition": "revision", + "affected_patterns": [ + "CAND-0009", + "CAND-0010", + "CAND-0016" + ], + "evidence": [ + "research/reviews/NavigationOwnershipExperiment.md", + "research/reviews/NavigationThreadReview.md", + "research/experiments/navigation-history/ownership-result.json", + "research/evolution/cycles/2026-09-27-navigation-ownership-effort.json" + ], + "remaining_uncertainty": [ + "One authored htmx family and author-model review, not production recurrence or AT validation.", + "History adapter is pinned implementation-dependent; pending-state, multiple-miss and lifecycle limits remain open.", + "Three distinct protocols are not a comparable diminishing-returns window." + ], + "reviewer": { + "name": "Codex", + "role": "author-model", + "independent_human": false + }, + "effort": { + "research_minutes": 13.918, + "execution_minutes": 1.238, + "reported_tokens": null, + "cost_usd": null + }, + "supersedes": [] + } + ] + }, + "context": { + "schema_version": 1, + "cases": [ + { + "id": "VC-01", + "state": "synthetic draft", + "ref": "research/walkthroughs/VC01-TransactionalAdministration.md" + }, + { + "id": "VC-02", + "state": "synthetic draft", + "ref": "research/walkthroughs/VC02-OfflineFieldNotes.md" + }, + { + "id": "VC-03", + "state": "provisional", + "ref": "research/walkthroughs/VC03-ContentPublication.md" + }, + { + "id": "VC-04", + "state": "planned", + "ref": "research/plan/ValidationCases.md" + }, + { + "id": "VC-05", + "state": "planned", + "ref": "research/plan/ValidationCases.md" + }, + { + "id": "VC-06", + "state": "provisional", + "ref": "research/walkthroughs/VC06-MicrofrontendEstate.md" + }, + { + "id": "VC-07", + "state": "planned", + "ref": "research/plan/ValidationCases.md" + }, + { + "id": "VC-08", + "state": "planned", + "ref": "research/plan/ValidationCases.md" + }, + { + "id": "VC-09", + "state": "planned", + "ref": "research/plan/ValidationCases.md" + }, + { + "id": "VC-10", + "state": "planned", + "ref": "research/plan/ValidationCases.md" + } + ], + "usefulness": { + "named_score": 18, + "prose_score": 18, + "denominator": 24, + "independent_human": false, + "decision_time_minutes": null, + "ref": "research/evaluations/language-pilot-01/submitted-review-01/adjudication.md", + "limit": "One frozen development pilot with submitted model review; six matched briefs. Equal aggregate scores do not establish equivalence. Stable anchors are consumed development cases, not fresh held-out tasks.", + "initial_unsupported_claims_each": 2, + "adjudicated_unsupported_claim_count": null + }, + "open_work": [ + "workplans/FEP-WP-0002-seed-language-validation.md", + "workplans/FEP-WP-0003-contrasting-schools.md", + "workplans/FEP-WP-0006-language-evolution.md" + ] + } + } +} diff --git a/research/experiments/navigation-history/README.md b/research/experiments/navigation-history/README.md index ecd828d..86aaca7 100644 --- a/research/experiments/navigation-history/README.md +++ b/research/experiments/navigation-history/README.md @@ -53,3 +53,24 @@ Raw rows observe behavior, so 22 passing rows do not mean raw and managed varian meet identical focus/feedback obligations. See NF01–NF06. The policy is authored experimental code; DOM focus and live-region text do not establish assistive-technology announcements or conformance. History and request-race limits remain explicit. + +## Competing completion follow-up and pause + +[LEARN-0013 protocol](../../evolution/cycles/2026-09-27-navigation-ownership.md), +[review](../../reviews/NavigationOwnershipExperiment.md), [receipt](ownership-result.json). +Use the same browser environment with `node ownership.mjs`; choose a new +`FEP_RESULT_PATH` (default `/tmp/fep-ownership-result.json`). Six scenarios × two +policies × two browsers: 24 completed rows, all obligations met by guard 12/12 and +previous policy 0/12. These are deliberately adversarial cases, not general quality +scores. Server barriers impose schedules; client completions are observed without +aborting transport or claiming remote rollback. + +The previous focus-policy.js remains byte-for-byte unchanged. New ownership-policy.js +uses a generation plus separate focus ownership; its history XHR handler wrapping is +explicitly tied to pinned internals. Initial runner/result retained under +ownership-initial.mjs / ownership-initial-result.json: four Firefox keyboard-helper +failures corrected by backward traversal, without changing policies or obligations. +Initial receipt's ownership.mjs hash corresponds to ownership-initial.mjs. + +The [thread review](../../reviews/NavigationThreadReview.md) pauses fixture expansion +and hands the next evidence question to an independent pinned application source study. diff --git a/research/experiments/navigation-history/ownership-initial-result.json b/research/experiments/navigation-history/ownership-initial-result.json new file mode 100644 index 0000000..847481b --- /dev/null +++ b/research/experiments/navigation-history/ownership-initial-result.json @@ -0,0 +1,2088 @@ +{ + "date": "2026-09-26T22:33:49.800Z", + "node": "v24.11.1", + "kind": "ordered-navigation-completion-races-in-authored-htmx-fixture", + "files": { + "ownership.mjs": "4fcd57e451231de9e6f8017f4ed16e34e602f0750f26b80beeac365c43cdba8f", + "ownership-policy.js": "154cd4aafe4c77ba826a1bc2e6eb0d728e4a9169f23dbfe8ee3c377744273dd9", + "focus-policy.js": "cb91524d66cfff97b0bed905502479ab3134eecdfb6964a3b226d516476b145a", + "package.json": "373e05f4d2b9e043abc9391e6ec28bcf6ffdd5530e52f3e5db88ed20e4462ed5", + "package-lock.json": "6fb5a45148a199c10fd9b67b1d5468a0334e5fcc154f1f079fd88462a89328d3", + "node_modules/htmx.org/dist/htmx.js": "30612ca7e3d3baf407481f1798281c4481dcb93390a9722d328ce07290250426" + }, + "browsers": { + "chromium": { + "version": "151.0.7922.34", + "executable": "/home/worsch/.cache/ms-playwright/chromium-1234/chrome-linux64/chrome", + "sha256": "0b20b130e7edd9dd51873be867761295fe0cfad490c2b9a64f95bd3cfc08fa71" + }, + "firefox": { + "version": "155.0", + "executable": "/tmp/fep-playwright-browsers/firefox-1543/firefox/firefox", + "sha256": "062272ac4d851eade5b75db2dc7c14569d96cb3ca38f949337cdc1b74367e35b" + } + }, + "results": [ + { + "id": "O01-history-focus-moved", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=managed", + "title": "beta — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded beta" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "new task", + "feedback": "Loaded alpha" + }, + "obligations": { + "selection": true, + "title": true, + "focus": false, + "typedText": true + }, + "obligationsMet": false, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "new task", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O02-history-superseded", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=gamma&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "obligations": { + "newerSelection": false, + "noFeedbackOrFocusTheft": false + }, + "obligationsMet": false, + "final": { + "topic": "alpha", + "url": "/articles?topic=gamma&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O03-old-success", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "newerSelection": false, + "noFeedbackOrFocusTheft": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O04-old-error", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "obligations": { + "newerSelection": true, + "noObsoleteFeedback": false + }, + "obligationsMet": false, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:responseError", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed&hold=old&fail=1", + "status": 503 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O05-newer-fails", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "committedView": false, + "newestFailureRetained": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:responseError", + "focus": "newfail", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed&fail=1", + "status": 503 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": false, + "released": true + } + ] + }, + { + "id": "O06-history-newer-than-request", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "historySelection": false, + "historyContinuation": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "old", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O01-history-focus-moved", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=guarded", + "title": "beta — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded beta" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded alpha" + }, + "obligations": { + "selection": true, + "title": true, + "focus": true, + "typedText": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O02-history-superseded", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noFeedbackOrFocusTheft": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-history", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O03-old-success", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noFeedbackOrFocusTheft": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O04-old-error", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noObsoleteFeedback": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old&fail=1" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old&fail=1", + "status": 503 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O05-newer-fails", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "obligations": { + "committedView": true, + "newestFailureRetained": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "events": [ + { + "name": "htmx:responseError", + "focus": "newfail", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded&fail=1", + "status": 503 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": false, + "released": true + } + ] + }, + { + "id": "O06-history-newer-than-request", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "obligations": { + "historySelection": true, + "historyContinuation": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "search", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "old", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O01-history-focus-moved", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=managed", + "title": "beta — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded beta" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "new task", + "feedback": "Loaded alpha" + }, + "obligations": { + "selection": true, + "title": true, + "focus": false, + "typedText": true + }, + "obligationsMet": false, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "new task", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O02-history-superseded", + "engine": "firefox", + "mode": "managed", + "status": "fail", + "error": "Cannot Tab to new", + "final": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=managed", + "title": "beta — Catalog", + "focus": "search", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O03-old-success", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "newerSelection": false, + "noFeedbackOrFocusTheft": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed&hold=old", + "feedback": "Loaded beta" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O04-old-error", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "obligations": { + "newerSelection": true, + "noObsoleteFeedback": false + }, + "obligationsMet": false, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:responseError", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed&hold=old&fail=1", + "status": 503 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O05-newer-fails", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "committedView": false, + "newestFailureRetained": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:responseError", + "focus": "newfail", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=managed", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + { + "name": "htmx:afterSettle", + "focus": "newfail", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed&hold=old", + "feedback": "Loaded beta" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=managed&fail=1", + "status": 503 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": false, + "released": true + } + ] + }, + { + "id": "O06-history-newer-than-request", + "engine": "firefox", + "mode": "managed", + "status": "fail", + "error": "Cannot Tab to old", + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed", + "title": "beta — Catalog", + "focus": "search", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=managed", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O01-history-focus-moved", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=guarded", + "title": "beta — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded beta" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded alpha" + }, + "obligations": { + "selection": true, + "title": true, + "focus": true, + "typedText": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O02-history-superseded", + "engine": "firefox", + "mode": "guarded", + "status": "fail", + "error": "Cannot Tab to new", + "final": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=guarded", + "title": "beta — Catalog", + "focus": "search", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O03-old-success", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noFeedbackOrFocusTheft": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O04-old-error", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noObsoleteFeedback": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old&fail=1" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old&fail=1", + "status": 503 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O05-newer-fails", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "obligations": { + "committedView": true, + "newestFailureRetained": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "events": [ + { + "name": "htmx:responseError", + "focus": "newfail", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=alpha&mode=guarded", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=gamma&mode=guarded&fail=1", + "status": 503 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": false, + "released": true + } + ] + }, + { + "id": "O06-history-newer-than-request", + "engine": "firefox", + "mode": "guarded", + "status": "fail", + "error": "Cannot Tab to old", + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=guarded", + "title": "beta — Catalog", + "focus": "search", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:39063/articles?topic=beta&mode=guarded", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + } + ], + "completed": 20, + "total": 24, + "obligationsMet": 10 +} diff --git a/research/experiments/navigation-history/ownership-initial.mjs b/research/experiments/navigation-history/ownership-initial.mjs new file mode 100644 index 0000000..c9de8f2 --- /dev/null +++ b/research/experiments/navigation-history/ownership-initial.mjs @@ -0,0 +1,64 @@ +import {chromium,firefox} from 'playwright'; +import {createServer} from 'node:http'; +import {once} from 'node:events'; +import {readFile,writeFile} from 'node:fs/promises'; +import {createHash} from 'node:crypto'; +import assert from 'node:assert/strict'; +const dir=new URL('.',import.meta.url); +const assets=new Map(await Promise.all([['/htmx.js','node_modules/htmx.org/dist/htmx.js'],['/baseline.js','focus-policy.js'],['/guarded.js','ownership-policy.js']].map(async([url,file])=>[url,await readFile(new URL(file,dir))]))); +const trace=`window.raceLog=[];for(const name of ['htmx:beforeRequest','htmx:historyCacheMiss'])document.addEventListener(name,e=>{const xhr=e.detail.xhr;xhr.addEventListener('load',()=>window.raceLog.push({event:'loaded',url:xhr.responseURL,status:xhr.status}));});`; +let requests=[],barriers=new Map(); +function barrier(key){let resolve;const reached=new Promise(r=>resolve=r);const b={reached,resolve,release:null};barriers.set(key,b);return b;} +const server=createServer((req,res)=>{ + const u=new URL(req.url,'http://local');res.setHeader('Cache-Control','no-store'); + if(assets.has(u.pathname)){res.setHeader('Content-Type','application/javascript');res.end(assets.get(u.pathname));return;} + if(u.pathname==='/trace.js'){res.setHeader('Content-Type','application/javascript');res.end(trace);return;} + if(u.pathname!=='/articles'){res.writeHead(404);res.end('Not found');return;} + const topic=['alpha','beta','gamma'].includes(u.searchParams.get('topic'))?u.searchParams.get('topic'):'alpha'; + const mode=u.searchParams.get('mode')==='guarded'?'guarded':'managed'; + const hx=req.headers['hx-request']==='true',history=req.headers['hx-history-restore-request']==='true'; + const status=hx&&u.searchParams.has('fail')?503:200; + const content=`

${topic}

Article ${topic}

`; + const boost='hx-boost="true" hx-target="#content" hx-select="#payload" hx-swap="innerHTML"'; + const href=(t,extra='')=>`/articles?topic=${t}&mode=${mode}${extra}`; + const nav=``; + const full=`${topic} — Catalog${nav}
${content}

`; + const record={path:req.url,hx,history,status,held:false,released:false};requests.push(record); + const send=()=>{record.released=true;res.writeHead(status,{'Content-Type':'text/html'});res.end(status===503?'Injected failure':hx&&!history?content:full);}; + const key=history?'history':u.searchParams.get('hold');const b=barriers.get(key); + if(b){record.held=true;b.release=send;b.resolve();}else send(); +}); +server.listen(0,'127.0.0.1');await once(server,'listening');const base=`http://127.0.0.1:${server.address().port}`; +const results=[],browsers={},output=process.env.FEP_RESULT_PATH||'/tmp/fep-ownership-result.json'; +const inspect=p=>p.evaluate(()=>({topic:document.querySelector('#heading')?.textContent,url:location.pathname+location.search,title:document.title,focus:document.activeElement.id||document.activeElement.tagName,search:document.querySelector('#search').value,feedback:document.querySelector('#feedback').textContent})); +async function tabTo(p,id){for(let n=0;n<15;n++){if((await inspect(p)).focus===id)return;await p.keyboard.press('Tab');}throw Error(`Cannot Tab to ${id}`);} +async function activate(p,id){await tabTo(p,id);await p.keyboard.press('Enter');} +async function selected(p,t){await p.waitForFunction(t=>document.querySelector('#heading')?.textContent===t,t);await p.waitForFunction(t=>document.querySelector('#feedback').textContent===`Loaded ${t}`,t);} +async function released(p,b,history=false){b.release();b.release=null;await p.waitForFunction(history=>window.raceLog.some(e=>e.event==='loaded'&&(history?e.url.includes('topic=alpha'):e.url.includes('hold=old'))),history);} +async function held(b){await Promise.race([b.reached,new Promise((_,reject)=>setTimeout(()=>reject(Error('Server barrier not reached')),4000))]);} +function same(a,b,keys){return keys.every(k=>a[k]===b[k]);} +try{ + for(const [engine,launcher]of [['chromium',chromium],['firefox',firefox]]){ + const path=engine==='chromium'?process.env.FEP_CHROMIUM_PATH:undefined;const browser=await launcher.launch({headless:true,...(path?{executablePath:path}:{})}); + browsers[engine]={version:browser.version(),executable:path||launcher.executablePath(),sha256:createHash('sha256').update(await readFile(path||launcher.executablePath())).digest('hex')}; + try{for(const mode of ['managed','guarded']){ + async function scenario(id,fn){ + requests=[];barriers=new Map();const context=await browser.newContext();const p=await context.newPage();p.setDefaultTimeout(4500); + const r={id,engine,mode,status:'pass'}; + try{await p.goto(base+`/articles?topic=alpha&mode=${mode}`);await p.waitForFunction(()=>window.htmx?.version==='2.0.11');Object.assign(r,await fn(p));r.obligationsMet=Object.values(r.obligations).every(Boolean);if(mode==='guarded')assert(r.obligationsMet,JSON.stringify(r.obligations));} + catch(e){r.status='fail';r.error=e.message;} + r.final=await inspect(p).catch(()=>null);r.events=await p.evaluate(()=>window.probe).catch(()=>[]);r.completions=await p.evaluate(()=>window.raceLog).catch(()=>[]);r.requests=[...requests];results.push(r); + for(const b of barriers.values())if(b.release){b.release();b.release=null;}await context.close();await writeFile(output,JSON.stringify({status:'incomplete',results},null,2)+'\n'); + } + async function backMiss(p){await activate(p,'beta');await selected(p,'beta');await p.evaluate(()=>sessionStorage.removeItem('htmx-history-cache'));const b=barrier('history');await p.goBack();await held(b);return b;} + await scenario('O01-history-focus-moved',async p=>{const b=await backMiss(p);await tabTo(p,'search');await p.keyboard.type('new task');const before=await inspect(p);await released(p,b,true);const after=await inspect(p);return {before,after,obligations:{selection:after.topic==='alpha'&&new URL(base+after.url).searchParams.get('topic')==='alpha',title:after.title==='alpha — Catalog',focus:after.focus==='search',typedText:after.search==='new task'}};}); + await scenario('O02-history-superseded',async p=>{const b=await backMiss(p);await activate(p,'new');await selected(p,'gamma');const before=await inspect(p);await released(p,b,true);const after=await inspect(p);return {before,after,obligations:{newerSelection:same(before,after,['topic','url','title']),noFeedbackOrFocusTheft:same(before,after,['feedback','focus'])}};}); + await scenario('O03-old-success',async p=>{const b=barrier('old');await activate(p,'old');await held(b);await activate(p,'new');await selected(p,'gamma');const before=await inspect(p);await released(p,b);const after=await inspect(p);return {before,after,obligations:{newerSelection:same(before,after,['topic','url','title']),noFeedbackOrFocusTheft:same(before,after,['feedback','focus'])}};}); + await scenario('O04-old-error',async p=>{const b=barrier('old');await activate(p,'oldfail');await held(b);await activate(p,'new');await selected(p,'gamma');const before=await inspect(p);await released(p,b);const after=await inspect(p);return {before,after,obligations:{newerSelection:same(before,after,['topic','url','title']),noObsoleteFeedback:same(before,after,['feedback','focus'])}};}); + await scenario('O05-newer-fails',async p=>{const b=barrier('old');await activate(p,'old');await held(b);await activate(p,'newfail');await p.waitForFunction(()=>document.querySelector('#feedback').textContent.includes('Navigation failed'));const before=await inspect(p);assert.equal(before.topic,'alpha');await released(p,b);const after=await inspect(p);return {before,after,obligations:{committedView:same(before,after,['topic','url','title']),newestFailureRetained:same(before,after,['feedback','focus'])}};}); + await scenario('O06-history-newer-than-request',async p=>{await activate(p,'beta');await selected(p,'beta');const b=barrier('old');await activate(p,'old');await held(b);await p.goBack();await selected(p,'alpha');const before=await inspect(p);await released(p,b);const after=await inspect(p);return {before,after,obligations:{historySelection:same(before,after,['topic','url','title']),historyContinuation:same(before,after,['feedback','focus'])}};}); + }}finally{await browser.close();} + } +}finally{for(const b of barriers.values())if(b.release)b.release();await new Promise(resolve=>server.close(resolve));} +const files={};for(const f of ['ownership.mjs','ownership-policy.js','focus-policy.js','package.json','package-lock.json','node_modules/htmx.org/dist/htmx.js'])files[f]=createHash('sha256').update(await readFile(new URL(f,dir))).digest('hex'); +const r={date:new Date().toISOString(),node:process.version,kind:'ordered-navigation-completion-races-in-authored-htmx-fixture',files,browsers,results,completed:results.filter(x=>x.status==='pass').length,total:results.length,obligationsMet:results.filter(x=>x.obligationsMet).length};await writeFile(output,JSON.stringify(r,null,2)+'\n');console.log(JSON.stringify({output,completed:r.completed,total:r.total,obligationsMet:r.obligationsMet,failures:results.filter(x=>x.status==='fail')},null,2));if(r.completed!==r.total)process.exitCode=1; diff --git a/research/experiments/navigation-history/ownership-policy.js b/research/experiments/navigation-history/ownership-policy.js new file mode 100644 index 0000000..9c49eb9 --- /dev/null +++ b/research/experiments/navigation-history/ownership-policy.js @@ -0,0 +1,31 @@ +// Experimental adapter pinned to htmx 2.0.11; not a production router. +window.probe=[]; +let generation=0,focusEpoch=0,historyMoveFocus=true; +const pending=new WeakMap(); +document.addEventListener('focusin',()=>focusEpoch++); +window.addEventListener('popstate',()=>{generation++;},true); +const notice=text=>{document.querySelector('#feedback').textContent=text;}; +function complete(move){const h=document.querySelector('#heading');document.title=`${h.textContent} — Catalog`;notice(`Loaded ${h.textContent}`);if(move)h.focus();} +document.addEventListener('htmx:beforeRequest',e=>{ + if(e.detail.target.id==='content')pending.set(e.detail.xhr,{owner:++generation,source:e.detail.elt,move:false}); +}); +document.addEventListener('htmx:beforeOnLoad',e=>{ + const state=pending.get(e.detail.xhr); + if(state&&state.owner!==generation){e.preventDefault();pending.delete(e.detail.xhr);window.raceLog.push({event:'discard-navigation',url:e.detail.xhr.responseURL});} +}); +document.addEventListener('htmx:beforeSwap',e=>{const state=pending.get(e.detail.xhr);if(state)state.move=document.activeElement===state.source;}); +document.addEventListener('htmx:afterSwap',e=>{const state=pending.get(e.detail.xhr);if(state){complete(state.move);pending.delete(e.detail.xhr);}}); +document.addEventListener('htmx:responseError',e=>{if(pending.has(e.detail.xhr)){notice('Navigation failed. Current article retained. Use Native recovery to continue.');pending.delete(e.detail.xhr);}}); +document.addEventListener('htmx:historyCacheHit',()=>{historyMoveFocus=true;}); +document.addEventListener('htmx:historyCacheMiss',e=>{ + const owner=generation,focusAtStart=focusEpoch,path=e.detail.path; + const xhr=e.detail.xhr,original=xhr.onload; + // The public miss event exposes XHR; wrapping its existing handler relies on the pinned implementation. + xhr.onload=function(event){ + if(owner!==generation||location.pathname+location.search!==path){window.raceLog.push({event:'discard-history',url:xhr.responseURL});return;} + historyMoveFocus=focusEpoch===focusAtStart; + return original.call(this,event); + }; +}); +document.addEventListener('htmx:historyRestore',()=>complete(historyMoveFocus)); +for(const name of ['htmx:afterSettle','htmx:historyRestore','htmx:responseError'])document.addEventListener(name,()=>window.probe.push({name,focus:document.activeElement.id||document.activeElement.tagName,title:document.title,url:location.href,feedback:document.querySelector('#feedback').textContent})); diff --git a/research/experiments/navigation-history/ownership-result.json b/research/experiments/navigation-history/ownership-result.json new file mode 100644 index 0000000..529eca1 --- /dev/null +++ b/research/experiments/navigation-history/ownership-result.json @@ -0,0 +1,2301 @@ +{ + "date": "2026-09-26T22:41:46.321Z", + "node": "v24.11.1", + "kind": "ordered-navigation-completion-races-in-authored-htmx-fixture", + "files": { + "ownership.mjs": "ad6e77d3e1704aeea13db9fcf5975bc7fa9f996b41a01ef1449a9f20f2c82e44", + "ownership-policy.js": "154cd4aafe4c77ba826a1bc2e6eb0d728e4a9169f23dbfe8ee3c377744273dd9", + "focus-policy.js": "cb91524d66cfff97b0bed905502479ab3134eecdfb6964a3b226d516476b145a", + "package.json": "373e05f4d2b9e043abc9391e6ec28bcf6ffdd5530e52f3e5db88ed20e4462ed5", + "package-lock.json": "6fb5a45148a199c10fd9b67b1d5468a0334e5fcc154f1f079fd88462a89328d3", + "node_modules/htmx.org/dist/htmx.js": "30612ca7e3d3baf407481f1798281c4481dcb93390a9722d328ce07290250426" + }, + "browsers": { + "chromium": { + "version": "151.0.7922.34", + "executable": "/home/worsch/.cache/ms-playwright/chromium-1234/chrome-linux64/chrome", + "sha256": "0b20b130e7edd9dd51873be867761295fe0cfad490c2b9a64f95bd3cfc08fa71" + }, + "firefox": { + "version": "155.0", + "executable": "/tmp/fep-playwright-browsers/firefox-1543/firefox/firefox", + "sha256": "062272ac4d851eade5b75db2dc7c14569d96cb3ca38f949337cdc1b74367e35b" + } + }, + "results": [ + { + "id": "O01-history-focus-moved", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=managed", + "title": "beta — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded beta" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "new task", + "feedback": "Loaded alpha" + }, + "obligations": { + "selection": true, + "title": true, + "focus": false, + "typedText": true + }, + "obligationsMet": false, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "new task", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O02-history-superseded", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=gamma&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "obligations": { + "newerSelection": false, + "noFeedbackOrFocusTheft": false + }, + "obligationsMet": false, + "final": { + "topic": "alpha", + "url": "/articles?topic=gamma&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O03-old-success", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "newerSelection": false, + "noFeedbackOrFocusTheft": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O04-old-error", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "obligations": { + "newerSelection": true, + "noObsoleteFeedback": false + }, + "obligationsMet": false, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:responseError", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old&fail=1", + "status": 503 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O05-newer-fails", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "committedView": false, + "newestFailureRetained": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:responseError", + "focus": "newfail", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed&fail=1", + "status": 503 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": false, + "released": true + } + ] + }, + { + "id": "O06-history-newer-than-request", + "engine": "chromium", + "mode": "managed", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "historySelection": false, + "historyContinuation": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "old", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O01-history-focus-moved", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=guarded", + "title": "beta — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded beta" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded alpha" + }, + "obligations": { + "selection": true, + "title": true, + "focus": true, + "typedText": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O02-history-superseded", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noFeedbackOrFocusTheft": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-history", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O03-old-success", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noFeedbackOrFocusTheft": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O04-old-error", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noObsoleteFeedback": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old&fail=1" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old&fail=1", + "status": 503 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O05-newer-fails", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "obligations": { + "committedView": true, + "newestFailureRetained": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "events": [ + { + "name": "htmx:responseError", + "focus": "newfail", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded&fail=1", + "status": 503 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": false, + "released": true + } + ] + }, + { + "id": "O06-history-newer-than-request", + "engine": "chromium", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "obligations": { + "historySelection": true, + "historyContinuation": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "old", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O01-history-focus-moved", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=managed", + "title": "beta — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded beta" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "new task", + "feedback": "Loaded alpha" + }, + "obligations": { + "selection": true, + "title": true, + "focus": false, + "typedText": true + }, + "obligationsMet": false, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "new task", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O02-history-superseded", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=gamma&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "obligations": { + "newerSelection": false, + "noFeedbackOrFocusTheft": false + }, + "obligationsMet": false, + "final": { + "topic": "alpha", + "url": "/articles?topic=gamma&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O03-old-success", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "newerSelection": false, + "noFeedbackOrFocusTheft": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old", + "feedback": "Loaded beta" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O04-old-error", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "obligations": { + "newerSelection": true, + "noObsoleteFeedback": false + }, + "obligationsMet": false, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=managed", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Loaded gamma" + }, + { + "name": "htmx:responseError", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old&fail=1", + "status": 503 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O05-newer-fails", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "committedView": false, + "newestFailureRetained": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:responseError", + "focus": "newfail", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + { + "name": "htmx:afterSettle", + "focus": "newfail", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old", + "feedback": "Loaded beta" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=managed&fail=1", + "status": 503 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=managed&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": false, + "released": true + } + ] + }, + { + "id": "O06-history-newer-than-request", + "engine": "firefox", + "mode": "managed", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=managed", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "after": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "obligations": { + "historySelection": false, + "historyContinuation": false + }, + "obligationsMet": false, + "final": { + "topic": "beta", + "url": "/articles?topic=beta&mode=managed&hold=old", + "title": "beta — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded beta" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "old", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=managed", + "feedback": "Loaded alpha" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old", + "feedback": "Loaded beta" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=managed&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=managed", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=managed&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O01-history-focus-moved", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "beta", + "url": "/articles?topic=alpha&mode=guarded", + "title": "beta — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded beta" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded alpha" + }, + "obligations": { + "selection": true, + "title": true, + "focus": true, + "typedText": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "search", + "search": "new task", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "search", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + } + ] + }, + { + "id": "O02-history-superseded", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noFeedbackOrFocusTheft": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-history", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": true, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O03-old-success", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noFeedbackOrFocusTheft": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O04-old-error", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "after": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "obligations": { + "newerSelection": true, + "noObsoleteFeedback": true + }, + "obligationsMet": true, + "final": { + "topic": "gamma", + "url": "/articles?topic=gamma&mode=guarded", + "title": "gamma — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded gamma" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "gamma — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "feedback": "Loaded gamma" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old&fail=1" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old&fail=1", + "status": 503 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + } + ] + }, + { + "id": "O05-newer-fails", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "obligations": { + "committedView": true, + "newestFailureRetained": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "newfail", + "search": "", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + }, + "events": [ + { + "name": "htmx:responseError", + "focus": "newfail", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Navigation failed. Current article retained. Use Native recovery to continue." + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=gamma&mode=guarded&fail=1", + "status": 503 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + }, + { + "path": "/articles?topic=gamma&mode=guarded&fail=1", + "hx": true, + "history": false, + "status": 503, + "held": false, + "released": true + } + ] + }, + { + "id": "O06-history-newer-than-request", + "engine": "firefox", + "mode": "guarded", + "status": "pass", + "before": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "after": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "obligations": { + "historySelection": true, + "historyContinuation": true + }, + "obligationsMet": true, + "final": { + "topic": "alpha", + "url": "/articles?topic=alpha&mode=guarded", + "title": "alpha — Catalog", + "focus": "heading", + "search": "", + "feedback": "Loaded alpha" + }, + "events": [ + { + "name": "htmx:afterSettle", + "focus": "heading", + "title": "beta — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:afterSettle", + "focus": "old", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Loaded beta" + }, + { + "name": "htmx:historyRestore", + "focus": "heading", + "title": "alpha — Catalog", + "url": "http://127.0.0.1:36469/articles?topic=alpha&mode=guarded", + "feedback": "Loaded alpha" + } + ], + "completions": [ + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded", + "status": 200 + }, + { + "event": "discard-navigation", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old" + }, + { + "event": "loaded", + "url": "http://127.0.0.1:36469/articles?topic=beta&mode=guarded&hold=old", + "status": 200 + } + ], + "requests": [ + { + "path": "/articles?topic=alpha&mode=guarded", + "hx": false, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded", + "hx": true, + "history": false, + "status": 200, + "held": false, + "released": true + }, + { + "path": "/articles?topic=beta&mode=guarded&hold=old", + "hx": true, + "history": false, + "status": 200, + "held": true, + "released": true + } + ] + } + ], + "completed": 24, + "total": 24, + "obligationsMet": 12 +} diff --git a/research/experiments/navigation-history/ownership.mjs b/research/experiments/navigation-history/ownership.mjs new file mode 100644 index 0000000..cf142b4 --- /dev/null +++ b/research/experiments/navigation-history/ownership.mjs @@ -0,0 +1,64 @@ +import {chromium,firefox} from 'playwright'; +import {createServer} from 'node:http'; +import {once} from 'node:events'; +import {readFile,writeFile} from 'node:fs/promises'; +import {createHash} from 'node:crypto'; +import assert from 'node:assert/strict'; +const dir=new URL('.',import.meta.url); +const assets=new Map(await Promise.all([['/htmx.js','node_modules/htmx.org/dist/htmx.js'],['/baseline.js','focus-policy.js'],['/guarded.js','ownership-policy.js']].map(async([url,file])=>[url,await readFile(new URL(file,dir))]))); +const trace=`window.raceLog=[];for(const name of ['htmx:beforeRequest','htmx:historyCacheMiss'])document.addEventListener(name,e=>{const xhr=e.detail.xhr;xhr.addEventListener('load',()=>window.raceLog.push({event:'loaded',url:xhr.responseURL,status:xhr.status}));});`; +let requests=[],barriers=new Map(); +function barrier(key){let resolve;const reached=new Promise(r=>resolve=r);const b={reached,resolve,release:null};barriers.set(key,b);return b;} +const server=createServer((req,res)=>{ + const u=new URL(req.url,'http://local');res.setHeader('Cache-Control','no-store'); + if(assets.has(u.pathname)){res.setHeader('Content-Type','application/javascript');res.end(assets.get(u.pathname));return;} + if(u.pathname==='/trace.js'){res.setHeader('Content-Type','application/javascript');res.end(trace);return;} + if(u.pathname!=='/articles'){res.writeHead(404);res.end('Not found');return;} + const topic=['alpha','beta','gamma'].includes(u.searchParams.get('topic'))?u.searchParams.get('topic'):'alpha'; + const mode=u.searchParams.get('mode')==='guarded'?'guarded':'managed'; + const hx=req.headers['hx-request']==='true',history=req.headers['hx-history-restore-request']==='true'; + const status=hx&&u.searchParams.has('fail')?503:200; + const content=`

${topic}

Article ${topic}

`; + const boost='hx-boost="true" hx-target="#content" hx-select="#payload" hx-swap="innerHTML"'; + const href=(t,extra='')=>`/articles?topic=${t}&mode=${mode}${extra}`; + const nav=``; + const full=`${topic} — Catalog${nav}
${content}

`; + const record={path:req.url,hx,history,status,held:false,released:false};requests.push(record); + const send=()=>{record.released=true;res.writeHead(status,{'Content-Type':'text/html'});res.end(status===503?'Injected failure':hx&&!history?content:full);}; + const key=history?'history':u.searchParams.get('hold');const b=barriers.get(key); + if(b){record.held=true;b.release=send;b.resolve();}else send(); +}); +server.listen(0,'127.0.0.1');await once(server,'listening');const base=`http://127.0.0.1:${server.address().port}`; +const results=[],browsers={},output=process.env.FEP_RESULT_PATH||'/tmp/fep-ownership-result.json'; +const inspect=p=>p.evaluate(()=>({topic:document.querySelector('#heading')?.textContent,url:location.pathname+location.search,title:document.title,focus:document.activeElement.id||document.activeElement.tagName,search:document.querySelector('#search').value,feedback:document.querySelector('#feedback').textContent})); +async function tabTo(p,id){for(let n=0;n<15;n++){if((await inspect(p)).focus===id)return;const backwards=await p.evaluate(id=>{const a=document.activeElement,t=document.getElementById(id);return a!==document.body&&Boolean(a.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_PRECEDING);},id);await p.keyboard.press(backwards?'Shift+Tab':'Tab');}throw Error(`Cannot Tab to ${id}`);} +async function activate(p,id){await tabTo(p,id);await p.keyboard.press('Enter');} +async function selected(p,t){await p.waitForFunction(t=>document.querySelector('#heading')?.textContent===t,t);await p.waitForFunction(t=>document.querySelector('#feedback').textContent===`Loaded ${t}`,t);} +async function released(p,b,history=false){b.release();b.release=null;await p.waitForFunction(history=>window.raceLog.some(e=>e.event==='loaded'&&(history?e.url.includes('topic=alpha'):e.url.includes('hold=old'))),history);} +async function held(b){await Promise.race([b.reached,new Promise((_,reject)=>setTimeout(()=>reject(Error('Server barrier not reached')),4000))]);} +function same(a,b,keys){return keys.every(k=>a[k]===b[k]);} +try{ + for(const [engine,launcher]of [['chromium',chromium],['firefox',firefox]]){ + const path=engine==='chromium'?process.env.FEP_CHROMIUM_PATH:undefined;const browser=await launcher.launch({headless:true,...(path?{executablePath:path}:{})}); + browsers[engine]={version:browser.version(),executable:path||launcher.executablePath(),sha256:createHash('sha256').update(await readFile(path||launcher.executablePath())).digest('hex')}; + try{for(const mode of ['managed','guarded']){ + async function scenario(id,fn){ + requests=[];barriers=new Map();const context=await browser.newContext();const p=await context.newPage();p.setDefaultTimeout(4500); + const r={id,engine,mode,status:'pass'}; + try{await p.goto(base+`/articles?topic=alpha&mode=${mode}`);await p.waitForFunction(()=>window.htmx?.version==='2.0.11');Object.assign(r,await fn(p));r.obligationsMet=Object.values(r.obligations).every(Boolean);if(mode==='guarded')assert(r.obligationsMet,JSON.stringify(r.obligations));} + catch(e){r.status='fail';r.error=e.message;} + r.final=await inspect(p).catch(()=>null);r.events=await p.evaluate(()=>window.probe).catch(()=>[]);r.completions=await p.evaluate(()=>window.raceLog).catch(()=>[]);r.requests=[...requests];results.push(r); + for(const b of barriers.values())if(b.release){b.release();b.release=null;}await context.close();await writeFile(output,JSON.stringify({status:'incomplete',results},null,2)+'\n'); + } + async function backMiss(p){await activate(p,'beta');await selected(p,'beta');await p.evaluate(()=>sessionStorage.removeItem('htmx-history-cache'));const b=barrier('history');await p.goBack();await held(b);return b;} + await scenario('O01-history-focus-moved',async p=>{const b=await backMiss(p);await tabTo(p,'search');await p.keyboard.type('new task');const before=await inspect(p);await released(p,b,true);const after=await inspect(p);return {before,after,obligations:{selection:after.topic==='alpha'&&new URL(base+after.url).searchParams.get('topic')==='alpha',title:after.title==='alpha — Catalog',focus:after.focus==='search',typedText:after.search==='new task'}};}); + await scenario('O02-history-superseded',async p=>{const b=await backMiss(p);await activate(p,'new');await selected(p,'gamma');const before=await inspect(p);await released(p,b,true);const after=await inspect(p);return {before,after,obligations:{newerSelection:same(before,after,['topic','url','title']),noFeedbackOrFocusTheft:same(before,after,['feedback','focus'])}};}); + await scenario('O03-old-success',async p=>{const b=barrier('old');await activate(p,'old');await held(b);await activate(p,'new');await selected(p,'gamma');const before=await inspect(p);await released(p,b);const after=await inspect(p);return {before,after,obligations:{newerSelection:same(before,after,['topic','url','title']),noFeedbackOrFocusTheft:same(before,after,['feedback','focus'])}};}); + await scenario('O04-old-error',async p=>{const b=barrier('old');await activate(p,'oldfail');await held(b);await activate(p,'new');await selected(p,'gamma');const before=await inspect(p);await released(p,b);const after=await inspect(p);return {before,after,obligations:{newerSelection:same(before,after,['topic','url','title']),noObsoleteFeedback:same(before,after,['feedback','focus'])}};}); + await scenario('O05-newer-fails',async p=>{const b=barrier('old');await activate(p,'old');await held(b);await activate(p,'newfail');await p.waitForFunction(()=>document.querySelector('#feedback').textContent.includes('Navigation failed'));const before=await inspect(p);assert.equal(before.topic,'alpha');await released(p,b);const after=await inspect(p);return {before,after,obligations:{committedView:same(before,after,['topic','url','title']),newestFailureRetained:same(before,after,['feedback','focus'])}};}); + await scenario('O06-history-newer-than-request',async p=>{await activate(p,'beta');await selected(p,'beta');const b=barrier('old');await activate(p,'old');await held(b);await p.goBack();await selected(p,'alpha');const before=await inspect(p);await released(p,b);const after=await inspect(p);return {before,after,obligations:{historySelection:same(before,after,['topic','url','title']),historyContinuation:same(before,after,['feedback','focus'])}};}); + }}finally{await browser.close();} + } +}finally{for(const b of barriers.values())if(b.release)b.release();await new Promise(resolve=>server.close(resolve));} +const files={};for(const f of ['ownership.mjs','ownership-policy.js','focus-policy.js','package.json','package-lock.json','node_modules/htmx.org/dist/htmx.js'])files[f]=createHash('sha256').update(await readFile(new URL(f,dir))).digest('hex'); +const r={date:new Date().toISOString(),node:process.version,kind:'ordered-navigation-completion-races-in-authored-htmx-fixture',files,browsers,results,completed:results.filter(x=>x.status==='pass').length,total:results.length,obligationsMet:results.filter(x=>x.obligationsMet).length};await writeFile(output,JSON.stringify(r,null,2)+'\n');console.log(JSON.stringify({output,completed:r.completed,total:r.total,obligationsMet:r.obligationsMet,failures:results.filter(x=>x.status==='fail')},null,2));if(r.completed!==r.total)process.exitCode=1; diff --git a/research/plan/OpenQuestions.md b/research/plan/OpenQuestions.md index cb15472..c5eb679 100644 --- a/research/plan/OpenQuestions.md +++ b/research/plan/OpenQuestions.md @@ -114,3 +114,12 @@ Q06 activation/reload follow-up: [conditional update and draft tests](../reviews show why disjoint-intent retry differs from competing rollback, and why preflight compatibility must be rechecked after reload. Same-tab draft preservation is narrower than durability or remote-outcome recovery. No question or maturity gate is closed. + +## Q05 navigation completion versus focus ownership — 2026-09-27 + +[NO01–NO06](../reviews/NavigationOwnershipExperiment.md) distinguish rights to apply +a navigation result from rights to move focus. Obsolete errors and history completions +can violate current intent even when the prior single-response policy seemed adequate. +Q05 remains open beyond one fixture family. [Thread review](../reviews/NavigationThreadReview.md) +pauses the fixture and proposes an independently developed application source contrast. +No new ownership pattern or canonical dimension is admitted. diff --git a/research/reviews/NavigationCoverage.md b/research/reviews/NavigationCoverage.md index ebf7106..d886c0d 100644 --- a/research/reviews/NavigationCoverage.md +++ b/research/reviews/NavigationCoverage.md @@ -40,3 +40,11 @@ accessibility work remains open. No maturity or M1/M2 promotion. the provisional VC-03 subset. Explicit focus/title/status policy and delayed-response ownership exercised; AT speech and full accessibility validation remain pending. This is a new stream-F comparison group, not another comparable cache cycle. + +## Ownership comparison and thread pause — 2026-09-27 + +[NO01–NO06](NavigationOwnershipExperiment.md) adds ordered competing-completion +evidence to provisional VC-03. Guarded policy meets 12/12 full obligations, prior +policy 0/12; one authored family, no AT/independent validation. The +[thread review](NavigationThreadReview.md) pauses local fixture expansion and names +a pinned Zulip navigation/search source contrast as the next evidence direction. diff --git a/research/reviews/NavigationOwnershipExperiment.md b/research/reviews/NavigationOwnershipExperiment.md new file mode 100644 index 0000000..43c64b5 --- /dev/null +++ b/research/reviews/NavigationOwnershipExperiment.md @@ -0,0 +1,95 @@ +# Competing navigation completion ownership — 2026-09-27 + +LEARN-0013, Codex author-model review. [Preregistration](../evolution/cycles/2026-09-27-navigation-ownership.md) +committed as `e484cae` before implementation/execution. Stream F; new group +F-navigation-ownership-v1. [Runner](../experiments/navigation-history/ownership.mjs), +[guarded policy](../experiments/navigation-history/ownership-policy.js), +[final receipt](../experiments/navigation-history/ownership-result.json). + +## Comparison and findings + +Same locked htmx 2.0.11/Playwright 1.63.0 and Chromium 151.0.7922.34/Firefox 155.0. +The unchanged previous focus-policy.js is the baseline, on a new fixture with stable +content target and persistent navigation links. Different controls can have concurrent +requests; there is no hx-sync configuration. Authored ownership policy is a separate +variant, not a vendor patch. Exact input/browser hashes and completion traces retained. + +All 24 rows completed in the corrected run. Baseline met all obligations in **0/12** +rows; guard met them in **12/12**. Baseline recording success is not obligation success. +These are six deliberately challenging scenarios in two browsers, not an application +quality score, independent trials or proof of all possible schedules. + +| Claim | Case | Baseline in both browsers | Guarded result in both browsers | +| --- | --- | --- | --- | +| NO01 | O01 delayed history, newer search focus | Restores alpha and preserves typed text but moves focus from search to heading | Restores alpha while retaining search focus/text | +| NO02 | O02 delayed history, newer gamma navigation | Old alpha replaces content/title/status under gamma's URL | Gamma content/URL/title/status/focus unchanged | +| NO03 | O03 older success after newer success | Old beta replaces gamma and pushes beta's URL | Gamma result retained | +| NO04 | O04 older failure after newer success | Gamma remains but old failure replaces its success feedback | Gamma feedback retained | +| NO05 | O05 newer request fails, older success follows | Old beta resurfaces, replacing committed alpha and newest failure feedback | Alpha and newest failure retained | +| NO06 | O06 browser Back supersedes old request | Old beta replaces restored alpha and pushes beta's URL | Alpha history result retained | + +O05 encodes an explicit latest-intent policy: a failed newer navigation does not revive +older intent without a new user decision. This is not a universal rule for every queue +or application. O01 distinguishes permission to restore content from permission to +move focus. During a pending Back miss, the browser URL already names alpha while beta +is still displayed; we measured completion obligations, not a complete pending-state +presentation/recovery design. No pending-URL consistency guarantee is established. + +## Mechanism and implementation limits + +Guarded navigation requests receive increasing generations; browser popstate advances +the same generation. Stale request completions are rejected at beforeOnLoad before +response processing. This covers success and error feedback, not just the content swap. +Focus checks remain separate from generation. History cache misses capture navigation +generation and a focus-change epoch. A still-current restoration can change the article +without moving focus after the user has started work in a surviving control. + +The history adapter wraps the XHR onload handler exposed by historyCacheMiss and checks +the generation and target path before calling the original. The public +[htmx event reference](https://htmx.org/events/) documents request cancellation and +modifiable history-request details; **wrapping the preinstalled handler is a pinned +implementation-dependent experiment**, not a portable supported router API. Inspected +htmx 2.0.11 loadHistoryFromServer sets the handler before emitting historyCacheMiss; +its historyCacheMissLoad notification alone does not veto the subsequent swap. No +claim that this implementation will remain valid across versions or extensions. + +No requests are aborted by this policy. Server traces show responses released and +client load events observed even when effects are discarded. Ignoring a completion is +not cancellation of server work, rollback, freshness verification or remote-write safety. +The fixture has no writes. A route generation is scoped to this one navigation surface, +not a global rule to suppress unrelated background work. + +## Retained harness correction + +[Initial receipt](../experiments/navigation-history/ownership-initial-result.json) +and [initial runner](../experiments/navigation-history/ownership-initial.mjs) preserve +20 completed rows and four Firefox harness failures. The forward-only Tab helper could +not return from the programmatically focused heading to earlier navigation controls in +O02/O06, in either policy. It did not execute those intended interleavings. The revised +helper chooses Shift+Tab when the target precedes the active element. No programmatic +focus, click, policy or assertion change was introduced. All 24 rows were rerun; initial +observations are not pooled as independent evidence. The initial runner file's hash +matches the initial receipt's ownership.mjs hash despite the archival filename. + +## Learning disposition: revision + +LEARN-0012 established only single-response continuation and explicitly left history/ +request races unresolved. This follow-up does not retract those bounded results. +It does revise the language's operational guidance: checking focus at swap time is +insufficient as an overall completion policy. Distinguish navigation ownership from +focus ownership; apply navigation checks to history, titles, URL and feedback, including +late errors and the case where the newest request fails. Record one consequential +revision across affected candidates, not twelve discoveries or a new pattern. + +URL-addressable State, Progressive Enhancement and the Focus Return scope boundary +remain hypotheses. Full-pattern recurrence, AT/human validation, repeated production +use, redirects, unload, nonzero swap/view-transition delays, multiple simultaneous +history misses, bfcache, pending-state disclosure and full lifecycle cleanup remain +unverified. The script has document-lifetime handlers; no mount/unmount reuse claim. + +[Measured effort](../evolution/cycles/2026-09-27-navigation-ownership-effort.json) +includes the initial run and corrected run as execution. Active time includes protocol, +implementation, analysis and recording; final administration excluded. No token/cost +estimate or diminishing-returns claim. See the [navigation-thread review](NavigationThreadReview.md) +for the agreed pause and next evidence direction. Residuals remain WP-0003 T01/T02; +measurement work remains WP-0006 T03. No further fixture-hardening cycle is started. diff --git a/research/reviews/NavigationThreadReview.md b/research/reviews/NavigationThreadReview.md new file mode 100644 index 0000000..a843dc3 --- /dev/null +++ b/research/reviews/NavigationThreadReview.md @@ -0,0 +1,59 @@ +# Navigation research thread review — 2026-09-27 + +Decision: pause expansion of the authored navigation fixture after LEARN-0013. +The user authorized a bounded ownership comparison followed by this review; completing +it does not close M1/M2, VC-03, the human-validation gate or the pattern language. + +| Cycle | Contribution | Learning disposition | +| --- | --- | --- | +| [LEARN-0011](NavigationHistoryExperiment.md) | Reproduced direct/native/history behavior and fragment-as-document reuse without Vary; separated history snapshots from HTTP cache | Corroboration | +| [LEARN-0012](NavigationFocusExperiment.md) | Distinguished native operation, same-ID focus retention, route continuation and feedback; preserved newer search focus for a single response | Corroboration | +| [LEARN-0013](NavigationOwnershipExperiment.md) | Exposed old history/success/error effects after newer intent; separated completion ownership from focus ownership, including newer failure | Revision | + +We now have executable support for a more precise public read-only navigation contract. +The third cycle changes operational guidance in existing candidates. It does not justify +another pattern solely because the fixture now has a generation counter. The modal +Focus Return candidate stays narrow; route continuation is a contrasting context. + +## What these results do not establish + +All three cycles share one authored htmx fixture family and one author-model reviewer. +Browser diversity strengthens the bounded mechanism observations; it does not supply +independent application recurrence. Screen-reader speech/usability, offline availability, +real intermediaries and deployed lifecycle behavior remain unverified. No fresh decision +usefulness evaluation was conducted; the frozen pilot's 18/24-versus-18/24 adjudication +and pending independent-human gate remain unchanged. + +Effort is recorded prospectively in each cycle's receipt. The protocols address different +question scopes: B-navigation-mechanism-v1, F-navigation-focus-v1 and +F-navigation-ownership-v1. They are **not three comparable observations of a learning +curve**. Do not infer acceleration, diminishing returns or a plateau from their rates. +Two corroborations followed by a revision are an account of this investigation, not a +productivity ranking. Harness correction effort remains visible rather than erased. + +## Why pause, and what follows + +Further fixture work could improve this adapter while leaving the main evidence gap +unchanged: whether the candidate contracts recur in independently developed applications. +Our next bounded direction is a **pinned, read-only Zulip navigation/search source +walkthrough** under WP-0003 T01. Ask where that application accepts, supersedes or +reports asynchronous navigation/search results, and how selection and focus ownership +are separated—or whether the proposed model does not fit. Reuse the existing provenance +workflow, pin the chosen revision, and cite exact mechanisms and counterexamples. +Do not count Zulip's previously inspected draft/send paths as new navigation evidence. +Static inspection would remain static evidence, not proof of deployed runtime behavior. +Register the question before execution; no additional model calls or study starts here. + +Keep these residuals live, without automatically extending the fixture: + +- WP-0003 T01: pending Back-state disclosure/recovery, multiple history misses, + redirects, nonzero swap delays, bfcache and lifecycle teardown before any production + recommendation; interrupted and late-script enhancement remains untested. +- WP-0003 T02: independent human/assistive-technology review and the offline-reading + branch of provisional VC-03. DOM live-region checks do not close these obligations. +- WP-0006 T03: reconcile remaining substantive-review dates and assess returns only + when useful comparable cycles exist. Do not manufacture cycles to satisfy a count. + +Reopen the local fixture when independent evidence exposes a specific contradiction +or a concrete consumer needs one of these limits resolved. The next source contrast +can narrow, merge or reject our claims; promotion is not its default outcome. diff --git a/research/walkthroughs/VC03-ContentPublication.md b/research/walkthroughs/VC03-ContentPublication.md index 5669bb7..ece3ed4 100644 --- a/research/walkthroughs/VC03-ContentPublication.md +++ b/research/walkthroughs/VC03-ContentPublication.md @@ -117,3 +117,14 @@ to persistent search. The managed policy passes its DOM obligations; raw same-ID focus retention does not itself update title or report errors in this fragment host. VC-03 stays provisional. Spoken feedback, focus visibility, delayed history/request races and offline availability remain open; no complete accessibility claim. + +## Competing navigation and bounded pause — 2026-09-27 + +[NO01–NO06](../reviews/NavigationOwnershipExperiment.md) show why result ownership +applies to content, URL, title and feedback separately from focus ownership. Old +history may overwrite newer content under a different URL; an old error may overwrite +newer success feedback. The guarded latest-intent policy handles the tested schedules, +including preserving committed content when the newest request fails. It is not a +general router or AT validation. Pending Back-state disclosure and broader history +lifecycle remain open. [Thread review](../reviews/NavigationThreadReview.md) pauses +fixture expansion; VC-03 stays provisional with independent/AT and offline gaps. diff --git a/workplans/FEP-WP-0003-contrasting-schools.md b/workplans/FEP-WP-0003-contrasting-schools.md index 473c976..b746c1b 100644 --- a/workplans/FEP-WP-0003-contrasting-schools.md +++ b/workplans/FEP-WP-0003-contrasting-schools.md @@ -215,3 +215,21 @@ WP-0003 T01 next: delayed history restoration and competing-navigation ownership interrupted/late enhancement remains open. T02 retains AT/independent review and offline branch. WP-0006 T03 remains progress for comparable windows and remaining review-date reconciliation. No M1/M2 completion. + +## Completion ownership compared; navigation fixture paused — 2026-09-27 + +LEARN-0013 preregistered at e484cae; 24 completed rows after a retained keyboard-helper +correction. Prior policy meets full obligations in 0/12, authored guard 12/12. Record +one revision: check navigation completion ownership separately from focus permission, +including history, errors and newer-request failure. Same authored family; hypotheses +and provisional VC-03 retained. See research/reviews/NavigationOwnershipExperiment.md +and NavigationThreadReview.md. Three distinct cycle groups do not establish a trend. + +Agreed pause: do not automatically extend the navigation fixture. Next bounded +WP-0003 T01 question is a preregistered, pinned read-only Zulip navigation/search +source contrast: locate selection/result/focus ownership or counterexamples outside +the authored fixture; prior draft/send evidence does not count as navigation support. +T01 retains pending history disclosure, multiple misses, redirects, delayed swaps, +bfcache/lifecycle and interrupted/late enhancement before any production claim. +T02 retains independent human/AT review and offline VC-03 branch. WP-0006 T03 retains +review-date reconciliation and useful comparable-cycle windows; no M1/M2 closure. diff --git a/workplans/FEP-WP-0006-language-evolution.md b/workplans/FEP-WP-0006-language-evolution.md index 924bdb7..b0fd4f9 100644 --- a/workplans/FEP-WP-0006-language-evolution.md +++ b/workplans/FEP-WP-0006-language-evolution.md @@ -94,3 +94,21 @@ WP-0003 T01 next: delayed history restoration and competing-navigation ownership interrupted/late enhancement remains open. T02 retains AT/independent review and offline branch. WP-0006 T03 remains progress for comparable windows and remaining review-date reconciliation. No M1/M2 completion. + +## Completion ownership compared; navigation fixture paused — 2026-09-27 + +LEARN-0013 preregistered at e484cae; 24 completed rows after a retained keyboard-helper +correction. Prior policy meets full obligations in 0/12, authored guard 12/12. Record +one revision: check navigation completion ownership separately from focus permission, +including history, errors and newer-request failure. Same authored family; hypotheses +and provisional VC-03 retained. See research/reviews/NavigationOwnershipExperiment.md +and NavigationThreadReview.md. Three distinct cycle groups do not establish a trend. + +Agreed pause: do not automatically extend the navigation fixture. Next bounded +WP-0003 T01 question is a preregistered, pinned read-only Zulip navigation/search +source contrast: locate selection/result/focus ownership or counterexamples outside +the authored fixture; prior draft/send evidence does not count as navigation support. +T01 retains pending history disclosure, multiple misses, redirects, delayed swaps, +bfcache/lifecycle and interrupted/late enhancement before any production claim. +T02 retains independent human/AT review and offline VC-03 branch. WP-0006 T03 retains +review-date reconciliation and useful comparable-cycle windows; no M1/M2 closure.