Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions src/opendox/web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,30 @@ export function createDoxBenchThreadLoader(consoleTokenOf, injectedFetch) {
};
}

// THE THREAD READ IS WIRED ONLY WHERE A SESSION COLUMN IS (plan 034 T102
// follow-on; holder ruling F1 (i) on openxFactory#656). A thread is a branch
// session's record, one sidecar per document on the session branch, and only a
// host that contributes `gate.workbench.session` has branch sessions. A
// standalone plane has none, so every thread read it made answered 403
// `thread_capability_unavailable`, and the browser logged one console error per
// switch of the rail's loaded document (the T096 dry run's finding F1). The
// condition is `refusalTransport`'s: `workbenchGate.session`. A composed host
// keeps reading threads exactly as before.
//
// NOT AN ABSENT SEAM. The rail reads an absent `thread` as the pre-§11 rail,
// which keeps the previous document's transcript across a switch, and carrying
// one document's turns into another's next request is the defect the switch
// exists to close (`switchThread` in views/doxbench-chat.js). So a plane with
// no session column gets a seam that answers "no readable thread" itself, and
// sends nothing: the same `null` the 403 produced, so the rail still adopts the
// empty transcript, without the request or its console error.
export function doxbenchThreadSeam(session, consoleTokenOf, injectedFetch) {
if (!session) {
return async function noThreadWithoutABranchSession() { return null; };
}
return createDoxBenchThreadLoader(consoleTokenOf, injectedFetch);
}

