finish three custodian workplans from live hub evidence
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Python Tests / pytest (push) Successful in 21s

Close CUST-WP-0064 after the 2026-08-24 unassisted fire ingested
clay-borg, close CUST-WP-0065 now that all 120 active repos project a
classification, and close ADHOC-2026-08-25. Mark CUST-WP-0067 T02/T10
done (reverse relays already gone; work-record recovery lives on 0068).
Park the later no-checkout SBOM regression as CUST-IN-0015. Teach the
classification gate to use this host's checkout path.
This commit is contained in:
codex 2026-08-28 20:27:05 +02:00
parent 349238cf8f
commit 93b8174abd
8 changed files with 143 additions and 21 deletions

View file

@ -60,3 +60,7 @@ Status 2026-08-24:
On railiance01 both services are reachable in-cluster with no tunnel at all — On railiance01 both services are reachable in-cluster with no tunnel at all —
this is where "abandon tunneling" genuinely applies. this is where "abandon tunneling" genuinely applies.
**Applied (2026-08-28):** both reverse relays are absent from the live
`tunnels.yaml` and from `bridge status`. `CUST-WP-0067-T02` is done. The
cache Postgres container remains until `CUST-WP-0068-T08`.

View file

@ -69,3 +69,20 @@ origin_ref: CUST-WP-0062
notes: "Live review after cutover found the Ready SBOM Nexus pod at restartCount 9 in under five hours. The last container ran exactly 30 minutes, then readiness/liveness returned HTTP 500 because PostgreSQL rejected the expired v-token-sbom-nex-* credential; Kubernetes restarted the process and it recovered. The corrected runtime deployed on 2026-08-23 rereads the mounted URL for every new connection, recycles the pool every five minutes, keeps credentials out of the engine URL, and separates process liveness from database readiness. Completion evidence at 2026-08-22T23:06:19Z exceeded the old failure point with 30m51s on one pod UID across repeated mounted Secret refreshes: Ready, restart count zero, process/database/repository checks passing, zero health 500s, and zero credential-pattern log matches. Absorbed by finished SBOM-WP-0004 and RAPP-SBOM-NEXUS-WP-0003." notes: "Live review after cutover found the Ready SBOM Nexus pod at restartCount 9 in under five hours. The last container ran exactly 30 minutes, then readiness/liveness returned HTTP 500 because PostgreSQL rejected the expired v-token-sbom-nex-* credential; Kubernetes restarted the process and it recovered. The corrected runtime deployed on 2026-08-23 rereads the mounted URL for every new connection, recycles the pool every five minutes, keeps credentials out of the engine URL, and separates process liveness from database readiness. Completion evidence at 2026-08-22T23:06:19Z exceeded the old failure point with 30m51s on one pod UID across repeated mounted Secret refreshes: Ready, restart count zero, process/database/repository checks passing, zero health 500s, and zero credential-pattern log matches. Absorbed by finished SBOM-WP-0004 and RAPP-SBOM-NEXUS-WP-0003."
state_hub_intake_id: "01a02e28-3beb-764a-b4fc-c34cdf59a01e" state_hub_intake_id: "01a02e28-3beb-764a-b4fc-c34cdf59a01e"
``` ```
## CUST-IN-0015 — Restore source-ref projection on later SBOM catch-up batches
```yaml
id: CUST-IN-0015
kind: intake
title: "Restore source-ref projection on later SBOM catch-up batches"
status: open
lane: blue
priority: high
owner: repo-manager
tags: [sbom, catch-up]
origin: residual
origin_ref: CUST-WP-0064
updated: "2026-08-28"
notes: "CUST-WP-0064-T04 is met: the 2026-08-24 07:15 UTC unassisted fire ingested clay-borg (snapshot 63abb22f, forgejo-archive-v1, revision 18c57f2e, 77 entries) and wrote truthful no-manifest terminals for citation-work and config-atlas at pinned SHAs. From 2026-08-25 through 2026-08-28 the same weekday schedule writes three no-checkout snapshots each day (feature-control / evidence-source / evidence-binder on 2026-08-28). never_count is 76. Diagnose why Repo Manager source-ref projection followed the 2026-08-24 batch and not later ones; do not widen catch_up_limit while diagnosing. SBOM Nexus and Activity Core are counterparties, not a second owner."
```

View file

