Skip to content

Commit 80f3823

Browse files
committed
Add distributed persistence posture receipts
1 parent 979126f commit 80f3823

5 files changed

Lines changed: 183 additions & 6 deletions

File tree

.blitz/test_state_v1/indexes/task_states.ndjson

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6887,6 +6887,7 @@
68876887
{"latest_passed_result_id":"sha256:59a7b8aaa66a4e9ff3c815015af869a7b61f37fb50a98402132bf2fd4a5ce89d","latest_result_id":"sha256:59a7b8aaa66a4e9ff3c815015af869a7b61f37fb50a98402132bf2fd4a5ce89d","project_path":"support/ai_run_lineage_scanner","schema":"blitz-task-state-index-v1","task":"compile","task_state_hash":"sha256:fdc56d59d336473888f6fb494493b55d02641bf79b8eba3ed3a7bc0f683d3725","updated_at":"2026-05-18T10:12:34Z"}
68886888
{"latest_passed_result_id":"sha256:b444b0c124c3d2d8730f4238653ce762f60d26a90cfc4ceefb8587159ef9db2f","latest_result_id":"sha256:b444b0c124c3d2d8730f4238653ce762f60d26a90cfc4ceefb8587159ef9db2f","project_path":"examples/skill_roundtrip","schema":"blitz-task-state-index-v1","task":"format","task_state_hash":"sha256:fdcb3130e43bcad95e17ca5ba0d0119b3413e6193e0afddd0a47be2cd018e4a9","updated_at":"2026-05-25T08:24:14Z"}
68896889
{"latest_passed_result_id":"sha256:83cbc48a23016c7cc56b498140054f05eb9e8e93b77a2133091cd5e4063e2c8c","latest_result_id":"sha256:83cbc48a23016c7cc56b498140054f05eb9e8e93b77a2133091cd5e4063e2c8c","project_path":"examples/trinity_parity_harness","schema":"blitz-task-state-index-v1","task":"credo","task_state_hash":"sha256:fdd2872ae6fb44233d3ceaf43398530b54d529e717f55e46dcbfafb92cdb60ca","updated_at":"2026-05-25T07:38:50Z"}
6890+
{"latest_passed_result_id":"sha256:8bedc64368074ac998fafa5c72ef7d925636ca3d854ddeca50148535485c9e28","latest_result_id":"sha256:8bedc64368074ac998fafa5c72ef7d925636ca3d854ddeca50148535485c9e28","project_path":"examples/gn_ten_distributed_stack","schema":"blitz-task-state-index-v1","task":"compile","task_state_hash":"sha256:fdd298de0438daf9468c9f30bdabb7ac14dc6b57252a97db46378e8680ce8692","updated_at":"2026-05-25T22:24:35Z"}
68906891
{"latest_passed_result_id":"sha256:229339b62d301dc1db45004395d508c386454a3f6c6f78f1dc11b1948fc9ea34","latest_result_id":"sha256:229339b62d301dc1db45004395d508c386454a3f6c6f78f1dc11b1948fc9ea34","project_path":"examples/replay_roundtrip","schema":"blitz-task-state-index-v1","task":"credo","task_state_hash":"sha256:fdd2eb7a0941b0dbc357a90d15476df73694784e840bed8ff28ba05211f5cd5a","updated_at":"2026-05-11T04:24:06Z"}
68916892
{"latest_passed_result_id":"sha256:01801a81fa83239214a090cf0dfae91927921ace5934b4c565fb4a5bf4d4f145","latest_result_id":"sha256:01801a81fa83239214a090cf0dfae91927921ace5934b4c565fb4a5bf4d4f145","project_path":"examples/session_lineage_drill","schema":"blitz-task-state-index-v1","task":"compile","task_state_hash":"sha256:fdd7830ce29c6ab20bd5bc6c775a446b0d432e9d10d754047ef2b3e5c87b90a9","updated_at":"2026-05-06T10:26:56Z"}
68926893
{"latest_passed_result_id":"sha256:4c3659e682ecc1e60ad155cbfc19709540eb0d3cc8dde5061390c8bfe70891a0","latest_result_id":"sha256:4c3659e682ecc1e60ad155cbfc19709540eb0d3cc8dde5061390c8bfe70891a0","project_path":"support/citadel_spine_harness","schema":"blitz-task-state-index-v1","task":"format","task_state_hash":"sha256:fde3e599a53515458c9bc807836f0528d26cadf4e6236a4df1cb69aa4559c5ad","updated_at":"2026-05-06T15:16:41Z"}