export function createDoxBenchTurnSubmitter(consoleTokenOf, injectedFetch) {
return async function submitDoxBenchTurn(request) {
// Same missing-token rule as the catalog loader (PR #63 review).
Expand Down Expand Up @@ -1467,8 +1491,11 @@ async function render() {
// add-doxbench-editing-phase-b task 7.2: the rail's loaded-document
// selector switches the transcript to that document's thread, and this
// is where it reads one. A READ seam only — there is no thread write on
// this bundle, because a thread is written by a turn.
thread: createDoxBenchThreadLoader(() => caps?.console_token),
// this bundle, because a thread is written by a turn. Read only where a
// session column is (T102 follow-on, ruling F1 (i)): elsewhere the seam
// answers "no readable thread" without a request (`doxbenchThreadSeam`).
thread: doxbenchThreadSeam(workbenchGate.session,
() => caps?.console_token),
// add-doxbench-distilled-abstract §7: the docs subpane's model-derived
// abstract. One seam, one route, one call site -- and no second provider
// path: the route sits behind the SAME three-part verdict the catalog and
Expand Down
6 changes: 3 additions & 3 deletions tests/fixtures/web_boundary_census.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,15 @@ measured_at: "opensoft/openDox-code main a99eba03e31a0aee1cc15a061fdf718cc88a2c4
# shape and `test_the_declared_totals_are_re_derived_from_the_rows` can refuse a
# drift between the two. Measured at slice S4 (see the S4 block above).
totals:
A: {files: 26, loc: 18459}
A: {files: 26, loc: 18486}
B: {files: 1, loc: 73}
C: {files: 14, loc: 12757}
"?": {files: 1, loc: 1586}
files:
- path: app.js
class: A
loc: 1725
note: "the shell; its only class-B import was gate.js at :43 (discharged by S3's view registry -- loc 1155 -> 1282 with the registry wiring, S3; 1282 -> 1337 with S4's two new gate bindings and the two mounts it hands down). Carries SIX transitional route-ownership sites, all in the CORE arm's class-B binding entries and all cleared at S5 when those entries leave for contributedViewBindings(): gate.bar's one route (S3) and gate.lens's and gate.projects's two each (S4). Declaring them is RULED Q3 working -- view_extension.py: 'a binding that declares the routes it calls is what makes that ruling checkable instead of aspirational' -- and it is a real breach by assertion 2's own rule only while the entry sits in app.js (class A) rather than in the class-B module (exempt by construction) loc 1492 -> 1549 on this PR's round-2 review (Copilot): RULED Q1's generic pass is no longer ONE pass before every core mount — every `dom` region is a root its core renderer CLEARS, so the pass is run per region by the caller that just rendered it (after mountExplorer, after mountStagingWorkbench, and through the tab router's onRegionRendered hook on a tab's first render), and the Q11 refusal frame became a named function so a late refusal reaches the same surface. loc 1549 -> 1584 on round 3 (Copilot): the per-region pass is bound to THIS render's signal (a pass started from a tab's first render must not mount a stale snapshot into the next render's region), and the Q11 refusal frame re-inserts `#loadstatus` where a successful render removed it, so a late assembly refusal is visible instead of dropped. loc 1584 -> 1602 on round 4 (Copilot): the six contributed resolves each await a dynamic import and EVERYTHING after them mounts (the page-overlay host, the dispose panel into it, every region's core render), so a render whose scope was aborted mid-import now stops between the last resolve and the first mount rather than mounting its stale snapshot into the newer render; its error path stops with it, since a refusal from a render the user has switched away from would otherwise be written over the live render's own surface. loc 1602 -> 1618 on round 6 (Copilot): round 4's finding one and two awaits further down -- the generic mount pass is AWAITED after `mountExplorer` and after `mountStagingWorkbench`, and `mountContributedViews`'s own signal check (round 3) stops only ITS mounts, never the caller that resumes; below those two awaits sit the staging workbench, the tab strip, the repository selector and `status.remove()`, which would have stripped the NEWER render's loading state, so the resuming caller now stops at both. loc 1719 -> 1725 on plan 034 T102 (RULED openxFactory#656 `5963618568`): `refusalTransport`, which is every standalone Save now, carries the model's GATELESS_SAVE_REFUSAL, naming the missing session transport, instead of a CLI remedy a standalone install does not have."
loc: 1752
note: "the shell; its only class-B import was gate.js at :43 (discharged by S3's view registry -- loc 1155 -> 1282 with the registry wiring, S3; 1282 -> 1337 with S4's two new gate bindings and the two mounts it hands down). Carries SIX transitional route-ownership sites, all in the CORE arm's class-B binding entries and all cleared at S5 when those entries leave for contributedViewBindings(): gate.bar's one route (S3) and gate.lens's and gate.projects's two each (S4). Declaring them is RULED Q3 working -- view_extension.py: 'a binding that declares the routes it calls is what makes that ruling checkable instead of aspirational' -- and it is a real breach by assertion 2's own rule only while the entry sits in app.js (class A) rather than in the class-B module (exempt by construction) loc 1492 -> 1549 on this PR's round-2 review (Copilot): RULED Q1's generic pass is no longer ONE pass before every core mount — every `dom` region is a root its core renderer CLEARS, so the pass is run per region by the caller that just rendered it (after mountExplorer, after mountStagingWorkbench, and through the tab router's onRegionRendered hook on a tab's first render), and the Q11 refusal frame became a named function so a late refusal reaches the same surface. loc 1549 -> 1584 on round 3 (Copilot): the per-region pass is bound to THIS render's signal (a pass started from a tab's first render must not mount a stale snapshot into the next render's region), and the Q11 refusal frame re-inserts `#loadstatus` where a successful render removed it, so a late assembly refusal is visible instead of dropped. loc 1584 -> 1602 on round 4 (Copilot): the six contributed resolves each await a dynamic import and EVERYTHING after them mounts (the page-overlay host, the dispose panel into it, every region's core render), so a render whose scope was aborted mid-import now stops between the last resolve and the first mount rather than mounting its stale snapshot into the newer render; its error path stops with it, since a refusal from a render the user has switched away from would otherwise be written over the live render's own surface. loc 1602 -> 1618 on round 6 (Copilot): round 4's finding one and two awaits further down -- the generic mount pass is AWAITED after `mountExplorer` and after `mountStagingWorkbench`, and `mountContributedViews`'s own signal check (round 3) stops only ITS mounts, never the caller that resumes; below those two awaits sit the staging workbench, the tab strip, the repository selector and `status.remove()`, which would have stripped the NEWER render's loading state, so the resuming caller now stops at both. loc 1719 -> 1725 on plan 034 T102 (RULED openxFactory#656 `5963618568`): `refusalTransport`, which is every standalone Save now, carries the model's GATELESS_SAVE_REFUSAL, naming the missing session transport, instead of a CLI remedy a standalone install does not have. loc 1725 -> 1752 on plan 034 T102 follow-on (F1) (holder ruling F1 (i) on openxFactory#656): the rail's thread read is wired only where a session column is (`doxbenchThreadSeam`); with none, the seam answers no readable thread and sends nothing."

- path: index.html
class: C
Expand Down
Loading
Loading