@ -81,3 +81,26 @@ def test_clean_active_fleet_converges_and_renders(tmp_path: Path) -> None:
assert report["source_warning_count"] == 0 assert report["source_warning_count"] == 0
assert "active classified: 1" in render_text(report) assert "active classified: 1" in render_text(report)
assert "converged: yes" in render_text(report) assert "converged: yes" in render_text(report)
def test_host_paths_for_this_machine_beat_other_host_local_path(tmp_path: Path) -> None:
local = tmp_path / "repo-manager"
_write_valid(local)
report = analyze_repositories(
[
{
"slug": "repo-manager",
"status": "active",
"category": "tooling",
"local_path": "/home/tegwick/repo-manager",
"host_paths": {
"bnt-lap001": str(local),
"239.62.205.92.host.secureserver.net": "/home/tegwick/repo-manager",
},
}
],
hostname="bnt-lap001",
)
assert report["projected_without_source"] == []
assert report["converged"] is True

View file

@ -10,6 +10,7 @@ from __future__ import annotations
import argparse import argparse
import json import json
import os import os
import socket
import sys import sys
import urllib.error import urllib.error
import urllib.request import urllib.request
@ -50,17 +51,48 @@ def fetch_repositories(
return payload return payload
def _source_path(record: dict[str, Any]) -> Path | None: def _checkout_candidates(record: dict[str, Any], *, hostname: str) -> list[Path]:
local_path = record.get("local_path") """Prefer this host's recorded checkout over a `local_path` from another machine."""
if not isinstance(local_path, str) or not local_path.strip(): seen: set[str] = set()
return None candidates: list[Path] = []
return Path(local_path) / ".repo-classification.yaml"
def add(raw: object) -> None:
if not isinstance(raw, str):
return
text = raw.strip()
if not text or text in seen:
return
seen.add(text)
candidates.append(Path(text))
host_paths = record.get("host_paths")
if isinstance(host_paths, dict):
short = hostname.split(".")[0]
add(host_paths.get(hostname))
add(host_paths.get(short))
for value in host_paths.values():
if isinstance(value, str) and Path(value).is_dir():
add(value)
add(record.get("local_path"))
return candidates
def _source_path(record: dict[str, Any], *, hostname: str) -> Path | None:
preferred: Path | None = None
for checkout in _checkout_candidates(record, hostname=hostname):
path = checkout / ".repo-classification.yaml"
if preferred is None:
preferred = path
if path.is_file():
return path
return preferred
def analyze_repositories( def analyze_repositories(
records: list[dict[str, Any]], records: list[dict[str, Any]],
*, *,
validate_sources: bool = True, validate_sources: bool = True,
hostname: str | None = None,
) -> dict[str, Any]: ) -> dict[str, Any]:
active = [record for record in records if record.get("status") == "active"] active = [record for record in records if record.get("status") == "active"]
classified = [record for record in active if record.get("category") is not None] classified = [record for record in active if record.get("category") is not None]
@ -74,10 +106,11 @@ def analyze_repositories(
slug_counts: dict[str, int] = {} slug_counts: dict[str, int] = {}
allowed = load_allowed() if validate_sources else None allowed = load_allowed() if validate_sources else None
current_host = hostname or socket.gethostname()
for record in active: for record in active:
slug = str(record.get("slug") or "<missing-slug>") slug = str(record.get("slug") or "<missing-slug>")
slug_counts[slug] = slug_counts.get(slug, 0) + 1 slug_counts[slug] = slug_counts.get(slug, 0) + 1
path = _source_path(record) path = _source_path(record, hostname=current_host)
source_present = path is not None and path.is_file() source_present = path is not None and path.is_file()
if record.get("category") is None: if record.get("category") is None:

View file

@ -4,10 +4,10 @@ type: workplan
title: "Ad hoc tasks 2026-08-25" title: "Ad hoc tasks 2026-08-25"
domain: infotech domain: infotech
repo: the-custodian repo: the-custodian
status: active status: finished
owner: codex owner: codex
created: "2026-08-25" created: "2026-08-25"
updated: "2026-08-25" updated: "2026-08-28"
--- ---
# Ad hoc tasks 2026-08-25 # Ad hoc tasks 2026-08-25

View file

@ -4,13 +4,13 @@ type: workplan
title: "Controlled scan inputs for authoritative daily SBOM catch-up" title: "Controlled scan inputs for authoritative daily SBOM catch-up"
domain: infotech domain: infotech
repo: the-custodian repo: the-custodian
status: active status: finished
owner: codex owner: codex
topic_slug: custodian topic_slug: custodian
planning_priority: high planning_priority: high
planning_order: 64 planning_order: 64
created: "2026-08-22" created: "2026-08-22"
updated: "2026-08-23" updated: "2026-08-28"
quality_dor: DoR-Ok quality_dor: DoR-Ok
quality_dor_at: "2026-08-22" quality_dor_at: "2026-08-22"
quality_dor_by: codex quality_dor_by: codex
@ -158,7 +158,7 @@ than the attended target set; T04 retains only the first unassisted fire.
```task ```task
id: CUST-WP-0064-T04 id: CUST-WP-0064-T04
status: progress status: done
priority: medium priority: medium
state_hub_task_id: "664d90b0-1169-58fa-9a77-df53e739f957" state_hub_task_id: "664d90b0-1169-58fa-9a77-df53e739f957"
``` ```
@ -180,11 +180,29 @@ An operator-trigger through the existing Temporal schedule subsequently
proved the production scheduled path and fleet summary without changing its proved the production scheduled path and fleet summary without changing its
weekday cadence. The first unassisted 09:15 Europe/Berlin fire remains. weekday cadence. The first unassisted 09:15 Europe/Berlin fire remains.
**Done (2026-08-28):** the first unassisted weekday fire ran at 2026-08-24
07:15 UTC (09:15 Europe/Berlin) against the next oldest three. `clay-borg`
ingested from `forgejo-archive-v1`:
| Field | Value |
|---|---|
| snapshot | `63abb22f-0701-4d56-ba16-75bdff9362c4` |
| repo | `clay-borg` |
| revision | `18c57f2e9dce0589c1f0e24dd4d939aea50cee86` |
| entries | 77 (`Cargo.lock`) |
| provenance | archive sha256 `df9e5fac…`, 1_033_378 bytes |
| siblings | `citation-work` and `config-atlas` terminal `no-manifest` at pinned SHAs |
`never_count` is 76 (was 94 on 2026-08-23). Daily 07:15 UTC fires continued
2428 August. Residual: from 2026-08-25 the same schedule writes `no-checkout`
again, so source-ref projection is not following later batches —
`CUST-IN-0015`.
## Acceptance ## Acceptance
- [x] Production scans consume a controlled, revision-pinned source input - [x] Production scans consume a controlled, revision-pinned source input
- [x] No workstation filesystem is mounted or implicitly trusted - [x] No workstation filesystem is mounted or implicitly trusted
- [x] Nexus remains the only authoritative snapshot writer - [x] Nexus remains the only authoritative snapshot writer
- [x] One fire remains bounded to its original N targets across retries - [x] One fire remains bounded to its original N targets across retries
- [ ] At least one normal scheduled fire produces real ingested snapshots - [x] At least one normal scheduled fire produces real ingested snapshots
- [x] Source cleanup, provenance, failure evidence, and rollback are verified - [x] Source cleanup, provenance, failure evidence, and rollback are verified

View file

@ -4,10 +4,10 @@ type: workplan
title: "Reclassify repos and guidance docs to the new sector domain scheme" title: "Reclassify repos and guidance docs to the new sector domain scheme"
domain: infotech domain: infotech
repo: the-custodian repo: the-custodian
status: active status: finished
owner: codex owner: codex
created: "2026-08-23" created: "2026-08-23"
updated: "2026-08-23" updated: "2026-08-28"
quality_dor: DoR-Ok quality_dor: DoR-Ok
quality_dor_at: "2026-08-23" quality_dor_at: "2026-08-23"
quality_dor_by: codex quality_dor_by: codex
@ -74,7 +74,7 @@ project names remain valid outside that field.
```task ```task
id: CUST-WP-0065-T03 id: CUST-WP-0065-T03
status: progress status: done
priority: high priority: high
state_hub_task_id: "a1ad7cd3-5bfb-58ee-8f97-6c2e864b2fd9" state_hub_task_id: "a1ad7cd3-5bfb-58ee-8f97-6c2e864b2fd9"
``` ```
@ -118,11 +118,18 @@ classification at revision `81f9279` (`tooling`, primary `agents`, secondary
digest matched the checkout, and the standard API registration completed with digest matched the checkout, and the standard API registration completed with
zero invalid results. Thirteen owner classifications remain. zero invalid results. Thirteen owner classifications remain.
**Closed (2026-08-28):** owner classifications landed. The remaining four
active null-category rows were present, valid source files that had never
been projected: `core-hub`, `fin-hub`, `rail-kubernetes`, and `repo-manager`
(the last looked missing only because hub `local_path` pointed at the node
checkout). `rmgr repo-onboard --api-base http://127.0.0.1:8000` projected all
four. Active fleet is 120/120 classified.
## Verify fleet convergence and close ## Verify fleet convergence and close
```task ```task
id: CUST-WP-0065-T04 id: CUST-WP-0065-T04
status: progress status: done
priority: medium priority: medium
state_hub_task_id: "0c7c6f53-8a89-5102-87ca-e1991c227038" state_hub_task_id: "0c7c6f53-8a89-5102-87ca-e1991c227038"
``` ```
@ -159,6 +166,15 @@ its historical classification. The active fleet is now 103/116 classified;
the same 13 owner-source gaps remain, with no projection or source-validity the same 13 owner-source gaps remain, with no projection or source-validity
failure. failure.
**Closed (2026-08-28):** after the four remaining projections, the live gate
is 125 registered, 120 active, 120 classified, zero null-category, zero
missing source, zero present-but-unprojected, zero invalid source. A false
`projected_without_source` on `repo-manager` (hub `local_path` is the node
checkout; this workstation's path is in `host_paths.bnt-lap001`) is fixed in
`tools/repo_classification_convergence.py`. `make classification-check`
passes. Project names were not rewritten. Non-blocking source-validation
warnings remain (75) and are not a close blocker.
## Indexing note ## Indexing note
**Resolved (2026-08-23):** Repo Manager revisions `7a15f1d` and `7b9fdaa` **Resolved (2026-08-23):** Repo Manager revisions `7a15f1d` and `7b9fdaa`
@ -175,6 +191,6 @@ none was rewritten or treated as the new records.
- [x] Live missing-classification baseline is reproducible and split by cause - [x] Live missing-classification baseline is reproducible and split by cause
- [x] Legacy project identity is distinguished from sector-domain metadata - [x] Legacy project identity is distinguished from sector-domain metadata
- [x] Canonical and agent-facing migration guidance is current - [x] Canonical and agent-facing migration guidance is current
- [ ] Missing source classifications are owner-reviewed and validated - [x] Missing source classifications are owner-reviewed and validated
- [x] Present source classifications project into State Hub - [x] Present source classifications project into State Hub
- [ ] Active fleet has zero unexplained null category projections - [x] Active fleet has zero unexplained null category projections

View file

@ -7,7 +7,7 @@ repo: the-custodian
status: active status: active
owner: codex owner: codex
created: "2026-08-24" created: "2026-08-24"
updated: "2026-08-24" updated: "2026-08-28"
quality_dor: DoR-Ok quality_dor: DoR-Ok
quality_dor_at: "2026-08-24" quality_dor_at: "2026-08-24"
quality_dor_by: codex quality_dor_by: codex
@ -104,7 +104,7 @@ the live API.
```task ```task
id: CUST-WP-0067-T02 id: CUST-WP-0067-T02
status: progress status: done
priority: high priority: high
state_hub_task_id: "4093e928-d752-5a91-96c3-2e80f0e1dac5" state_hub_task_id: "4093e928-d752-5a91-96c3-2e80f0e1dac5"
``` ```
@ -161,6 +161,14 @@ any repo and was blocked in-session; the change and its sequencing constraint
are recorded in `docs/recovery/tunnels-yaml-proposed-changes-CUST-WP-0067.md`. are recorded in `docs/recovery/tunnels-yaml-proposed-changes-CUST-WP-0067.md`.
Remote agents and the documented port map must be repointed *before* removal. Remote agents and the documented port map must be repointed *before* removal.
**Done (2026-08-28):** both reverse relays are gone from
`~/.config/bridge/tunnels.yaml` and from `bridge status`. The only
`state-hub-*` tunnel is `state-hub-primary` (`direction: local`,
`127.0.0.1:8000` → cluster `10.43.68.154:8000`). Live check: one listener on
8000, it is `ssh`, and `/state/health` reports `instance_role=primary`
(`railiance01`). Local uvicorn is not running. Cache Postgres
`infra-postgres-1` is still up on purpose until `CUST-WP-0068-T08`.
## Make the hub target explicit and unspoofable ## Make the hub target explicit and unspoofable
```task ```task
@ -650,7 +658,7 @@ their classification later, with no separate backfill path to write or trust.
```task ```task
id: CUST-WP-0067-T10 id: CUST-WP-0067-T10
status: todo status: done
priority: high priority: high
state_hub_task_id: "509414a4-dee9-5892-96ab-eab8f85982c8" state_hub_task_id: "509414a4-dee9-5892-96ab-eab8f85982c8"
``` ```
@ -731,3 +739,6 @@ It is a content-conformance pass, an identifier decision overlapping
`RMGR-WP-0005`, an orphan disposition, and a per-repository unblocking pass — `RMGR-WP-0005`, an orphan disposition, and a per-repository unblocking pass —
across ~40 repositories, several needing owner judgement. The mechanical share across ~40 repositories, several needing owner judgement. The mechanical share
is done. is done.
**Done (2026-08-25, recorded 2026-08-28):** promoted to `CUST-WP-0068`. This
task's remaining work is that workplan; it is not tracked twice.