I3176 — The committed mesh declaration names its hubs by node, and no private address is tracked or published
Let the declaration name a hub by its node id and resolve its endpoint from signed, expiring mesh records (tailnet or Bonjour discovery, the hub's own advertisement), then remove the LAN and tailnet addresses from .ai/repo/mesh/majordomus.yaml and the fleet table of docs/MESH.md.
BLOCKED wave 1 · p2 · implementation profile · parallel safe
Blocked. This issue cannot start until I2410 is done. The status is derived from that, not declared.
Objective
Let the declaration name a hub by its node id and resolve its endpoint from signed, expiring mesh records (tailnet or Bonjour discovery, the hub's own advertisement), then remove the LAN and tailnet addresses from .ai/repo/mesh/majordomus.yaml and the fleet table of docs/MESH.md.
Why
The repository is public. ADR 0157 already says 'a private address is never written to a tracked file or a published page', while ADR 0059 committed the hubs' LAN and tailnet addresses; the 10-08 audit flagged it, and on 09-15 the owner said lundra's address must be detected, never hard-coded. A MacBook hub was unreachable for a while because its declared DHCP address moved (docs/MESH.md). It serves bootstrap-is-signed as its prerequisite: the manifest of I3188 lists hubs by node id, which only this issue lets the declaration say. It delivers no part of path-is-explained (candidates, choice or reason), so it no longer claims that criterion. It is also the repository's private-address hygiene (ADR 0157). Endpoint IPs are also read by firewall.rs:281-288 and 340-346, root.rs and doctor.rs, so changing the declaration's endpoint form without them would bring back the 10-08 lundra outage. It extends milestone runtime-trust. Proposed in ADR 0202 (The mesh routes work to an identity, never an address, and selects among proven transports instead of implementing NAT traversal) (proposed; it carries no authority until the owner accepts it). Sources: chatgpt-majordomus:c193#1, chatgpt-majordomus:c138#2.
Current state
Verified: .ai/repo/mesh/majordomus.yaml enabled: true with rendezvous endpoints on private LAN (RFC 1918) and tailnet (CGNAT) addresses; case 491 refuses only public addresses; Tailscale discovery (I2410) is on a branch.
Desired state
rendezvous endpoints by node id; case 491 also refuses a private address in the tracked declaration; docs/MESH.md names machines by node, not address.
Scope
- .ai/repo/mesh/majordomus.yaml
- apps/majordomus-cli/src/mesh/config.rs
- apps/majordomus-cli/src/mesh/rendezvous.rs
- share/schemas/majordomus/mesh-declaration
- test/cases/491_the_mesh_is_on_here.sh
- docs/MESH.md
- apps/majordomus-cli/src/mesh/firewall.rs
- apps/majordomus-cli/src/mesh/root.rs
- apps/majordomus-cli/src/mesh/doctor.rs
- test/cases/495_the_firewall_admits_the_mesh.sh
- test/cases/1023_a_branch_cannot_widen_the_mesh_trust.sh
- .ai/repo/offload/derive.yaml
- apps/majordomus-cli/src/offload/declaration.rs
- apps/majordomus-cli/src/http/router.rs
- site/content/docs/mesh.md
- scripts/generate-site-data
Out of scope
- Changing who is trusted
- Editing another issue's record: the addresses I2123.yaml quotes are removed by an amendment of I2123 itself
Dependencies
What waits on this
Acceptance criteria
- No RFC 1918 or CGNAT address in .ai/repo/mesh, in any file this issue's scope names, or in the published mesh page; case 491 refuses one in the tracked declaration
- A hub whose address changes is reached with no commit
- With node-id rendezvous endpoints, mesh firewall plans the TCP hub rule from the networks of the endpoints resolved at runtime, and a hub still recognises itself (firewall.rs no longer depends on parse_endpoint of a literal IP); case 495 proves it
- The trust root narrows a working-tree declaration of node-id hubs by node id, and an address resolved at runtime is admitted only through a signed, unexpired record of a trusted node; case 1023 still refuses a widening branch
- mesh doctor still reports the rendezvous endpoint count for node-id endpoints, and case 491's match is updated in the same change
- No LAN or tailnet address is removed from .ai/repo/mesh/majordomus.yaml until I2410 is on master and every declared hub is measured linked through discovery alone
- Doc-test and unit-test fixtures use RFC 5737 documentation addresses, never a fleet address; site/content/docs/mesh.md is regenerated by scripts/generate-site-data, never hand-edited
Validation
- majordomus plan validate
- bash test/run.sh 491_the_mesh_is_on_here
- bash test/run.sh 495_the_firewall_admits_the_mesh
- bash test/run.sh 1023_a_branch_cannot_widen_the_mesh_trust
- cargo test --lib mesh::firewall
Evidence required
- case_491_refuses_private_addresses
Evidence
None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.
Timeline
- started
- —
- verified
- —
- completed
- —
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I3176.yaml. Read it back with majordomus plan show I3176.