Complete local coordination view switching and record remaining blockers
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e3b8-9815-70f2-9ac5-37bcde2c5090
This commit is contained in:
parent
6923d4bfd0
commit
b47dd43b04
7 changed files with 227 additions and 55 deletions
|
|
@ -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 |
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
70
tests/test_graph_mode_switch.py
Normal file
70
tests/test_graph_mode_switch.py
Normal 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)
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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).
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue