57/P1: The node-engine knows who owns a placed file at runtime (issue 667) #109

Merged
mesh-admin merged 1 commits from pkg/57-p1-ownership into feat/57-config-and-provisioning 2026-10-13 23:52:13 +00:00
Contributor

Work package P1 of hq design 57 (ADR 0349 clause 5), issue 667.

What changed

  • declaration.File gains owner-at-runtime: owned (written back whenever it differs), seed (written once, then the program's) or managed (only its keys or marked block are the mesh's). File.Ownership() gives the word, or the one the old form implies (into -> managed, create-once -> seed, else owned). File.Seeded() is create-once or seed.
  • The declaration gains filled_files (Declaration.Filled, Declaration.Fills(path)): the paths of the files the provisioner fills.
  • Validation: an unknown word is refused; owned refuses create-once and into; seed refuses into (seed alone is enough, create-once beside it is allowed); managed requires into (which names the format). The old rule that into excludes sealed, bytes, secrets and create-once is unchanged. A filled path must be non-empty, named once, and be the path of a declared file, and every file at that path must say owner-at-runtime.
  • Apply: the words map onto today's write paths with no new code path. applyFile already dispatches on into (managed -> applyBlock / applyInto); the create-once check now reads Seeded(), so seed by the word alone is kept once present. declaredResolvConf reads Seeded() too.
  • link.OwnershipContract = 9, and the health statement now says it, so a controller (P6) sends the new fields only to an engine that reads them. An older engine refuses them under the strict parse.

Why

The provisioner's client (P5) and the narrow write verb (P2, P7) need to know which files the provisioner fills and who owns each one at runtime. Nothing sends these fields yet: the reader comes first.

How it is proven (all failed before, pass now)

  • internal/apply/ownership_test.go: TestEachOwnershipBehavesAsItsOldForm applies each word beside its old form, through the same drift, and requires the same actions and the same bytes: owned is created corrected, seed is created kept, managed json is updated corrected with the machine's own keys kept, and managed block is updated corrected with the lines outside the region kept. TestASeedByTheWordAloneKeepsWhatGrew.
  • internal/declaration/ownership_test.go: TestAFileSaysWhoOwnsItAtRuntime, TestAFileThatDoesNotSayIsOwnedByItsOldForm, TestAnOwnershipThatContradictsTheFileIsRefused, TestTheDeclarationNamesTheFilesTheProvisionerFills, TestAFilledFileMustBeADeclaredFileThatSaysItsOwner.
  • validate/validate_test.go: the exported validator (the one the controller vendors) accepts a declaration with the new fields and refuses an undeclared filled path.
  • cmd/mesh-host/units_test.go: updated to expect OwnershipContract (one above BusyContract). This is the only existing test changed, because the contract number rises.

Deliberately left for later packages

  • The write verb that accepts only filled paths: P2 (issue 668).
  • The controller sending owner-at-runtime, filled_files and checking OwnershipContract: P6 (issue 672).
  • The engine no longer writing filled files from the declaration: P7 (issue 673).

Reviewer's checklist

  1. Does what issue 667 and design 57 P1 say, and nothing else. The fields, the mapping onto the existing paths, and validation are here. No write path changed except that Seeded() replaces CreateOnce in two reads.
  2. The Done-when proof is in the tests above. I ran them first and they failed (the fields were refused as unknown, and the package did not compile). Existing tests are unchanged except the contract-number test, explained above.
  3. A declaration without the new fields composes and applies as before. Both fields are omitempty, Seeded() equals CreateOnce when the word is absent, and TestEachOwnershipBehavesAsItsOldForm compares old and new form byte for byte.
  4. No secret in any log, event, fixture or commit. No database change.
  5. Strict parse: the node-engine reader accepts the new keys, and OwnershipContract tells a controller when it may send them. No writer sends them in this change.
  6. Ran gofmt -l . (empty), go vet ./..., go test ./... and sh merge-check.sh (exit 0). merge-check said: NOT RUN AGAINST A BUS, because this toolchain has no nats-server, so the bus tests were skipped.
  7. Words: owned, seed, managed (glossary, issue 653), node-engine, provisioner, controller.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

