From edd84a5d63c8070bdda2888d54e60ad572d6022b Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Mon, 20 Jul 2026 15:14:41 -0700 Subject: [PATCH 01/10] Add temporary Linux build workflow for math ingestion bootstrap --- .../workflows/math-ingestion-bootstrap.yml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/math-ingestion-bootstrap.yml diff --git a/.github/workflows/math-ingestion-bootstrap.yml b/.github/workflows/math-ingestion-bootstrap.yml new file mode 100644 index 0000000..a7b6092 --- /dev/null +++ b/.github/workflows/math-ingestion-bootstrap.yml @@ -0,0 +1,50 @@ +name: Math ingestion bootstrap + +on: + push: + branches: + - codex/math-ingestion-bootstrap + workflow_dispatch: + +permissions: + contents: read + +jobs: + build-linux: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install stable Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + + - name: Test workspace + run: cargo test -q + + - name: Build Linux release binaries + run: cargo build --release -p l64 -p l64-cli -p l64-admin + + - name: Package binaries and source metadata + shell: bash + run: | + set -euo pipefail + mkdir -p dist + cp target/release/l64 dist/ + cp target/release/l64-cli dist/ + cp target/release/l64-admin dist/ + cp README.md Cargo.toml Cargo.lock dist/ + git rev-parse HEAD > dist/SOURCE_COMMIT.txt + sha256sum dist/l64 dist/l64-cli dist/l64-admin > dist/SHA256SUMS.txt + tar -C dist -czf locus64-linux-x86_64.tar.gz . + + - name: Upload Linux artifact + uses: actions/upload-artifact@v4 + with: + name: locus64-linux-x86_64 + path: locus64-linux-x86_64.tar.gz + if-no-files-found: error + retention-days: 7 From 779d2352c3f7cbed1d6c4802ae2c8a8b3abe1df7 Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Mon, 20 Jul 2026 15:15:31 -0700 Subject: [PATCH 02/10] Make bootstrap build visible on draft PR --- .github/workflows/math-ingestion-bootstrap.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/math-ingestion-bootstrap.yml b/.github/workflows/math-ingestion-bootstrap.yml index a7b6092..a6cb3c8 100644 --- a/.github/workflows/math-ingestion-bootstrap.yml +++ b/.github/workflows/math-ingestion-bootstrap.yml @@ -4,6 +4,9 @@ on: push: branches: - codex/math-ingestion-bootstrap + pull_request: + branches: + - main workflow_dispatch: permissions: From b51eda6362679d05f6d0592424c96a4a602d8b6a Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:32:24 -0700 Subject: [PATCH 03/10] Add atlas export crate manifest --- l64-atlas-export/Cargo.toml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 l64-atlas-export/Cargo.toml diff --git a/l64-atlas-export/Cargo.toml b/l64-atlas-export/Cargo.toml new file mode 100644 index 0000000..ba0b938 --- /dev/null +++ b/l64-atlas-export/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "l64-atlas-export" +edition.workspace = true +version.workspace = true +license.workspace = true + +[dependencies] +anyhow = { workspace = true } +clap = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +l64-atlas = { path = "../l64-atlas" } +l64-bundle = { path = "../l64-bundle" } +l64-core = { path = "../l64-core" } +l64-registry = { path = "../l64-registry" } From c51dd7f9ed1cba570f6d7d824b4424159bca9624 Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:33:00 -0700 Subject: [PATCH 04/10] Add native bundle atlas export utility --- l64-atlas-export/src/main.rs | 222 +++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 l64-atlas-export/src/main.rs diff --git a/l64-atlas-export/src/main.rs b/l64-atlas-export/src/main.rs new file mode 100644 index 0000000..963340a --- /dev/null +++ b/l64-atlas-export/src/main.rs @@ -0,0 +1,222 @@ +use anyhow::{Context, Result, anyhow}; +use clap::Parser; +use l64_atlas::{CompiledAtlas, CompiledEdge}; +use l64_bundle::{import_bundle_file, load_bundle_world}; +use l64_core::{AtlasCell, BundleConflictPolicy, RegistryLookup}; +use serde::Serialize; +use std::{collections::BTreeMap, fs, path::Path}; + +#[derive(Debug, Parser)] +#[command(name = "l64-atlas-export")] +#[command(about = "Compile and export a Locus64 atlas from seed or bundle overlay authority")] +struct Cli { + #[arg(long, conflicts_with = "bundle")] + file: Option, + #[arg(long, conflicts_with = "file")] + bundle: Option, + #[arg(long, default_value_t = false)] + overlay_only: bool, + #[arg(long, default_value_t = false)] + dump_edges: bool, + #[arg(long, default_value_t = false)] + dump_cells: bool, + #[arg(long)] + out: Option, + #[arg(long)] + dot_out: Option, +} + +#[derive(Debug, Serialize)] +struct RouteBucket { + source_regime: String, + target_regime: String, + edge_count: usize, + atlas_cell_ids: Vec, + burden_classes: Vec, + minimum_loss_count: usize, + minimum_surface_penalty: usize, +} + +#[derive(Debug, Serialize)] +struct AtlasExport { + source: String, + bundle_id: Option, + overlay_only: bool, + edge_count: usize, + atlas_cell_count: usize, + claim_packet_count: usize, + regime_pair_count: usize, + burden_pair_count: usize, + route_buckets: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + edges: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + cells: Option>, +} + +fn build_export( + registry: &R, + source: String, + bundle_id: Option, + overlay_only: bool, + dump_edges: bool, + dump_cells: bool, +) -> Result { + let atlas = CompiledAtlas::compile(registry).map_err(anyhow::Error::msg)?; + let cells = registry.atlas_cells(); + let claims = registry.claim_packets(); + let mut grouped: BTreeMap<(String, String), Vec<&CompiledEdge>> = BTreeMap::new(); + for edge in &atlas.edges { + grouped + .entry((edge.src.clone(), edge.tgt.clone())) + .or_default() + .push(edge); + } + let route_buckets = grouped + .into_iter() + .map(|((src, tgt), edges)| { + let mut cell_ids = edges + .iter() + .map(|edge| edge.atlas_cell_id.clone()) + .collect::>(); + cell_ids.sort(); + cell_ids.dedup(); + let mut burdens = edges + .iter() + .map(|edge| format!("{:?}", edge.burden_class)) + .collect::>(); + burdens.sort(); + burdens.dedup(); + RouteBucket { + source_regime: src, + target_regime: tgt, + edge_count: edges.len(), + atlas_cell_ids: cell_ids, + burden_classes: burdens, + minimum_loss_count: edges.iter().map(|edge| edge.loss_count).min().unwrap_or(0), + minimum_surface_penalty: edges + .iter() + .map(|edge| edge.surface_penalty) + .min() + .unwrap_or(0), + } + }) + .collect::>(); + let summary = atlas.compile_summary(); + Ok(AtlasExport { + source, + bundle_id, + overlay_only, + edge_count: summary.edge_count, + atlas_cell_count: cells.len(), + claim_packet_count: claims.len(), + regime_pair_count: summary.indexed_src_tgt_pairs, + burden_pair_count: summary.indexed_burden_pairs, + route_buckets, + edges: dump_edges.then_some(atlas.edges), + cells: dump_cells.then_some(cells), + }) +} + +fn escape_dot(value: &str) -> String { + value.replace('\\', "\\\\").replace('"', "\\\"") +} + +fn write_dot(path: &str, export: &AtlasExport) -> Result<()> { + let edges = export + .edges + .as_ref() + .ok_or_else(|| anyhow!("--dot-out requires --dump-edges"))?; + let mut out = String::from("digraph locus64_atlas {\n rankdir=LR;\n"); + for edge in edges { + let label = format!( + "{}\\n{:?}\\nloss={} surface={}", + edge.atlas_cell_id, edge.burden_class, edge.loss_count, edge.surface_penalty + ); + out.push_str(&format!( + " \"{}\" -> \"{}\" [label=\"{}\"];\n", + escape_dot(&edge.src), + escape_dot(&edge.tgt), + escape_dot(&label) + )); + } + out.push_str("}\n"); + fs::write(path, out).with_context(|| format!("failed to write DOT output `{path}`"))?; + Ok(()) +} + +fn main() -> Result<()> { + let cli = Cli::parse(); + let export = if let Some(file) = cli.file.as_deref() { + let world = import_bundle_file( + Path::new(file), + None, + BundleConflictPolicy::ExactMatch, + None, + )?; + let bundle_id = Some(world.manifest.id.clone()); + if cli.overlay_only { + let local = world.overlay.local_only(); + build_export( + &local, + format!("file:{file}"), + bundle_id, + true, + cli.dump_edges, + cli.dump_cells, + )? + } else { + build_export( + &world.overlay, + format!("file:{file}"), + bundle_id, + false, + cli.dump_edges, + cli.dump_cells, + )? + } + } else if let Some(bundle_id) = cli.bundle.as_deref() { + let world = load_bundle_world(bundle_id)?; + if cli.overlay_only { + let local = world.overlay.local_only(); + build_export( + &local, + format!("bundle:{bundle_id}"), + Some(bundle_id.to_string()), + true, + cli.dump_edges, + cli.dump_cells, + )? + } else { + build_export( + &world.overlay, + format!("bundle:{bundle_id}"), + Some(bundle_id.to_string()), + false, + cli.dump_edges, + cli.dump_cells, + )? + } + } else { + let registry = l64_registry::SeedRegistry::load()?; + build_export( + ®istry, + "seed".into(), + None, + false, + cli.dump_edges, + cli.dump_cells, + )? + }; + + if let Some(dot_out) = cli.dot_out.as_deref() { + write_dot(dot_out, &export)?; + } + let json = serde_json::to_string_pretty(&export)?; + if let Some(out) = cli.out.as_deref() { + fs::write(out, json).with_context(|| format!("failed to write JSON output `{out}`"))?; + } else { + println!("{json}"); + } + Ok(()) +} From cdb332b4051730029931b8cb8b81e78b06f5ad1b Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:33:07 -0700 Subject: [PATCH 05/10] Document atlas export utility --- l64-atlas-export/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 l64-atlas-export/README.md diff --git a/l64-atlas-export/README.md b/l64-atlas-export/README.md new file mode 100644 index 0000000..576b22c --- /dev/null +++ b/l64-atlas-export/README.md @@ -0,0 +1,10 @@ +# l64-atlas-export + +A narrow atlas export utility for compiling Locus64 atlas cells from the seed registry or an imported DNA bundle overlay. + +It does not introduce a second atlas schema. It reuses native `regime`, `bridge`, `atlas`, `claim-packet`, and bundle-overlay authority, then exports route summaries, compiled edges, source cells, and a Graphviz projection. + +```text +l64-atlas-export --file framework.dna --overlay-only --dump-edges --dump-cells \ + --out framework.atlas.json --dot-out framework.atlas.dot +``` From a872a6f993691d9f8cb19230d8232bc021ac3cfa Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:33:20 -0700 Subject: [PATCH 06/10] Register atlas export utility in workspace --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 3a7c67a..bd1bbab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "l64-runtime", "l64-canon", "l64-atlas", + "l64-atlas-export", "l64-cert", "l64-bundle", "l64-policy", From 72137538f9e0379723294eb396a32ba3062965f0 Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:33:33 -0700 Subject: [PATCH 07/10] Build and package atlas export utility --- .github/workflows/math-ingestion-bootstrap.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/math-ingestion-bootstrap.yml b/.github/workflows/math-ingestion-bootstrap.yml index a6cb3c8..0dc6762 100644 --- a/.github/workflows/math-ingestion-bootstrap.yml +++ b/.github/workflows/math-ingestion-bootstrap.yml @@ -29,7 +29,7 @@ jobs: run: cargo test -q - name: Build Linux release binaries - run: cargo build --release -p l64 -p l64-cli -p l64-admin + run: cargo build --release -p l64 -p l64-cli -p l64-admin -p l64-atlas-export - name: Package binaries and source metadata shell: bash @@ -39,9 +39,10 @@ jobs: cp target/release/l64 dist/ cp target/release/l64-cli dist/ cp target/release/l64-admin dist/ + cp target/release/l64-atlas-export dist/ cp README.md Cargo.toml Cargo.lock dist/ git rev-parse HEAD > dist/SOURCE_COMMIT.txt - sha256sum dist/l64 dist/l64-cli dist/l64-admin > dist/SHA256SUMS.txt + sha256sum dist/l64 dist/l64-cli dist/l64-admin dist/l64-atlas-export > dist/SHA256SUMS.txt tar -C dist -czf locus64-linux-x86_64.tar.gz . - name: Upload Linux artifact From 5f273461dc9cd422b6f1f746fbe06c686402883c Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:45:05 -0700 Subject: [PATCH 08/10] Test native atlas export command surface --- l64-atlas-export/tests/cli.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 l64-atlas-export/tests/cli.rs diff --git a/l64-atlas-export/tests/cli.rs b/l64-atlas-export/tests/cli.rs new file mode 100644 index 0000000..2cdee22 --- /dev/null +++ b/l64-atlas-export/tests/cli.rs @@ -0,0 +1,28 @@ +use std::process::Command; + +#[test] +fn exports_seed_atlas_through_binary_surface() { + let output = Command::new(env!("CARGO_BIN_EXE_l64-atlas-export")) + .args(["--dump-edges", "--dump-cells"]) + .output() + .expect("run l64-atlas-export"); + assert!( + output.status.success(), + "stderr: {}", + String::from_utf8_lossy(&output.stderr) + ); + let value: serde_json::Value = + serde_json::from_slice(&output.stdout).expect("parse atlas export JSON"); + assert!(value["edge_count"].as_u64().unwrap_or(0) > 0); + assert!(value["atlas_cell_count"].as_u64().unwrap_or(0) > 0); + assert_eq!( + value["edges"].as_array().map(Vec::len), + value["edge_count"].as_u64().map(|count| count as usize) + ); + assert_eq!( + value["cells"].as_array().map(Vec::len), + value["atlas_cell_count"] + .as_u64() + .map(|count| count as usize) + ); +} From 56d29bc7fa5b807d65eb2679eb0e7b121a96a1ba Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Tue, 21 Jul 2026 11:11:15 -0700 Subject: [PATCH 09/10] Export engine-resolved claim packets from atlas overlays --- l64-atlas-export/src/main.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/l64-atlas-export/src/main.rs b/l64-atlas-export/src/main.rs index 963340a..a63af8c 100644 --- a/l64-atlas-export/src/main.rs +++ b/l64-atlas-export/src/main.rs @@ -2,7 +2,7 @@ use anyhow::{Context, Result, anyhow}; use clap::Parser; use l64_atlas::{CompiledAtlas, CompiledEdge}; use l64_bundle::{import_bundle_file, load_bundle_world}; -use l64_core::{AtlasCell, BundleConflictPolicy, RegistryLookup}; +use l64_core::{AtlasCell, BundleConflictPolicy, ClaimPacket, RegistryLookup}; use serde::Serialize; use std::{collections::BTreeMap, fs, path::Path}; @@ -10,18 +10,35 @@ use std::{collections::BTreeMap, fs, path::Path}; #[command(name = "l64-atlas-export")] #[command(about = "Compile and export a Locus64 atlas from seed or bundle overlay authority")] struct Cli { + /// Import a .dna bundle before compiling the atlas. #[arg(long, conflicts_with = "bundle")] file: Option, + + /// Load a previously imported bundle by ID. #[arg(long, conflicts_with = "file")] bundle: Option, + + /// Compile only the bundle-local overlay instead of seed + overlay. #[arg(long, default_value_t = false)] overlay_only: bool, + + /// Include complete compiled edge records in JSON output. #[arg(long, default_value_t = false)] dump_edges: bool, + + /// Include source atlas-cell records in JSON output. #[arg(long, default_value_t = false)] dump_cells: bool, + + /// Include engine-resolved governed claim packets in JSON output. + #[arg(long, default_value_t = false)] + dump_claims: bool, + + /// Write JSON output to a file instead of stdout. #[arg(long)] out: Option, + + /// Write a Graphviz DOT projection of compiled atlas edges. #[arg(long)] dot_out: Option, } @@ -52,6 +69,8 @@ struct AtlasExport { edges: Option>, #[serde(skip_serializing_if = "Option::is_none")] cells: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + claims: Option>, } fn build_export( @@ -61,6 +80,7 @@ fn build_export( overlay_only: bool, dump_edges: bool, dump_cells: bool, + dump_claims: bool, ) -> Result { let atlas = CompiledAtlas::compile(registry).map_err(anyhow::Error::msg)?; let cells = registry.atlas_cells(); @@ -115,6 +135,7 @@ fn build_export( route_buckets, edges: dump_edges.then_some(atlas.edges), cells: dump_cells.then_some(cells), + claims: dump_claims.then_some(claims), }) } @@ -164,6 +185,7 @@ fn main() -> Result<()> { true, cli.dump_edges, cli.dump_cells, + cli.dump_claims, )? } else { build_export( @@ -173,6 +195,7 @@ fn main() -> Result<()> { false, cli.dump_edges, cli.dump_cells, + cli.dump_claims, )? } } else if let Some(bundle_id) = cli.bundle.as_deref() { @@ -186,6 +209,7 @@ fn main() -> Result<()> { true, cli.dump_edges, cli.dump_cells, + cli.dump_claims, )? } else { build_export( @@ -195,6 +219,7 @@ fn main() -> Result<()> { false, cli.dump_edges, cli.dump_cells, + cli.dump_claims, )? } } else { @@ -206,6 +231,7 @@ fn main() -> Result<()> { false, cli.dump_edges, cli.dump_cells, + cli.dump_claims, )? }; From bb31b30aaeeaa117d5988dd53a669f1a220df3a7 Mon Sep 17 00:00:00 2001 From: FreshSoftware4 <99464939+FreshSoftware4@users.noreply.github.com> Date: Tue, 21 Jul 2026 11:11:27 -0700 Subject: [PATCH 10/10] Test engine-resolved claim export --- l64-atlas-export/tests/cli.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/l64-atlas-export/tests/cli.rs b/l64-atlas-export/tests/cli.rs index 2cdee22..3b2f5c9 100644 --- a/l64-atlas-export/tests/cli.rs +++ b/l64-atlas-export/tests/cli.rs @@ -3,7 +3,7 @@ use std::process::Command; #[test] fn exports_seed_atlas_through_binary_surface() { let output = Command::new(env!("CARGO_BIN_EXE_l64-atlas-export")) - .args(["--dump-edges", "--dump-cells"]) + .args(["--dump-edges", "--dump-cells", "--dump-claims"]) .output() .expect("run l64-atlas-export"); assert!( @@ -25,4 +25,10 @@ fn exports_seed_atlas_through_binary_surface() { .as_u64() .map(|count| count as usize) ); + assert_eq!( + value["claims"].as_array().map(Vec::len), + value["claim_packet_count"] + .as_u64() + .map(|count| count as usize) + ); }