examples/gn_ten_distributed_stack/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ Phase 11 records local fault and recovery posture:
3131
- keep WAN, production discovery, release boot, and live-provider retry
3232
semantics as explicit non-claims.
3333

34+
Phase 12 adds persistence and external-substrate posture:
35+
36+
- include the existing deterministic persistence matrix proof in distributed
37+
receipts;
38+
- require `:mickey_mouse` and `:memory_debug` profile facts before a receipt is
39+
`pass`;
40+
- record Postgres and Temporal as opt-in external profiles only;
41+
- do not start Postgres, Temporal, or Toxiproxy from this proof app.
42+
3443
## Commands
3544

3645
```bash

examples/gn_ten_distributed_stack/lib/stack_lab/examples/gn_ten_distributed_stack.ex

Lines changed: 141 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ defmodule StackLab.Examples.GnTenDistributedStack.Receipt do
1616
:aitrace_exports,
1717
:replay_bundle,
1818
:evidence_status,
19+
:persistence_profiles,
20+
:persistence_status,
1921
:node_lab_run,
2022
:distributed_envelope_scan,
2123
:node_placement,
@@ -38,6 +40,8 @@ defmodule StackLab.Examples.GnTenDistributedStack.Receipt do
3840
aitrace_exports: [map()],
3941
replay_bundle: map(),
4042
evidence_status: String.t(),
43+
persistence_profiles: map(),
44+
persistence_status: String.t(),
4145
node_lab_run: map(),
4246
distributed_envelope_scan: map(),
4347
node_placement: map(),
@@ -71,6 +75,8 @@ defmodule StackLab.Examples.GnTenDistributedStack.RouterModelReceipt do
7175
:aitrace_exports,
7276
:replay_bundle,
7377
:evidence_status,
78+
:persistence_profiles,
79+
:persistence_status,
7480
:node_lab_run,
7581
:distributed_envelope_scan,
7682
:node_placement,
@@ -101,6 +107,8 @@ defmodule StackLab.Examples.GnTenDistributedStack.RouterModelReceipt do
101107
aitrace_exports: [map()],
102108
replay_bundle: map(),
103109
evidence_status: String.t(),
110+
persistence_profiles: map(),
111+
persistence_status: String.t(),
104112
node_lab_run: map(),
105113
distributed_envelope_scan: map(),
106114
node_placement: map(),
@@ -120,6 +128,8 @@ defmodule StackLab.Examples.GnTenDistributedStack.FaultRecoveryReceipt do
120128
:baseline_receipt_ref,
121129
:fault_receipts,
122130
:owner_recovery_evidence,
131+
:persistence_profiles,
132+
:persistence_status,
123133
:trace_refs,
124134
:node_lab_run,
125135
:does_not_prove
@@ -135,6 +145,8 @@ defmodule StackLab.Examples.GnTenDistributedStack.FaultRecoveryReceipt do
135145
baseline_receipt_ref: String.t(),
136146
fault_receipts: [map()],
137147
owner_recovery_evidence: [map()],
148+
persistence_profiles: map(),
149+
persistence_status: String.t(),
138150
trace_refs: [String.t()],
139151
node_lab_run: map(),
140152
does_not_prove: [String.t()]
@@ -161,6 +173,7 @@ defmodule StackLab.Examples.GnTenDistributedStack do
161173
@envelope_schema_version "stack_lab.distributed_envelope.v1"
162174
@context_roundtrip Module.concat([StackLab, Examples, ContextABIRoundtrip])
163175
@router_roundtrip Module.concat([StackLab, Examples, NSHKRRouterFabricRoundtrip])
176+
@persistence_roundtrip Module.concat([StackLab, Examples, PersistenceModeRoundtrip])
164177
@aitrace_evidence Module.concat([AITrace, RemoteFacade, Evidence])
165178
@aitrace_fixture_transport Module.concat([AITrace, NSHKR, ExportTransport, Fixture])
166179
@replay_bundle Module.concat([AITrace, Trace, ReplayBundle])
@@ -195,12 +208,14 @@ defmodule StackLab.Examples.GnTenDistributedStack do
195208
node_trace_refs = node_trace_refs(baseline, node_lab_run, :context)
196209
aitrace_exports = export_trace_evidence(node_trace_refs, :context, evidence_opts)
197210
replay_bundle = replay_bundle(baseline, :context)
211+
persistence_profiles = persistence_profiles()
198212

199213
{:ok,
200214
%Receipt{
201215
receipt_ref: receipt_ref(baseline),
202216
schema_version: @context_schema_version,
203-
status: status(baseline, node_lab_run, envelope_scan, aitrace_exports),
217+
status:
218+
status(baseline, node_lab_run, envelope_scan, aitrace_exports, persistence_profiles),
204219
profile: @context_profile,
205220
topology_ref: node_lab_run["topology_ref"],
206221
monolith_baseline_receipt_ref: baseline.receipt_ref,
@@ -212,6 +227,8 @@ defmodule StackLab.Examples.GnTenDistributedStack do
212227
aitrace_exports: aitrace_exports,
213228
replay_bundle: replay_bundle,
214229
evidence_status: evidence_status(aitrace_exports),
230+
persistence_profiles: persistence_profiles,
231+
persistence_status: persistence_status(persistence_profiles),
215232
node_lab_run: node_lab_run,
216233
distributed_envelope_scan: envelope_scan,
217234
node_placement: node_placement(node_lab_run),
@@ -253,12 +270,20 @@ defmodule StackLab.Examples.GnTenDistributedStack do
253270
node_trace_refs = node_trace_refs(baseline, node_lab_run, :router_model)
254271
aitrace_exports = export_trace_evidence(node_trace_refs, :router_model, evidence_opts)
255272
replay_bundle = replay_bundle(baseline, :router_model)
273+
persistence_profiles = persistence_profiles()
256274

257275
{:ok,
258276
%RouterModelReceipt{
259277
receipt_ref: router_model_receipt_ref(baseline),
260278
schema_version: @router_model_schema_version,
261-
status: router_model_status(baseline, node_lab_run, envelope_scan, aitrace_exports),
279+
status:
280+
router_model_status(
281+
baseline,
282+
node_lab_run,
283+
envelope_scan,
284+
aitrace_exports,
285+
persistence_profiles
286+
),
262287
profile: @router_model_profile,
263288
topology_ref: node_lab_run["topology_ref"],
264289
monolith_baseline_receipt_ref: baseline.receipt_ref,
@@ -278,6 +303,8 @@ defmodule StackLab.Examples.GnTenDistributedStack do
278303
aitrace_exports: aitrace_exports,
279304
replay_bundle: replay_bundle,
280305
evidence_status: evidence_status(aitrace_exports),
306+
persistence_profiles: persistence_profiles,
307+
persistence_status: persistence_status(persistence_profiles),
281308
node_lab_run: node_lab_run,
282309
distributed_envelope_scan: envelope_scan,
283310
node_placement: node_placement(node_lab_run),
@@ -308,6 +335,8 @@ defmodule StackLab.Examples.GnTenDistributedStack do
308335
baseline_receipt_ref: baseline.receipt_ref,
309336
fault_receipts: fault_receipts,
310337
owner_recovery_evidence: owner_recovery_evidence(),
338+
persistence_profiles: baseline.persistence_profiles,
339+
persistence_status: baseline.persistence_status,
311340
trace_refs: baseline.trace_refs,
312341
node_lab_run: baseline.node_lab_run,
313342
does_not_prove: [
@@ -398,19 +427,27 @@ defmodule StackLab.Examples.GnTenDistributedStack do
398427
}
399428
end
400429

401-
defp status(baseline, node_lab_run, envelope_scan, aitrace_exports) do
430+
defp status(baseline, node_lab_run, envelope_scan, aitrace_exports, persistence_profiles) do
402431
if baseline.status == :pass and node_lab_run["status"] == "pass" and
403-
envelope_scan["status"] == "pass" and evidence_status(aitrace_exports) == "pass" do
432+
envelope_scan["status"] == "pass" and evidence_status(aitrace_exports) == "pass" and
433+
persistence_status(persistence_profiles) == "pass" do
404434
:pass
405435
else
406436
:open_defect
407437
end
408438
end
409439

410-
defp router_model_status(baseline, node_lab_run, envelope_scan, aitrace_exports) do
440+
defp router_model_status(
441+
baseline,
442+
node_lab_run,
443+
envelope_scan,
444+
aitrace_exports,
445+
persistence_profiles
446+
) do
411447
if baseline.status == :pass and node_lab_run["status"] == "pass" and
412448
envelope_scan["status"] == "pass" and route_and_model_refs_present?(baseline) and
413-
model_accounting_present?(baseline) and evidence_status(aitrace_exports) == "pass" do
449+
model_accounting_present?(baseline) and evidence_status(aitrace_exports) == "pass" and
450+
persistence_status(persistence_profiles) == "pass" do
414451
:pass
415452
else
416453
:open_defect
@@ -518,6 +555,104 @@ defmodule StackLab.Examples.GnTenDistributedStack do
518555
if Enum.all?(exports, &(Map.get(&1, "status") == "pass")), do: "pass", else: "open_defect"
519556
end
520557

558+
defp persistence_profiles do
559+
case call(@persistence_roundtrip, :run, []) do
560+
{:ok, receipt} ->
561+
profile_receipts = Enum.map(receipt.profile_receipts, &profile_receipt_fact/1)
562+
deterministic_profile_ids = ["mickey_mouse", "memory_debug"]
563+
564+
deterministic_profiles =
565+
Enum.filter(profile_receipts, &(&1["profile_id"] in deterministic_profile_ids))
566+
567+
%{
568+
"status" => Atom.to_string(receipt.status),
569+
"source_receipt_ref" => receipt.receipt_ref,
570+
"deterministic_profiles" => deterministic_profiles,
571+
"opt_in_external_profiles" => opt_in_external_profiles(profile_receipts),
572+
"matrix_scan" => json_safe(receipt.matrix_scan),
573+
"substrate_started_by_stack_lab?" => false,
574+
"temporal_started_by_stack_lab?" => false,
575+
"postgres_started_by_stack_lab?" => false,
576+
"raw_debug_payloads_persisted?" => false
577+
}
578+
579+
{:error, reason} ->
580+
%{
581+
"status" => "open_defect",
582+
"reason" => inspect(reason),
583+
"deterministic_profiles" => [],
584+
"opt_in_external_profiles" => [],
585+
"substrate_started_by_stack_lab?" => false,
586+
"temporal_started_by_stack_lab?" => false,
587+
"postgres_started_by_stack_lab?" => false,
588+
"raw_debug_payloads_persisted?" => false
589+
}
590+
end
591+
end
592+
593+
defp persistence_status(%{
594+
"status" => "pass",
595+
"deterministic_profiles" => deterministic_profiles
596+
}) do
597+
profile_ids =
598+
deterministic_profiles
599+
|> Enum.map(&Map.fetch!(&1, "profile_id"))
600+
|> MapSet.new()
601+
602+
if MapSet.subset?(MapSet.new(["mickey_mouse", "memory_debug"]), profile_ids) do
603+
"pass"
604+
else
605+
"open_defect"
606+
end
607+
end
608+
609+
defp persistence_status(_profiles), do: "open_defect"
610+
611+
defp profile_receipt_fact(profile_receipt) do
612+
%{
613+
"profile_id" => profile_receipt.profile_id |> Atom.to_string(),
614+
"selected_tier" => profile_receipt.selected_tier |> Atom.to_string(),
615+
"store_set_id" => profile_receipt.store_set_id |> Atom.to_string(),
616+
"capture_level" => profile_receipt.capture_level |> Atom.to_string(),
617+
"restart_claim" => profile_receipt.restart_claim |> Atom.to_string(),
618+
"durable_opt_in?" => profile_receipt.durable_opt_in?,
619+
"durable_tag" => profile_receipt.durable_tag,
620+
"proof_command" => profile_receipt.proof_command,
621+
"storage_behavior_ref" => profile_receipt.storage_behavior_ref,
622+
"authority_semantics_ref" => profile_receipt.authority_semantics_ref
623+
}
624+
end
625+
626+
defp opt_in_external_profiles(profile_receipts) do
627+
postgres_profiles =
628+
profile_receipts
629+
|> Enum.filter(&(&1["profile_id"] in ["integration_postgres", "full_debug_tracked"]))
630+
|> Enum.map(fn profile ->
631+
Map.merge(profile, %{
632+
"proof_mode" => "opt_in_preflight_only",
633+
"compose_ref" => "tools/compose/multi-node.yml",
634+
"toxiproxy_ref" => "tools/toxiproxy/toxiproxy.json",
635+
"substrate_started_by_stack_lab?" => false
636+
})
637+
end)
638+
639+
postgres_profiles ++
640+
[
641+
%{
642+
"profile_id" => "ops_durable_temporal",
643+
"selected_tier" => "ops_durable",
644+
"store_set_id" => "temporal_workflow_runtime",
645+
"capture_level" => "metadata",
646+
"restart_claim" => "durable_restart",
647+
"durable_opt_in?" => true,
648+
"durable_tag" => "persistence-durable-opt-in",
649+
"proof_mode" => "blocked_until_repo_owned_just",
650+
"just_command" => "cd /home/home/p/g/n/mezzanine && just dev-status",
651+
"substrate_started_by_stack_lab?" => false
652+
}
653+
]
654+
end
655+
521656
defp replay_bundle(baseline, scenario) do
522657
attrs =
523658
%{

examples/gn_ten_distributed_stack/mix.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ defmodule StackLab.GnTenDistributedStack.MixProject do
3030
{:stack_lab_context_abi_roundtrip, path: "../context_abi_roundtrip", runtime: false},
3131
{:stack_lab_nshkr_router_fabric_roundtrip,
3232
path: "../nshkr_router_fabric_roundtrip", runtime: false},
33+
{:stack_lab_persistence_mode_roundtrip,
34+
path: "../persistence_mode_roundtrip", runtime: false},
3335
{:app_kit_mezzanine_bridge,
3436
path: "../../../app_kit/bridges/mezzanine_bridge", runtime: false},
3537
{:mezzanine_execution_engine,

examples/gn_ten_distributed_stack/test/stack_lab/examples/gn_ten_distributed_stack_test.exs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ defmodule StackLab.Examples.GnTenDistributedStackTest do
1414
assert File.exists?(receipt.node_lab_run["log_artifact"]["path"])
1515
assert receipt.distributed_envelope_scan["status"] == "pass"
1616
assert receipt.evidence_status == "pass"
17+
assert receipt.persistence_status == "pass"
18+
assert deterministic_profile?(receipt, "mickey_mouse", "none")
19+
assert deterministic_profile?(receipt, "memory_debug", "none")
20+
assert external_profile?(receipt, "integration_postgres", "durable")
21+
assert external_profile?(receipt, "ops_durable_temporal", "durable_restart")
1722
assert length(receipt.node_trace_refs) == 5
1823
assert length(receipt.aitrace_exports) == 5
1924
assert Enum.all?(receipt.aitrace_exports, &(&1["status"] == "pass"))
@@ -40,6 +45,12 @@ defmodule StackLab.Examples.GnTenDistributedStackTest do
4045
assert File.exists?(receipt.node_lab_run["log_artifact"]["path"])
4146
assert receipt.distributed_envelope_scan["status"] == "pass"
4247
assert receipt.evidence_status == "pass"
48+
assert receipt.persistence_status == "pass"
49+
assert receipt.persistence_profiles["matrix_scan"]["status"] == "pass"
50+
refute receipt.persistence_profiles["substrate_started_by_stack_lab?"]
51+
refute receipt.persistence_profiles["temporal_started_by_stack_lab?"]
52+
refute receipt.persistence_profiles["postgres_started_by_stack_lab?"]
53+
refute receipt.persistence_profiles["raw_debug_payloads_persisted?"]
4354
assert length(receipt.node_trace_refs) == 6
4455
assert length(receipt.aitrace_exports) == 6
4556
assert Enum.all?(receipt.aitrace_exports, &(&1["status"] == "pass"))
@@ -74,6 +85,9 @@ defmodule StackLab.Examples.GnTenDistributedStackTest do
7485

7586
assert receipt.status == :pass
7687
assert receipt.profile == "partition_recovery"
88+
assert receipt.persistence_status == "pass"
89+
assert deterministic_profile?(receipt, "mickey_mouse", "none")
90+
assert external_profile?(receipt, "ops_durable_temporal", "durable_restart")
7791
assert length(receipt.fault_receipts) == 7
7892
assert Enum.all?(receipt.fault_receipts, &(&1["status"] == "pass"))
7993
assert Enum.any?(receipt.fault_receipts, &(&1["fault_kind"] == "node_crash"))
@@ -86,5 +100,21 @@ defmodule StackLab.Examples.GnTenDistributedStackTest do
86100
refute json =~ "cookie_value"
87101
refute json =~ "raw_prompt"
88102
refute json =~ "provider_payload\":"
103+
refute json =~ "DATABASE_URL"
104+
end
105+
106+
defp deterministic_profile?(receipt, profile_id, restart_claim) do
107+
Enum.any?(receipt.persistence_profiles["deterministic_profiles"], fn profile ->
108+
profile["profile_id"] == profile_id and profile["restart_claim"] == restart_claim and
109+
profile["durable_opt_in?"] == false
110+
end)
111+
end
112+
113+
defp external_profile?(receipt, profile_id, restart_claim) do
114+
Enum.any?(receipt.persistence_profiles["opt_in_external_profiles"], fn profile ->
115+
profile["profile_id"] == profile_id and profile["restart_claim"] == restart_claim and
116+
profile["durable_opt_in?"] == true and
117+
profile["substrate_started_by_stack_lab?"] == false
118+
end)
89119
end
90120
end

0 commit comments

Comments
 (0)