Work package P1 of hq design 57 (ADR 0349 clause 5), issue 667. ## What changed - `declaration.File` gains `owner-at-runtime`: `owned` (written back whenever it differs), `seed` (written once, then the program's) or `managed` (only its keys or marked block are the mesh's). `File.Ownership()` gives the word, or the one the old form implies (into -> managed, create-once -> seed, else owned). `File.Seeded()` is create-once or seed. - The declaration gains `filled_files` (`Declaration.Filled`, `Declaration.Fills(path)`): the paths of the files the provisioner fills. - Validation: an unknown word is refused; owned refuses create-once and into; seed refuses into (seed alone is enough, create-once beside it is allowed); managed requires into (which names the format). The old rule that into excludes sealed, bytes, secrets and create-once is unchanged. A filled path must be non-empty, named once, and be the path of a declared file, and every file at that path must say owner-at-runtime. - Apply: the words map onto today's write paths with no new code path. applyFile already dispatches on `into` (managed -> applyBlock / applyInto); the create-once check now reads `Seeded()`, so seed by the word alone is kept once present. `declaredResolvConf` reads `Seeded()` too. - `link.OwnershipContract = 9`, and the health statement now says it, so a controller (P6) sends the new fields only to an engine that reads them. An older engine refuses them under the strict parse. ## Why The provisioner's client (P5) and the narrow write verb (P2, P7) need to know which files the provisioner fills and who owns each one at runtime. Nothing sends these fields yet: the reader comes first. ## How it is proven (all failed before, pass now) - internal/apply/ownership_test.go: `TestEachOwnershipBehavesAsItsOldForm` applies each word beside its old form, through the same drift, and requires the same actions and the same bytes: owned is `created corrected`, seed is `created kept`, managed json is `updated corrected` with the machine's own keys kept, and managed block is `updated corrected` with the lines outside the region kept. `TestASeedByTheWordAloneKeepsWhatGrew`. - internal/declaration/ownership_test.go: `TestAFileSaysWhoOwnsItAtRuntime`, `TestAFileThatDoesNotSayIsOwnedByItsOldForm`, `TestAnOwnershipThatContradictsTheFileIsRefused`, `TestTheDeclarationNamesTheFilesTheProvisionerFills`, `TestAFilledFileMustBeADeclaredFileThatSaysItsOwner`. - validate/validate_test.go: the exported validator (the one the controller vendors) accepts a declaration with the new fields and refuses an undeclared filled path. - cmd/mesh-host/units_test.go: updated to expect OwnershipContract (one above BusyContract). This is the only existing test changed, because the contract number rises. ## Deliberately left for later packages - The write verb that accepts only filled paths: P2 (issue 668). - The controller sending `owner-at-runtime`, `filled_files` and checking `OwnershipContract`: P6 (issue 672). - The engine no longer writing filled files from the declaration: P7 (issue 673). ## Reviewer's checklist 1. [x] Does what issue 667 and design 57 P1 say, and nothing else. The fields, the mapping onto the existing paths, and validation are here. No write path changed except that `Seeded()` replaces `CreateOnce` in two reads. 2. [x] The Done-when proof is in the tests above. I ran them first and they failed (the fields were refused as unknown, and the package did not compile). Existing tests are unchanged except the contract-number test, explained above. 3. [x] A declaration without the new fields composes and applies as before. Both fields are `omitempty`, `Seeded()` equals `CreateOnce` when the word is absent, and `TestEachOwnershipBehavesAsItsOldForm` compares old and new form byte for byte. 4. [x] No secret in any log, event, fixture or commit. No database change. 5. [x] Strict parse: the node-engine reader accepts the new keys, and `OwnershipContract` tells a controller when it may send them. No writer sends them in this change. 6. [x] Ran `gofmt -l .` (empty), `go vet ./...`, `go test ./...` and `sh merge-check.sh` (exit 0). merge-check said: NOT RUN AGAINST A BUS, because this toolchain has no nats-server, so the bus tests were skipped. 7. [x] Words: owned, seed, managed (glossary, issue 653), node-engine, provisioner, controller. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mesh-admin added 1 commit 2026-10-13 23:48:07 +00:00
Say who owns a placed file at runtime, and which files the provisioner fills
mesh/merge-gate head 1cc588ebc060 merged into trunk 1203f96a24c8 — pass: builds mesh-host → ace, g14, novox, shanks; no bus step; every machine composes wi…
mesh/repo-check head 1cc588ebc060 merged into trunk 1203f96a24c8 — pass: its merge-check.sh passed
mesh/delivery delivered
1cc588ebc0
The provisioner (ADR 0349 §5) needs each file it places to say whether it is
owned, a seed or managed, and the node-engine needs to know which paths it
fills. The words map onto today's forms (drift written back, create-once,
into), so no write changes; the reader accepts the fields and states
OwnershipContract before any controller sends them. Issue 667.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Contributor

Delivery novox/mesh-host@1cc588ebc060 — delivered since 2026-10-13T23:53:19Z

