Skip to content

refactor(capco): #565 — split lattice.rs (5545 lines) into lattice/ module (≤800 each)#703

Merged
bashandbone merged 6 commits into
stagingfrom
worktree-565-lattice-split
May 22, 2026
Merged

refactor(capco): #565 — split lattice.rs (5545 lines) into lattice/ module (≤800 each)#703
bashandbone merged 6 commits into
stagingfrom
worktree-565-lattice-split

Conversation

@bashandbone
Copy link
Copy Markdown
Collaborator

@bashandbone bashandbone commented May 22, 2026

Summary

Closes #565. Structural-only refactor — splits crates/capco/src/lattice.rs (5545 lines, ~7× over Constitution coding-style §"File Organization" max of 800) into crates/capco/src/lattice/ (17 files, each ≤800 lines).

File layout (post-split, all ≤800 lines)

crates/capco/src/lattice/
├── mod.rs                 ~95 lines  — module doc + decls + re-exports
├── helpers.rs            ~290 lines  — HierarchicalTreeSet + comparators (pub(super))
├── test_support.rs        ~92 lines  — `#[cfg(test)] pub(crate)` fixtures
├── aea.rs                ~462 lines  — AeaPrimary + UcniKind + AeaSet
├── classification.rs     ~693 lines  — ClassificationLattice + 5 private helpers
├── declass_exemption.rs  ~129 lines  — DeclassExemptionAccumulator (projection, not lattice)
├── declassify_on.rs      ~123 lines  — DeclassifyOnLattice (MaxDate)
├── display_only.rs       ~525 lines  — DisplayOnlyBlock (Join-only)
├── dissem.rs             ~368 lines  — DissemSet (Join-only per #456 / PR #502)
├── fgi.rs                ~750 lines  — FgiSet (both impl blocks)
├── joint.rs              ~438 lines  — JointSet (Join-only, 4-variant state)
├── nato_class.rs         ~113 lines  — NatoClassLattice
├── nato_dissem.rs         ~93 lines  — NatoDissemSet
├── non_ic_dissem.rs      ~553 lines  — NonIcDissemSet (projection, not lattice)
├── rel_to.rs             ~304 lines  — RelToBlock (IntersectSet, 4-variant)
├── sar.rs                ~220 lines  — SarSet
└── sci.rs                ~625 lines  — SciSet + sci_controls_from_markings + SystemKey

Largest file: fgi.rs at ~750 lines. Line counts include round-1/2/3 reviewer fix-up edits.

Diff shape (post-round-3)

D	crates/capco/src/lattice.rs
A	crates/capco/src/lattice/{17 files}
M	crates/capco/src/render/{7 files}  (6 sort_smolstrs_by_sar path updates + 1 DeclassifyOnLattice path in round 2)
M	crates/capco/src/scheme/{4 files}  (path-reference updates added round 2)
M	crates/capco/tests/{6 files}       (path-reference updates added round 2)

1 D + 17 A + 17 M = 35 file ops total at HEAD = f8791d96. Six commits (recommend squash on merge).

Visibility / shared infrastructure

  • HierarchicalTreeSet<K> (shared by SciSet + SarSet) + its 10 inherent methods: pub(super) in helpers.
  • sort_smolstrs_by_sar, cmp_country_code_trigraph_first, sorted_compartment_items: pub(super) in helpers.
  • SystemKey (SCI-only): private to sci.rs.
  • 5 classification_* free helpers: private to classification.rs.
  • DISSEM_SUPERSESSION_TABLE static + apply_overlays method: private to dissem.rs (preserves the single-call-site convention enforced by module privacy).
  • 6 test fixtures (portion_us, portion_with_rel_to, portion_with_display_only, portion_with_dissem_us, mk_sci, mk_sar_portion): #[cfg(test)] pub(crate) in test_support.

Critical invariants verified preserved

  • DissemSet's manual impl Default (C-8 invariant — derive would silently regress relido_observed_unanimous). Travels atomically with DissemSet to dissem.rs.
  • FgiSet's two impl blocks (original L684-891 inherent + Join + Meet + L3414-3623 from_attrs_iter) — both land in fgi.rs.
  • #[non_exhaustive] carried on FgiSet, JointSet, RelToBlock, DisplayOnlyBlock.
  • #[cfg_attr(coverage_nightly, coverage(off))] replicated on every per-type #[cfg(test)] mod tests block.
  • 82 unit tests preserved verbatim across 6 per-type mod tests blocks. Round-2 added 1 regression test for the HierarchicalTreeSet::sorted_entries determinism fix; lib-test count: 354 → 355.

Reviewer panel (3 internal agents) + Copilot (3 rounds)

Internal agents:

  • Rust-specialist: APPROVE-WITH-FIXES (2 doc-link prose fixes applied in round 1).
  • General code reviewer: APPROVE-WITH-FIXES (1 stale cross-file reference applied in round 1).
  • Lattice-consultant: APPROVE (no fixes; algebraic-law invariants + citations + 82-test parity verified intact).

Copilot rounds:

  • Round 1 (6 comments): Stale Lattice::join / Lattice::meet doc references — pre-PR-feat(scheme): split Lattice into JoinSemilattice + MeetSemilattice halves (#456) #502 wording that's now misleading (Lattice/BoundedLattice became blanket-impl markers; methods live on JoinSemilattice / MeetSemilattice). Fixed 6 named sites + 1 adjacent site Copilot missed (joint.rs:45).
  • Round 2 (2 comments): (a) Substantive determinism bug in HierarchicalTreeSet::sorted_entries — comparator returns Equal for distinct outer keys when projection text collides; fixed with .then_with(|| a.0.cmp(b.0)) + regression test. (b) Stale crates/capco/src/lattice.rs prose references in non-test files — fixed 24 sites across 13 files (Copilot named 4 production files; sweep found 7 production + 6 test files).
  • Round 3 (4 comments): (a-c) CountryCode::USA constant usage instead of c.as_str() == "USA" / CountryCode::try_new(b"USA") patterns — fixed 5 production + 3 test sites (Copilot named 3 production). (d) PR description noted "6 render files" but round-2 added a 7th — this update.

Verification (final state at f8791d96)

cargo +stable check --workspace --all-targets
cargo +stable clippy --workspace --all-targets -- -D warnings   # catches stable-only lints
cargo +stable fmt --all -- --check
cargo test --workspace                              # 198 test binaries, zero failures
cargo test -p marque-capco --test lattice_static_assertions   # PR #502 trait-shape pin
cargo test -p marque-capco --test post_4b_lattice_inventory_pin  # 5/5
cargo +stable doc -p marque-capco --no-deps         # ZERO warnings in crates/capco/src/lattice/*.rs
cargo check -p marque-wasm --target wasm32-unknown-unknown   # Constitution III

All PASS.

Commit history (6 commits — recommend squash on merge)

  1. c5ff9572 — refactor: split lattice.rs into lattice/ module
  2. d2678def — chore: stage missed lattice.rs deletion (non-destructive fixup; the original commit created the new files + modified renders but the lattice.rs deletion was untracked locally and wasn't git rmed)
  3. 5f4a6391 — refactor: reviewer fixups (doc-link prose + cross-file ref)
  4. be936877 — refactor: round-1 Copilot — replace stale Lattice::join/meet doc refs
  5. e367a442 — refactor: round-2 Copilot — sorted_entries determinism + stale path refs
  6. f8791d96 — refactor: round-3 Copilot — CountryCode::USA constant + clippy::manual_contains fix

Test plan

  • cargo check --workspace --all-targets green
  • cargo test --workspace green (198 binaries pass, 0 fail)
  • cargo +stable clippy --workspace --all-targets -- -D warnings green
  • cargo +stable fmt --all -- --check green
  • lattice_static_assertions pin still compiles (PR feat(scheme): split Lattice into JoinSemilattice + MeetSemilattice halves (#456) #502 trait-shape preserved)
  • post_4b_lattice_inventory_pin (30 PageRewrites + 10 ClosureRules + 41 Constraints) all pass
  • All 17 lattice/ files ≤800 lines
  • External consumer paths byte-identical
  • Zero stale crates/capco/src/lattice.rs references in crates/capco/ post-fix
  • WASM target compiles
  • Determinism regression test added

🤖 Generated with Claude Code

@bashandbone bashandbone requested a review from a team as a code owner May 22, 2026 21:13
Copilot AI review requested due to automatic review settings May 22, 2026 21:13

This comment was marked as resolved.

bashandbone added a commit that referenced this pull request May 22, 2026
…/meet` doc refs

Copilot review on PR #703 flagged 6 inline comments — all on the same
theme: doc comments that refer to `Lattice::join` / `Lattice::meet`
as if they were methods. PR #502 / issue #456 split `Lattice` into
`JoinSemilattice + MeetSemilattice` halves; `Lattice` and `BoundedLattice`
became blanket-impl marker traits with no methods of their own. The
stale wording is pre-#502-era and was preserved verbatim across the
#565 split, so the misleading references propagated into the new
files.

Sites fixed:

- `mod.rs:9-15` — module-level header. Rewrote the "implement
  `[Lattice]`" claim to accurately describe the semilattice-trait
  surface and call out the PR #502 / issue #456 reality that
  `DissemSet` / `JointSet` / `DisplayOnlyBlock` are join-only and
  therefore do *not* satisfy `marque_scheme::Lattice` (which now
  requires both halves via blanket impl).
- `mod.rs:37`   — `Lattice::meet` → fully-qualified
  `[marque_scheme::MeetSemilattice::meet]` (trait isn't `use`'d at
  module level; FQ form is the only one rustdoc resolves cleanly).
- `aea.rs:462`  — `[Lattice::join]` / `[Lattice::meet]` →
  `[JoinSemilattice::join]` / `[MeetSemilattice::meet]`.
- `sci.rs:214`  — same fix.
- `sar.rs:110-111` — same fix.
- `fgi.rs:257`  — `Lattice::join operation` →
  `JoinSemilattice::join operation`.
- `joint.rs:45-47` — `Lattice::join` x2 + `Lattice` module-docs ref →
  `JoinSemilattice::join` x2 + `JoinSemilattice` module-docs ref.
  This 7th site was NOT in Copilot's 6 comments; caught by an
  adjacent-paths grep per the PM's "agents fix one site and miss
  the others" rule.

Verification:
- `cargo +stable check --workspace --all-targets`              PASS
- `cargo +stable clippy --workspace --all-targets -- -D warnings` PASS
- `cargo +stable fmt --all -- --check`                         PASS
- `cargo test --workspace`                                     PASS
  (198 test binaries, zero failures — identical to pre-Copilot)
- `cargo +stable doc -p marque-capco --no-deps`: 53 warnings
  total (one fewer than pre-Copilot's 54; the stale `Lattice::`
  refs weren't intra-doc links — `[Lattice::meet]` resolved to
  nothing visible at the module scope, so it had been silently
  rendered as plain code text. The FQ rewrites resolve cleanly.)
- ZERO doc warnings in any `crates/capco/src/lattice/*.rs` file.

No semantic changes. No new imports. No grep matches for
`Lattice::join` / `Lattice::meet` remain in
`crates/capco/src/lattice/` (verified post-edit).
@bashandbone
Copy link
Copy Markdown
Collaborator Author

Round 1 — addressed in be936877.

All 6 Copilot inline comments + 1 adjacent site Copilot didn't flag (joint.rs:45) — all the same defect: doc comments that reference Lattice::join / Lattice::meet as if they were methods, when PR #502 / issue #456 made Lattice (and BoundedLattice) blanket-impl marker traits with no methods. The join/meet operations live on JoinSemilattice / MeetSemilattice.

Sites updated:

  • mod.rs:9-15 — rewrote the "implement [Lattice]" claim to accurately describe the semilattice-trait surface; explicitly notes that DissemSet / JointSet / DisplayOnlyBlock are join-only and don't satisfy marque_scheme::Lattice (PR feat(scheme): split Lattice into JoinSemilattice + MeetSemilattice halves (#456) #502 / issue marque-scheme: split Lattice into JoinSemilattice+MeetSemilattice OR weaken DissemSet/JointSet trait impls #456).
  • mod.rs:37Lattice::meet[marque_scheme::MeetSemilattice::meet] (fully-qualified — the trait isn't use'd at module level so FQ is the only form rustdoc resolves).
  • aea.rs:462 / sci.rs:214 / sar.rs:110-111[Lattice::join] / [Lattice::meet][JoinSemilattice::join] / [MeetSemilattice::meet].
  • fgi.rs:257Lattice::join operationJoinSemilattice::join operation.
  • joint.rs:45-47Lattice::join (x2) + the "Lattice module-docs" reference → JoinSemilattice::join (x2) + JoinSemilattice module-docs ref. This 7th site was NOT in your inline comments — caught by grep -rn 'Lattice::' crates/capco/src/lattice/ per project policy on checking adjacent sites for the same defect class.

Verification post-fix:

  • cargo +stable check --workspace --all-targets PASS
  • cargo +stable clippy --workspace --all-targets -- -D warnings PASS
  • cargo +stable fmt --all -- --check PASS
  • cargo test --workspace PASS (198 binaries, zero failures)
  • cargo +stable doc -p marque-capco --no-deps: ZERO warnings in crates/capco/src/lattice/*.rs post-fix (down from the 4 pre-existing HierarchicalTreeSet private-link warnings the split inherited from the monolith, which were cleared in 5f4a6391).

No semantic changes; doc-comment text only.

This comment was marked as resolved.

bashandbone added a commit that referenced this pull request May 22, 2026
… stale path refs

Two issues from PR #703 Copilot round 2:

1. (Substantive) `helpers.rs:241` — `HierarchicalTreeSet::sorted_entries`
   could return `Equal` for distinct outer keys when the `key_text`
   projection collided. Concrete case: `SystemKey::Published(Si)` and
   `SystemKey::Custom("SI")` both project to the text `"SI"`. The
   comparator chain `sar_sort_key(ta).cmp(&sar_sort_key(tb))
   .then_with(|| ta.cmp(tb))` would return `Equal`, and `slice::sort_by`
   is unstable on `Equal` keys — output ordering of such pairs would be
   determined by the unstable-sort implementation, which Rust does not
   guarantee across versions.

   Fix: add a final `.then_with(|| a.0.cmp(b.0))` on the outer key
   itself, making the comparator a strict total order on the entry-
   pair domain. The `K: Ord` bound on the `impl<K> HierarchicalTreeSet<K>`
   block already permits this. WASM-size impact: negligible (one extra
   `.cmp()` call inside the existing closure body; the LTO+ICF
   monomorphization-collapse story from issue #689 is unaffected).

   Regression test added at `lattice/sci.rs::tests::
   sci_set_text_collision_between_published_and_custom_is_deterministic`
   — constructs both collision-prone SystemKey variants in a single
   SciSet, asserts deterministic ordering across both input orders.
   Updated doc comment on `sorted_entries` documents the third
   tie-breaker tier.

2. (Citation drift, expanded from earlier follow-up) Stale
   `crates/capco/src/lattice.rs` prose references in 11 production
   files + 13 test-file sites, all dead post-split. Per project memory
   `feedback_avoid_line_number_anchoring`, line-number anchors stripped
   in favor of symbolic names where possible. Files updated:

   Production (7 files, 11 sites):
   - `scheme/actions/fgi.rs:25` → `lattice/fgi.rs`
   - `scheme/mod.rs:114` (historical comment) → `lattice/`
   - `render/render_declassify.rs:16` → `lattice/declassify_on.rs`
   - `scheme/actions/intent.rs:281` (DISSEM_SUPERSESSION_TABLE) →
     symbolic name in `lattice/dissem.rs`; line-range anchor dropped
   - `scheme/actions/intent.rs:606` → `lattice/non_ic_dissem.rs`
   - `scheme/marking.rs:54,287` → `lattice/`
   - `scheme/constraints/categories.rs:97,115,133,162` (4 sites:
     SarSet / AeaSet / FgiSet / RelToBlock) → respective sub-files

   Test files (6 files, 13 sites):
   - `proptest_lattice.rs:366,513,530` → FgiSet/RelToBlock/DisplayOnlyBlock
     respective sub-files
   - `category_lattice_laws.rs:741,2701,2822` →
     classification/non_ic_dissem/display_only sub-files
   - `lattice_vs_scheme_parity.rs:2293` → non_ic_dissem
   - `r1_sort_byte_identity.rs:12,23,33` (3 sites incl. 2 line-anchored)
     → helpers.rs + display_only.rs + helpers.rs::HierarchicalTreeSet
     symbolic
   - `lattice_static_assertions.rs:54` → `lattice/`
   - `proptest_page_rollup.rs:248` → `lattice/`-level cfg-test mods

Out-of-scope intentionally NOT touched: `specs/006-engine-rule-refactor/
tasks.md` (historical task tracking, marked closed) and
`.claude/skills/marque-lattice-consultant/references/marque-applied.md`
(Claude-skill reference material outside the marque codebase).

Round 2's missed-by-Copilot adjacent sites that the
`grep -rn lattice.rs crates/capco/` sweep caught beyond Copilot's
4 named files: `scheme/mod.rs`, `scheme/marking.rs` (2 sites), and
the 13 test-file sites (Copilot mentioned "several tests" without
naming them — all 13 named and fixed here).

Verification:
- `cargo +stable check --workspace --all-targets`               PASS
- `cargo +stable clippy --workspace --all-targets -- -D warnings` PASS
- `cargo +stable fmt --all -- --check`                          PASS
- `cargo test --workspace`                                      PASS
  (198 binaries, zero failures; marque-capco lib up 354 → 355
  with new regression test)

`grep -rn 'lattice\.rs' crates/capco/` post-fix: only matches are
(a) `crates/capco/src/lattice/declass_exemption.rs:18` referencing
`crates/scheme/src/lattice.rs:55-64` (a different file — the
marque-scheme crate's lattice trait definitions, still exists), and
(b) `category_lattice_laws.rs:2369` which contains the string
`proptest_lattice.rs` (matches `lattice.rs` as substring; false
positive).
@bashandbone
Copy link
Copy Markdown
Collaborator Author

Round 2 — addressed in e367a442.

(1) Substantive: helpers.rs:241 non-determinism. Real bug. HierarchicalTreeSet::sorted_entries could return Equal for distinct outer keys when key_text(a.0) == key_text(b.0) — e.g. SystemKey::Published(Si) and SystemKey::Custom("SI") both project to "SI". Since slice::sort_by is unstable on Equal keys, output ordering of such pairs is implementation-defined and could shift across Rust versions.

Fix: added .then_with(|| a.0.cmp(b.0)) on the outer key itself, making the comparator a strict total order on the entry-pair domain. The K: Ord bound on the impl block already permits this. Negligible WASM-size impact (single extra .cmp() call inside the existing closure; the LTO+ICF monomorphization-collapse story from issue #689 is unaffected — same closure body, one extra chained method, still inline-only).

Regression test added at lattice/sci.rs::tests::sci_set_text_collision_between_published_and_custom_is_deterministic — constructs both collision-prone SystemKey variants in a single SciSet, asserts deterministic ordering across both input orders. marque-capco --lib test count now 354 → 355.

(2) Citation drift in non-test files. Expanded scope per the PM "walk adjacent code paths" rule.

You named 4 production files. Sweeping grep -rn 'lattice\.rs' crates/capco/ found:

  • 11 stale refs across 7 production files (your 4 + scheme/mod.rs + scheme/marking.rs x2)
  • 13 stale refs across 6 test files (you said "several tests" — naming and fixing all 13)

All 24 sites updated to point at the new crates/capco/src/lattice/<sub>.rs locations. Where the old reference carried a :LINE or :LINE-LINE anchor, the line numbers were dropped in favor of symbolic names (function / static / type names) per project memory feedback_avoid_line_number_anchoring. E.g.:

  • lattice.rs:2018-2032 (DISSEM_SUPERSESSION_TABLE) → lattice/dissem.rs + symbolic name in prose.
  • lattice.rs:3989 (DisplayOnlyBlock::to_vec) → lattice/display_only.rs.
  • lattice.rs:229 (HierarchicalTreeSet::sorted_entries) → lattice/helpers.rs::HierarchicalTreeSet::sorted_entries.

Out-of-scope, intentionally NOT touched:

  • specs/006-engine-rule-refactor/tasks.md — historical task tracking, marked closed. Path references document past state.
  • .claude/skills/marque-lattice-consultant/references/marque-applied.md — Claude-skill reference material outside the marque codebase proper.

Verification post-fix:

  • cargo +stable check --workspace --all-targets PASS
  • cargo +stable clippy --workspace --all-targets -- -D warnings PASS
  • cargo +stable fmt --all -- --check PASS
  • cargo test --workspace PASS (198 binaries, zero failures)
  • marque-capco --lib: 355 passing (was 354 — new regression test)
  • grep -rn 'lattice\.rs' crates/capco/ post-fix returns only the scheme/src/lattice.rs references (different file, still exists) and one false-positive substring match. Zero stale crates/capco/src/lattice.rs references remain.

@bashandbone bashandbone linked an issue May 22, 2026 that may be closed by this pull request
@bashandbone bashandbone added the EPIC-Lattice Addressed by Epic for lattice refactor (5-2-26 plan) label May 22, 2026
@bashandbone bashandbone requested a review from Copilot May 22, 2026 22:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 35 out of 36 changed files in this pull request and generated 4 comments.

Comment thread crates/capco/src/lattice/fgi.rs Outdated
Comment on lines +342 to +344
let usa = CountryCode::try_new(b"USA");
for c in j.countries.iter() {
if Some(*c) != usa {
Comment thread crates/capco/src/lattice/joint.rs Outdated
// Authority: §H.3 p56 (JOINT grammar requires non-empty
// `[LIST]` AND USA in the producer list). Verified
// 2026-05-16 against CAPCO-2016.md.
let has_usa = |j: &JointClassification| j.countries.iter().any(|c| c.as_str() == "USA");
Comment thread crates/capco/src/lattice/joint.rs Outdated
let mut union_non_us: BTreeSet<CountryCode> = BTreeSet::new();
for j in &joint_portions {
for c in j.countries.iter() {
if c.as_str() != "USA" {
Comment on lines 13 to 17
//! - CAPCO-2016 §E.3 (Multiple Sources and the Declassify On Line
//! Hierarchy) — only one value per CAB. When multiple sources
//! contribute, use the longest-duration value. The lattice form
//! `DeclassifyOnLattice` (in `crates/capco/src/lattice.rs`)
//! `DeclassifyOnLattice` (in `crates/capco/src/lattice/declassify_on.rs`)
//! composes per-portion values via the `MaxDate` projection
@bashandbone
Copy link
Copy Markdown
Collaborator Author

Round 3 — addressed in f8791d96.

(1-3) CountryCode::USA constant usage. Accepted. All 3 named sites + 2 adjacent sites you didn't flag (joint.rs:373 and joint.rs:405 — same pattern, both also reachable from the JointSet::join impl) + 3 test-code sites for consistency. Sweep used grep -rn '"USA"' crates/capco/src/lattice/ to confirm zero remaining sites.

The Some(*c) != usa pattern in fgi.rs:344 was the most defensible to fix beyond style — your soundness note is correct: if CountryCode::try_new ever returned None, the check would silently treat every country as non-USA. The CountryCode::USA constant is compile-time-validated and sidesteps that.

One bonus catch: the converted joint.rs:177 j.countries.iter().any(|c| *c == CountryCode::USA) form triggered clippy::manual_contains on stable (-D warnings). Switched to j.countries.contains(&CountryCode::USA). The lint doesn't fire on local nightly per project memory feedback_clippy_nightly_vs_stable_drift — caught only by cargo +stable clippy before push. Would have been CI red.

All 8 sites updated (5 production + 3 test). grep -rn 'as_str() [!=]= "USA"\|try_new(b"USA")' crates/capco/src/lattice/ returns zero matches.

(4) PR description accuracy on render-file count. Accepted. The round-1 commit (c5ff9572) modified 6 render files (sort_smolstrs_by_sar path updates: render/mod.rs, render_aea.rs, render_dissem.rs, render_non_ic_dissem.rs, render_sar.rs, render_sci.rs). Round-2 (e367a442) added render_declassify.rs (the DeclassifyOnLattice reference), bringing the total to 7. PR description updated with the corrected diff-shape inventory.

Verification post-fix:

  • cargo +stable check --workspace --all-targets PASS
  • cargo +stable clippy --workspace --all-targets -- -D warnings PASS (manual_contains lint cleared)
  • cargo +stable fmt --all -- --check PASS
  • cargo test --workspace PASS (198 binaries, zero failures; lib still 355)

…odule (17 files, each ≤800)

Purely structural refactor — zero semantic changes. Every byte of behavior
preserved. The public API surface at `marque_capco::lattice::*` is byte-
identical (16 types + 1 free fn).

File layout (post-split):

  lattice/mod.rs                88 lines  — module doc + mod decls + re-exports
  lattice/test_support.rs       92        — shared `#[cfg(test)] pub(crate)` fixtures
  lattice/nato_dissem.rs        93
  lattice/nato_class.rs        113
  lattice/declassify_on.rs     123
  lattice/declass_exemption.rs 129
  lattice/sar.rs               219
  lattice/helpers.rs           281        — `HierarchicalTreeSet<K>` + comparators
  lattice/rel_to.rs            304
  lattice/dissem.rs            368        — Join-only per #456 / PR #502
  lattice/joint.rs             438        — Join-only per #456 / PR #502
  lattice/aea.rs               462
  lattice/display_only.rs      526        — Join-only
  lattice/non_ic_dissem.rs     553        — projection helper (not a Lattice)
  lattice/sci.rs               588        — incl. `sci_controls_from_markings`
  lattice/classification.rs    693
  lattice/fgi.rs               752

Each lattice-type submodule owns its type definition, inherent impls,
trait impls (JoinSemilattice / MeetSemilattice / BoundedJoin* /
BoundedMeet* as applicable), and per-type `#[cfg(test)] mod tests`.
Cross-submodule test fixtures (`portion_us`, `portion_with_rel_to`,
`portion_with_display_only`, `portion_with_dissem_us`, `mk_sci`,
`mk_sar_portion`) live in `test_support` and are `pub(crate)`-scoped.

Shared infrastructure visibility:
- `HierarchicalTreeSet<K>` + its 10 inherent methods: `pub(super)`
  in `helpers`, consumed by `sci` and `sar`.
- `sort_smolstrs_by_sar`, `cmp_country_code_trigraph_first`,
  `sorted_compartment_items`: `pub(super)` in `helpers`.
- `SystemKey` (SCI-only): private in `sci`.
- `classification_*` free helpers (5 fns): private in `classification`.
- `DISSEM_SUPERSESSION_TABLE` static + `apply_overlays` method:
  private in `dissem`.

Render-module doc-comment references updated from
`crate::lattice::sort_smolstrs_by_sar` to
`crate::lattice::helpers::sort_smolstrs_by_sar`
across 6 files (render_aea, render_dissem, render_non_ic_dissem,
render_sar, render_sci, render/mod). Bare-name "`sort_smolstrs_by_sar`"
references in prose left as-is (no path prefix to update).

Intra-doc links inside SciSet / SarSet method docs retargeted from
`[\`HierarchicalTreeSet::join_with\`]` to
`[\`super::helpers::HierarchicalTreeSet::join_with\`]` (and `::meet_with`).
The 4 "public documentation for `join`/`meet` links to private item"
rustdoc warnings are byte-identical in count to baseline — the original
file emitted the same 4 warnings (verified via git stash) since
`HierarchicalTreeSet` was always private.

External consumers (`marque_capco::lattice::*` paths in `crates/scheme/`,
`crates/capco/src/scheme/`, `crates/capco/src/rules.rs`, `marque/`,
`crates/capco/tests/`) require no edits — the public re-exports in
`lattice/mod.rs` preserve the same surface lib.rs already exposes.

Verification:
- `cargo check --workspace --all-targets`         PASS
- `cargo test --workspace`                        PASS (zero failures)
- `cargo test -p marque-capco --test lattice_static_assertions
  --test post_4b_lattice_inventory_pin`           PASS (#565-cited pins)
- `cargo +stable clippy --workspace --all-targets -- -D warnings`  PASS
- `cargo +stable fmt --all -- --check`            PASS
- `cargo check -p marque-wasm --target wasm32-unknown-unknown`     PASS
  (Constitution III WASM-safe property preserved)
- File size cap: largest is fgi.rs at 752 lines (≤800)
- Diff shape: 1 D + 17 A + 6 M (verified via `git diff --name-status
  origin/staging...HEAD`)

No new dependencies. No `Cargo.toml` edits. No rule logic touched.
No engine-crate touch. Constitution VII scheme-adoption boundary
observed for the split — `marque-capco` is the only crate edited.
The implementation commit c5ff957 created the 17 new files under
`crates/capco/src/lattice/` and modified 6 `render/*` doc-comments but
did not stage the `crates/capco/src/lattice.rs` deletion. The local
worktree had the file removed on disk (untracked), which let
`cargo check` pass locally — but the pushed commit still carries the
old file alongside the new directory, which is a Rust module-ambiguity
error (`pub mod lattice;` in `lib.rs:58` cannot resolve when both
`lattice.rs` and `lattice/mod.rs` exist).

Stages the deletion as a non-destructive follow-up commit rather than
amending + force-pushing the prior commit, per project memory on
sub-agent force-push authorization discipline.

Verification:
- `cargo check --workspace --all-targets`  PASS
- File tree now contains only `crates/capco/src/lattice/*.rs`
  (17 files); `crates/capco/src/lattice.rs` is gone.
…ref)

Three small fixes from the 3-reviewer panel on the lattice split:

1. crates/capco/src/lattice/sar.rs:87,97 — replaced two
   `[`super::helpers::HierarchicalTreeSet::join_with`]` /
   `[::meet_with]` intra-doc links with prose. `HierarchicalTreeSet`
   is `pub(super)` and therefore not a valid public doc-link target;
   the bracketed form fired `rustdoc::broken_intra_doc_links`. Prose
   form: "Delegates to the internal `HierarchicalTreeSet::join_with`
   method in `super::helpers`."

2. crates/capco/src/lattice/sci.rs:181,199 — same fix at the two
   analogous SciSet sites.

3. crates/capco/src/lattice/nato_dissem.rs:35 — replaced the stale
   cross-file reference "See DissemSet doc above for rationale."
   (which was coherent in the monolith where DissemSet was defined
   ~300 lines above NatoDissemSet) with an explicit intra-doc link
   to `[`super::dissem::DissemSet`]` that resolves correctly post-
   split.

Reviewers + verdicts:
- Rust-specialist:    APPROVE-WITH-FIXES (#1, #2 above; one MEDIUM
  `test_support` cfg-gate finding was incorrect — gate is present at
  `mod.rs:57` ahead of the `pub(crate) mod test_support;` line)
- General reviewer:   APPROVE-WITH-FIXES (#3 above; plus a non-
  blocking follow-up note about stale `lattice.rs:NNNN` line-number
  anchors in 6 integration-test prose comments — out of scope; will
  file as separate tracking issue)
- Lattice-consultant: APPROVE (no fixes required; all algebraic-law
  invariants, citations, and 82-test parity verified intact)

Verification post-fix:
- `cargo +stable check --workspace --all-targets`              PASS
- `cargo +stable clippy --workspace --all-targets -- -D warnings` PASS
- `cargo +stable fmt --all -- --check`                         PASS
- `cargo test --workspace`                                     PASS
  (198 test binaries, zero failures)
- `cargo +stable doc -p marque-capco --no-deps`: 54 warnings
  (down from 59 pre-fix — the 4 new HierarchicalTreeSet intra-doc
  warnings are gone; all 54 remaining are pre-existing, none in
  `crates/capco/src/lattice/`)
…/meet` doc refs

Copilot review on PR #703 flagged 6 inline comments — all on the same
theme: doc comments that refer to `Lattice::join` / `Lattice::meet`
as if they were methods. PR #502 / issue #456 split `Lattice` into
`JoinSemilattice + MeetSemilattice` halves; `Lattice` and `BoundedLattice`
became blanket-impl marker traits with no methods of their own. The
stale wording is pre-#502-era and was preserved verbatim across the
#565 split, so the misleading references propagated into the new
files.

Sites fixed:

- `mod.rs:9-15` — module-level header. Rewrote the "implement
  `[Lattice]`" claim to accurately describe the semilattice-trait
  surface and call out the PR #502 / issue #456 reality that
  `DissemSet` / `JointSet` / `DisplayOnlyBlock` are join-only and
  therefore do *not* satisfy `marque_scheme::Lattice` (which now
  requires both halves via blanket impl).
- `mod.rs:37`   — `Lattice::meet` → fully-qualified
  `[marque_scheme::MeetSemilattice::meet]` (trait isn't `use`'d at
  module level; FQ form is the only one rustdoc resolves cleanly).
- `aea.rs:462`  — `[Lattice::join]` / `[Lattice::meet]` →
  `[JoinSemilattice::join]` / `[MeetSemilattice::meet]`.
- `sci.rs:214`  — same fix.
- `sar.rs:110-111` — same fix.
- `fgi.rs:257`  — `Lattice::join operation` →
  `JoinSemilattice::join operation`.
- `joint.rs:45-47` — `Lattice::join` x2 + `Lattice` module-docs ref →
  `JoinSemilattice::join` x2 + `JoinSemilattice` module-docs ref.
  This 7th site was NOT in Copilot's 6 comments; caught by an
  adjacent-paths grep per the PM's "agents fix one site and miss
  the others" rule.

Verification:
- `cargo +stable check --workspace --all-targets`              PASS
- `cargo +stable clippy --workspace --all-targets -- -D warnings` PASS
- `cargo +stable fmt --all -- --check`                         PASS
- `cargo test --workspace`                                     PASS
  (198 test binaries, zero failures — identical to pre-Copilot)
- `cargo +stable doc -p marque-capco --no-deps`: 53 warnings
  total (one fewer than pre-Copilot's 54; the stale `Lattice::`
  refs weren't intra-doc links — `[Lattice::meet]` resolved to
  nothing visible at the module scope, so it had been silently
  rendered as plain code text. The FQ rewrites resolve cleanly.)
- ZERO doc warnings in any `crates/capco/src/lattice/*.rs` file.

No semantic changes. No new imports. No grep matches for
`Lattice::join` / `Lattice::meet` remain in
`crates/capco/src/lattice/` (verified post-edit).
… stale path refs

Two issues from PR #703 Copilot round 2:

1. (Substantive) `helpers.rs:241` — `HierarchicalTreeSet::sorted_entries`
   could return `Equal` for distinct outer keys when the `key_text`
   projection collided. Concrete case: `SystemKey::Published(Si)` and
   `SystemKey::Custom("SI")` both project to the text `"SI"`. The
   comparator chain `sar_sort_key(ta).cmp(&sar_sort_key(tb))
   .then_with(|| ta.cmp(tb))` would return `Equal`, and `slice::sort_by`
   is unstable on `Equal` keys — output ordering of such pairs would be
   determined by the unstable-sort implementation, which Rust does not
   guarantee across versions.

   Fix: add a final `.then_with(|| a.0.cmp(b.0))` on the outer key
   itself, making the comparator a strict total order on the entry-
   pair domain. The `K: Ord` bound on the `impl<K> HierarchicalTreeSet<K>`
   block already permits this. WASM-size impact: negligible (one extra
   `.cmp()` call inside the existing closure body; the LTO+ICF
   monomorphization-collapse story from issue #689 is unaffected).

   Regression test added at `lattice/sci.rs::tests::
   sci_set_text_collision_between_published_and_custom_is_deterministic`
   — constructs both collision-prone SystemKey variants in a single
   SciSet, asserts deterministic ordering across both input orders.
   Updated doc comment on `sorted_entries` documents the third
   tie-breaker tier.

2. (Citation drift, expanded from earlier follow-up) Stale
   `crates/capco/src/lattice.rs` prose references in 11 production
   files + 13 test-file sites, all dead post-split. Per project memory
   `feedback_avoid_line_number_anchoring`, line-number anchors stripped
   in favor of symbolic names where possible. Files updated:

   Production (7 files, 11 sites):
   - `scheme/actions/fgi.rs:25` → `lattice/fgi.rs`
   - `scheme/mod.rs:114` (historical comment) → `lattice/`
   - `render/render_declassify.rs:16` → `lattice/declassify_on.rs`
   - `scheme/actions/intent.rs:281` (DISSEM_SUPERSESSION_TABLE) →
     symbolic name in `lattice/dissem.rs`; line-range anchor dropped
   - `scheme/actions/intent.rs:606` → `lattice/non_ic_dissem.rs`
   - `scheme/marking.rs:54,287` → `lattice/`
   - `scheme/constraints/categories.rs:97,115,133,162` (4 sites:
     SarSet / AeaSet / FgiSet / RelToBlock) → respective sub-files

   Test files (6 files, 13 sites):
   - `proptest_lattice.rs:366,513,530` → FgiSet/RelToBlock/DisplayOnlyBlock
     respective sub-files
   - `category_lattice_laws.rs:741,2701,2822` →
     classification/non_ic_dissem/display_only sub-files
   - `lattice_vs_scheme_parity.rs:2293` → non_ic_dissem
   - `r1_sort_byte_identity.rs:12,23,33` (3 sites incl. 2 line-anchored)
     → helpers.rs + display_only.rs + helpers.rs::HierarchicalTreeSet
     symbolic
   - `lattice_static_assertions.rs:54` → `lattice/`
   - `proptest_page_rollup.rs:248` → `lattice/`-level cfg-test mods

Out-of-scope intentionally NOT touched: `specs/006-engine-rule-refactor/
tasks.md` (historical task tracking, marked closed) and
`.claude/skills/marque-lattice-consultant/references/marque-applied.md`
(Claude-skill reference material outside the marque codebase).

Round 2's missed-by-Copilot adjacent sites that the
`grep -rn lattice.rs crates/capco/` sweep caught beyond Copilot's
4 named files: `scheme/mod.rs`, `scheme/marking.rs` (2 sites), and
the 13 test-file sites (Copilot mentioned "several tests" without
naming them — all 13 named and fixed here).

Verification:
- `cargo +stable check --workspace --all-targets`               PASS
- `cargo +stable clippy --workspace --all-targets -- -D warnings` PASS
- `cargo +stable fmt --all -- --check`                          PASS
- `cargo test --workspace`                                      PASS
  (198 binaries, zero failures; marque-capco lib up 354 → 355
  with new regression test)

`grep -rn 'lattice\.rs' crates/capco/` post-fix: only matches are
(a) `crates/capco/src/lattice/declass_exemption.rs:18` referencing
`crates/scheme/src/lattice.rs:55-64` (a different file — the
marque-scheme crate's lattice trait definitions, still exists), and
(b) `category_lattice_laws.rs:2369` which contains the string
`proptest_lattice.rs` (matches `lattice.rs` as substring; false
positive).
…clippy::manual_contains fix

Copilot round 3 flagged 3 sites coupling to the textual form of the
USA trigraph (`c.as_str() == "USA"` / `Some(*c) != CountryCode::try_new(b"USA")`)
and pointed out that `CountryCode::USA` (a `pub const Self = match try_new(b"USA") {…}`
at `crates/ism/src/attrs.rs:1515`) is the idiomatic accessor. Soundness
note on the `try_new` form: if validation ever returns `None`, the
`Some(*c) != usa` check silently treats every country as non-USA;
the compile-time-validated constant sidesteps that.

Per the "walk adjacent code paths" PM rule, the sweep
`grep -rn '"USA"' crates/capco/src/lattice/` found 5 production sites
+ 3 test-code sites — Copilot named 3 production sites; I fixed all 5
production sites and the 3 test sites for consistency. Production:
- `fgi.rs:340-348` (Joint branch): dropped the `let usa = try_new(b"USA")`
  binding entirely; compare via `*c != CountryCode::USA`.
- `joint.rs:177` (`has_usa` lambda): converted to
  `j.countries.contains(&CountryCode::USA)` — this satisfied the
  `clippy::manual_contains` lint, which fires on stable but not
  nightly per project memory `feedback_clippy_nightly_vs_stable_drift`.
  Caught by `cargo +stable clippy` pre-push; would have been a CI
  red.
- `joint.rs:250` (DisunityCollapse non-US union): `*c != CountryCode::USA`.
- `joint.rs:373` (UnanimousProducers→Disunity transition): same.
- `joint.rs:405` (DisunityCollapse + UnanimousProducers merge): same.

Test sites:
- `fgi.rs:710-723` (joint exclusion test): replaced two
  `try_new(b"USA").unwrap()` constructions with `CountryCode::USA`.
- `display_only.rs:430` (USA-not-in-DO assertion): same.

All sites pre-existed on `origin/staging` — verified via
`git show origin/staging:crates/capco/src/lattice.rs | grep '"USA"'`
matching the new lattice/* surface line-for-line. Not regressed by
the split; rather the split surfaced them in smaller files where
the consistency gap becomes more obvious.

PR description also updated: the round-2 commit (e367a44) modified
`render/render_declassify.rs` (the `DeclassifyOnLattice` path
reference), bringing the render-module touch total from 6 to 7
files. PR body's diff-shape inventory revised accordingly.

Verification:
- `cargo +stable check --workspace --all-targets`               PASS
- `cargo +stable clippy --workspace --all-targets -- -D warnings` PASS
  (catches the `manual_contains` lint that nightly didn't)
- `cargo +stable fmt --all -- --check`                          PASS
- `cargo test --workspace`                                      PASS
  (198 binaries, zero failures; marque-capco lib still 355)
- `grep -rn 'as_str() [!=]= "USA"\|try_new(b"USA")' crates/capco/src/lattice/`
  returns ZERO matches — full coverage.
@bashandbone bashandbone force-pushed the worktree-565-lattice-split branch from f8791d9 to 0cdd68e Compare May 22, 2026 22:48
@bashandbone bashandbone merged commit f3ed334 into staging May 22, 2026
24 of 25 checks passed
@bashandbone bashandbone deleted the worktree-565-lattice-split branch May 22, 2026 22:52
bashandbone added a commit that referenced this pull request May 24, 2026
…odule (≤800 each) (#703)

FIXES (#1, #2 above; one MEDIUM
FIXES (#3 above; plus a non-
bashandbone added a commit that referenced this pull request May 24, 2026
…odule (≤800 each) (#703)

FIXES (#1, #2 above; one MEDIUM
FIXES (#3 above; plus a non-
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

EPIC-Lattice Addressed by Epic for lattice refactor (5-2-26 plan)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor: Split crates/capco/src/lattice.rs (5295 lines → ≤800)

2 participants