Skip to content

Commit 52b132c

Browse files
committed
Add gn-ten node lab package
1 parent 2a109ef commit 52b132c

21 files changed

Lines changed: 1187 additions & 11 deletions

File tree

.blitz/test_state_v1/indexes/task_states.ndjson

Lines changed: 312 additions & 0 deletions
Large diffs are not rendered by default.

build_support/weld.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ defmodule StackLab.Build.WeldContract do
66
@proof_projects [
77
"support/spec_cell",
88
"support/gn_ten_control_plane",
9+
"support/gn_ten_node_lab",
910
"support/connector_hardening_scanner",
1011
"support/tenant_isolation_scanner",
1112
"support/no_bypass_scanner",

build_support/workspace_contract.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ defmodule StackLab.Build.WorkspaceContract do
55
"support/lab_core",
66
"support/spec_cell",
77
"support/gn_ten_control_plane",
8+
"support/gn_ten_node_lab",
89
"support/connector_hardening_scanner",
910
"support/tenant_isolation_scanner",
1011
"support/no_bypass_scanner",

docs/gn_ten_proof_matrix.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,14 @@ path, and run GitHub or Linear live commands by prefixing them with
163163
over-cap. It does not prove EPMD startup, peer lifecycle, owner facade
164164
availability, distributed business semantics, monolith/distributed parity,
165165
or 49-node scale feasibility.
166-
- `gn_ten_distributed_preflight`: records the v2 Phase 2 host preflight. It
167-
proves EPMD can start, a shortname StackLab controller node can come up, a
168-
redacted per-run cookie can be generated, the planned distribution port range
169-
validates, a temporary peer can start/respond/stop/clean up, listen-socket
170-
exposure is recorded, and existing multi-node proofs remain parallel in root
166+
- `gn_ten_distributed_preflight`: records the v2 Phase 3 node-lab package
167+
preflight. It proves `support/gn_ten_node_lab` owns reusable preflight and
168+
peer lifecycle checks; EPMD can start; a shortname StackLab controller node
169+
can come up; a redacted per-run cookie can be generated; the planned
170+
distribution port range validates; frozen topology specs can be parsed with
171+
node-cap enforcement; a temporary peer can start, sync code paths, answer
172+
bounded `:erpc`, stop, and become unreachable after cleanup; listen-socket
173+
exposure is recorded; and existing multi-node proofs remain parallel in root
171174
CI until node-lab migration. It does not prove owner facades, domain
172175
semantics, parity, production security, per-run cookie application to peers,
173176
or release boot.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"cookie_posture": {
3+
"byte_size": 43,
4+
"distribution_security_claim": "local_dev_only",
5+
"posture": "generated_redacted",
6+
"production_security_proven?": false,
7+
"secret_value_present?": false
8+
},
9+
"distribution": {
10+
"node_alive?": true,
11+
"node_name": "stack_lab_node_lab_controller_1@ubuntu-dev",
12+
"started_by_node_lab?": true
13+
},
14+
"does_not_prove": [
15+
"owner facade availability",
16+
"domain business semantics",
17+
"monolith/distributed parity",
18+
"production distribution security",
19+
"release artifact boot"
20+
],
21+
"epmd": {
22+
"command": {
23+
"args": [
24+
"-daemon"
25+
],
26+
"command": "/home/home/.asdf/installs/erlang/28.3/erts-16.2/bin/epmd",
27+
"duration_ms": 4,
28+
"exit_status": 0,
29+
"status": "ok"
30+
},
31+
"path": "/home/home/.asdf/installs/erlang/28.3/erts-16.2/bin/epmd"
32+
},
33+
"failures": [],
34+
"finished_at": "2026-05-25T08:18:51.639875Z",
35+
"peer_probe": {
36+
"code_paths_synced?": true,
37+
"peer_node": "stack_lab_node_lab_peer_2@ubuntu-dev",
38+
"reachable_after_stop?": false,
39+
"remote_call": "ok",
40+
"started?": true,
41+
"stopped?": true
42+
},
43+
"receipt_ref": "receipt://stack_lab/gn_ten_node_lab_preflight/latest",
44+
"schema_version": "stack_lab.gn_ten_node_lab.preflight.v1",
45+
"started_at": "2026-05-25T08:18:51.460102Z",
46+
"status": "pass"
47+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# gn-ten Node Lab Preflight Receipt
2+
3+
Receipt ref:
4+
5+
```text
6+
receipt://stack_lab/gn_ten_node_lab_preflight/latest
7+
```
8+
9+
Command:
10+
11+
```bash
12+
mix stack_lab.gn_ten.node_lab.preflight \
13+
--receipt docs/receipts/gn_ten_distributed/node_lab_preflight.json \
14+
--json
15+
```
16+
17+
Status: pass.
18+
19+
This receipt records the Phase 3 package-owned preflight for
20+
`support/gn_ten_node_lab`. It proves the generic support package can start
21+
EPMD, start a shortname controller node, generate a redacted local-dev cookie
22+
posture, start a peer with `:peer.start_link/1`, synchronize code paths, call
23+
the peer with bounded `:erpc.call/5`, stop the peer, and verify cleanup.
24+
25+
This receipt does not prove owner facade availability, domain business
26+
semantics, monolith/distributed parity, production distribution security, or
27+
release artifact boot.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
defmodule Mix.Tasks.StackLab.GnTen.NodeLab.Preflight do
2+
@moduledoc "Runs the package-owned gn-ten node-lab preflight."
3+
4+
use Mix.Task
5+
6+
alias StackLab.GnTenNodeLab.Preflight
7+
8+
@shortdoc "Runs the gn-ten node-lab preflight"
9+
10+
@impl Mix.Task
11+
def run(args) do
12+
Mix.Task.run("app.start")
13+
14+
{opts, _argv, invalid} =
15+
OptionParser.parse(args,
16+
strict: [
17+
receipt: :string,
18+
json: :boolean
19+
]
20+
)
21+
22+
if invalid != [] do
23+
Mix.raise("invalid options: #{inspect(invalid)}")
24+
end
25+
26+
preflight_opts = [
27+
receipt_path:
28+
Keyword.get(
29+
opts,
30+
:receipt,
31+
"docs/receipts/gn_ten_distributed/node_lab_preflight.json"
32+
)
33+
]
34+
35+
case Preflight.run(preflight_opts) do
36+
{:ok, receipt} ->
37+
print(receipt, Keyword.get(opts, :json, false), :info)
38+
39+
{:error, receipt} ->
40+
print(receipt, Keyword.get(opts, :json, false), :error)
41+
exit({:shutdown, 1})
42+
end
43+
end
44+
45+
defp print(receipt, true, level) do
46+
encoded = Jason.encode!(receipt, pretty: true)
47+
if level == :error, do: Mix.shell().error(encoded), else: Mix.shell().info(encoded)
48+
end
49+
50+
defp print(receipt, false, :info) do
51+
Mix.shell().info("stack_lab.gn_ten.node_lab.preflight passed")
52+
Mix.shell().info("receipt=#{receipt["receipt_path"]}")
53+
Mix.shell().info("receipt_ref=#{receipt["receipt_ref"]}")
54+
end
55+
56+
defp print(receipt, false, :error) do
57+
Mix.shell().error("stack_lab.gn_ten.node_lab.preflight failed")
58+
Mix.shell().error("receipt=#{receipt["receipt_path"]}")
59+
Mix.shell().error("failures=#{inspect(receipt["failures"])}")
60+
end
61+
end

mix.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ defmodule StackLab.Workspace.MixProject do
5353
{:weld, "~> 0.8.2", only: [:dev, :test], runtime: false},
5454
{:jason, "~> 1.4", runtime: false},
5555
{:stack_lab_lab_core, path: "support/lab_core"},
56+
{:stack_lab_gn_ten_node_lab, path: "support/gn_ten_node_lab"},
5657
DependencySources.dep(:ground_plane_contracts, __DIR__),
5758
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
5859
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},

