D50 = A (R-1290): the published gate asserts the newest 5 released versions plus the pinned MinAgent (0.158.1) and day-0 agent (0.165.0); a pin with no tag fails; decoys red-proved. No binary change.
gates / gates (push) Successful in 1m41s
gates / gates (push) Successful in 1m41s
This commit is contained in:
@@ -98,7 +98,8 @@ TAG_RE = re.compile(r"^v(\d+\.\d+\.\d+)$")
|
||||
# THE retention number, read from the one file that owns it. A check and the policy it enforces
|
||||
# must read the same number from the same place, or they drift and the drift looks like a defect
|
||||
# in something else — which is exactly what happened on 2026-08-08/09 (R-287).
|
||||
RETENTION_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "retention-policy.json")
|
||||
RETENTION_FILE = os.environ.get("FELHOM_RETENTION_POLICY") or \
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), "retention-policy.json") # the env: decoy tests only
|
||||
|
||||
|
||||
def retention_kept():
|
||||
@@ -114,6 +115,21 @@ def retention_kept():
|
||||
raise ValueError("generic_versions_kept must be a positive int, got %r" % (n,))
|
||||
return n
|
||||
|
||||
|
||||
def retention_pinned():
|
||||
"""D50 = A: the versions kept besides the newest N — the hub's MinAgent floor and the day-0 agent. Copies of hub
|
||||
state the vouching session writes into the policy file (CI holds no hub secret). Missing key = no pins."""
|
||||
with open(RETENTION_FILE, encoding="utf-8") as fh:
|
||||
pins = json.load(fh).get("pinned") or {}
|
||||
if not isinstance(pins, dict):
|
||||
raise ValueError("pinned must be an object, got %r" % (pins,))
|
||||
out = {}
|
||||
for name, v in pins.items():
|
||||
if not isinstance(v, str) or not re.match(r"^\d+\.\d+\.\d+$", v):
|
||||
raise ValueError("pinned %s must be X.Y.Z, got %r" % (name, v))
|
||||
out[name] = v
|
||||
return out
|
||||
|
||||
tried = []
|
||||
|
||||
|
||||
@@ -211,6 +227,7 @@ def main():
|
||||
all_versions = versions
|
||||
try:
|
||||
keep = retention_kept()
|
||||
pins = retention_pinned()
|
||||
except Exception as e:
|
||||
inconclusive("cannot read the retention policy (%s): %s" % (RETENTION_FILE, e))
|
||||
|
||||
@@ -218,10 +235,15 @@ def main():
|
||||
# lexically: "0.9.0" > "0.10.0" as strings, and that would silently drop the wrong end.
|
||||
def _key(v):
|
||||
return tuple(int(x) for x in v.split("."))
|
||||
versions = sorted(all_versions, key=_key)[-keep:]
|
||||
window = sorted(all_versions, key=_key)[-keep:]
|
||||
# D50 = A: the pinned versions are asserted wherever they sit. A pin with no tag cannot be installed at all —
|
||||
# a failure, never a skip.
|
||||
unpinned_tags = sorted(("%s=%s" % (k, v)) for k, v in pins.items() if v not in all_versions)
|
||||
versions = sorted(set(window) | set(v for v in pins.values() if v in all_versions), key=_key)
|
||||
dropped = [v for v in all_versions if v not in versions]
|
||||
|
||||
print(" %d released version(s); retention policy keeps the newest %d" % (len(all_versions), keep))
|
||||
print(" %d released version(s); retention policy keeps the newest %d plus the pinned %s" % (
|
||||
len(all_versions), keep, ", ".join("%s=%s" % kv for kv in sorted(pins.items())) or "(none)"))
|
||||
print(" verifying: %s" % ", ".join(versions))
|
||||
if dropped:
|
||||
# NEVER silent. A bounded check that does not say what it stopped covering is how a
|
||||
@@ -232,6 +254,9 @@ def main():
|
||||
print(" their configs resolve; what is no longer asserted is the BINARY's presence.")
|
||||
|
||||
bad = []
|
||||
for pin in unpinned_tags:
|
||||
bad.append((pin, ["the pinned version has NO git tag — nothing can install it (D50 = A)"]))
|
||||
print(" FAIL pinned %s: no git tag v%s" % (pin, pin.split("=")[1]))
|
||||
for v in versions:
|
||||
pkg_url = "%s/api/packages/%s/generic/%s/%s/%s" % (GITEA_BASE, OWNER, PKG, v, PKG)
|
||||
raw_url = "%s/%s/%s/raw/tag/v%s/%s" % (GITEA_BASE, OWNER, REPO, v, PROBE_CONFIG)
|
||||
|
||||
Reference in New Issue
Block a user