Complete local coordination view switching and record remaining blockers
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e3b8-9815-70f2-9ac5-37bcde2c5090
This commit is contained in:
codex 2026-09-27 18:44:21 +02:00
parent 6923d4bfd0
commit b47dd43b04
7 changed files with 227 additions and 55 deletions

View file

@ -11,10 +11,10 @@
| workplan | RAIL-FAB-WP-0025 | finished | — | workplans/RAIL-FAB-WP-0025-rail-rapp-reef-fabric-adaptation.md | | workplan | RAIL-FAB-WP-0025 | finished | — | workplans/RAIL-FAB-WP-0025-rail-rapp-reef-fabric-adaptation.md |
| workplan | RAIL-FAB-WP-0026 | finished | — | workplans/RAIL-FAB-WP-0026-repo-family-relation-projection.md | | workplan | RAIL-FAB-WP-0026 | finished | — | workplans/RAIL-FAB-WP-0026-repo-family-relation-projection.md |
| workplan | RAIL-FAB-WP-0027 | finished | — | workplans/RAIL-FAB-WP-0027-versioned-rail-readiness-projection.md | | workplan | RAIL-FAB-WP-0027 | finished | — | workplans/RAIL-FAB-WP-0027-versioned-rail-readiness-projection.md |
| workplan | RAIL-FAB-WP-0028 | proposed | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md | | workplan | RAIL-FAB-WP-0028 | blocked | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md |
| workplan | RAIL-FAB-WP-0029 | proposed | — | workplans/RAIL-FAB-WP-0029-coordination-graph-perspective.md | | workplan | RAIL-FAB-WP-0029 | blocked | — | workplans/RAIL-FAB-WP-0029-coordination-graph-perspective.md |
| workplan | RAIL-FAB-WP-0030 | finished | — | workplans/RAIL-FAB-WP-0030-flavor-and-depends-on-graph.md | | workplan | RAIL-FAB-WP-0030 | finished | — | workplans/RAIL-FAB-WP-0030-flavor-and-depends-on-graph.md |
| workplan | RAIL-FAB-WP-0031 | active | — | workplans/RAIL-FAB-WP-0031-flex-auth-access-engine-rename.md | | workplan | RAIL-FAB-WP-0031 | blocked | — | workplans/RAIL-FAB-WP-0031-flex-auth-access-engine-rename.md |
| task | RAIL-FAB-WP-0025-T01 | done | — | workplans/RAIL-FAB-WP-0025-rail-rapp-reef-fabric-adaptation.md | | task | RAIL-FAB-WP-0025-T01 | done | — | workplans/RAIL-FAB-WP-0025-rail-rapp-reef-fabric-adaptation.md |
| task | RAIL-FAB-WP-0025-T02 | done | — | workplans/RAIL-FAB-WP-0025-rail-rapp-reef-fabric-adaptation.md | | task | RAIL-FAB-WP-0025-T02 | done | — | workplans/RAIL-FAB-WP-0025-rail-rapp-reef-fabric-adaptation.md |
| task | RAIL-FAB-WP-0025-T03 | done | — | workplans/RAIL-FAB-WP-0025-rail-rapp-reef-fabric-adaptation.md | | task | RAIL-FAB-WP-0025-T03 | done | — | workplans/RAIL-FAB-WP-0025-rail-rapp-reef-fabric-adaptation.md |
@ -26,11 +26,11 @@
| task | RAIL-FAB-WP-0027-T02 | done | — | workplans/RAIL-FAB-WP-0027-versioned-rail-readiness-projection.md | | task | RAIL-FAB-WP-0027-T02 | done | — | workplans/RAIL-FAB-WP-0027-versioned-rail-readiness-projection.md |
| task | RAIL-FAB-WP-0027-T03 | done | — | workplans/RAIL-FAB-WP-0027-versioned-rail-readiness-projection.md | | task | RAIL-FAB-WP-0027-T03 | done | — | workplans/RAIL-FAB-WP-0027-versioned-rail-readiness-projection.md |
| task | RAIL-FAB-WP-0027-T04 | done | — | workplans/RAIL-FAB-WP-0027-versioned-rail-readiness-projection.md | | task | RAIL-FAB-WP-0027-T04 | done | — | workplans/RAIL-FAB-WP-0027-versioned-rail-readiness-projection.md |
| task | RAIL-FAB-WP-0028-T01 | todo | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md | | task | RAIL-FAB-WP-0028-T01 | wait | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md |
| task | RAIL-FAB-WP-0028-T02 | todo | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md | | task | RAIL-FAB-WP-0028-T02 | wait | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md |
| task | RAIL-FAB-WP-0028-T03 | todo | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md | | task | RAIL-FAB-WP-0028-T03 | wait | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md |
| task | RAIL-FAB-WP-0028-T04 | todo | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md | | task | RAIL-FAB-WP-0028-T04 | wait | — | workplans/RAIL-FAB-WP-0028-hosted-financial-fabric-authority.md |
| task | RAIL-FAB-WP-0029-T01 | todo | — | workplans/RAIL-FAB-WP-0029-coordination-graph-perspective.md | | task | RAIL-FAB-WP-0029-T01 | wait | — | workplans/RAIL-FAB-WP-0029-coordination-graph-perspective.md |
| task | RAIL-FAB-WP-0030-T01 | done | — | workplans/RAIL-FAB-WP-0030-flavor-and-depends-on-graph.md | | task | RAIL-FAB-WP-0030-T01 | done | — | workplans/RAIL-FAB-WP-0030-flavor-and-depends-on-graph.md |
| task | RAIL-FAB-WP-0030-T02 | done | — | workplans/RAIL-FAB-WP-0030-flavor-and-depends-on-graph.md | | task | RAIL-FAB-WP-0030-T02 | done | — | workplans/RAIL-FAB-WP-0030-flavor-and-depends-on-graph.md |
| task | RAIL-FAB-WP-0030-T03 | done | — | workplans/RAIL-FAB-WP-0030-flavor-and-depends-on-graph.md | | task | RAIL-FAB-WP-0030-T03 | done | — | workplans/RAIL-FAB-WP-0030-flavor-and-depends-on-graph.md |

