diff --git a/state-hub/dashboard/observablehq.config.js b/state-hub/dashboard/observablehq.config.js index 3024fb6..37cd68d 100644 --- a/state-hub/dashboard/observablehq.config.js +++ b/state-hub/dashboard/observablehq.config.js @@ -33,6 +33,7 @@ export default { collapsible: true, open: false, pages: [ + { name: "Repository DoI", path: "/policy/repo-doi" }, { name: "Workstream DoD", path: "/policy/workstream-dod" }, ], }, diff --git a/state-hub/dashboard/src/policy/repo-doi.md b/state-hub/dashboard/src/policy/repo-doi.md new file mode 100644 index 0000000..9c1252c --- /dev/null +++ b/state-hub/dashboard/src/policy/repo-doi.md @@ -0,0 +1,90 @@ +--- +title: Repository Definition of Integrated (DoI) +--- + +```js +import {API} from "../components/config.js"; +``` + +```js +import {marked} from "npm:marked"; + +const _resp = await fetch(`${API}/policy/repo-doi`); +if (!_resp.ok) throw new Error(`Failed to load policy: ${_resp.status}`); +const _policy = await _resp.json(); +``` + +```js +let _content = _policy.content; +let _editing = false; + +const _root = display(html`
`); + +async function _save(text) { + const r = await fetch(`${API}/policy/repo-doi`, { + method: "PUT", + headers: {"Content-Type": "application/json"}, + body: JSON.stringify({content: text}), + }); + if (!r.ok) throw new Error(`Save failed: ${r.status}`); + _content = text; +} + +function _toolbar(...nodes) { + return html`
${nodes}
`; +} + +function _btn(label, primary = false) { + return html``; +} + +function _render() { + _root.innerHTML = ""; + + if (_editing) { + const area = html``; + + const saveBtn = _btn("Save", true); + const cancelBtn = _btn("Cancel"); + + saveBtn.onclick = async () => { + saveBtn.disabled = true; + saveBtn.textContent = "Saving…"; + try { + await _save(area.value); + _editing = false; + _render(); + } catch (e) { + saveBtn.disabled = false; + saveBtn.textContent = "Save"; + alert(e.message); + } + }; + + cancelBtn.onclick = () => { _editing = false; _render(); }; + + _root.append(_toolbar(saveBtn, cancelBtn), area); + + } else { + const editBtn = _btn("Edit"); + editBtn.onclick = () => { _editing = true; _render(); }; + + const body = html`
`; + body.innerHTML = marked.parse(_content); + + _root.append(_toolbar(editBtn), body); + } +} + +_render(); +``` diff --git a/state-hub/policies/repo-doi.md b/state-hub/policies/repo-doi.md new file mode 100644 index 0000000..22176dc --- /dev/null +++ b/state-hub/policies/repo-doi.md @@ -0,0 +1,120 @@ +# Repository Definition of Integrated (DoI) + +A repository is considered **fully integrated** with the Custodian State Hub +when all criteria below are satisfied. Criteria are grouped by tier: a repo +that meets all **Core** criteria is *registered*; meeting **Standard** criteria +makes it *integrated*; meeting **Full** criteria makes it *fully integrated*. + +--- + +## Tier 1 — Core (Registered) + +These are the minimum requirements for the state-hub to be aware of a repo. + +- [ ] **Registered in state-hub** — repo exists in `managed_repos` with correct + `slug`, `domain_slug`, `local_path`, and `remote_url`. Verify: + `GET /repos/{slug}` + +- [ ] **Domain assigned** — repo is linked to an active domain. The domain must + exist in `domains` and be in `active` status. + +- [ ] **Local path resolves** — `_resolve_repo_path()` finds an existing + directory on the current host (either via `host_paths[hostname]` or + `local_path`, both support `~` expansion). + +- [ ] **Remote URL reachable** — `remote_url` points to a live Gitea/GitHub + repository. The repo must be pushable from the registered local path. + +--- + +## Tier 2 — Standard (Integrated) + +A repo at this tier participates in state-hub tracking and tooling. + +- [ ] **SCOPE.md present** — a `SCOPE.md` exists at the repo root following the + standard template (`state-hub/scripts/project_rules/scope.template`). + Sections: One-liner, Core Idea, In Scope, Out of Scope, Relevant When, + Not Relevant When, Current State, How It Fits, Provided Capabilities. + +- [ ] **CLAUDE.md present** — a `CLAUDE.md` exists at the repo root with at + minimum: domain context, session protocol (start: `get_domain_summary`, + end: `add_progress_event`), and stack/commands reference. + +- [ ] **Workplan convention followed** — any workplans live under + `workplans/-.md` with valid YAML frontmatter + (`id`, `type`, `title`, `domain`, `status`, `state_hub_workstream_id`). + Verified by: `make check-consistency REPO={slug}` → PASS or WARN only + (no FAIL). + +- [ ] **SBOM ingested** — at least one dependency lockfile exists + (`uv.lock`, `requirements.txt`, `package-lock.json`, `yarn.lock`, + `Cargo.lock`, `go.sum`) and has been ingested: + `make ingest-sbom REPO={slug}` succeeded with ≥1 entry. + `last_sbom_at` is set on the repo record. + +- [ ] **TPSC declared** — a `tpsc.yaml` exists at the repo root declaring all + external service dependencies, and has been ingested: + `make ingest-tpsc REPO={slug}` succeeded. If the repo has no external + service dependencies, `tpsc.yaml` must exist with an empty `services: []` + to make the absence explicit. + +--- + +## Tier 3 — Full (Fully Integrated) + +A fully integrated repo contributes to cross-repo planning and capability routing. + +- [ ] **Active repo goal** — at least one `RepoGoal` with `status: active` + exists for the repo in the state-hub. Goals connect workstreams to + strategic intent. Create via: `create_repo_goal(repo_slug, title, ...)` + +- [ ] **Provided Capabilities declared** — if the repo exposes capabilities to + other domains, they are declared in the `## Provided Capabilities` section + of `SCOPE.md` using `capability` fenced blocks and have been ingested via + `make ingest-capabilities REPO={slug}`. + +- [ ] **Agents template applied** — `CLAUDE.md` references the kaizen agent + system (`get_kaizen_agent()`) and includes the `agents.template` section + listing available specialised personas for the domain. + +- [ ] **Consistency check clean** — `make check-consistency REPO={slug}` + reports **0 FAIL, 0 WARN** (C-12 warnings on legacy DB-only tasks are + exempt if the workstream predates ADR-001). + +- [ ] **Host path registered for all active hosts** — `host_paths` contains + an entry for every machine where the repo is actively worked on. Use + `update_repo_path(slug, path)` to register additional hosts. + +--- + +## Integration Checklist (Quick Reference) + +| # | Criterion | Tier | Verified by | +|---|---|---|---| +| 1 | Registered in state-hub | Core | `GET /repos/{slug}` | +| 2 | Domain assigned | Core | `GET /repos/{slug}` → `domain_slug` | +| 3 | Local path resolves | Core | `check_repo_consistency(slug)` | +| 4 | Remote URL reachable | Core | `git push` dry-run | +| 5 | SCOPE.md present | Standard | `ls SCOPE.md` | +| 6 | CLAUDE.md present | Standard | `ls CLAUDE.md` | +| 7 | Workplan convention followed | Standard | `make check-consistency` | +| 8 | SBOM ingested | Standard | `last_sbom_at` on repo record | +| 9 | TPSC declared | Standard | `make ingest-tpsc` | +| 10 | Active repo goal | Full | `get_repo_goals(slug)` | +| 11 | Provided Capabilities declared | Full | `make ingest-capabilities` | +| 12 | Agents template applied | Full | `CLAUDE.md` review | +| 13 | Consistency check clean | Full | `make check-consistency` → 0 FAIL/WARN | +| 14 | Host paths registered | Full | `GET /repos/{slug}` → `host_paths` | + +--- + +## Notes + +- The DoI is enforced by convention, not by automated gates (as of v0.6). + A future `make check-doi REPO={slug}` target is planned. +- Repos that are `archived` or `deprecated` are exempt from DoI compliance. +- The **Core** tier is a prerequisite for all state-hub tooling + (`check_repo_consistency`, `ingest_sbom_tool`, `ingest_tpsc_tool`). +- A repo may satisfy **Standard** without **Full** indefinitely — Full + integration is appropriate when the repo is actively contributing to + cross-domain work or exposing capabilities to other repos.