A registration change now self-heals: PATCH of a composition field advances
composed_at on the next plain GET, while a description-only PATCH leaves the
cache alone. Both confirmed against the production hub.
Record the revision 9 lesson: it reported STATUS: deployed and Upgrade
complete while shipping nothing, because the values file still pinned the
previous tag. A successful helm upgrade proves the chart applied, not that the
code changed -- confirm the running image afterwards.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Enabling a federation source left /v1/federated serving its cached compose and
reporting stale: false while doing it, so a repo could be correctly registered
and silently invisible for as long as its cached index survived. That is how
evidence-binder stayed missing after re-enabling until a manual
POST /v1/federated/compose was issued.
Registration writes now mark the composed index stale, and a plain GET
recomposes when the flag is set. Clearing it there is not a silent clear: that
pass really did refetch. A PATCH touching only a description does not
invalidate anything.
This changes a contract documented in specs/FederationHubAPI.md, so the
staleness section is rewritten rather than left to drift, including the two
triggers that now set the flag.
The first two tests written for this were worthless -- they passed with the fix
removed, because a newly registered repo has no cache entry and gets fetched
regardless. The real failure needs a populated cache holding stale content
inside its 24h TTL. test_re_enabled_source_refetches_a_stale_cache models that
and fails on pre-fix code; verified by reverting the mark_stale calls.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
evidence-binder published their repaired index at e462775 and correctly held
the re-enable request until it was visible on Forgejo. Pre-checked this time
before touching production: backing entries return 200, and a local compose of
all 61 sources gave 64 capabilities with zero warnings and no duplicate IDs.
Public endpoint now serves 61 sources / 64 capabilities, with both
capability.evidence.binding and capability.evidence.rect-registry at
D3 / A2 / C3 / R3.
Open T09 for the gap this exposed: enabling a source does not invalidate the
composed index. The endpoint kept serving a stale compose, reporting
stale: false throughout, until POST /v1/federated/compose was called by hand.
A repo can be correctly registered and silently invisible.
SCOPE.md: refresh the federated counts, record the deployed image, and correct
the multi-domain claim — member rows have begun carrying their own domain
(evidence-binder publishes domain: infotech) even though the manifest is still
composed under helix_forge.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Helm revision 8. /health returns 200 from uvicorn instead of 404 from the
landing nginx, / still serves the landing page, and make reuse-smoke passes
end to end for the first time.
Also resolves the composed_at observation: it was not a bug, just a build
that predated REUSE-WP-0019-T06. The timestamp now advances per recompose.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An index row with no id now says whether it looks like a SCOPE.md capability
block, instead of leaving the author to work out why their repo contributes
nothing to the federated index. That confusion is invisible without a
diagnostic: the row is valid YAML, the file parses, and the member just
silently disappears.
Swept all 61 federation sources with --refresh: evidence-binder is the only
affected member. The other ten zero-count repos are genuine empty scaffolds.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Helm revision 7 on Railiance01. Production now runs a Forgejo image; the Gitea
dependency is gone from both the federation sources and the image reference.
/v1/reuse-events returns 200 for the first time, so REUSE-WP-0019 T04/T05 are
finally live. PVC and all 61 registrations survived.
Also diagnose T06: /health is served correctly by the app (200 in-cluster) but
Traefik routes it to the landing nginx, because router priority is derived from
rule-string length and Path(/health) ties with PathPrefix(/). Raise T06 to
medium — make reuse-smoke is the documented deploy check and it false-negatives.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Inspection showed the defect is larger than the missing id that broke compose:
both rows use a non-conforming shape and registry/capabilities/ is empty, so
they are orphans with no backing entry Markdown.
Left to that repo rather than edited here. Reshaping the rows is mechanical,
but assigning maturity vectors is an assessment of their own delivery state.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The guide described gitea.coulomb.social as the live registry and its manual
build commands still pushed there. CoulombCore is switched off 2026-08-31.
Also record what the registry actually contains: authenticated tags/list shows
latest, main-bca7165, main-f9d957a and no e3ae22e — so the tag pinned in
railiance-apps/helm/reuse-surface-values.yaml cannot be pulled today, making
ImagePullBackOff a present risk on any restart rather than a future one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Repointing the production hub's 50 Gitea-hosted federation sources to Forgejo
ahead of the 2026-08-31 CoulombCore retirement took /v1/federated to HTTP 500.
One member index (evidence-binder) has capability rows with no `id`, and
compose_federated_index dereferenced item["id"] unguarded. Its Gitea copy was a
stale snapshot returning a non-mapping, so those rows had never been parsed.
A single malformed member index must not take down the whole endpoint. Extract
_read_index_entries(): unparseable YAML, a non-mapping body, an empty file, and
a non-list `capabilities` each degrade to a warning and an empty row list, and
rows without an `id` are skipped individually. A failed source stays listed with
count 0 so it remains visible to operators rather than silently disappearing.
Also fix wall-clock rot in tests/test_plan_check.py, which was already failing
at clean HEAD: three tests pinned the compose date to a literal that has now
aged past STALE_DAYS.
Add workplan REUSE-WP-0020 covering the full cutover.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>