proof_matrix.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,17 @@ proofs:
150150
contract_family: "300 architecture"
151151
status: implemented
152152
profile: local_quick
153-
command: mix gn_ten.distribution.preflight --json
154-
fixture: lib/stack_lab/gn_ten/distribution_preflight.ex
155-
receipt: receipt://stack_lab/gn_ten_distributed_preflight/latest
153+
command: mix stack_lab.gn_ten.node_lab.preflight --json
154+
fixture: support/gn_ten_node_lab
155+
receipt: receipt://stack_lab/gn_ten_node_lab_preflight/latest
156156
proves:
157+
- the reusable support/gn_ten_node_lab package owns preflight and peer lifecycle checks
157158
- EPMD can be found and started on this host
158159
- StackLab can start a shortname controller node
159160
- StackLab can generate a redacted per-run cookie value without writing it to receipts
160161
- the planned distribution port range is validated
161-
- a temporary peer can start, answer bounded erpc, stop, and become unreachable after cleanup
162+
- frozen topology specs can be parsed with node-cap enforcement
163+
- a temporary peer can start, sync code paths, answer bounded erpc, stop, and become unreachable after cleanup
162164
- current EPMD names and listen-socket exposure are recorded
163165
- existing multi-node proofs remain parallel in root CI until node-lab migration
164166
does_not_prove:
@@ -168,10 +170,10 @@ proofs:
168170
- per-run cookie application to peers
169171
- production distribution security
170172
- release artifact boot
171-
next_action: create support/gn_ten_node_lab and move reusable peer lifecycle APIs behind the package boundary
173+
next_action: use support/gn_ten_node_lab for Phase 5 topology specs, app boot, facade readiness, and pg group checks
172174
trace_receipt:
173175
schema: aitrace.single_node_proof_trace.v1
174-
ref: trace://stack_lab/gn_ten_distributed_preflight/latest
176+
ref: trace://stack_lab/gn_ten_node_lab_preflight/latest
175177
posture:
176178
authoritative_audit?: false
177179
production_deployment_proven?: false
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[
2+
inputs: ["{mix,.formatter}.exs", "{lib,test}/**/*.{ex,exs}"]
3+
]

0 commit comments

Comments
 (0)