View file

@ -1,6 +1,6 @@
# Coordination graph (workplans and waits) # Coordination graph (workplans and waits)
State Hub owns workplans. Fabric does not author them. This view *projects* Repository files own workplans; State Hub indexes them. The Fabric explorer does not edit them. This view *projects*
open workplans and open tasks into the existing graph explorer so chokepoints open workplans and open tasks into the existing graph explorer so chokepoints
are inspectable. are inspectable.
@ -48,3 +48,15 @@ Chokepoint size is in-degree of **visible** (by default: non-residual)
workplan nodes from `depends_on` and remaining `waits_on` edges. workplan nodes from `depends_on` and remaining `waits_on` edges.
Solid blue = indexed `depends_on`. Dashed amber = citation `waits_on`. Solid blue = indexed `depends_on`. Dashed amber = citation `waits_on`.
## Switching views
The mode selector switches between topology and coordination in the same page.
Residual visibility refreshes the coordination payload and is retained in the
shareable URL. A failed refresh leaves the prior graph visible and shows an
error; an empty result can still be switched back to topology. Graph-specific
rules, selection, and zone placement reset when replacing the dataset.
The registry route is available locally. Hosted acceptance remains blocked by
RAIL-FAB-WP-0028's runtime, persistence, access, and deployment decisions; this
UI change does not establish a production authority.

View file

