feat(bert-core): kernel projection + mode ladder (bert#88 Parts 1-3)#92
Conversation
Re-found the data model on the K≅2 kernel. Three additive pieces: - WorldModel::kernel() projects the kernel (things, dep), mirroring Lean Kernel.toKlir — pure, derived, never stored. - Mode field (Core/Structural/Operational/Full). Absent ≡ Full, so pre-v2.0 files deserialize and re-serialize byte-identical; the save path emits no `mode` key. - validate_mode(model, target) gates *entry* into a view by its own precondition: Structural=HasBond (Bunge Def 1.1), Operational= irreflexivity / no self-loop (Mobus §4.3, the one new rule), Full=dynamical face (warns, since Full is the default view). Modes are parallel lenses over one kernel, not a cumulative tower: Structural and Operational impose independent preconditions and share only Core's on-ness, matching ViewGeneration.lean's parallel toBunge/toMobus. validate() is untouched (zero breakage for existing callers). Round-trip + mode-boundary regression tests green. Out of scope, filed separately: presentation/semantic split (A6.2), typing the dynamical face (A6.3), mode-transition UI (§A5), GSR cross-substrate agreement test, Cybernetic mode. Refs bert#88; proof in systems-science-foundations ViewGeneration.lean 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Code ReviewOverview: Additive PR (413 lines, 0 deletions) that realizes the K≅2 kernel spec in Rust across three pieces: Strengths
Issues1.
|
- Compare Id directly with ==/!= in check_bond/check_self_loops instead of round-tripping through serialize_id (Id: Eq) — faster and clearer. - kernel() now includes the environment node in `things`, matching the endpoint set check_interaction_references accepts; the Core on-ness rule and the projection now agree by construction. - check_dynamical_face warns once at model level (no system has a face) rather than per leaf subsystem — same signal, far less noise. - is_system: note it must track IdType; tighten the read-only test comment (the immutable borrow is the guarantee, the test pins it). cargo test -p bert-core → 27 pass.
|
Addressed the review in a4a3f31:
27 tests still pass; clippy |
Code Review: feat(bert-core): kernel projection + mode ladder (bert#88 Parts 1-3)OverviewThis PR introduces three additive pieces atop the Potential Bug:
|
- is_system: exhaustive IdType match, so a new variant is a compile error rather than a silent misclassification. - interface_mediated_bond_enters_structural: guards the invariant that source/sink carry the *systems* and interfaces live in source_interface/sink_interface — verified across every example model, so check_bond is not fooled by interface-mediated bonds. - kernel_includes_environment_externals: exercises the env source/sink branch of kernel() that no prior test covered. cargo test -p bert-core → 29 pass.
|
Round 2 addressed in latest push:
29 tests pass; clippy |
Code Review —
|
…el single-pass - Mode: derive Hash (Copy+Eq without Hash blocks HashMap/HashSet keys; Wednesday's mode matrix may key by Mode — avoid a later breaking change). - empty_dynamical_face_warns_in_full_mode: covers the warning path check_dynamical_face emits (previously only the no-error path was tested). - kernel(): single pass over systems (was two); environment node first. Behavior-equivalent (things is a bag, order unspecified). - Document dep as a multiset — BERT is a multigraph, parallel edges are kept. - .expect() over .unwrap() on the examples read_dir for a clearer failure. cargo test -p bert-core → 30 pass.
|
Round 3 addressed:
30 tests pass; clippy |
Code Review — feat(bert-core): kernel projection + mode ladder (bert#88 Parts 1–3)Overall this is a well-scoped, thoughtful PR. The design decisions are clearly articulated and match the systems-science intent. Below are specific findings ordered by severity. Issues worth discussing1.
Consider accepting a pre-computed result or splitting into two functions: pub fn validate_mode_from(base: ValidationResult, model: &WorldModel, target: Mode) -> ValidationResult
pub fn validate_mode(model: &WorldModel, target: Mode) -> ValidationResult {
validate_mode_from(validate(model), model, target)
}This keeps the ergonomic single-call API while letting callers amortize the base scan. Out-of-scope if the UI won't hot-path this, but worth noting. 2.
pub mode: Option<Mode>,The doc comment says "Read it through Options: 3. The
But the inverse — a duplicate ID from two systems colliding — is only prevented if the caller ran /// Duplicates are possible when the model has not been validated; call [`validate`] first
/// or dedup at the consumer if set semantics are needed.
pub things: Vec<Id>,Minor observations4.
5. If 6.
What's done well
Out-of-scope noteThe PR description notes 🤖 Generated with Claude Code |
|
Round 4 triaged — merging.
Everything actionable is resolved or filed (#93, #94, #95, #96, #97). 30 tests pass, clippy clean except pre-existing #94. Thanks for the reviews — rounds 1 and 3 caught real things. |
What
The implementation half of bert#88 — re-founds the data model on the K≅2 kernel. The proof (
ViewGeneration.lean, 6/11) and spec (system-language-spec-v2-addendum.md, 6/11) are now realized in Rust. Part 0 (thefeature/bert-coremerge) landed in #90; this is Parts 1–3.Three additive pieces:
WorldModel::kernel()— projects the kernel(things, dep), the Rust twin of LeanKernel.toKlir. Pure, derived, never stored (the cheap path the spec left open in A6.1).Modefield (Core/Structural/Operational/Full) — absent ≡Full, so pre-v2.0 files deserialize and re-serialize byte-identical; the save path emits nomodekey. Read viaWorldModel::mode().validate_mode(model, target)— a mode-entry gate. Each view checks its own precondition:Structural= a bond between distinct components (Bunge Def 1.1),Operational= no self-loop (Mobus §4.3, the one new rule),Full= dynamical face (warns, since Full is the default view).Design notes
Structural(Bunge/HasBond) andOperational(Mobus/Irreflexive) impose independent preconditions and share onlyCore's on-ness — matching the paralleltoBunge/toMobusprojections in the proof. A single-component model with external flows is a valid Operational/Full model but legitimately not Structural.validate()is untouched and stays universal (orphans/dangling-refs/duplicates are errors in every mode) → zero breakage for existing callers (BERT app, bert-typedb, GSR).validate_modeborrows immutably, so a lens-switching UI can ask "can this enter Operational?" as a pure query.Scope
+413 / −0, additive across 5 files. No struct rewrites, no migration, no storage change.Out of scope (to be filed): presentation/semantic split (A6.2), typing the dynamical face (A6.3), mode-transition UI + §3.8 loss warnings (§A5, Wednesday's lenses prototype), GSR cross-substrate agreement test, Cybernetic mode.
Tests
cargo test -p bert-core→ 27 pass. New: mode-boundary fixtures (aggregate passes Core / fails Structural; self-loop passes Structural / fails Operational; independent-lenses), byte-stability, all example models enter Full, kernel projection, read-only round-trip invariant.Notes for reviewer
bert-core,bert,bert-composeallcargo checkclean.bert-tauri/bert-typedbfail to compile on a clean checkout due to the pre-existing parked typedb-driver 3.11.5 WIP (unrelated to this PR).items_after_test_moduleatlib.rs:1844(surfaces only under--all-targets) is untouched by this PR.Refs bert#88 · proof:
systems-science-foundations/Systems/Klir/ViewGeneration.lean🤖 Generated with Claude Code