Commit Graph

82 Commits

Author SHA1 Message Date
2d0ce8f943 feat(api): CUST-WP-0018 — API hardening & code quality
T01: Fix datetime.utcnow() → datetime.now(tz=timezone.utc) in MCP server
T02: Wrap _get/_post/_patch/_delete with try/except; return error dicts
T03: Log warnings when write_log skips missing project path
T04: Add priority + due_date_before filters to GET /tasks/
T05: Add owner + slug filters to GET /workstreams/
T06: Add offset param to GET /progress/ for proper pagination
T07: Low-severity bundle:
  - CORS origins from CORS_ORIGINS env var (TD-017)
  - seed.py upsert domains+topics on re-run (TD-011)
  - normalise filter bar CSS → filter-text-input everywhere (TD-016)
  - add 30.5 avg-days-per-month comment in decisions.md (TD-019)
  - TD-009, TD-018 already resolved by existing code

Closes CUST-WP-0018.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 02:17:04 +01:00
b66291aac1 fix(dashboard): rename Repository → Repositories, Policy → Policies
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 02:08:54 +01:00
e9190c179f fix(dashboard): pin Overview as first nav entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 02:07:03 +01:00
b4e26fdc8f feat(dashboard): reorder nav — flat pages first (alpha), sections below (alpha), Reference last
Sub-pages within sections also sorted alphabetically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 02:06:23 +01:00
f0e9bb0143 feat(dashboard): CUST-WP-0019 — Repository nav section, config.js cleanup
T01: Restructure nav — "Repos" → collapsible "Repository" section with
     Repo Sync, SBOM, Debt as sub-pages; Debt moved out of Workstreams
T02: workstream-dod.md migrated from inline const API to config.js import
T03: todo.md suggestion filter (done in previous commit)

Closes CUST-WP-0019. Resolves UI suggestion c2fc284a.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 02:01:10 +01:00
0969f3258c feat(workplans): CUST-WP-0018/0019/0020 — API hardening, dashboard UX polish, test suite
Consolidates all open technical debt into three workplans:
- CUST-WP-0018: API hardening & code quality (TD-006–019 medium/high items)
- CUST-WP-0019: Dashboard UX polish (Repos nav restructure, config.js cleanup,
  todo filter fix for new suggestion workflow statuses)
- CUST-WP-0020: pytest test suite with real DB (TD-014)

Also fixes todo.md Suggestions filter: was checking status===open but new
suggestions enter with status=submitted; now excludes terminal statuses only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 01:55:37 +01:00
d9b9a0eaec feat(dashboard): extend suggestions to TOC right margin + 1s shift delay
- Shift+click now works on #observablehq-toc links, KPI boxes, and [id] elements
- _inferWidgetName detects TOC context and labels suggestions accordingly
- Click handler adds inToc branch alongside existing inSidebar
- _updateMode: 1-second setTimeout before activating highlight mode
  so normal Shift+typing doesn't flicker the UI; clears immediately on
  Shift release or window blur

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 01:42:11 +01:00
e7565ce789 feat(dashboard): extend shift+click suggestions to sidebar navigation
- Click handler: sidebar <a> and <summary> are no longer excluded;
  e.preventDefault() stops navigation while shift is held
- _inferWidgetName: sidebar-first branch returns nav link text,
  section heading text, or "Navigation" fallback
- pageName is "Navigation" for sidebar clicks (not the current page title)
- CSS: sidebar a and summary highlighted (dashed indigo outline + tint)
  when shift is held, same as main content widgets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 01:29:13 +01:00
1f1da56533 feat(suggestions): full suggestion workflow with per-step notes
DB migration h5c6d7e8f9a0:
- Extends tdstatus enum: submitted → analyse → plan → implement →
  test → review → finished (+ wont_fix remains)
- New td_notes table: td_id FK (CASCADE), step, author, content, created_at