@ -568,8 +568,8 @@ def graph_explorer_page() -> str:
(() => { (() => {
const manifestUrl = "/exports/graph-explorer/manifest"; const manifestUrl = "/exports/graph-explorer/manifest";
const pageParams = new URLSearchParams(window.location.search); const pageParams = new URLSearchParams(window.location.search);
const graphMode = pageParams.get("mode"); let graphMode = pageParams.get("mode") === "coordination" ? "coordination" : "full";
const includeResidualsParam = ["1", "true", "yes"].includes( let includeResidualsParam = ["1", "true", "yes"].includes(
(pageParams.get("include_residuals") || "").toLowerCase() (pageParams.get("include_residuals") || "").toLowerCase()
); );
const graphUrl = graphMode === "coordination" const graphUrl = graphMode === "coordination"
@ -2141,6 +2141,7 @@ def graph_explorer_page() -> str:
const state = currentViewState(); const state = currentViewState();
if (state.search) params.set("search", state.search); if (state.search) params.set("search", state.search);
if (state.mode && state.mode !== "full") params.set("mode", state.mode); if (state.mode && state.mode !== "full") params.set("mode", state.mode);
if (state.mode === "coordination" && includeResidualsParam) params.set("include_residuals", "true");
if (state.layout && state.layout !== "cose") params.set("layout", state.layout); if (state.layout && state.layout !== "cose") params.set("layout", state.layout);
if (state.labelMode && state.labelMode !== "auto") params.set("labelMode", state.labelMode); if (state.labelMode && state.labelMode !== "auto") params.set("labelMode", state.labelMode);
if (state.nodeTypes.length !== allNodeTypes.length) params.set("nodeTypes", state.nodeTypes.join(",")); if (state.nodeTypes.length !== allNodeTypes.length) params.set("nodeTypes", state.nodeTypes.join(","));
@ -2201,6 +2202,10 @@ def graph_explorer_page() -> str:
}; };
const applyViewState = (state, options = {}) => { const applyViewState = (state, options = {}) => {
if (cy && "mode" in state && ((state.mode === "coordination") !== (graphMode === "coordination"))) {
switchGraph(state.mode, includeResidualsParam, state);
return;
}
if ("search" in state) searchInput.value = state.search || ""; if ("search" in state) searchInput.value = state.search || "";
if ("mode" in state) modeSelect.value = optionExists(modeSelect, state.mode) ? state.mode : "full"; if ("mode" in state) modeSelect.value = optionExists(modeSelect, state.mode) ? state.mode : "full";
if ("layout" in state) layoutSelect.value = optionExists(layoutSelect, state.layout) ? state.layout : "cose"; if ("layout" in state) layoutSelect.value = optionExists(layoutSelect, state.layout) ? state.layout : "cose";
@ -2828,11 +2833,7 @@ def graph_explorer_page() -> str:
residualsWrap.style.display = coordinationActive ? "" : "none"; residualsWrap.style.display = coordinationActive ? "" : "none";
residualsToggle.checked = includeResidualsParam; residualsToggle.checked = includeResidualsParam;
residualsToggle.addEventListener("change", () => { residualsToggle.addEventListener("change", () => {
const url = new URL(window.location.href); switchGraph("coordination", residualsToggle.checked);
url.searchParams.set("mode", "coordination");
if (residualsToggle.checked) url.searchParams.set("include_residuals", "true");
else url.searchParams.delete("include_residuals");
window.location.search = url.search;
}); });
} }
profiles = loadProfiles(); profiles = loadProfiles();
@ -2841,12 +2842,6 @@ def graph_explorer_page() -> str:
...element, ...element,
data: {...element.data, color: layerColors[element.data.layer] || "#667085"} data: {...element.data, color: layerColors[element.data.layer] || "#667085"}
})); }));
if (elements.length === 0) {
canvas.innerHTML = "<p class='canvas-notice'>No graph entities were returned by the registry.</p>";
counts.textContent = "0 nodes / 0 edges";
hiddenSummary.textContent = "Hidden 0";
return;
}
canvas.innerHTML = ""; canvas.innerHTML = "";
cy = cytoscape({ cy = cytoscape({
container: canvas, container: canvas,
@ -2975,6 +2970,69 @@ def graph_explorer_page() -> str:
applyViewState(urlState, {skipUrl: true}); applyViewState(urlState, {skipUrl: true});
runLayout(); runLayout();
updateUrlState(); updateUrlState();
if (!elements.length) profileSummary.textContent = "No graph entities were returned by the registry.";
};
let graphRequest = 0;
const switchGraph = async (mode, includeResiduals = includeResidualsParam, viewState = null) => {
const request = ++graphRequest;
const coordination = mode === "coordination";
const url = coordination
? `/exports/graph-explorer?mode=coordination${includeResiduals ? "&include_residuals=true" : ""}`
: "/exports/graph-explorer";
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const payload = await response.json();
if (!Array.isArray(payload.elements)) throw new Error("Invalid graph response");
if (request !== graphRequest) return;
const elements = payload.elements.map((element) => ({
...element,
data: {...element.data, color: layerColors[element.data.layer] || "#667085"}
}));
graphMode = coordination ? "coordination" : "full";
includeResidualsParam = includeResiduals;
activeMode = mode;
modeSelect.value = mode;
document.getElementById("include-residuals-wrap").style.display = coordination ? "" : "none";
document.getElementById("include-residuals").checked = includeResiduals;
selected = null;
selectedAnchor = null;
selectedZoneId = "";
focusSet = null;
manualOverrides = {};
filterRules = [];
editingRuleId = "";
collapsedZoneSnapshots.clear();
zoneContainerState.clear();
zoneSummaries.clear();
currentProfileId = "";
profileSelect.value = "";
allEdgeTypes = [...new Set(elements.map(({data}) => data.edgeType).filter(Boolean))].sort();
renderChecklist(nodeTypeFilter, allNodeTypes, nodeTypeLabels, "node-type");
renderChecklist(edgeTypeFilter, allEdgeTypes, {}, "edge-type");
cy.elements().remove();
cy.add(elements);
popup.style.display = "none";
refreshRuleBuilder();
renderRules();
syncFilterSummaries();
if (viewState) applyViewState(viewState);
else {
applyFilters();
runLayout();
updateUrlState();
}
showDetails(null);
updateProfileControls();
updateProfileSummary();
if (!elements.length) profileSummary.textContent = "No graph entities were returned by the registry.";
} catch (error) {
if (request !== graphRequest) return;
modeSelect.value = activeMode;
document.getElementById("include-residuals").checked = includeResidualsParam;
profileSummary.textContent = `Could not load graph: ${error.message}`;
}
}; };
const handleFilterChange = () => { const handleFilterChange = () => {
@ -2992,27 +3050,14 @@ def graph_explorer_page() -> str:
nodeTypeFilter.addEventListener("change", handleFilterChange); nodeTypeFilter.addEventListener("change", handleFilterChange);
edgeTypeFilter.addEventListener("change", handleFilterChange); edgeTypeFilter.addEventListener("change", handleFilterChange);
modeSelect.addEventListener("input", () => { modeSelect.addEventListener("input", () => {
if (modeSelect.value === "coordination" && graphMode !== "coordination") { const mode = modeSelect.value || "full";
const url = new URL(window.location.href); if ((mode === "coordination") !== (graphMode === "coordination")) {
url.searchParams.set("mode", "coordination"); switchGraph(mode);
window.location.search = url.search;
return; return;
} }
if (graphMode === "coordination" && modeSelect.value !== "coordination") { graphRequest += 1;
const url = new URL(window.location.href); activeMode = mode;
url.searchParams.delete("mode"); handleFilterChange();
url.searchParams.delete("include_residuals");
window.location.search = url.search;
return;
}
activeMode = modeSelect.value || "full";
focusSet = null;
currentProfileId = "";
profileSelect.value = "";
applyFilters();
updateProfileControls();
updateProfileSummary();
updateUrlState();
}); });
layoutSelect.addEventListener("input", () => { layoutSelect.addEventListener("input", () => {
currentProfileId = ""; currentProfileId = "";
@ -3179,8 +3224,8 @@ def graph_explorer_page() -> str:
document.querySelector("[data-action='focus']").addEventListener("click", applyFocus); document.querySelector("[data-action='focus']").addEventListener("click", applyFocus);
document.querySelector("[data-action='clear']").addEventListener("click", () => { document.querySelector("[data-action='clear']").addEventListener("click", () => {
searchInput.value = ""; searchInput.value = "";
modeSelect.value = "full"; modeSelect.value = graphMode;
activeMode = "full"; activeMode = graphMode;
labelSelect.value = "auto"; labelSelect.value = "auto";
activeLabelMode = "auto"; activeLabelMode = "auto";
zoneBoundaryToggle.checked = true; zoneBoundaryToggle.checked = true;

View file

@ -0,0 +1,70 @@
"""Execute the browser transition against a small graph/DOM harness."""
import shutil
import subprocess
import pytest
from railiance_fabric.graph_explorer_ui import graph_explorer_page
def test_graph_switch_replaces_data_and_retains_previous_graph_on_failure(tmp_path):
if not shutil.which("node"):
pytest.skip("Node.js is required for the UI transition test")
page = graph_explorer_page()
transition = page.split(" let graphRequest = 0;", 1)[1].split(
" const handleFilterChange", 1
)[0]
script = r'''
const assert = require("node:assert/strict");
let graphMode = "full", includeResidualsParam = false, activeMode = "full";
let selected, selectedAnchor, selectedZoneId, focusSet, manualOverrides, filterRules;
let editingRuleId, currentProfileId, allEdgeTypes;
const layerColors = {}, allNodeTypes = [], nodeTypeLabels = {};
const collapsedZoneSnapshots = new Map(), zoneContainerState = new Map(), zoneSummaries = new Map();
const modeSelect = {}, profileSelect = {}, nodeTypeFilter = {}, edgeTypeFilter = {};
const popup = {style: {}}, profileSummary = {};
const controls = {};
const document = {getElementById(id) {return controls[id] ||= {style: {}};}};
let data = [{data: {id: "old"}}], urls = [], updated = 0;
const cy = {elements: () => ({remove() {data = [];}}), add(elements) {data.push(...elements);}};
const renderChecklist = () => {}, refreshRuleBuilder = () => {}, renderRules = () => {};
const syncFilterSummaries = () => {}, applyFilters = () => {}, runLayout = () => {};
const updateUrlState = () => {updated++;}, showDetails = () => {};
const updateProfileControls = () => {}, updateProfileSummary = () => {};
const applyViewState = () => {};
let response = {ok: true, json: async () => ({elements: [{data: {id: "workplan:a"}}]})};
let fetch = async (url) => {urls.push(url); return response;};
let graphRequest = 0;
'''
script += transition + r'''
(async () => {
await switchGraph("coordination", true);
assert.equal(data[0].data.id, "workplan:a");
assert.equal(modeSelect.value, "coordination");
assert.equal(controls["include-residuals-wrap"].style.display, "");
assert.match(urls[0], /include_residuals=true/);
response = {ok: false, status: 503};
await switchGraph("full");
assert.equal(data[0].data.id, "workplan:a");
assert.equal(modeSelect.value, "coordination");
assert.match(profileSummary.textContent, /503/);
response = {ok: true, json: async () => ({elements: []})};
await switchGraph("by-access-zone");
assert.deepEqual(data, []);
assert.equal(activeMode, "by-access-zone");
assert.equal(graphMode, "full");
assert.equal(controls["include-residuals-wrap"].style.display, "none");
let resolveOld;
fetch = () => new Promise(resolve => {resolveOld = resolve;});
const oldRequest = switchGraph("coordination");
fetch = async () => ({ok: true, json: async () => ({elements: [{data: {id: "latest"}}]})});
await switchGraph("full");
resolveOld({ok: true, json: async () => ({elements: [{data: {id: "stale"}}]})});
await oldRequest;
assert.equal(data[0].data.id, "latest");
assert.equal(updated, 3);
})().catch(error => {console.error(error); process.exitCode = 1;});
'''
path = tmp_path / "switch.cjs"
path.write_text(script)
subprocess.run(["node", str(path)], check=True, capture_output=True, text=True)

View file

@ -4,14 +4,14 @@ type: workplan
title: "Host and operate the financial Fabric authority" title: "Host and operate the financial Fabric authority"
domain: financials domain: financials
repo: railiance-fabric repo: railiance-fabric
status: proposed status: blocked
flavor: residual flavor: residual
origin: residual origin: residual
origin_ref: STATE-WP-0079 origin_ref: STATE-WP-0079
owner: codex owner: codex
topic_slug: railiance topic_slug: railiance
created: "2026-08-31" created: "2026-08-31"
updated: "2026-09-22" updated: "2026-09-27"
state_hub_workstream_id: "58a56363-3bda-50f7-8240-1e45131bc7d9" state_hub_workstream_id: "58a56363-3bda-50f7-8240-1e45131bc7d9"
--- ---
@ -31,7 +31,7 @@ rollback rehearsal.
```task ```task
id: RAIL-FAB-WP-0028-T01 id: RAIL-FAB-WP-0028-T01
status: todo status: wait
flavor: residual flavor: residual
priority: high priority: high
state_hub_task_id: "65702f41-b87e-59e5-9396-cd1fda5e8ef4" state_hub_task_id: "65702f41-b87e-59e5-9396-cd1fda5e8ef4"
@ -45,7 +45,7 @@ snapshot history and deterministic snapshot-set provenance.
```task ```task
id: RAIL-FAB-WP-0028-T02 id: RAIL-FAB-WP-0028-T02
status: todo status: wait
flavor: residual flavor: residual
priority: high priority: high
state_hub_task_id: "cad1af1d-177b-5a47-a9fa-d99c40bb2649" state_hub_task_id: "cad1af1d-177b-5a47-a9fa-d99c40bb2649"
@ -59,7 +59,7 @@ Do not expose mutation endpoints without the authorization selected in T01.
```task ```task
id: RAIL-FAB-WP-0028-T03 id: RAIL-FAB-WP-0028-T03
status: todo status: wait
flavor: residual flavor: residual
priority: high priority: high
state_hub_task_id: "78a73d4e-46aa-53c7-911b-be5f79bc25e8" state_hub_task_id: "78a73d4e-46aa-53c7-911b-be5f79bc25e8"
@ -73,7 +73,7 @@ accepted snapshot set.
```task ```task
id: RAIL-FAB-WP-0028-T04 id: RAIL-FAB-WP-0028-T04
status: todo status: wait
flavor: residual flavor: residual
priority: high priority: high
state_hub_task_id: "c66c3fa4-8856-5999-8c47-dbb2f6efc21e" state_hub_task_id: "c66c3fa4-8856-5999-8c47-dbb2f6efc21e"
@ -82,3 +82,19 @@ state_hub_task_id: "c66c3fa4-8856-5999-8c47-dbb2f6efc21e"
Starts after T03. Run the fin-hub consumer gate against the hosted owner endpoint, inventory and Starts after T03. Run the fin-hub consumer gate against the hosted owner endpoint, inventory and
switch any real callers, exercise rollback, and hand the receipts back to switch any real callers, exercise rollback, and hand the receipts back to
`STATE-WP-0079-T04` before State Hub's Fabric projection routes retire. `STATE-WP-0079-T04` before State Hub's Fabric projection routes retire.
## Loose-end review — 2026-09-27
T01–T04 remain blocked. The fin-hub consumer contract selects Fabric as the
specialized authority, but does not select or admit its production runtime,
persistent volume, offsite backup ownership, authentication policy, or deployment
repository. No hosted Fabric onboarding decision was found in this repository
or railiance-platform's workplans. A workstation SQLite service does not satisfy
this plan's durability gate.
T01 needs a runtime/persistence and access decision with railiance-platform and
railiance-enablement, including named backup/recovery ownership and deployment
admission. T02 waits for that decision; T03 waits for the deployed authority;
T04 waits for freshness/recovery receipts and the fin-hub consumer gate. Keep
State Hub projection routes available until those gates pass. Existing tasks
retain all work; no new task or workplan was opened.

View file

@ -4,17 +4,17 @@ type: workplan
title: "Inspectable workplan and wait graph in the Fabric explorer" title: "Inspectable workplan and wait graph in the Fabric explorer"
domain: financials domain: financials
repo: railiance-fabric repo: railiance-fabric
status: proposed status: blocked
flavor: planning flavor: planning
owner: grok owner: grok
topic_slug: railiance topic_slug: railiance
created: "2026-09-14" created: "2026-09-14"
updated: "2026-09-14" updated: "2026-09-27"
related: [RAIL-FAB-WP-0028, CUST-WP-0071] related: [RAIL-FAB-WP-0028, CUST-WP-0071]
state_hub_workstream_id: "1daac341-94dd-5f44-9907-91c611e7e3c1" state_hub_workstream_id: "1daac341-94dd-5f44-9907-91c611e7e3c1"
--- ---
State Hub remains the workplan authoring surface. Fabric already has a Repository files remain the workplan source; State Hub indexes them. Fabric already has a
graph-explorer shell. This plan is a *perspective*: open workplans, open graph-explorer shell. This plan is a *perspective*: open workplans, open
tasks, and wait/depends_on edges, so the 100+ loose ends are inspectable. tasks, and wait/depends_on edges, so the 100+ loose ends are inspectable.
@ -26,7 +26,7 @@ First slice (this file's companion commit):
```task ```task
id: RAIL-FAB-WP-0029-T01 id: RAIL-FAB-WP-0029-T01
status: todo status: wait
priority: medium priority: medium
state_hub_task_id: "f80a8b15-ea3d-5701-9707-0a6151f50b5c" state_hub_task_id: "f80a8b15-ea3d-5701-9707-0a6151f50b5c"
``` ```
@ -35,3 +35,19 @@ Keep the projection a read of State Hub. Add mode switching without a full
page reload, chokepoint sizing from in-degree, and a hosted registry path page reload, chokepoint sizing from in-degree, and a hosted registry path
under RAIL-FAB-WP-0028 when that authority exists. Do not let Fabric become under RAIL-FAB-WP-0028 when that authority exists. Do not let Fabric become
the place workplans are edited. the place workplans are edited.
## Loose-end review — 2026-09-27
Completed the repo-local portion of T01: topology/coordination mode changes
and residual visibility now fetch and replace the graph without page reload.
The requested topology mode survives the switch back; empty payloads remain
switchable, failed fetches retain the previous graph, and stale responses cannot
overwrite a newer request. Shared URLs retain residual visibility. Existing
in-degree sizing and indexed/citation edge precedence remain in place.
T01 stays `wait` and the workplan is `blocked` solely for hosted acceptance
under RAIL-FAB-WP-0028. The read-only coordination export already has a registry
route (`/exports/graph-explorer?mode=coordination`); it must be verified on the
admitted hosted authority once available. No separate task was created for this
remaining gate. Validation: JavaScript syntax check, executable transition
regression, and the repository Python suite (see session progress receipt).

View file

@ -4,14 +4,14 @@ type: workplan
title: "Follow the flex-auth to access-engine repository rename in Fabric" title: "Follow the flex-auth to access-engine repository rename in Fabric"
domain: financials domain: financials
repo: railiance-fabric repo: railiance-fabric
status: active status: blocked
flavor: residual flavor: residual
origin: residual origin: residual
origin_ref: FLEX-WP-0020 origin_ref: FLEX-WP-0020
owner: codex owner: codex
topic_slug: railiance topic_slug: railiance
created: "2026-09-22" created: "2026-09-22"
updated: "2026-09-22" updated: "2026-09-27"
state_hub_workstream_id: "631e2974-55ba-58e3-b8ca-dc6c1c294111" state_hub_workstream_id: "631e2974-55ba-58e3-b8ca-dc6c1c294111"
--- ---
@ -68,3 +68,16 @@ Re-run `scan-manifest` for the renamed entry and re-export the graph. Confirm
that no `repo:flex-auth` repository node remains, that the `flex-auth.*` that no `repo:flex-auth` repository node remains, that the `flex-auth.*`
runtime nodes are unchanged, and that no edge endpoint is left unresolved. runtime nodes are unchanged, and that no edge endpoint is left unresolved.
Then reply to flex-auth with the evidence. Then reply to flex-auth with the evidence.
## Loose-end review — 2026-09-27
T01–T03 remain `wait`; the workplan is now `blocked`. The local checkout remains
`/home/worsch/flex-auth`; `/home/worsch/access-engine` is absent. The owner's
FLEX-WP-0020 still records T05 (fresh preflight and exact human approval) and T06
(Forgejo rename) as `wait`. There is no execution receipt satisfying T01.
Resume only after the owner reports the completed rename with unchanged
repository UUID and Forge ID 42. Then update coordinates and re-ingest under
T02/T03, preserving all `flex-auth.*` runtime identities. Preemptive manifest
changes would point to a missing checkout; no declarations or historical
snapshots were renamed during this review.