release: v4.0.0 - the home node's arbitrations, its inventory, and naming.v4 #12
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "review/home-node-arbitration"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
100% integrated: rows 1-12 of section 6 landed by
0cf96f4, row 13 with the cut (b69e4a8),make checkgreen.This merges
review/home-node-arbitrationintomainas v4.0.0: the home node's eleven arbitrations on v3.0.0, its contradictory review, the maintainer's decisions on both (decisions/2026-10-29-home-node-arbitration-review.md), then the home node's exhaustive inventory - 198 objects confronted with the tool - and the fifteen arbitrations on it (decisions/2026-10-29-home-node-inventory-arbitrations.md, I1-I15). There is no v3.x: the patches merge untagged into this release.Rows to commits (inventory, section 6)
runner(hrn) andbackup(hbk)63106dddd14e13single, the separator is whatsubstituted_controlsdeclares (D4)e2d5f58management,blacklist,ipfilter-net<n>316e2d79131d2b064c354ab877fdper-shr-ops-foundation-proj, runner at15009049178d4ec29c1e7d96ef967bfe16adecisions/README.mdindexba99ce20cf96f4registry/conventions.yamlto version 4;kit.tagand every pin tov4.0.0b69e4a8What the table does not show.
ipfilter-net<n>was verified before it was added. In pve-firewall master,src/PVE/Firewall.pm,compute_ipfilter_ipset_namereturns"ipfilter-$iface". The Proxmox VE Firewall documentation (current, 8.x) lists all three names as standard IP sets. Both were read on 2026-10-29; nothing was re-measured on a node.reserved_names(anchored regexes), read by the tool, the module and the policy, and linted.1500902inCONVENTION.mdandconventions.yaml. The PBS exampleshr-bkp-pbs-main-vault(a v2 shape) inCONVENTION.mdand the datastore note.naming.v4, and the policy fixtures and tests follow.tests/address.py's own comment carriedref=with a tag as an example and had been counted as a 25th pin. It is reworded, and the sweep finds the 24 real ones.make checkThe cut was validated with a provisional local
v4.0.0tag, becauseaddressrequires the declared tag to exist.All five spot checks give the expected value:
per-shr-ops-runner-vm-04,1500904,per-shr-bkp-base-vault,managementOK,per-shr-ops-foundation-proj.grep "to decide" adoption/home-node-infra.mdfinds nothing.Still open after v4.0.0
make english: it let a French note through because the note contained none of the listed function words. The tool is not fixed in this release.review/home-node-inventoryis fully contained in this branch. It is not deleted here.home-node-infrahas no remaining use, now that its archives are on itsmain(ba8d35d).perso->personalcomes last, by the maintainer, in the interface.🤖 Generated with Claude Code
A test bench for the eleven points arbitrated on 2026-10-29, not a release: section 5 of decisions/2026-10-29-home-node-arbitration-review.md proposes the split into six branches, of which two are a major. Accepted and implemented here: A1 the allocated identifier - a kind letter plus the VMID's own seven digits, across naming.py, the module and the policy. One coordinate, two uses, confronted rather than copied. The reservation joins vmids.yaml, and HOW it is confronted is declared per type: by_name where the plan carries the readable name, by_presence where the platform offers none - a blind spot written down instead of discovered. A8 a product code is global. 'pfm' was declared by both repositories and the global lookup answered with one of them, so decode() labelled a seeds name's target home-node-infra. Measured, linted, mutated, and home-node platform becomes hpf. The other half of the question was already enforced: a target code reading as a domain has been refused since v3, and 'plt' is now a mutation in the suite. A2c the substrate declared per repository, in registry/repositories.yaml - with A7's apply rule beside it. Three decisions said "declared per repository" and all three were written once, globally, in prose: grep found no reader outside conventions.yaml. The module now refuses a repo that declares nothing, which fires before a plan. Corrected by measurement, against svalabs/forgejo 1.6.1 and 1.7.0, read from source: forgejo_organization renames by REPLACEMENT, not in place, and implements no ImportState at either tag. The entry said in_place with confidence: likely. A namespace rename is a decision about the forge, never a diff - which is the answer to A4. forgejo_repository.name renames in place, but .owner replaces: moving a repository between namespaces destroys it. The Tailscale device tag note had no org in it - the v2 shape, which makes two orgs on one tailnet indistinguishable. A Proxmox security group has 18 characters, so a direction belongs in the component: per-shr-net-in-sg fits, per-shr-net-base-in-sg comes back as a hash. A3 is measured, not a matter of taste. 85 module tests, 65 policy tests, 62 shared cases, 36 lint mutations with 0 silent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>The three new arbitrations the review raised were put to the maintainer on 2026-10-29 and each took the recommendation. N4 is deferred on purpose, N5 is answered by a temporary read-only deploy key. N1 - THE SHORTENED "compact" STYLE IS REMOVED FROM THE KIT. The six remaining SDN types (two controllers, four fabrics) join the twelve already allocated, with the kind letters c and f. What decided it was a measurement rather than the argument: component spine -> psnetspi component spineB -> psnetspi Eight characters: p + s + net spends six, leaving THREE for the component. One plan holding both was caught by the duplicate rule; two stacks, two plans, were caught by nothing - and an SDN identifier is unique at cluster level, so the second apply fails or clobbers. There is no width at which four codes and a word fit into eight characters. 70 occurrences over 19 files. The normative ones were rewritten; the closed decision record and the closed changelog entries keep their words. And one guard disappeared rather than moving: "a shortened name that cannot hold the run" has no subject left, because an allocated identifier never carries one. N2 - THE CROSSING DEPENDS ON THE SUBSTRATE. cloud: public_path_only, measured 2026-10-13; machine: no_principal_on_the_substrate, the rented Proxmox cluster. The flat value had been measured on a cloud and written as a universal, which forbade a case the home node had already decided. The two are not interchangeable - allowing the machine's crossing on a cloud reopens the argument the amendment of 2026-10-10 closed after two wrong turns in two days - and a mutation says so. A2a is written down beside it as org_segment: owner_not_substrate. N3 - EVERY NAMESPACE DECLARES A VISIBILITY, not only the reserved ones. namespaces.visibility_default: private, by asymmetry: a namespace holding only private repositories loses nothing by being private, and a public one publishes whatever it ever comes to hold. That rule had been a comment about namespaces the block did not cover, so nothing would ever have reported that two org namespaces were public. AND ONE GUARD NO ARBITRATION ASKED FOR. tests/reservations.py confronts every vmids.yaml git tracks with the width vmid() actually produces. It found four live drifts on its first run: three five-digit reservations in examples/proxmox and the pre-v3 formula still documented in templates/consumer/vmids.yaml, three days after the width changed. The policy looks a reservation up by the key the plan computes, so one of the wrong width is never matched and never reported - the registry stops being consulted rather than failing. 63 shared cases, 85 module tests, 62 policy tests (three of the shortened style went, two allocated ones replaced them), 42 lint mutations with 0 silent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>Found by running home-node-infra's REAL inventory through the registry, with a temporary read-only deploy key, on 2026-10-29. Before this commit: per-shr-ops-foundation-bkt-hn1 accepted by generate(), by check(), and by the policy A Scaleway bucket whose name claims to sit on a Proxmox node, on a type whose rename is a replacement. The registry has declared a provider on every location and on every type since v3. Nobody had asked the question. THE HOME NODE IS THE CASE THAT MAKES IT BITE, and the only one: it is the single repository mixing two substrates - Scaleway objects in fr-par, Proxmox objects on hn1 - with ONE location in the context. A single naming context would have named every Scaleway object for the node, permanently. The guard sits in all three implementations, as the kit's rule requires: naming.py refuses at generation and at check, the module has a precondition naming both providers, the policy has a deny that reads the location token out of the name. "any" passes (the global pseudo-location), and a provider for which no location is declared - a forge, a tailnet - has nothing to be confronted with. AND IT FOUND THREE MIXED-PLATFORM FIXTURES IN THIS REPOSITORY'S OWN SUITE, all green until now: v3_grammar.tftest.hcl a Proxmox VM at location par, in two separate runs naming_test.rego an AWS bucket named see-prd-data-lake-raw-bkt-par The first two are split into one call per platform, which is what the convention always meant by "one call of the module per component"; the third was an AWS bucket wearing a Scaleway region since the day it was written. Two refusal tests were added so the case that was passing now fails. Also recorded in the review document: the object-by-object pass itself. 26 types used, 26 in the registry, 0 absent. Twenty-one named objects, twenty named with no truncation and no collision, one refused - a vnet serving a product, which has no VMID digit allocated. That refusal is N6, and it has the same "cheap exactly once" shape as A1 and A8. And the finding that changes what this review can claim: the home node's own convention documents are NOT on the forge. main is at 47781e0, dated 2026-10-23, one branch, and 453e50b is not a valid object there. H1-H16, the full pass and D1-D5 live in a working tree and have never been pushed. 87 module tests, 64 policy tests, 63 shared cases, 42 lint mutations with 0 silent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>The question came from home-node-infra's real inventory: its per-instance boundary objects - a pool, a vnet, two storages - exist to serve another product, which is exactly what the target slot is for, and the vnet was refused for want of a VMID digit. DECIDED BY THE ARITHMETIC OF ONE DIGIT, not by taste. Zero means "no target", so nine values exist for every entity and every product that ever appears as a Proxmox target - and eight products are already declared, so the space would be full the day somebody declared what already exists. Widening it is measured impossible: a kind letter plus eight digits is nine characters, and a Proxmox SDN identifier holds eight. A digit is never reused, so allocating one is permanent. So a boundary object carries the bounded product as its COMPONENT: per-shr-plt-atelier-proj the pool v1500801 the vnet, domain plt, allocation 01 per-shr-plt-atelier-vm-zfs the guest storage per-shr-plt-atelier-snippets-dir the snippets storage It reads as "the platform's atelier block" and costs nothing. A product in the target slot still has no digit, and asking for one is still REFUSED rather than read as zero - the guard that raised the question stays exactly as it was. The registry now records this as a DECISION WITH ITS DATE rather than as a wait: the note used to say "the day one does, the product entries get digits", which a reader would take for a pending task. It was asked on 2026-10-29 and sent back, and the next reader needs to know that. AND ONE MEASUREMENT THAT WAS EXPECTED TO HURT AND DOES NOT. The home node lays an ACL per VMID range, derived from the block. Under v4 the range moves and widens rather than scattering, because only the last two digits vary within one product instance: today block 11 110 .. 119 10 values v4 per/shr/ops 1500901 .. 1500999 99 values its templates 1900901 .. 1900999 Still contiguous, so the rights stack keeps its shape - vmid_first and vmid_last are computed from the coordinate instead of from the block. 66 shared cases (three of them the boundary objects, so the choice is exercised rather than remembered), 90 module tests, 64 policy tests, 42 lint mutations with 0 silent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>0cf96f4, each row of section 6 with its commit a1f88c7c79