API:
- TDNote model + TDNoteCreate/TDNoteRead schemas
- TDRead includes notes[] (selectin loaded)
- New routes: GET/POST /technical-debt/{id}/notes/
- list_td status filter accepts str (all enum values)

Modal: new submissions use status="submitted" instead of "open"

UI Feedback page revamp:
- Visual step-by-step stepper (submitted→analyse→plan→implement→test→review→finished)
- Per-step notes: view all notes, add note inline
- Action buttons: advance to next step, won't fix
- Review step highlighted as awaiting original suggester confirmation
- Closed items (finished/wont_fix) shown with last 2 notes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:57:34 +01:00
7566851335 fix(dashboard): repair broken SBOM card on Overview
The card titled "SBOM" was displaying contribution type counts (FR/BR/EP/UPR)
which is unrelated to SBOM data. Added a sbomSnapState generator that fetches
/sbom/snapshots/ and shows: total tracked packages (sum of entry_count across
all snapshots), repos tracked, and copyleft risk count from the existing
licence_risk_count in the summary. Card turns orange if licenceRisk > 0.

Resolves suggestion b6775727.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:42:30 +01:00
6cd9f75d7e fix(dashboard): domain field name in TD payload; rename Improvements → Suggestions
- improvement-modal.js: API expects `domain` not `domain_slug` (422 fix)
- todo.md: section heading and KPI label renamed to "Suggestions"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:36:46 +01:00
71488729a1 fix(dashboard): inline improvement modal script via readFileSync in config
Observable Framework proxies all src/*.js files through its own bundler —
<script type="module"> imports from <head> resolve to circular re-export
shims and never execute. The fix: read improvement-modal.js at config load
time in Node.js, strip the ES module export keyword, and interpolate the
content as a plain <script> block in the head config. It runs on every page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:32:54 +01:00
f3568cb111 fix(dashboard): inject improvement modal via head config, not _footer.md
_footer.md is not a supported special file in Observable Framework 1.13.3
and was silently ignored. The preview server does serve src/*.js files at
their root-relative path, so the correct approach is a <script type="module">
in the head config — runs once on page load, persists across SPA navigation.
Removed _footer.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:28:06 +01:00
4d0941b524 fix(dashboard): robust shift-mode tracking via mousemove + element highlights
- updateMode() now subscribes to keydown, keyup AND mousemove so the
  body class stays in sync regardless of where focus is (mirrors the
  pattern from the working modifier-click demo)
- cursor: copy replaces crosshair (matches copy-affordance semantics)
- figure, h2–h4 and [data-widget-name] elements get a dashed indigo
  outline + subtle background tint when shift is held, so the user
  can see which elements are annotatable before clicking

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:18:56 +01:00
46f4b0c25d feat(dashboard): shift+click trigger + Improvements section in Todo
improvement-modal.js:
- Replace contextmenu handler with click+shiftKey check — browser
  context menu is no longer intercepted
- Add keydown/keyup/blur listeners: holding Shift applies
  .impr-shift-mode to <body>, switching cursor to crosshair
  across the entire page as a visual affordance
- Update hint text to "Ctrl + Enter to submit · Escape to cancel"

todo.md:
- New "Improvements" section shows open dashboard-improvement TD items
  with a "review →" link to the UI Feedback page
- KPI sidebar row added for open improvement count (indigo when > 0)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 23:56:34 +01:00
b558610de6 feat(dashboard): right-click improvement modal + UI Feedback page
- improvement-modal.js: global contextmenu handler that opens a modal
  showing page/widget context; submits suggestions as TD items with
  debt_type="dashboard-improvement" to POST /technical-debt/
- _footer.md: shared Observable footer that auto-initialises the modal
  on every dashboard page
- ui-feedback.md: review/approval page — lists open suggestions with
  resolve / won't-fix / in-progress action buttons; archived items shown
  below; live-polled
- observablehq.config.js: "UI Feedback" added under Workstreams group

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 23:47:59 +01:00
4b3cb1b039 feat(CUST-WP-0015): implement agent inbox for inter-agent coordination
Adds a message-passing layer to state-hub so Claude instances can
coordinate across sessions without polling shared progress events.

- Migration f3a4b5c6d7e8: agent_messages table with thread support
- FastAPI router: POST/GET /messages/, thread view, mark-read, archive, reply
- 4 MCP tools: send_message, get_messages, mark_message_read, reply_to_message
- Observable dashboard: /inbox page with unread/read/archived sections + KPI
- CLAUDE.md updates: global, custodian, marki-docx, activity-core, template
- TOOLS.md: Agent Inbox tools section documented

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 02:55:45 +01:00
5e7a72e144 feat(CUST-WP-0014): repo sync automation & Gitea inventory
- Migration e2f3a4b5c6d7: add last_state_synced_at to managed_repos
- consistency_check.py: PATCH last_state_synced_at after fix run;
  fix ~ treated as non-empty state_hub_task_id (C-03 vs C-11);
  fix _inject_task_id_into_block skipping injection when field exists
  with null value
- install_hooks.sh: idempotent post-commit hook installer for all
  registered repos (make install-hooks REPO= / install-hooks-all)
- gitea_inventory.py: compare coulomb Gitea org against state-hub
  registered repos — registered / unregistered / hub-only sections
- infra/README.md: document systemd user timer + crontab fallback
- systemd user timer: custodian-sync.{service,timer} runs
  fix-consistency-all every 15 min (enabled)
- dashboard/src/repo-sync.md: Repo Sync Health page — sync age table,
  unregistered Gitea repos, hub-only repos
- api/routers/repos.py: GET /repos/{slug}/dispatch endpoint returning
  active goal, pending tasks per workstream, human interventions
- mcp_server/server.py: get_repo_dispatch() MCP tool

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 01:41:16 +01:00
a2db606dcc docs(dashboard): add Ralph Workplan reference page
Covers installation, usage, workplan file format, task status lifecycle,
custodian naming conventions, COULOMBCORE usage, and manual cancellation.
Registered in Reference nav + reference.md index.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:29:48 +01:00
fbdc6dda80 docs(dashboard): add Connecting to the Hub reference page
Covers local setup, remote (COULOMBCORE) one-liner registration,
ops-bridge tunnel config, bridge states, MCP transport modes, and
adding new remote hosts. Registered in Reference nav + reference.md index.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:22:43 +01:00
4a8942f310 fix(dashboard): resolve button calls /resolve endpoint, not PATCH
PATCH /decisions/{id}/ is a blind field-setter with no decided_at logic.
POST /decisions/{id}/resolve is the correct endpoint — it auto-sets
decided_at and emits a decision_resolved progress event.

Fixes: resolved decisions showing last in the sorted list because
decided_at was never populated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 22:16:17 +01:00
4393a501e6 fix(dashboard): scope decided_at sort to resolved/superseded only
Previous fix applied the decided_at branch to all status groups,
causing open decisions without decided_at (e.g. COULOMBCORE decision)
to sort last behind any open decision that had decided_at set.

Now: decided_at desc only for resolved/superseded; open/escalated
use deadline asc → created_at desc.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 22:09:43 +01:00
aef86a1934 fix(dashboard): reverse-chronological sort within decision status groups
Within resolved/superseded: most recently decided_at first.
Within open/escalated: soonest deadline first, then most recently
created_at (previously had no created_at fallback).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 22:06:13 +01:00
9f744dd7f3 feat(ep-td+dashboard): complete CUST-WP-0004 EP/TD tracking workstream
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 <style> block; removed from 9 pages
- Build: 0 errors, 0 warnings

API (T09):
- progress.py: limit param now Query(100, le=1000) — prevents unbounded
  list requests; closes TD-CUST-004 for the only endpoint that had limit

CUST-WP-0004 marked completed (all 10 tasks done).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 01:40:52 +01:00
651df73e3a feat(goals): add domain/repo goal tracking and update_workstream MCP tool
- Migration c5d6e7f8a9b0: domain_goals and repo_goals tables, repo_goal_id FK on workstreams
- DomainGoal: one active per domain (partial unique index), status active/archived/superseded
- RepoGoal: integer priority, status active/paused/completed/archived, optional domain_goal_id link
- WorkstreamUpdate schema and router extended with repo_goal_id and repo_goal_id filter
- 6 new MCP goal tools: create_domain_goal, get_domain_goals, activate_domain_goal, create_repo_goal, get_repo_goals, update_repo_goal
- update_workstream MCP tool: patch any subset of workstream fields (title, description, owner, due_date, repo_goal_id, status)
- get_domain_summary extended with goal_guidance (needs_workplan, alignment_warnings) signals
- Dashboard goals.md page and docs/goals.md reference page
- CLAUDE.md template updated to act on goal_guidance signals at session start
- CUST-WP-0010 workplan for this feature

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 00:15:29 +01:00
4ab56494ad feat(dashboard): order Workstreams by Domain chart by most recent activity
Domains are sorted top-to-bottom by the latest updated_at across their
workstreams (most recently active domain first). Within a domain,
workstreams are also ordered by updated_at desc. Replaces alphabetical sort.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 09:24:06 +01:00
0bdf4929fc feat(dashboard): Interventions page improvements and action-confirm modal
- Move Interventions under Workstreams in the navigator
- Add action-confirm.js: shared modal component for actions requiring a
  mandatory comment (survives live-poll re-renders, unlike inline DOM mutation)
- Wire action-confirm into Interventions (Mark done) and Decisions (Resolve)
- Fix Interventions completed section: fetch all tasks and filter client-side
  so resolved interventions (needs_human=false) still appear under Completed
- Add docs/interventions.md help page with ? button on the h1
- Replace all hardcoded "Bernd" with "human" across dashboard src and docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 23:15:06 +01:00
c792ab0bc0 feat(tasks): add needs_human intervention flag (CUST-WP-0009)
- Migration b4c5d6e7f8a9: adds needs_human (bool) + intervention_note (text) to tasks
- API: needs_human filter on GET /tasks/; 422 if flagged without note
- 3 MCP tools: flag_for_human, clear_human_flag, list_human_interventions
- Dashboard: interventions.md with amber cards and "Mark done" button
- Policy router + workstream DoD policy (workstream-dod.md)
- Workstream lifecycle docs page + workplan CUST-WP-0010
- CLAUDE.md: add step 4 (run fix-consistency after workplan writes)
- consistency_check.py: promote C-11 unlinked tasks from INFO to WARN

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:44:14 +01:00
fc87e26b4b feat(gems): three-pass schema migration aligning state-hub with GEMS
Implements CUST-WP-0007. Resolves inconsistencies I-1, I-2, I-5, I-6
identified in the GEMS audit (GenericEntityModellingSystem.md).

Pass 1 (e1f2a3b4c5d6): domain_id FK on extension_points and
technical_debt (replaces raw string column); repo_id FK on contributions.
Fixes domain-filtering bugs in EP/TD dashboard pages.

Pass 2 (f2a3b4c5d6e7): repo_id nullable FK on workstreams, aligning
the GEMS primary attachment with ADR-001 (repo > topic). Dashboard
pages updated to prefer repo->domain over topic->domain.

Pass 3 (a3b4c5d6e7f8): SBOMSnapshot container entity (GEMS Complex
between Repository and SBOMEntry). Ingest is now additive — each call
creates a new snapshot; history is retained. List/report endpoints
filter to latest snapshot per repo via _latest_snapshot_ids_subquery().
New endpoints: GET /sbom/snapshots/, GET /sbom/snapshots/{id}/.
Dashboard gains a Snapshot History section.

Also adds GEMS analysis artefacts: wiki/GEMS-StateHub-TypeRegistry.md,
wiki/GEMS-StateHub-SWOT.md, workplans/CUST-WP-0006 (analysis),
workplans/CUST-WP-0007 (migration, now completed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 23:39:17 +01:00
62fbe884e3 feat(sbom): add custodian ingest-sbom + fix help button target
custodian_cli.py:
- new ingest-sbom subcommand: auto-detects repo slug from local_path
  registration, runs ingest_sbom.py --scan from the repo root
- --dry-run flag passes through to the underlying script
- --slug override for repos where path lookup fails

repos.md:
- ? button on "⚠ not ingested" now opens /docs/sbom (not /docs/repos)

docs/sbom.md:
- Ingest commands section now leads with `custodian ingest-sbom` (repo-root)
- make ingest-sbom kept as low-level alternative
- Per-ecosystem and gap-type references updated to new command

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:31:08 +01:00
944104307a feat(repos): add ? help button to SBOM "not ingested" cells
Each "⚠ not ingested" entry in the Coverage Map now shows a hoverable ?
button linking to /docs/repos (SBOM ingestion section).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:14:16 +01:00
c7f22fd199 docs(onboarding): mention /init to trigger integration in step 3
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 11:16:08 +01:00
fe6704b9d0 feat(onboarding): redesign repo integration journey
custodian_cli.py:
- register-project now writes CLAUDE.custodian.md (suggestion) instead
  of overwriting CLAUDE.md; includes preamble with integration instructions
- registers repo via POST /repos/
- creates a "Repo Integration: {slug}" workstream in the domain's topic
  with 4 onboarding tasks (integrate CLAUDE.md, first workplan, SBOM,
  EPs/TDs); checks for existing workstream to be idempotent
- fixes {REPO_SLUG} template substitution (previously missing)

dashboard:
- repos.md: fetches workstreams; detects active repo-integration-* slugs;
  adds "Integrating" KPI card; shows ⚙ integrating badge per repo in
  coverage map and table; replaces "How to Ingest a Repo" with
  "Onboard a New Repo" 4-step panel with doc help button
- docs/repo-integration.md (new): full collaboration model doc — custodian
  as coach, repo agent as executor; journey, generated tasks, first session
  protocol, ongoing relationship
- docs/repos.md: links to new repo-integration doc; updates "What is a
  managed repo?" section; adds onboarding quick reference
- docs/reference.md: fix latent build error — code examples were in ```js
  fences (executed by OF); changed to ```javascript (display only)
- observablehq.config.js: adds "Repo Integration" to Reference nav

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 08:42:30 +01:00
6ea8afb6ff fix(dashboard): hide escalation notes on resolved/superseded decisions
- `escalated` filter now excludes decisions with status resolved or
  superseded — a lingering escalation_note on a closed decision no
  longer triggers the warning box or shows the amber note on the card
- Resolves D1 Vault backend appearing to re-surface an escalation alert

Also resolved ADR-001 decision (was made/open, now made/resolved);
overview blocking-decision count is now 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 23:57:30 +01:00
947c2e8824 feat(dashboard): nav restructure, full context-help coverage, 11 new ref docs
Navigation:
- New order: Overview · Todo · Domains · Repos · Workstreams (collapsible,
  open:false, with atomic sub-entries: Decisions, Tasks, Debt, Extends,
  Dependencies) · Contributions · SBOM · Progress · Reference (collapsible)
- Reference section gains path:/reference landing page; all 18 doc pages
  listed in nav (alphabetical) and in reference.md table

New pages:
- todo.md — Internal / Ecosystem / Third-party todo classification
- dependencies.md — dependency edge table derived from state/summary
- reference.md — Reference landing page with full doc index

New reference doc pages (11):
  contributions, debt, dependencies, domains, extensions, overview,
  repos, tasks, todo + reference (meta) already added previously

doc-overlay.js — lazy bubblehelp tooltip:
- _titleCache Map + _fetchDocTitle(docPath): on first hover of any ?
  button, fetches the target doc page, parses <h1>, sets btn.title
- Native browser tooltip appears exactly on the ? circle on subsequent hover

Context-help wired on all 14 dashboard pages:
- h1 withDocHelp added to: index, todo, domains, repos, tasks, techdept,
  extensions, dependencies (contributions/workstreams/decisions/sbom/
  progress/reference were already wired)
- domains.md + repos.md: added missing withDocHelp import and live-data link
- tasks/techdept/extensions: removed duplicate _h1 const that caused
  SyntaxError: Identifier '_h1' has already been declared

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 23:46:26 +01:00
a3338c3a23 chore(dashboard): sort Reference nav pages alphabetically
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 21:09:32 +01:00
6d97a992ae feat(dashboard): collapse Reference nav section by default
Observable Framework 1.13.3 supports collapsible: true on nav sections,
rendering them as <details> elements. Collapsed by default; auto-expands
when any page within the section is active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 21:07:56 +01:00
ba89ebfa67 feat(canon): add inter-repo communication standard with todo taxonomy
Establishes the repo boundary rule and a formal vocabulary for classifying
work items by scope:

- Task: neutral state hub data entity
- Todo: a task scoped to the current session's repo/domain
  - Internal todo: addressed within this repo by this agent
  - Ecosystem todo: work for another registered repo → state hub task [repo:<slug>]
  - Third-party todo: work for an upstream repo → contribution artifact (BR/FR/EP/UPR)

New dashboard doc: /docs/inter-repo-communication — defines the boundary rule,
the full terminology, ecosystem and third-party todo workflows, and a decision
table for classifying any piece of work found during a session.

Also:
- sbom.md: replace verbose inter-repo section with a 3-line summary + link
- observablehq.config.js: add "Inter-Repo Communication" to Reference nav
- project_claude_md.template: add "### Repo Boundary Rule" section; fix
  Workplan Convention section (removing incorrect claim that the custodian
  writes workplan files in other repos — that is the target repo's job)

Cross-repo: created state hub task [repo:railiance-bootstrap] for that repo's
agent to apply the boundary rule and workplan convention fix to its own CLAUDE.md
(task 78d43cb0, workstream 59155efb).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 20:52:07 +01:00
7caaec25a2 docs(sbom): add SBOM reference page + withDocHelp on SBOM dashboard
- docs/sbom.md: what SBOM is, lockfile semantics, 5-level maturity standard,
  gap types A–E, per-ecosystem guidance, Syft OSS tooling, inter-repo task
  communication convention, ingest commands, compliance check commands
- sbom.md: wire withDocHelp(h1, "/docs/sbom") — ? button on page title
- observablehq.config.js: add SBOM entry to Reference nav section

EP-CUST-002 registered: Syft-based comprehensive SBOM generation
Task 5f8cade5 created: [repo:railiance-bootstrap] Add Ansible lockfile

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 19:29:20 +01:00
9bfb0c130a feat(dashboard): Repos page with coverage map; expose last_sbom_at on RepoRead
- RepoRead schema: add last_sbom_at + sbom_source fields (already in model,
  now surfaced in API response)
- repos.md: new dashboard page — KPI row (total/domains/ingested/gaps),
  domain-grouped coverage map with SBOM/EP/TD chips, per-repo table with
  gap highlighting, domain filter + gap-only toggle, ingest how-to section
- observablehq.config.js: add Repos after Domains in nav

Coverage state: 3 repos registered (custodian×1, railiance×2);
2 ingested (the-custodian + railiance-hosts), 1 gap (railiance-bootstrap
— infra-only, no lockfile, expected)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 18:53:25 +01:00
4c157d43a8 feat(sbom): scan mode, domain grouping dashboard, SBOM convention doc
- ingest_sbom.py: add --scan flag (recursive lockfile discovery) +
  --lockfile repeatable for explicit multi-file ingestion; skip
  .venv/node_modules/.git/dist/etc; Makefile gains SCAN= and REPO_PATH= vars
- sbom.md: add /domains/ fetch; domain-level summary table; per-repo
  accordion with details/summary; domain filter on package table; dual-
  licence false-positive note; +1 KPI card (Domains Covered)
- canon/standards/sbom-convention_v0.1.md: authoritative lockfile table,
  ingest workflow (single/scan/explicit), snapshot semantics, direct-vs-
  transitive caveats, licence governance + copyleft escalation, update
  cadence, multi-repo domain pattern, planned enhancements

First ingest: the-custodian — 420 pkgs (88 python + 332 node), 13 licence
groups, 1 copyleft flag (jszip dual-licensed MIT OR GPL-3.0-or-later)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 16:15:40 +01:00
afac54ec09 feat(state-hub): v0.3 MCP tools + dashboard pages for contributions and SBOM
MCP server additions (5 tools + 3 resources):
- register_contribution(), update_contribution_status(), get_contributions()
- ingest_sbom_tool(repo_slug, lockfile_path) — shells out to ingest_sbom.py
- get_licence_report()
- state://contributions, state://sbom/aggregated, state://sbom/{repo_slug}

Dashboard pages:
- contributions.md — live-polled Kanban by status (draft→merged), filter bar
  (type/status/repo), KPI grid (total + per type), follow-up banner, full table
- sbom.md — licence distribution bar chart (Plot), copyleft risk section,
  package table with ecosystem/direct/dev filters, repo-slug resolution
- data/contributions.json.py, data/sbom.json.py — Observable data loaders
- index.md — added Contribution & SBOM Health KPI row (total, follow-up count,
  copyleft risk indicator; sourced from state summary fields)
- observablehq.config.js — added Contributions + SBOM to nav

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 17:28:41 +01:00
fccb7b2375 fix(dashboard): replace stale t.domain with t.domain_slug across all pages
After the v0.5 migration TopicRead.domain was renamed to domain_slug.
index.md, decisions.md and tasks.md still referenced the old field,
causing every workstream domain to fall back to "unknown". Also
updated tasks.md to load the domain filter list dynamically from
/domains/ instead of the hardcoded 6-slug array.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 15:31:28 +01:00
fcd0f06536 feat(state-hub): implement v0.5 — dynamic domains & multi-repo
Replaces the hardcoded 6-domain PostgreSQL ENUM with a first-class
`domains` DB table, and adds a `managed_repos` table for multi-repo
support per domain.

P1 — Domain as a DB entity:
- Migration b1c2d3e4f5a6: creates `domains` table, migrates topics.domain
  ENUM column to domain_id FK, drops the domain ENUM type
- Domain ORM model (api/models/domain.py) + Pydantic schemas
- Domain API router: GET/POST /domains/, GET/PATCH /domains/{slug}/,
  rename and archive endpoints with EP/TD cascade on rename
- Topic model updated: domain_id FK + @property domain_slug for
  backwards-compatible JSON serialization (field renamed domain → domain_slug)
- TopicCreate/TopicRead updated; seed.py rewritten to use FK lookup

P2 — Multi-repo support:
- ManagedRepo ORM model (api/models/managed_repo.py) + schemas
- Repo API router: GET/POST /repos/, GET/PATCH /repos/{slug}/, archive
- Makefile: add-domain, rename-domain, add-repo, list-repos targets
- register_project.sh: verify domain via /domains/ API + POST /repos/

P3 — MCP tools & live validation:
- 6 new MCP tools: list_domains, create_domain, rename_domain,
  archive_domain, list_domain_repos, register_repo
- EP/TD routers: replace hardcoded VALID_DOMAINS set with per-request
  DB lookup — returns 422 with list of valid slugs on unknown domain
- State summary: adds domains: list[DomainSummary] (slug, name,
  repo_count, active_workstream_count, ep_count, td_count)
- TOOLS.md updated with domain management section

P4 — Dashboard:
- New domains.md page with KPI row + domain cards + repo lists
- domains.json.py + repos.json.py data loaders
- Domains page added to observablehq.config.js nav
- workstreams.md, extensions.md, techdept.md: domain_slug fix +
  dynamic domain list loaded from /domains/ API (no longer hardcoded)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 15:20:15 +01:00
0546a1bb2a feat(dashboard): add entity detail modal and fixed-layout tables
Replace Inputs.table() with buildEntityTable() across workstreams and
tasks pages. Add click-to-detail modal (openEntityModal) on all entity
list views: workstreams, tasks, extension points, and technical debt.

- New component: src/components/entity-modal.js
  - openEntityModal(entity, type) — full-detail overlay (Esc/click-outside to close)
  - buildEntityTable(rows, cols, onRowClick) — table-layout:fixed, overflow-safe wrapper
  - CSS injected lazily; no separate stylesheet required

- Tables: table-layout:fixed keeps content within the content column;
  title col 32%, workstream col 14%, all cells ellipsis + title tooltip
- Cards (EP, TD): onclick → modal; workstream name span gets title tooltip
- Blocked task cards also wired to modal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 18:28:44 +01:00
bd6e16394a chore: mark llm-shared-library workstream completed
All 9 tasks done (S1.1–S3.2). llm-connect is now a standalone
installable package at /home/worsch/llm-connect, integrated into
state-hub as its first consumer (S3.1, commit 444b35d).

Also tracks workstream-kpi.md spec (previously untracked).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 08:53:43 +01:00
f8e76deeaa feat(dashboard): replace title tooltips with <help-tip> web component
New custom element (src/components/help-tip.js):
- Floating card appears on hover/focus, appended to document.body
  (position:fixed) so it escapes overflow:hidden in the TOC sidebar
- Attributes: label (bold), description (body), doc (optional
  "Learn more →" link)
- Mouse-over-card grace period so the link stays reachable
- Correct viewport clamping (horizontal + prefer-above/fallback-below)

workstreams.md:
- WHI metric abbreviations (DD/BR/SPR/PEP/CDDR) now use <help-tip>
  with full name, one-sentence description, and doc link
- Domain breakdown labels show domain-scoped stats (open count,
  blocked%, runnable%) and a doc link
- Cycle ⚠ icon upgraded to <help-tip> with explanation
- Removed dotted underline; cursor:help comes from the element CSS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 08:11:09 +01:00
29a0368e6d feat(dashboard): add mouseover tooltips to WHI metric abbreviations
DD, BR, SPR, PEP, CDDR now show full name + one-sentence explanation
on hover via title attributes. Metric labels get a dotted underline
and cursor:help to signal they are hoverable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 08:03:19 +01:00
090a206f3d feat(state-hub): add Extension Points and Technical Debt tracking
New entity types (DB tables, API routers, Pydantic schemas, Alembic
migration a3f1c2d4e5b6):
- extension_points: ep_id, domain, title, ep_type, status, priority,
  location, description, topic_id, workstream_id
- technical_debt: td_id, domain, title, debt_type, severity, status,
  location, description, topic_id, workstream_id

MCP server: 6 new tools — register_extension_point, list_extension_points,
update_ep_status, register_technical_debt, list_technical_debt,
update_td_status (each write emits a progress_event)

Dashboard: two new pages (extensions.md, techdept.md) with KPI sidebar,
charts, urgent-items section, and filterable card lists. Both added to
nav in observablehq.config.js.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 07:29:51 +01:00
c0f6f01bff Add Tasks dashboard page
New page with:
- Data fetch: /tasks/ + /workstreams/ + /topics/ in parallel, enriched
  with domain and workstream_title per task
- Task Overview KPI card in TOC sidebar: open / blocked (red if >0) /
  in progress / done with % of total
- Status Distribution chart (horizontal bar, colour-coded by status)
- Blocked Tasks section: cards with priority badge, domain, workstream,
  blocking_reason highlighted in amber
- All Tasks: filterable table (status, priority, domain, assignee
  multiselect + text), sorted blocked→in_progress→todo→done, 25 rows

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 01:04:19 +01:00