feat: let a profile state that its upstream is gone

Saying those profiles would stay open no matter what was wrong. A dead
forge is a verifiable fact, and a fact can be recorded: upstream_gone
carries why, and the profile stops being an open problem. The refs
describe the last revision anyone could reach, which is all any reader
can ask of them.

The declaration is guarded rather than trusted, because a forge can come
back and a profile that keeps asserting a death nobody rechecks is worse
than one that fails loudly. Declared and unreachable reports as a
recorded fact; declared and answering reports as the contradiction it
is, and the profile has to be read again.

yuzu and suyu carry GitHub's 451. citron carries the loss of
git.citron-emu.org and the squatter now sitting on the .com. Each names
what was probed and when, so the next reader retraces it rather than
repeating it.
This commit is contained in:
Abdessamad Derraz committed 2026-09-04 17:25:23 +02:00
1 parent 70d121e99a
commit ece637d52d
8 files changed
+80 -1

No files matched your search

+19 -1
View File
@@ -1218,7 +1218,25 @@ def build_report(
report.skipped = f"unsupported host: {declared or 'none declared'}"
return report
views = select_views(profile, cache_dir, offline)
stated_gone = str(profile.get("upstream_gone") or "").strip()
try:
views = select_views(profile, cache_dir, offline)
except upstream.GoneError as exc:
if stated_gone:
# The profile says the forge is gone and the forge agrees. That is
# a recorded fact, not an open problem: the refs describe the last
# revision anyone can reach, and nothing further is possible.
report.skipped = f"upstream gone (declared): {stated_gone}"
return report
raise
if stated_gone and views:
# Declared dead, yet it answered. A profile that keeps saying so stops
# being read, so the contradiction is the finding.
report.skipped = (
f"upstream_gone is declared but the forge answers: {stated_gone}"
)
return report
if not views:
report.skipped = (
"no source_commit and no resolvable profiled_date "