R-1228: retire DooPlex's copy of the website (operator yes); the installer pin moves to INSTALLER-TAG
gates / gates (push) Successful in 3m25s

- INSTALLER-TAG (one line) is the only installer pin; publish-site-cloudflare.sh reads it.
- hostinstall gate 6c: pin file holds one tag, no manifest pins one, publish script takes
  the site from origin/main and scripts/ from the tag. Red seen on five mutants.
- manifests: webpage.yaml keeps only FileBrowser; contact-mailer.yaml loses the old
  felhom.eu/api Ingress (an orphan: glued to the next doc by a `80---` typo).
- R-110 fence text, manifests/website rules, build skill, runbooks, poster facts updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-11-07 23:10:21 +01:00
1 parent 7c6d3236df
commit c28ce7ce2f
16 files changed
+107 -418

No files matched your search

+45 -25
View File
@@ -182,8 +182,8 @@ else:
# invisible in a diff that touches one line.
# 6b. `fetch_raw` still pins to the resolved agent version — the positive form, so the mechanism
# cannot be quietly deleted rather than regressed.
# 6c. the website manifest still syncs `/scripts/` from a TAG ref and the website from `main` —
# the split is the deploy-side half of the same channel, and reverting it is one word.
# 6c. INSTALLER-TAG is the one pin, no manifest pins a second one, and the publish script takes the site
# from `main` and `/scripts/` from the tag — the deploy-side half of the same channel (R-1228).
branch_refs = [l for l in lines if "raw/branch/" in l and not l.lstrip().startswith("#")]
if branch_refs:
fail("installer still fetches from a BRANCH ref — the run-time channel is floating again "
@@ -197,34 +197,54 @@ else:
fail("fetch_raw no longer pins to $ART_AGENT_VER — the agent's configs and its binary can "
"again come from different refs in one install (R-183)")
WEBPAGE = os.path.join(ROOT, "manifests", "webpage.yaml")
# Since 2026-11-07 (R-1228, DooPlex's copy retired) the installer tag is pinned in ONE place, INSTALLER-TAG, and
# Cloudflare Pages is the only publish path (scripts/publish-site-cloudflare.sh). What must hold:
# - INSTALLER-TAG names exactly one `installer-vX.Y.Z` (the script refuses anything else; the gate says so first);
# - no manifest names an installer tag any more — a second pin is how two copies serve different installers;
# - the publish script reads the pin file, takes the site from origin/main and scripts/ from the tag.
PIN = os.path.join(ROOT, "INSTALLER-TAG")
try:
with io.open(WEBPAGE, "r", encoding="utf-8") as f:
wp = f.read()
with io.open(PIN, "r", encoding="utf-8") as f:
pin_lines = [l.strip() for l in f if l.strip() and not l.lstrip().startswith("#")]
except IOError as e:
fail("cannot read manifests/webpage.yaml to check the publish channel: %s" % e)
wp = None
if wp is not None:
# The scripts sync must name a tag ref; the website sync must still track main.
if re.search(r'--ref=installer-v', wp):
ok("manifest: /scripts/ syncs from an installer tag")
fail("cannot read INSTALLER-TAG (the installer pin, R-110/R-1228): %s" % e)
pin_lines = None
if pin_lines is not None:
if len(pin_lines) == 1 and re.match(r'^installer-v\d+\.\d+\.\d+$', pin_lines[0]):
ok("INSTALLER-TAG pins one installer tag (%s)" % pin_lines[0])
else:
fail("manifests/webpage.yaml has no `--ref=installer-v…` sync — /scripts/ is not served "
"from a tag, so pushing the installer publishes it again (R-110)")
if re.search(r'--(branch|ref)=main', wp):
ok("manifest: the website still tracks main (a copy edit must not need a release)")
fail("INSTALLER-TAG must hold exactly ONE line `installer-vX.Y.Z` (found: %s) — the publish script "
"refuses it, and the public installer cannot be moved" % (pin_lines or "nothing"))
stale = []
for dirpath, _dirs, files in os.walk(os.path.join(ROOT, "manifests")):
for fn in files:
if fn.endswith((".yaml", ".yml")):
with io.open(os.path.join(dirpath, fn), "r", encoding="utf-8") as f:
if re.search(r'--ref=installer-v', f.read()):
stale.append(os.path.relpath(os.path.join(dirpath, fn), ROOT))
if stale:
fail("a manifest still pins an installer tag (%s) — the pin lives ONLY in INSTALLER-TAG since R-1228; "
"two pins can serve two different installers" % ", ".join(stale))
else:
ok("no manifest pins an installer tag (INSTALLER-TAG is the only pin)")
PUB = os.path.join(ROOT, "scripts", "publish-site-cloudflare.sh")
try:
with io.open(PUB, "r", encoding="utf-8") as f:
pub = f.read()
except IOError as e:
fail("cannot read scripts/publish-site-cloudflare.sh (the only publish path): %s" % e)
pub = None
if pub is not None:
code = "\n".join(l for l in pub.splitlines() if not l.lstrip().startswith("#"))
if '"$REPO/INSTALLER-TAG"' in code:
ok("publish script reads INSTALLER-TAG")
else:
fail("manifests/webpage.yaml no longer tracks main for the website — pinning the SITE to "
"the installer tag turns every copy edit into a release")
# All four git-sync containers (two sidecars, two init containers) must read the SAME repo: they moved to
# the in-cluster Gitea address together (2026-10-19), and an init container left on another URL seeds the
# pod from a different source than the sidecar that keeps it fresh.
repos = re.findall(r'--repo=(\S+)', wp)
if len(repos) == 4 and len(set(repos)) == 1:
ok("manifest: all four git-syncs read the same repo (%s)" % repos[0])
fail("publish-site-cloudflare.sh no longer reads INSTALLER-TAG — it can upload an installer nobody pinned")
if re.search(r'archive origin/main website', code) and re.search(r'archive "\$TAG" scripts', code):
ok("publish script: the site from main, scripts/ from the tag (a copy edit must not need a release)")
else:
fail("manifests/webpage.yaml: the git-sync `--repo` values differ or are not four (%s) — the "
"sidecars and init containers must read one repo" % ", ".join(repos))
fail("publish-site-cloudflare.sh: the site must come from origin/main and scripts/ from the tag — "
"pinning the SITE to the tag turns every copy edit into a release; scripts/ from main publishes on push")
# ── R-185: every path that RESOLVES the backup target must also grant on it ──────────────────
#