Operations Runbook
How to view findings, triage them, and keep the registry up-to-date in steady-state operations.
Part 1 — Where findings live
Findings live in two complementary places:
1. Raw YAML files (source of truth)
hmp-docs/registry/findings/FD-<YYYY-MM-DD>-<NNN>.yaml
Every finding has its own YAML. File naming: FD-<date>-<seq>.yaml.
Example finding:
id: FD-2026-04-23-001
title: api AP-sample-login missing from code but still referenced by 1 story
created: 2026-04-23
detector: drift-checker
severity: high
context:
entityKind: apis
entityId: AP-sample-login
direction: missing-with-refs
referencedBy:
- ST-901-001
status: detected
Key fields:
detector— which tool emitted it (drift-checker,coverage-check,manual-sp2-triage, etc.)severity—blocker | high | medium | lowcontext.direction— the rule that fired:new— scanner found an entity not in registrymissing— registry has entity but scanner can't find itmissing-with-refs— missing AND referenced by a story (upgraded to high)stale-built-status— story claimsbuiltbut has 0-1 implementationsstory-unclaimed— entity exists but no story references it
status—detected(fresh) |triaged(decision recorded) |resolved(fix shipped)triageDecision(added after triage) —confirmed-drift | invalid | feature-gap | needs-developer | wontfixetc.context.triageNote(added after triage) — human rationale
2. Drift Dashboard (visual)
Web view at /docs/platform-registry/drift in the Docusaurus build.
Reads docs/platform-registry/_data/drift-report.json (regenerated by
every drift-check run). Shows findings sorted by severity in a
filterable table.
To regenerate the dashboard locally:
cd hmp-docs
npx tsx tools/registry/src/cli.ts drift-check
npm start # Docusaurus dev server at http://localhost:3000
3. Nightly CI
The Azure Pipeline .azuredevops/pipelines/registry-nightly.yml runs at
18:00 UTC daily, scans all 23 repos, regenerates findings, and commits
any changes. So the findings directory is kept fresh automatically
overnight.
Part 2 — How to triage & act on findings
Triage decision tree
For each finding, ask:
1. Is the entity real (exists in code today)?
NO → Entity was deleted. Either:
(a) Remove the registry YAML (if truly gone): git rm registry/<kind>/<id>.yaml
(b) Annotate finding as invalid-fixture (for sample/test entities)
(c) Annotate as confirmed-drift + open cleanup task
YES → go to 2.
2. Does the finding say it's "missing"?
YES → Scanner regressed or entity was renamed. Either:
(a) Update the entity YAML with the new id/path
(b) Investigate why scanner can't find it (common: file moved to new repo)
3. Is the finding "missing-with-refs"?
YES → Story's implementations.* block points to a deleted entity. Either:
(a) Fix the story YAML: remove the stale ref
(b) Restore the entity in code if removal was accidental
(This is HIGH severity — resolve within the same sprint.)
4. Is the finding "stale-built-status"?
YES → Story claims built but has fewer than 2 implementations. Either:
(a) Flip status: built → in-progress (if not actually shipped)
(b) Add the missing implementations.* refs (if shipped but under-curated)
(c) Flip status: built → deprecated (if story was rolled back)
5. Is the finding "story-unclaimed"?
YES → Entity exists but no story owns it. Either:
(a) Add entity id to a relevant story's implementations.*
(b) If entity is tangential (test fixture, dev-only route), ignore with
triageDecision: wontfix + a short reason
Recording a triage decision
Edit the finding YAML in-place. Add or update these fields:
# finding.yaml
status: triaged # was: detected
triageDecision: confirmed-drift # or: invalid | feature-gap | needs-developer | wontfix
context:
# ... existing fields ...
triageNote: "Rolled back in PR #123; story marker not updated. Owner to fix this week."
Commit the annotation:
git add registry/findings/FD-<id>.yaml
git commit -m "triage(registry): FD-<id> marked as <decision>"
Resolving a finding (not just annotating)
After the fix ships:
# finding.yaml
status: resolved # was: triaged
resolvedAt: 2026-04-30
resolvedBy: @ajay
resolvedIn: PR#456 # or commit sha
Or delete the YAML entirely if it's obsolete:
git rm registry/findings/FD-<id>.yaml
Either is fine. Keeping resolved findings gives audit history; deleting keeps the directory lean. Pick one convention and stick to it.
Part 3 — Steady-state audit cadence
Weekly (first 4-6 weeks of SP-4)
Owner: reviewer-on-rotation (developer who owns registry that week)
Monday:
- Pull latest master:
git pull origin master - Run:
npx tsx tools/registry/src/cli.ts drift-check - Open the Drift Dashboard at
/docs/platform-registry/drift - Sort by severity. Focus on blocker → high → medium.
Monday-Thursday:
- Triage the top-20 findings per the decision tree in Part 2
- For each: edit finding YAML with triageDecision + triageNote; commit
- For fixable ones: also fix the referenced story/entity and commit
Friday:
- Re-run drift-check. Confirm finding count dropped.
- Commit + push the week's triage batch. PR title:
triage(registry): week <N> (<date>) - Update
docs/platform-registry/drift.mdxweekly-cadence section with your notes.
After 4-6 weeks
Evaluate whether weekly is still worthwhile:
- If finding volume is steady-low (fewer than 10 new per week), downshift to biweekly.
- If 0 new findings for 2 weeks, downshift to monthly.
- If ever 20+ new findings in a week, escalate — something's drifting faster than the ops cadence can absorb.
Monthly / Quarterly
- Stale story audit — any
status: builtstory with noimplementations.*growth for 90 days → flip todeprecatedor investigate why. - Gate promotion review — watch bake metrics for report-only gates. Promote when stable.
- UI adoption check — update
uiAdoptioncounts indocs/platform-registry/_data/dashboard.json. Track wave progress.
Part 4 — Keeping the registry up-to-date
When you WRITE code
Follow the discipline in /docs/platform-registry/workflow:
- Added an API route? → Add/update
registry/apis/AP-<service>-<METHOD>-<path>.yamlOr runnpx tsx tools/registry/src/cli.ts scan-routesto auto-write from code. - Added a screen? →
registry/screens/SC-<app>-<route>.yamlorscan-screens. - Added an event? →
registry/events/EV-<topic>.yamlorscan-events. - Added a Prisma model? →
registry/tables/TB-<service>-<model>.yamlorscan-tables. - Added a test? →
registry/tests/TS-<path>.yamlorscan-tests. - Shipped a story? → flip
status: in-progress → builtinregistry/stories/ST-*.yaml. - Added the entity's owning story? → update story
implementations.<kind>to include the new entity's id.
When you REVIEW a PR
- CI is blocking on
validate-yaml+check-cross-links(SP-6 gates). If either fails, don't merge until fixed. - PR comment shows drift + coverage summary for registry-touching PRs. Scan it.
- For major features, verify the PR updated the relevant story YAML's
implementations.*— if a dev shipped code but didn't update the registry, leave a comment.
When you SHIP a release
- Run
npx tsx tools/registry/src/cli.ts drift-checkon the release branch. - Triage any new findings before merging the release PR.
- Update the parent epic's
lastVerified: <today>after the release is stable.
Periodic refresh
Nightly (automated): scans regenerate entity YAMLs. No action needed.
After large refactors (manual): run all scanners:
cd hmp-docs
for cmd in scan-routes scan-screens scan-events scan-tables scan-tests; do
npx tsx tools/registry/src/cli.ts $cmd
done
git add registry/ && git commit -m "chore(registry): refresh scans after <refactor>"
Part 5 — Common scenarios
"I added a new API, what do I update?"
- Scan auto-emits the YAML:
npx tsx tools/registry/src/cli.ts scan-routeswritesregistry/apis/AP-<service>-<METHOD>-<path>.yaml. - If the new API implements an existing story, edit
registry/stories/ST-<id>.yamland add the new API id toimplementations.apis. - If the API is a new feature that doesn't fit any existing story, either:
- Create a new story, OR
- Leave the entity unclaimed (coverage-check will flag it, triage can assign later).
"I deleted an API, what do I update?"
- Delete the entity YAML:
git rm registry/apis/AP-<id>.yaml - Grep for the id in stories:
grep -rl "AP-<id>" registry/stories/ - Remove the id from each story's
implementations.apisarray. validate-yaml+check-cross-linkswill refuse to let you merge if you miss step 3.
"validate-yaml is failing in my PR, what do I do?"
- Run locally:
npx tsx tools/registry/src/cli.ts validate-yaml - Read the error — it tells you which file and which schema rule failed.
- Common cause: unquoted colons in acceptance strings (YAML mis-parses as mapping). Wrap the string in double quotes.
- Fix + commit + push.
"check-cross-links is failing, what do I do?"
- Run locally:
npx tsx tools/registry/src/cli.ts check-cross-links - Error says:
ST-<id> references AP-<x> but AP-<x> not found - Either fix the typo in the story YAML, or check whether the entity was renamed / deleted (maybe you're the one who deleted it).
"I see a finding but it's wrong / not actionable, what do I do?"
Annotate it as triageDecision: wontfix with a triageNote explaining why:
status: triaged
triageDecision: wontfix
context:
triageNote: "Sample fixture — never in real code. Kept for SP-1 schema tests."
Commit. Don't delete — keeping the annotation documents the decision for future triages.
Part 6 — Current finding state (as of 2026-04-24)
Total findings: 45
- drift-checker: 19 (0 high, 19 medium, 0 low, 0 blocker — post-SP-4 triage)
- manual-sp2-triage: 25 (legacy findings from Frontdesk pilot, already triaged)
- coverage-check: 0 (only ever run --dry-run)
Blocking gates enforced:
- validate-yaml ✅ on every PR
- check-cross-links ✅ on every PR
Non-blocking (PR comment):
- drift-check report-only
- coverage-check report-only
The next thing that will change this state:
- A developer makes a PR that touches code/registry → PR comment appears
- Nightly pipeline runs → scans regenerate → new drift findings may appear
- Weekly SP-4 cycle runs → triage top-20 → state shifts