- scripts/cleanup_stale_tasks.py: daily script that cancels open tasks in completed/archived workstreams; handles 307 redirects; emits a cleanup progress event summarising results - Makefile: add cleanup-stale target (also suitable for cron) - ADR-001: append Workstream Closure Protocol section — mandatory closure review before marking workstream completed, with task classification table (done/cancelled/carry-forward) and Closure Review file format - WP-0002 + WP-0005: append Closure Review sections documenting the 2026-03-02 cleanup run (26 stale DB rows cancelled — all were legacy pre-ADR-001 DB-first records; file status was already done) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 KiB
id, type, title, domain, status, owner, topic_slug, state_hub_workstream_id, created, updated
| id | type | title | domain | status | owner | topic_slug | state_hub_workstream_id | created | updated |
|---|---|---|---|---|---|---|---|---|---|
| CUST-WP-0002 | workplan | State Hub v0.3 — Contribution Tracking & SBOM | custodian | completed | custodian | custodian | 2446400d-6d01-4679-a314-92af0601c608 | 2026-02-26 | 2026-02-28 |
State Hub v0.3 — Contribution Tracking & SBOM
Summary
Establish the custodian as the central authority for cross-repo upstream contribution management (bug reports, feature requests, extension points, upstream PRs) and software supply-chain transparency (SBOM aggregation, licence governance).
Context
Three interconnected layers:
- Layer 1 — Convention & Canon: define contrib/ directory structure and artifact types (BR, FR, EP, UPR) in markdown with typed YAML frontmatter.
- Layer 2 — Schema & API: DB tables for contributions, repos (deferred to v0.5), and SBOM entries; FastAPI routers.
- Layer 3 — MCP Tools & Dashboard: tracking tools and Observable pages.
Dependencies
- Depends on:
dynamic-domains-multi-repo(v0.5, CUST-WP-0005). Four tasks in this workplan (P2.2, P2.4, P3.2, P4.1) are reduced in scope because v0.5 supersedes their original designs:managed_repostable → done by v0.5 P2.1/repos/API router → done by v0.5 P2.2register_repoMCP tool → done by v0.5 P3.1- Base registration workflow → done by v0.5 P2.3
- state_hub_dep_id: 2033172d-2462-4253-acb7-cb64c7432480
Phase 1 — Convention & Canon
P1.1 — Write canon/standards/contribution-convention_v0.1.md
id: CUST-WP-0002-T01
state_hub_task_id: c2d7df02-5f37-4c02-a418-fe7ab0050edc
status: done
priority: high
Define the master contrib/ convention: directory layout, artifact types (BR/FR/EP/UPR), frontmatter schema per type, ID schemes (EP--NNN for EPs; date-prefixed slug for others), status lifecycle, and relationship to state-hub. Authoritative reference for other repos.
P1.2 — Create contrib/ templates for BR, FR, EP, UPR
id: CUST-WP-0002-T02
state_hub_task_id: 5ef89639-950c-4d57-9578-6d0211edc2df
status: done
priority: high
Four Markdown template files under canon/standards/contrib-templates/:
br-template.md, fr-template.md, ep-template.md, upr-template.md.
Each has typed YAML frontmatter matching the schema in P1.1 plus a guided
prose skeleton.
P1.3 — Store Observable Framework TOC sidebar UPR as first artifact
id: CUST-WP-0002-T03
state_hub_task_id: e8251873-647c-4a4b-b283-298260b19c22
status: done
priority: medium
Create contrib/upstream-prs/2026-02-26--observablehq--framework--toc-sidebar-inject.md
using the UPR template. Captures: summary of the injectTocTop utility,
motivation, link to local component, target upstream file, draft PR body.
Status: draft.
P1.4 — Align Railiance EP convention docs with canon master spec
id: CUST-WP-0002-T04
state_hub_task_id: 1c982457-de52-4fc1-a439-3bf3120bb5b6
status: done
priority: low
The staged-promotion-lifecycle workstream defines EP-RAIL-NNN IDs and inline doc markers. Review and update so the Railiance convention is a proper instance of the custodian master spec, not a parallel one.
Phase 2 — Schema & API
P2.1 — Design and implement contributions DB table + migration
id: CUST-WP-0002-T05
state_hub_task_id: c41d71bd-dc88-4201-bd9a-3f8a4eae4910
status: done
priority: high
Add contributions table: id (UUID PK), type (enum: br|fr|ep|upr),
target_org, target_repo, slug, title, status (enum:
draft|submitted|acknowledged|accepted|rejected|merged|withdrawn),
body_path (relative path to .md file), related_topic_id (nullable FK),
related_workstream_id (nullable FK), submitted_at, resolved_at, notes,
created_at, updated_at. Alembic migration.
P2.2 — sbom_entries table + migration (managed_repos deferred to v0.5)
id: CUST-WP-0002-T06
state_hub_task_id: 28c9bd38-05d8-4466-bff3-3ba4e3957635
status: done
priority: high
SCOPE REDUCED — managed_repos superseded by v0.5 P2.1.
Do not create managed_repos here. After v0.5 P2.1 lands, add
sbom_source (text) and last_sbom_at (timestamp) columns to the
existing managed_repos table via an additive migration.
Then create sbom_entries table: id (UUID PK), repo_id (FK
managed_repos), package_name, package_version, ecosystem, license_spdx
(nullable), is_direct (bool), is_dev (bool), snapshot_at (timestamp —
new ingest replaces old entries for that repo), created_at.
Prerequisite: v0.5 P2.1 (managed_repos table) must be complete.
P2.3 — Implement /contributions/ router (CRUD + status patch)
id: CUST-WP-0002-T07
state_hub_task_id: ee1cd17c-6dbd-4321-bb72-4499147c4837
status: done
priority: high
FastAPI router: GET list (filter by type, status, target_repo), POST
create, GET by id, PATCH status (validates lifecycle transitions), soft
delete (sets status=withdrawn). Schemas: ContributionCreate,
ContributionRead, ContributionStatusPatch. Add
contribution_counts to /state/summary.
P2.4 — Implement /sbom/ router (basic /repos/ endpoints implemented by v0.5)
id: CUST-WP-0002-T08
state_hub_task_id: 25f7ab5c-69d8-41d7-a108-38380eb1f3a9
status: done
priority: high
SCOPE REDUCED — /repos/ superseded by v0.5 P2.2.
This task covers the /sbom/ router only:
POST /sbom/ingest— accept repo_slug + list of package entries; replace existing snapshot for that repo.GET /sbom/— aggregated view across all repos, grouped by license_spdx.GET /sbom/{repo_slug}/— single-repo SBOM.GET /sbom/report/licences/— counts and repo lists per SPDX identifier, flagging copyleft (GPL/AGPL/LGPL).- Add
licence_risk_countto/state/summary.
Prerequisite: v0.5 P2.1 (managed_repos) and P2.2 (sbom_entries) must be complete.
P2.5 — Write make ingest-sbom tooling (pyproject + package.json parsers)
id: CUST-WP-0002-T09
state_hub_task_id: edcf9b02-8177-4abc-b133-d303cc7ea19d
status: done
priority: medium
scripts/ingest_sbom.py: parses uv.lock (Python deps with licence
metadata), package-lock.json / yarn.lock (Node deps); outputs
normalised list; POSTs to /sbom/ingest/. Makefile target:
make ingest-sbom REPO=<slug>. Composable into make seed.
Phase 3 — MCP Tools & Dashboard
P3.1 — New MCP tools: register_contribution, update_contribution_status, get_contributions
id: CUST-WP-0002-T10
state_hub_task_id: 51b2999b-a9c7-4871-8ef8-f5c927ac2454
status: done
priority: high
register_contribution(type, target_org, target_repo, title, body_path, related_workstream_id?, notes?)→ ContributionReadupdate_contribution_status(contribution_id, status, notes?)→ ContributionReadget_contributions(type?, status?, target_repo?)→ list- Add
state://contributionsresource.
P3.2 — New MCP tools: ingest_sbom, get_licence_report (register_repo implemented by v0.5)
id: CUST-WP-0002-T11
state_hub_task_id: 20c5c2ae-7758-42cc-885c-a886957e44c2
status: done
priority: high
SCOPE REDUCED — register_repo superseded by v0.5 P3.1.
ingest_sbom(repo_slug: str, lockfile_path: str)— callsscripts/ingest_sbom.py, POSTs result to/sbom/ingest/.get_licence_report()— returns licence groups with copyleft flag from/sbom/report/licences/.- Add resources:
state://sbom/aggregated,state://sbom/{repo_slug}.
Prerequisite: v0.5 P3.1 (register_repo tool) and P2.4 (/sbom/ router) must be complete.
P3.3 — Dashboard: contributions.md page
id: CUST-WP-0002-T12
state_hub_task_id: 1eb13411-b2da-4d0d-8fe2-e926d029c50f
status: done
priority: medium
New Observable Framework page. Layout: filter bar (type, status,
target_repo), status Kanban columns
(draft → submitted → acknowledged → accepted/rejected/merged), count KPIs
per type. Chart: contribution velocity over time (cumulative, same period
selector as decisions page). Apply injectTocTop for page-level KPI.
P3.4 — Dashboard: sbom.md page
id: CUST-WP-0002-T13
state_hub_task_id: 1267f313-1bf3-4059-8276-bfefcd9f6aed
status: done
priority: medium
New Observable Framework page. Aggregated dependency table: package,
version, licence, repos using it, direct/dev flags. Licence summary donut
chart (MIT vs Apache-2.0 vs GPL family vs other). Copyleft risk section
(red highlight for GPL/AGPL/LGPL in direct prod deps). Per-repo
drill-down accordion. Register in observablehq.config.js.
P3.5 — Update index.md overview to surface contribution and SBOM health
id: CUST-WP-0002-T14
state_hub_task_id: abab0022-d3a4-45ef-a7e1-e0e7c05d295f
status: done
priority: low
Add contribution counts KPI card (total, by type, any needing follow-up).
Add licence risk indicator (green if no copyleft in direct prod deps, red
otherwise). Uses /state/summary fields added in P2.3 and P2.4.
Phase 4 — Repo Integration Tooling
P4.1 — Add sbom_source prompt + ingest-sbom step to registration workflow (base workflow by v0.5)
id: CUST-WP-0002-T15
state_hub_task_id: 47987720-23db-4465-861b-1f93bb1bb391
status: done
priority: low
SCOPE REDUCED — base registration workflow superseded by v0.5 P2.3.
SBOM-specific additions to the workflow:
- Extend the
add-repocommand to prompt forecosystemandsbom_source(path or URL to lockfile). - Optionally run
make ingest-sbom REPO=<slug>automatically at end of registration. - Update
project_claude_md.templateto document the contrib/ convention, SBOM MCP tools, andmake ingest-sbomtarget.
Prerequisite: v0.5 P2.3 (updated registration workflow) must be complete.
Closure Review — 2026-03-02
Outcome: All 15 tasks completed. No carry-forwards. No dropped tasks.
Context: This workplan was created DB-first on 2026-02-28, before ADR-001 was formalised. The workplan file correctly recorded all tasks as status: done, but the DB rows were never synced from the file — they remained in their initial todo state in the database. The daily stale-task cleanup script (scripts/cleanup_stale_tasks.py) detected these 15 stale DB rows and cancelled them on 2026-03-02. No actual work was lost: all deliverables in Phase 1–4 were shipped as part of State Hub v0.3.
Completed (DB updated at delivery time; file status = done)
- CUST-WP-0002-T01 — Write canon/standards/contribution-convention_v0.1.md
- CUST-WP-0002-T02 — Create contrib/ templates for BR, FR, EP, UPR
- CUST-WP-0002-T03 — Store Observable Framework TOC sidebar UPR as first artifact
- CUST-WP-0002-T04 — Align Railiance EP convention docs with canon master spec
- CUST-WP-0002-T05 — Design and implement contributions DB table + migration
- CUST-WP-0002-T06 — sbom_entries table + migration
- CUST-WP-0002-T07 — Implement /contributions/ router (CRUD + status patch)
- CUST-WP-0002-T08 — Implement /sbom/ router
- CUST-WP-0002-T09 — Write make ingest-sbom tooling
- CUST-WP-0002-T10 — New MCP tools: register_contribution, update_contribution_status, get_contributions
- CUST-WP-0002-T11 — New MCP tools: ingest_sbom, get_licence_report
- CUST-WP-0002-T12 — Dashboard: contributions.md page
- CUST-WP-0002-T13 — Dashboard: sbom.md page
- CUST-WP-0002-T14 — Update index.md overview to surface contribution and SBOM health
- CUST-WP-0002-T15 — Add sbom_source prompt + ingest-sbom step to registration workflow
Cancelled (DB records only — legacy stale rows, not real cancellations)
All 15 DB task rows were cancelled by the cleanup script. The workplan file was authoritative; the DB rows were artefacts of the pre-ADR-001 DB-first creation pattern. This does not reflect a change in work outcome.