Delivery plan — builds mesh-host → ace, g14, novox, shanks; no bus step

  • tier 0: mesh-host
  • ace: receives mesh-host
  • g14: receives mesh-host
  • novox: receives mesh-host
  • shanks: receives mesh-host
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before mesh-host is judged on its first machine

Transitions

  • 2026-10-13 23:48 (new) → proposed (announced): novox/mesh-host#109's head announced
  • 2026-10-13 23:51 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
  • 2026-10-13 23:51 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-13 23:52 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
  • 2026-10-13 23:52 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
  • 2026-10-13 23:53 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says

The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.

<!-- mesh-delivery:view --> **Delivery** `novox/mesh-host@1cc588ebc060` — **delivered** since 2026-10-13T23:53:19Z **Delivery plan** — builds mesh-host → ace, g14, novox, shanks; no bus step - tier 0: mesh-host - ace: receives mesh-host - g14: receives mesh-host - novox: receives mesh-host - shanks: receives mesh-host - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before mesh-host is judged on its first machine **Transitions** - 2026-10-13 23:48 (new) → proposed (announced): novox/mesh-host#109's head announced - 2026-10-13 23:51 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit - 2026-10-13 23:51 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-13 23:52 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move - 2026-10-13 23:52 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit - 2026-10-13 23:53 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Author
Contributor

Merge check at 1cc588eb
Judged: head 1cc588ebc060 merged into trunk 1203f96a24c8; read beside it: mesh-catalog ebf7f3773dc7, mesh-controller ca3f43c400ba, mesh-controller-main ca3f43c400ba, mesh-tools 954e1a53eef9

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-host)
  • mesh/repo-check: PASS — its merge-check.sh passed

Delivery plan — builds mesh-host → ace, g14, novox, shanks; no bus step

  • tier 0: mesh-host
  • ace: receives mesh-host
  • g14: receives mesh-host
  • novox: receives mesh-host
  • shanks: receives mesh-host
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before mesh-host is judged on its first machine
  • read by no module's build: cmd/mesh-host/units_test.go, internal/apply/ownership_test.go, internal/declaration/ownership_test.go, validate/validate_test.go

Run by the build seat on shanks as build-1791935307449323964 (builds --log build-1791935307449323964).

--- the gate: mesh-host
mesh-host: ok
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T23:45:15Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-13T23:45:15Z

machines:
  - a machine (f35): composes
  - holds mesh-dns-resolver (idt): composes
  - holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
  - a machine (yvbpsm): composes

a merge would rebuild 1 module(s) in 1 tier(s): mesh-host

notes:
  - cmd/mesh-host/units_test.go, internal/apply/ownership_test.go, internal/declaration/ownership_test.go and validate/validate_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok  	github.com/novox/mesh-host/cmd/mesh-bootstrap	1.017s
