Reconcile with hq 128: hosts template is the region form, node-names is shared

The merge commit took only the staged index; these reconciliation edits sat
unstaged in the working tree. Integrate the template mechanism with #79's
region write (hq 128): RosterFile gains Shared, FactsInto sets into:block for
a shared fact, /etc/hosts becomes the region form (no floor) and node-names is
marked shared. Without this the merge would have regressed /etc/hosts back to
a whole-file write, replacing the operator's own lines.
This commit is contained in:
2026-09-27 01:50:11 +02:00
parent 966c5ddad3
commit a6d89e3f73
3 changed files with 54 additions and 15 deletions
+18 -2
View File
@@ -39,6 +39,13 @@ type RosterFile struct {
// Template is the module's format, a Go text/template over the rosterView. It is the module's,
// not the mesh's: the mesh renders it and does not read it.
Template string `json:"template"`
// Shared is whether the file the fact goes to belongs to the machine rather than the mesh. When
// it does, the mesh owns only a marked region of it and keeps the rest byte for byte (novox/hq
// issue 128) — a hosts file is shared, since the distribution's `localhost`, the operator's own
// lines and other tools' blocks live there too; a resolver's zones file is not, the mesh owns it
// whole. A property of the fact, not of the path: the format determines whether the file is
// wholly the mesh's, not where a module happened to ask for it.
Shared bool `json:"shared,omitempty"`
}
// rosterView is what a RosterFile's template sees. A closed shape — a template referencing a field
@@ -91,10 +98,19 @@ func FactsInto(m Manifest, r Resolution, every, machines map[string]string, suff
if err != nil {
return nil, fmt.Errorf("%s cannot render %q: %w", m.Module, name, err)
}
out = append(out, map[string]any{
file := map[string]any{
"id": "fact-" + name, "type": "file", "path": fact.Path, "mode": "0644",
"content": content,
})
}
if fact.Shared {
// The host owns only the lines between `# BEGIN mesh <id>` and `# END mesh <id>` and
// keeps the rest of the file byte for byte; undeclared, the region goes and nothing else
// does (novox/hq issue 128). Every node on the private network receives this, so every
// node's host — the controller's own machine included — must be block-aware before a
// controller emitting it is rolled out: the order ADR 0102 set for `into: json`.
file["into"] = "block"
}
out = append(out, file)
}
return out, nil
}