C-33 returned early when the generator produced no rows, so a leftover
index kept listing archived workplans as active. Rewrite that file to an
empty table instead of leaving the stale rows in place.
Assistant: grok
Assistant-Session: 01a04d7c-846d-77e3-af8d-020019e4eb61
The upgrade failed as `pre-upgrade hooks failed: timed out waiting for the
condition`. The migrate hook was in ImagePullBackOff: tag main-11f689d does not
exist. `.forgejo/workflows/image.yaml` has a `paths:` filter that excludes
deploy/**, so the chart-only commit was green in CI and built nothing — the two
green runs on it were host-smoke and container-smoke, not build-and-push.
470ece8 carries all the code; every commit after it touches only the chart and
generated docs.
scripts/verify_image_pin.py refuses a pin whose commit has no successful
build-and-push run, and says so in those terms rather than as a timeout five
minutes later. Verified against both the bad pin and the good one; treats an
unreachable forge as inconclusive rather than as failure.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2583210@bnt-lap001
Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
The API validates repo classification against the-custodian canon allowed
values. A container has no such checkout, so every classification write failed
with a 500 and classification could only ever be written from a workstation.
Mounts the vocabulary as a ConfigMap and points
REPO_CLASSIFICATION_ALLOWED_PATH at it.
The copy is the risk, so it is owned rather than trusted:
scripts/sync_classification_allowed.py regenerates it from canon and --check
fails on drift. make check-classification-allowed and
make railiance-state-hub-render both refuse to proceed when the copy diverges,
so a release cannot silently validate against a stale vocabulary.
The container volumeMounts and env blocks are merged rather than appended —
a second pair would have produced duplicate YAML keys as soon as sweep was
re-enabled.
Refs CUST-WP-0067-T09
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2583210@bnt-lap001
Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
capture_legacy_meter_evidence.py fell back to hours=8 whenever --days was
omitted, and --hours itself defaulted to 8. Every unattended capture sampled
06:00Z-14:00Z while writing a file named weekly-review with cadence: weekly.
39 of 40 captures ran this way; only 2026-07-08 used a true 7-day window.
Calls outside the band were never sampled, so interfaces with live callers
reported as retirement candidates -- GET /tasks/?workstream_id was flagged on
2026-08-19 despite traffic on 2026-08-18.
Default the script to days=7; keep --hours for spot checks, documented as not
retirement evidence. Adds corrected capture for 2026-08-20 and records the
residual gap (candidate rule ignores last_seen_at) against STATE-WP-0079-T05.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
STATE-WP-0080-T02: statehub register routes project-flavor scaffolding
through rmgr scaffold and keeps only repo + host-path registration.
T01 refuse remains when GOAL.md is missing and --wp-prefix is not set.
RMGR-WP-0005-T01: C-06/C-11/C-32 skip mint+writeback unless this
instance is the identifier registrar (STATEHUB_REGISTRAR or railiance
hostname).
First cut of the transclusion-style index named in the stage-3 seed: a
WORK-RECORDS.md at repo root listing kind/id/status/lane/source for
every workplan, task, intake, decision, and engagement found in the
repo -- derived purely from files (no hub query), matching the ADR-001
rebuild principle. Full markitect transclusion rendering is a
follow-on, not this first cut.
- _generate_work_record_index(): reuses iter_workplan_files/
parse_frontmatter/get_tasks_from_workplan for workplan+task rows,
and the repo-wide yaml-block scan already proven by C-31/C-32 for
intake/decision/engagement rows. Archived workplans excluded (index
is for current orientation, not history); closed decisions/intakes/
engagements stay listed. Returns None (no file written) for repos
with zero work records, to avoid clutter.
- _check_work_record_index_freshness(): C-33, WARN+fixable when
WORK-RECORDS.md is missing or its content differs from a fresh
regeneration.
- fix_repo C-33 dispatch: overwrites the file with the regenerated
content.
13 new tests (generation across all kinds, sort order, archived
exclusion, self-scan exclusion, freshness detection incl. idempotence).
No regressions: full repo suite green (561 tests).
Live-verified at two scales: binky-control (5 workplans, 31 tasks, 3
intake, 4 decisions, 5 engagements) and the-custodian (52 workplans,
332 tasks) -- both generated correctly on first run, confirmed
idempotent (identical second run produces no C-33 fix), and the larger
repo's scan added no material overhead to the existing ~1.5min
fix-consistency run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mechanism named in canon/standards/work-record-types_v0.1.md:
"Promotion is a first-class transition... manual transcription of an
intake item into other kinds is a process defect." This is what AWQ-010
needed and didn't have -- a human/agent had to notice, transcribe, and
re-register it by hand. One call now does what that manual pass did.
scripts/promote_intake.py: intake.routed -> workplan | task | decision |
engagement.
- workplan: new ADR-001 file at workplans/{ID}-{slug}.md, registered
against the hub (repo+topic resolution, POST /workplans, frontmatter
id write-back)
- task: appended as a ```task``` block to an existing --workplan-file,
registered via POST /tasks, reuses the existing
_inject_task_id_into_block writeback helper
- decision: appended as a ```yaml``` block with a fresh
{PREFIX}-DEC-{YYYY}-{NNN} id to --target-file, registered the same
way C-32 registers decisions (reuses _inject_yaml_block_field)
- engagement: appended as a ```yaml``` block with a fresh
{PREFIX}-ENG-{YYYY}-{NNN} id -- file-only, no hub entity exists yet
(same honest deferral as C-32), reported not silently skipped
In every case the intake is closed with outcome=promoted and
promoted_to=<new canonical id>; the new record carries an
origin: "intake:<id>" back-link.
Wired as `statehub promote-intake <intake-id> --to <kind> --repo-slug
<slug> --repo-path <path> --domain <domain> [--target-file ...]
[--workplan-file ...]`, matching the CLI shape named in the workplan text.
17 tests: pure helpers (_slugify, _next_number, _append_yaml_block,
frontmatter injection) offline; full promote_intake() flow with the hub
API mocked.
Live-verified against the real running API/DB and a real repo
(binky-control), not just mocks -- and the live proof caught a real bug:
the first workplan-promotion run silently produced a false success (the
intake was closed outcome=promoted, but /workplans/ actually 422'd on a
missing repo_id that the code never resolved, so no workstream was ever
created). Fixed to resolve repo_id via /repos/{slug} and to raise loudly
on registration failure instead of writing a half-registered file
silently; locked in as two regression tests. Re-verified clean:
workplan promotion (CLI direct + through `statehub promote-intake`
itself) and decision promotion both proven end-to-end against the live
hub, with all scratch artefacts (files + hub rows) cleaned up afterward.
No regressions: full state-hub suite (271 tests across
test_promote_intake, test_intake, test_work_record_registration,
test_work_record_check, test_routers_core, test_consistency_check,
test_consistency_sweep, test_mcp_smoke, test_mcp_write_tools) green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extends fix-consistency to scan any file for kind: intake / kind: decision
YAML blocks (not just workplans/, per canon: any file is a potential
work-record source), create the corresponding hub entity when missing a
state_hub_intake_id / state_hub_decision_id, and write the id back into
the source block -- same write-back pattern as C-06 for workplans.
kind: engagement is reported INFO (deferred, not fixable): no hub entity
exists for it yet, a separate stage-3 follow-on.
- _load_work_record_kind_registry(): kind-aware registry loader, factored
out so C-31's existing flat _load_work_record_patterns() builds on it
without duplication (verified: C-31's 16 tests still pass unmodified)
- _check_work_record_registration(): detection, wired into check_repo
right after C-31
- _inject_yaml_block_field(): write-back helper for fenced
blocks, mirroring _inject_task_id_into_block's pattern for
blocks
- fix_repo C-32 dispatch: creates the intake (scoped to repo_id) or
decision (scoped to resolved topic_id, reusing C-06's domain->topic
resolution) via the REST API, then writes the id back
- tests/test_work_record_registration.py: 15 tests (classification,
detection incl. engagement-deferred and workplan-kind-exclusion,
injection incl. idempotence and non-interference with sibling blocks)
Live-verified end to end against a real registered repo (binky-control,
not just synthetic fixtures): a real fix-consistency run found and
registered 3 genuinely open, previously-unlinked intake items
(AWQ-002/003/006) sitting in AutopilotWorkQueue.md, and correctly
deferred 5 real OH- engagement items as INFO. No regressions: full
consistency_check + consistency_sweep suite (128 tests) and C-31's own
suite (16 tests) still green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Warn on YAML-block ids matching no kind in the canon work-record type
registry (~/the-custodian/canon/standards/work-record-types.yaml, override
via WORK_RECORD_REGISTRY). Detection only; registration of non-workplan
kinds is a later stage. Skips template placeholders and repos without the
registry available.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
T03: MCP alias retirement gate was unstartable — deprecation notices existed
but no mcp:* interfaces were ever registered or metered. Add
_meter_legacy_mcp() posting /legacy-meter/usage (kind mcp_tool, component
state-hub.mcp) from create_workstream, list_workstreams, update_workstream,
update_workstream_status, and state://workstreams/{topic_slug}; register all
five phase-3 backlog keys so zero-window streaks accrue from today.
T04: trace residual POST /progress/ workstream_id (3 calls/8h, unknown) to
.custodian-brief.md labelling workplans "workstream_id:"; brief generator now
prints "workplan_id:". Briefs refresh on each repo's next fix-consistency run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Expose hours query param on /legacy-meter/summary and weekly-review;
capture_legacy_meter_evidence.py defaults to --hours 8 (--days 7 for
weekly retirement gate). Re-capture post-deploy evidence with tighter window.
Add X-StateHub-Component to fix-consistency and other State Hub REST callers for
legacy-meter attribution. Archive STATE-WP-0069; open STATE-WP-0070 for
meter-gated phase-2 retirement. Task POST bodies use workplan_id only.
Stop dual-publishing org.statehub.workstream.completed; return 410 Gone for
legacy DELETE /workstreams/{id}. Migrate fix-consistency, MCP adhoc bootstrap,
and dashboard token summary to /workplans/. Add legacy-meter evidence capture
script and pytest snapshot; update docs and close out the workplan.
Introduce scripts/project_rules/gitignore-claude.template with the fleet
pattern that tracks .claude/rules/ while ignoring machine-local Claude state.
ensure_gitignore_claude_rules.py applies it during statehub register,
register_project.sh, and update_agent_instruction_files fleet regen.
Add legacy terminology compatibility footnote to workplan-convention, align
session-protocol and first-session with workplan-first registration, and point
agents-codex at GET /workplans/ plus the fleet canon addendum.
Cancelled or done DB tasks without file backing are historical duplicates
after workplan linkage. Do not warn on active workstreams when the orphan
is already terminal.
Add C-25..C-30 fix-consistency checks for blocked-workplan inbox sweeps,
stale unread triage, workplan ID prefix/collision lint, and SCOPE freshness.
Extend brief generation and get_domain_summary with inbox hygiene warnings.
Complete workplan_id aliases on remaining MCP tools and retry transient
_api_get failures to reduce false stale-reference errors under load.
Add git/ssh to the runtime image, mount /home/tegwick into the state-hub pod,
resolve host_paths via STATE_HUB_SWEEP_HOSTNAME, and fall back to the
railiance01 the-custodian canon path for classification validation.
- Review integration files; fill SCOPE where templated
- Document dev workflow in stack-and-commands.md
- Seed WP-0002 implementation workplan; mark bootstrap finished
- Hub sync via fix-consistency
Infer workplan prefixes from on-disk filenames instead of first-token
derivation, add a frontmatter normalization script, and wire Make targets
for dirty-repo sweeps.
Introduce canonical MCP_SERVER_NAME constants, shared registration helpers,
and a migrate_mcp_config.py script for ~/.claude.json upgrades. Registration,
patch, and custodian CLI checks accept both dev-hub and legacy state-hub during
transition. API root metadata and session-protocol template reflect the new name.