ok  	github.com/novox/mesh-host/cmd/mesh-host	6.364s
ok  	github.com/novox/mesh-host/examples	1.027s
ok  	github.com/novox/mesh-host/internal/accounts	2.324s
ok  	github.com/novox/mesh-host/internal/apply	5.156s
ok  	github.com/novox/mesh-host/internal/bootstrap	4.434s
ok  	github.com/novox/mesh-host/internal/bundle	1.036s
ok  	github.com/novox/mesh-host/internal/declaration	1.104s
ok  	github.com/novox/mesh-host/internal/firewall	1.867s
ok  	github.com/novox/mesh-host/internal/identity	1.148s
ok  	github.com/novox/mesh-host/internal/image	1.046s
ok  	github.com/novox/mesh-host/internal/inventory	1.080s
ok  	github.com/novox/mesh-host/internal/link	10.519s
ok  	github.com/novox/mesh-host/internal/liveness	2.132s
ok  	github.com/novox/mesh-host/internal/meshcli	1.593s
ok  	github.com/novox/mesh-host/internal/network	1.079s
ok  	github.com/novox/mesh-host/internal/outward	1.057s
ok  	github.com/novox/mesh-host/internal/profile	1.665s
ok  	github.com/novox/mesh-host/internal/reachable	1.058s
ok  	github.com/novox/mesh-host/internal/store	1.260s
ok  	github.com/novox/mesh-host/internal/system	1.061s
ok  	github.com/novox/mesh-host/internal/tunnel	1.064s
ok  	github.com/novox/mesh-host/internal/units	1.050s
ok  	github.com/novox/mesh-host/internal/upgrade	1.183s
ok  	github.com/novox/mesh-host/internal/witness	4.875s
ok  	github.com/novox/mesh-host/packaging	1.058s
?   	github.com/novox/mesh-host/rootsearch	[no test files]
ok  	github.com/novox/mesh-host/validate	1.049s
**Merge check** at `1cc588eb` Judged: head `1cc588ebc060` merged into trunk `1203f96a24c8`; read beside it: mesh-catalog `ebf7f3773dc7`, mesh-controller `ca3f43c400ba`, mesh-controller-main `ca3f43c400ba`, mesh-tools `954e1a53eef9` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-host) - `mesh/repo-check`: **PASS** — its merge-check.sh passed **Delivery plan** — builds mesh-host → ace, g14, novox, shanks; no bus step - tier 0: mesh-host - ace: receives mesh-host - g14: receives mesh-host - novox: receives mesh-host - shanks: receives mesh-host - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before mesh-host is judged on its first machine - read by no module's build: cmd/mesh-host/units_test.go, internal/apply/ownership_test.go, internal/declaration/ownership_test.go, validate/validate_test.go Run by the build seat on shanks as `build-1791935307449323964` (`builds --log build-1791935307449323964`). ``` --- the gate: mesh-host mesh-host: ok long-running resources without health: 0 files asking for a setting without saying whether it is trusted: 0 1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T23:45:15Z says they run composing every machine as the mesh is the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued composing every machine with the change the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose) judged by controller development build against the facts of 2026-10-13T23:45:15Z machines: - a machine (f35): composes - holds mesh-dns-resolver (idt): composes - holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes - a machine (yvbpsm): composes a merge would rebuild 1 module(s) in 1 tier(s): mesh-host notes: - cmd/mesh-host/units_test.go, internal/apply/ownership_test.go, internal/declaration/ownership_test.go and validate/validate_test.go read by no module's build, and rebuild nothing (issue 280) --- its merge-check.sh (go toolchain) ok github.com/novox/mesh-host/cmd/mesh-bootstrap 1.017s ok github.com/novox/mesh-host/cmd/mesh-host 6.364s ok github.com/novox/mesh-host/examples 1.027s ok github.com/novox/mesh-host/internal/accounts 2.324s ok github.com/novox/mesh-host/internal/apply 5.156s ok github.com/novox/mesh-host/internal/bootstrap 4.434s ok github.com/novox/mesh-host/internal/bundle 1.036s ok github.com/novox/mesh-host/internal/declaration 1.104s ok github.com/novox/mesh-host/internal/firewall 1.867s ok github.com/novox/mesh-host/internal/identity 1.148s ok github.com/novox/mesh-host/internal/image 1.046s ok github.com/novox/mesh-host/internal/inventory 1.080s ok github.com/novox/mesh-host/internal/link 10.519s ok github.com/novox/mesh-host/internal/liveness 2.132s ok github.com/novox/mesh-host/internal/meshcli 1.593s ok github.com/novox/mesh-host/internal/network 1.079s ok github.com/novox/mesh-host/internal/outward 1.057s ok github.com/novox/mesh-host/internal/profile 1.665s ok github.com/novox/mesh-host/internal/reachable 1.058s ok github.com/novox/mesh-host/internal/store 1.260s ok github.com/novox/mesh-host/internal/system 1.061s ok github.com/novox/mesh-host/internal/tunnel 1.064s ok github.com/novox/mesh-host/internal/units 1.050s ok github.com/novox/mesh-host/internal/upgrade 1.183s ok github.com/novox/mesh-host/internal/witness 4.875s ok github.com/novox/mesh-host/packaging 1.058s ? github.com/novox/mesh-host/rootsearch [no test files] ok github.com/novox/mesh-host/validate 1.049s ```
mesh-admin left a comment
Author
Contributor

Verdict: APPROVE at 1cc588ebc0

Independent review of issue 667 (design 57 package P1, ADR 0349 clause 5). I ran these in my own worktree of the head: gofmt -l . printed nothing; go vet ./... passed; sh merge-check.sh exited 0 and ran the whole suite under the race detector (27 packages ok). I reverted the non-test files (main.go, apply.go, declaration.go, messages.go) to the base branch: the new apply tests and the validate test fail ("a file does not use owner-at-runtime", "unknown field filled_files"), and internal/declaration and cmd/mesh-host do not build. With the change, all of them pass. Nothing outside P1 is touched. A declaration without the new fields parses and applies as before, because Seeded() equals CreateOnce when the word is absent. No secret, fixture credential or database change is involved.

Findings. None of them blocks the merge.

  1. internal/link/messages.go:303 and cmd/mesh-host/units_test.go:90. OwnershipContract = 9 is right, and it is needed now. Every earlier field set shipped its reader, its contract and this same units_test.go change in one commit; bb60e7b (BusyContract, ADR 0335) is an example. An engine that reads the fields must say so, or the controller can never send them. The controller's internal/link/protocol.go copies only the contract numbers it checks (1, 2, 3 and 8). P6 (issue 672) must therefore add OwnershipContract = 9 there. No other open mesh-host pull request claims 9. The test change makes the check stricter: it now requires OwnershipContract to be BusyContract+1.
  2. internal/link/messages.go:298-303. This should be settled in P6 or P7, and it can follow. Contract 9 means the engine reads filled_files, but it still writes those files from the declaration. P7 (issue 673) is what stops that. If P6 sends a filled list to an engine at 9 that does not have P7, the engine and the provisioner's client would both write the file, which breaks ADR 0349 clause 5 (one writer). P7 should raise its own contract, or P6 should send filled_files only once P7 is on the node. The comment on 9 should not promise more than it does now.
  3. internal/declaration/declaration.go:1651. This should be handled in P2. Fills compares the path string exactly. P2's write verb must look up the path exactly as declared: refuse an unclean path such as /etc//a or /etc/a/../a, rather than letting it be read as some other path.
  4. The words owned, seed and managed are not in hq main's glossary yet. That is F4 (issue 653), not this pull request.
  5. The tests that need a bus did not run in my check: 10 TestNats* tests in internal/link were skipped. This machine's toolchain has no nats-server. The only nats-server in the mesh is the bus module's container, and installing one by hand is not allowed. The only change in internal/link is a constant, so these tests do not exercise the change. mesh/repo-check on the build seat runs them if its toolchain holds nats-server.
Verdict: APPROVE at 1cc588ebc0606413cafed86ba4ef471203855a05 Independent review of issue 667 (design 57 package P1, ADR 0349 clause 5). I ran these in my own worktree of the head: `gofmt -l .` printed nothing; `go vet ./...` passed; `sh merge-check.sh` exited 0 and ran the whole suite under the race detector (27 packages ok). I reverted the non-test files (main.go, apply.go, declaration.go, messages.go) to the base branch: the new apply tests and the validate test fail ("a file does not use owner-at-runtime", "unknown field filled_files"), and internal/declaration and cmd/mesh-host do not build. With the change, all of them pass. Nothing outside P1 is touched. A declaration without the new fields parses and applies as before, because `Seeded()` equals `CreateOnce` when the word is absent. No secret, fixture credential or database change is involved. Findings. None of them blocks the merge. 1. internal/link/messages.go:303 and cmd/mesh-host/units_test.go:90. OwnershipContract = 9 is right, and it is needed now. Every earlier field set shipped its reader, its contract and this same units_test.go change in one commit; bb60e7b (BusyContract, ADR 0335) is an example. An engine that reads the fields must say so, or the controller can never send them. The controller's internal/link/protocol.go copies only the contract numbers it checks (1, 2, 3 and 8). P6 (issue 672) must therefore add `OwnershipContract = 9` there. No other open mesh-host pull request claims 9. The test change makes the check stricter: it now requires OwnershipContract to be BusyContract+1. 2. internal/link/messages.go:298-303. This should be settled in P6 or P7, and it can follow. Contract 9 means the engine *reads* `filled_files`, but it still writes those files from the declaration. P7 (issue 673) is what stops that. If P6 sends a filled list to an engine at 9 that does not have P7, the engine and the provisioner's client would both write the file, which breaks ADR 0349 clause 5 (one writer). P7 should raise its own contract, or P6 should send `filled_files` only once P7 is on the node. The comment on 9 should not promise more than it does now. 3. internal/declaration/declaration.go:1651. This should be handled in P2. `Fills` compares the path string exactly. P2's write verb must look up the path exactly as declared: refuse an unclean path such as `/etc//a` or `/etc/a/../a`, rather than letting it be read as some other path. 4. The words owned, seed and managed are not in hq main's glossary yet. That is F4 (issue 653), not this pull request. 5. The tests that need a bus did not run in my check: 10 `TestNats*` tests in internal/link were skipped. This machine's toolchain has no nats-server. The only nats-server in the mesh is the bus module's container, and installing one by hand is not allowed. The only change in internal/link is a constant, so these tests do not exercise the change. mesh/repo-check on the build seat runs them if its toolchain holds nats-server.
mesh-admin merged commit 6b54fed706 into feat/57-config-and-provisioning 2026-10-13 23:52:13 +00:00
mesh-admin deleted branch pkg/57-p1-ownership 2026-10-13 23:52:14 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-host#109