From 9f744dd7f3784be76facc48e8dba0d1059068315 Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 11 Mar 2026 01:40:52 +0100 Subject: [PATCH] feat(ep-td+dashboard): complete CUST-WP-0004 EP/TD tracking workstream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EP catalogue (all domains): - EP-RAIL-001 ep_id patched (schema fix: add ep_id to EPUpdate) - EP-RAIL-003 (git bare-repo mirrors) and EP-RAIL-004 (offsite secondary backup) registered from railiance-cluster/docs/backup-restore.md - EP-CUST-003..007 ep_ids assigned to existing custodian EPs - EP-CUST-008 (State Hub API auth) and EP-CUST-009 (update_workstream MCP tool) registered as new custodian extension points TD catalogue (railiance — first 5 items): - TD-RAIL-001: backup cron runs as root without audit trail (high/security) - TD-RAIL-002: k3s kubeconfig world-readable mode 644 (medium/security) - TD-RAIL-003: no Ansible role unit tests (medium/test) - TD-RAIL-004: age key extracted via awk — fragile (medium/impl) - TD-RAIL-005: etcd snapshot retention uncoordinated (low/impl) Dashboard (T08 + T10): - Extract API URL and POLL to src/components/config.js; all 15 pages now import from the shared module (contributions/goals keep custom POLL) - Shared .kpi-infobox, .filter-bar, .filter-search/.filter-owner CSS moved to observablehq.config.js head `, footer: "Custodian State Hub — local-first, append-only, sovereignty-preserving.", }; diff --git a/dashboard/src/components/config.js b/dashboard/src/components/config.js new file mode 100644 index 0000000..e84e170 --- /dev/null +++ b/dashboard/src/components/config.js @@ -0,0 +1,2 @@ +export const API = "http://127.0.0.1:8000"; +export const POLL = 15_000; diff --git a/dashboard/src/contributions.md b/dashboard/src/contributions.md index 0915195..0bfa3ca 100644 --- a/dashboard/src/contributions.md +++ b/dashboard/src/contributions.md @@ -3,7 +3,7 @@ title: Contributions --- ```js -const API = "http://127.0.0.1:8000"; +import {API} from "./components/config.js"; const POLL = 30_000; ``` diff --git a/dashboard/src/decisions.md b/dashboard/src/decisions.md index c5ae0c7..77ad493 100644 --- a/dashboard/src/decisions.md +++ b/dashboard/src/decisions.md @@ -3,8 +3,7 @@ title: Decisions --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js @@ -392,25 +391,6 @@ if (escalated.length > 0) { margin-bottom: 0.75rem; } -/* ── KPI infobox ──────────────────────────────────────────────────────────── */ -.kpi-infobox { - background: var(--theme-background-alt, #f9f9f9); - border: 1px solid var(--theme-foreground-faint, #e0e0e0); - border-radius: 10px; - padding: 0.75rem 1rem; - position: relative; - box-shadow: 0 1px 6px rgba(0,0,0,0.07); - margin-bottom: 1.25rem; -} -.kpi-infobox-title { - font-size: 0.68rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.08em; - color: var(--theme-foreground-muted, #888); - margin-bottom: 0.55rem; - padding-right: 1.6rem; /* room for ? button */ -} .kpi-row { display: flex; justify-content: space-between; @@ -445,10 +425,6 @@ if (escalated.length > 0) { /* ── Utility ──────────────────────────────────────────────────────────────── */ .dim { color: gray; font-style: italic; } -/* ── Filter bar ───────────────────────────────────────────────────────────── */ -.filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 1rem; } -.filter-search { display: flex; align-items: center; } -.filter-search input { height: 30px; font-size: 0.85rem; padding: 0.25rem 0.5rem; border-radius: 6px; border: 1px solid var(--theme-foreground-faint, #ccc); background: var(--theme-background, #fff); font-family: inherit; color: inherit; } /* ── Decision list ────────────────────────────────────────────────────────── */ .dec-list { display: flex; flex-direction: column; gap: 0.5rem; } diff --git a/dashboard/src/dependencies.md b/dashboard/src/dependencies.md index 8c15fde..f047d59 100644 --- a/dashboard/src/dependencies.md +++ b/dashboard/src/dependencies.md @@ -3,8 +3,7 @@ title: Dependencies --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js @@ -136,8 +135,6 @@ if (edges.length === 0) { .live-indicator { font-size: 0.8rem; color: gray; position: relative; padding: 0.55rem 1.8rem 0.55rem 0.7rem; margin-bottom: 0.75rem; } /* ── KPI infobox ──────────────────────────────────────────────────────────── */ -.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; } -.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; } .kpi-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.3rem 0; } .kpi-row + .kpi-row { border-top: 1px solid var(--theme-foreground-faint, #eee); } .kpi-row-label { font-size: 0.8rem; color: var(--theme-foreground-muted, #666); white-space: nowrap; } diff --git a/dashboard/src/domains.md b/dashboard/src/domains.md index 6f31c04..a004378 100644 --- a/dashboard/src/domains.md +++ b/dashboard/src/domains.md @@ -3,8 +3,7 @@ title: Domains --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js diff --git a/dashboard/src/extensions.md b/dashboard/src/extensions.md index 9563089..fdc7245 100644 --- a/dashboard/src/extensions.md +++ b/dashboard/src/extensions.md @@ -3,8 +3,7 @@ title: Extension Points --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js @@ -210,8 +209,6 @@ display(html`
${filtered.map(ep => html` .live-indicator { font-size: 0.8rem; color: gray; position: relative; padding: 0.55rem 1.8rem 0.55rem 0.7rem; margin-bottom: 0.75rem; } /* ── KPI infobox ──────────────────────────────────────────────────────────── */ -.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; } -.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; } .kpi-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.3rem 0; border-top: 1px solid var(--theme-foreground-faint, #eee); } .kpi-row:first-of-type { border-top: none; } .kpi-row-label { font-size: 0.8rem; color: var(--theme-foreground-muted, #666); } @@ -225,7 +222,6 @@ display(html`
${filtered.map(ep => html` .chart-row { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: flex-start; } /* ── Filters ──────────────────────────────────────────────────────────────── */ -.filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 1rem; } /* ── EP list ──────────────────────────────────────────────────────────────── */ .ep-list { display: flex; flex-direction: column; gap: 0.5rem; } diff --git a/dashboard/src/goals.md b/dashboard/src/goals.md index d3eba71..c109537 100644 --- a/dashboard/src/goals.md +++ b/dashboard/src/goals.md @@ -3,7 +3,7 @@ title: Goals --- ```js -const API = "http://127.0.0.1:8000"; +import {API} from "./components/config.js"; const POLL = 20_000; ``` @@ -253,8 +253,6 @@ if (unlinkedRepoGoals.length > 0) { .live-indicator { font-size: 0.8rem; color: gray; position: relative; padding: 0.55rem 1.8rem 0.55rem 0.7rem; margin-bottom: 0.75rem; } /* ── KPI infobox ──────────────────────────────────────────────────────────── */ -.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; } -.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; } .kpi-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.3rem 0; } .kpi-row + .kpi-row { border-top: 1px solid var(--theme-foreground-faint, #eee); } .kpi-row-label { font-size: 0.8rem; color: var(--theme-foreground-muted, #666); white-space: nowrap; } diff --git a/dashboard/src/index.md b/dashboard/src/index.md index c180c28..be14899 100644 --- a/dashboard/src/index.md +++ b/dashboard/src/index.md @@ -3,8 +3,7 @@ title: Overview --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js diff --git a/dashboard/src/interventions.md b/dashboard/src/interventions.md index dad9da1..c450ccd 100644 --- a/dashboard/src/interventions.md +++ b/dashboard/src/interventions.md @@ -3,8 +3,7 @@ title: Interventions --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js @@ -193,8 +192,6 @@ if (closed.length === 0) { .live-indicator { font-size: 0.8rem; color: gray; position: relative; padding: 0.55rem 1.8rem 0.55rem 0.7rem; margin-bottom: 0.75rem; } /* ── KPI infobox ──────────────────────────────────────────────────────────── */ -.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; } -.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; } .kpi-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.3rem 0; } .kpi-row + .kpi-row { border-top: 1px solid var(--theme-foreground-faint, #eee); } .kpi-row-label { font-size: 0.8rem; color: var(--theme-foreground-muted, #666); white-space: nowrap; } diff --git a/dashboard/src/progress.md b/dashboard/src/progress.md index 3b5e5ed..8394032 100644 --- a/dashboard/src/progress.md +++ b/dashboard/src/progress.md @@ -3,8 +3,7 @@ title: Progress --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js diff --git a/dashboard/src/repos.md b/dashboard/src/repos.md index 051975c..a130c8f 100644 --- a/dashboard/src/repos.md +++ b/dashboard/src/repos.md @@ -3,7 +3,7 @@ title: Repos --- ```js -const API = "http://127.0.0.1:8000"; +import {API} from "./components/config.js"; ``` ```js diff --git a/dashboard/src/sbom.md b/dashboard/src/sbom.md index 824343f..8603988 100644 --- a/dashboard/src/sbom.md +++ b/dashboard/src/sbom.md @@ -3,7 +3,7 @@ title: SBOM --- ```js -const API = "http://127.0.0.1:8000"; +import {API} from "./components/config.js"; ``` ```js diff --git a/dashboard/src/tasks.md b/dashboard/src/tasks.md index 9c8e9a6..1578402 100644 --- a/dashboard/src/tasks.md +++ b/dashboard/src/tasks.md @@ -3,8 +3,7 @@ title: Tasks --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js @@ -235,8 +234,6 @@ display(buildEntityTable( .live-indicator { font-size: 0.8rem; color: gray; position: relative; padding: 0.55rem 1.8rem 0.55rem 0.7rem; margin-bottom: 0.75rem; } /* ── KPI infobox ──────────────────────────────────────────────────────────── */ -.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; } -.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; padding-right: 1.6rem; } .kpi-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.3rem 0; } .kpi-row + .kpi-row { border-top: 1px solid var(--theme-foreground-faint, #eee); } .kpi-row-label { font-size: 0.8rem; color: var(--theme-foreground-muted, #666); white-space: nowrap; } @@ -245,9 +242,6 @@ display(buildEntityTable( .kpi-row-sub { font-size: 0.68rem; color: var(--theme-foreground-faint, #aaa); line-height: 1.2; } /* ── Filters ──────────────────────────────────────────────────────────────── */ -.filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 1rem; } -.filter-owner { display: flex; align-items: center; } -.filter-owner input { height: 30px; font-size: 0.85rem; padding: 0.25rem 0.5rem; border-radius: 6px; border: 1px solid var(--theme-foreground-faint, #ccc); background: var(--theme-background, #fff); font-family: inherit; color: inherit; } /* ── Blocked task cards ───────────────────────────────────────────────────── */ .task-blocked-list { display: flex; flex-direction: column; gap: 0.5rem; } diff --git a/dashboard/src/techdept.md b/dashboard/src/techdept.md index 0fa2ef6..f2545ec 100644 --- a/dashboard/src/techdept.md +++ b/dashboard/src/techdept.md @@ -3,8 +3,7 @@ title: Technical Debt --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js @@ -246,8 +245,6 @@ display(html`
${filtered.map(t => html` .live-indicator { font-size: 0.8rem; color: gray; position: relative; padding: 0.55rem 1.8rem 0.55rem 0.7rem; margin-bottom: 0.75rem; } /* ── KPI infobox ──────────────────────────────────────────────────────────── */ -.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; } -.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; } .kpi-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.3rem 0; border-top: 1px solid var(--theme-foreground-faint, #eee); } .kpi-row:first-of-type { border-top: none; } .kpi-row-label { font-size: 0.8rem; color: var(--theme-foreground-muted, #666); } @@ -259,7 +256,6 @@ display(html`
${filtered.map(t => html` .chart-row { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: flex-start; } /* ── Filters ──────────────────────────────────────────────────────────────── */ -.filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 1rem; } /* ── TD list ──────────────────────────────────────────────────────────────── */ .td-list { display: flex; flex-direction: column; gap: 0.5rem; } diff --git a/dashboard/src/todo.md b/dashboard/src/todo.md index 769b182..b02e13c 100644 --- a/dashboard/src/todo.md +++ b/dashboard/src/todo.md @@ -3,8 +3,7 @@ title: Todo --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; const THIS_REPO = "the-custodian"; ``` @@ -204,8 +203,6 @@ if (thirdParty.length === 0) { .live-indicator { font-size: 0.8rem; color: gray; position: relative; padding: 0.55rem 1.8rem 0.55rem 0.7rem; margin-bottom: 0.75rem; } /* ── KPI infobox ──────────────────────────────────────────────────────────── */ -.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; } -.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; } .kpi-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.3rem 0; } .kpi-row + .kpi-row { border-top: 1px solid var(--theme-foreground-faint, #eee); } .kpi-row-label { font-size: 0.8rem; color: var(--theme-foreground-muted, #666); white-space: nowrap; } diff --git a/dashboard/src/workstreams.md b/dashboard/src/workstreams.md index b6b8f12..3576ede 100644 --- a/dashboard/src/workstreams.md +++ b/dashboard/src/workstreams.md @@ -3,8 +3,7 @@ title: Workstreams --- ```js -const API = "http://127.0.0.1:8000"; -const POLL = 15_000; +import {API, POLL} from "./components/config.js"; ``` ```js @@ -330,8 +329,6 @@ if (wsWithDeps.length === 0) { .live-indicator { font-size: 0.8rem; color: gray; position: relative; padding: 0.55rem 1.8rem 0.55rem 0.7rem; margin-bottom: 0.75rem; } /* ── KPI infobox base (shared) ───────────────────────────────────────────── */ -.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; } -.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; padding-right: 1.6rem; } .kpi-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.3rem 0; } .kpi-muted { color: var(--theme-foreground-faint, #aaa); font-style: italic; font-size: 0.8rem; } @@ -352,9 +349,6 @@ if (wsWithDeps.length === 0) { .whi-domain-name { flex: 1; font-size: 0.75rem; color: var(--theme-foreground-muted, #666); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .whi-domain-score { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 0.75rem; } .dim { color: gray; font-style: italic; } -.filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 1rem; } -.filter-owner { display: flex; align-items: center; } -.filter-owner input { height: 30px; font-size: 0.85rem; padding: 0.25rem 0.5rem; border-radius: 6px; border: 1px solid var(--theme-foreground-faint, #ccc); background: var(--theme-background, #fff); font-family: inherit; color: inherit; } .dep-grid { display: flex; flex-direction: column; gap: 0.75rem; } .dep-card { border: 1px solid #e0e0e0; border-radius: 6px; padding: 0.75rem 1rem; background: var(--theme-background-alt, #fafafa); } .dep-title { font-weight: 600; margin-bottom: 0.25rem; }