Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/tally/compatibility/compatibility-matrix.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"schema_version": 1,
"bridge_commit_sha": "be1c20cc3fd66fa1ece196505c69f26e555e4b8e",
"compatibility_surface_sha256": "632ae96b7599ff062311687f9188c8001ec53b655c07cf7986be878f419e7781",
"compatibility_surface_sha256": "4dc0c7118372a4bc4a6b3b58346b0b113ce4b6bb07a154f208546f6cd43757a8",
"claims": [
{
"claim_id": "erp9-6-6-3-windows-education-xml-one-company",
Expand Down
60 changes: 58 additions & 2 deletions docs/tally/compatibility/compatibility-surface.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@
"path": "src-tauri/crates/bridge-tally-protocol/src/bills_payments_observation.rs",
"sha256": "070bae560982c3f9553c2cacfffe83a7debe0415688c43bb1b77befac0cec648"
},
{
"path": "src-tauri/crates/bridge-tally-protocol/src/group_ancestry.rs",
"sha256": "877f9a70d0192f53650621aa0ccded00b9cab30af635cf59b4ba7ec6de46f0a6"
},
{
"path": "src-tauri/crates/bridge-tally-protocol/src/lib.rs",
"sha256": "449dfdf499a818a571289e2fb05a77feb5ac926265dbef807b7d0d5a2bf39853"
Expand Down Expand Up @@ -337,18 +341,46 @@
"path": "src-tauri/src/agent_catalog.rs",
"sha256": "55632c680704c2784545e422cf6847b81d2423191d651a0119d45188d9bf2671"
},
{
"path": "src-tauri/src/agent_company.rs",
"sha256": "c719ff31cb8e14959dcaecd851156356cc7e38fe50a07aaf0dd339cfd78641dc"
},
{
"path": "src-tauri/src/agent_delivery.rs",
"sha256": "631ec5ea5a1caf06f1ad171dc719546107a52917ba4d15a94eddcec731229248"
},
{
"path": "src-tauri/src/agent_desktop_journal.rs",
"sha256": "9922e27217b13f1834c2cd40e5f99a9ada32eae1be180dd46dd4ba209bb41ae6"
},
{
"path": "src-tauri/src/agent_egress.rs",
"sha256": "4f2393e288858468c53ac02d35c1b2ef8aa4b239d6cf0b26038845f9f2e9783c"
},
{
"path": "src-tauri/src/agent_import.rs",
"sha256": "0259e8828d9c6bea10dd98f523e7c982137eed5354097efd5b866475d703f74e"
},
{
"path": "src-tauri/src/agent_import_cash_bank.rs",
"sha256": "9085893b9204cdb42647340eba8bde77c9fc691f6a4fa1562572d980fe791437"
},
{
"path": "src-tauri/src/agent_import_identity.rs",
"sha256": "124fbf3d2d255523ce9fc9dbf32502eb3c8dd013c9dd2a7b206eafd966611d89"
},
{
"path": "src-tauri/src/agent_import_ledger.rs",
"sha256": "cf5a4aa896afcc358876c58305dffdfa7fdbc618b77cce3e0775e007666f40f0"
},
{
"path": "src-tauri/src/agent_import_persistence.rs",
"sha256": "50fdab872d872759fe4b093c67f4b120f8eac4060fc501cefd39d70b097581d4"
},
{
"path": "src-tauri/src/agent_import_post.rs",
"sha256": "f23d9b2c535a8dea5a2bdcc41e2852a1994562aeda1bb7338b3ce47f7e3d4541"
},
{
"path": "src-tauri/src/agent_ledgers.rs",
"sha256": "a891e4ac51addc9dc17ae28ce4634bd2cfeb8f3f0df78e072290771d29a3131b"
Expand All @@ -361,6 +393,10 @@
"path": "src-tauri/src/agent_presence_tests.rs",
"sha256": "11d35d8a5dd60178f02d070c8b33f9b2c1cf44cb7cf5517eac11430f2aa74796"
},
{
"path": "src-tauri/src/agent_protocol.rs",
"sha256": "74245b53df856003283df6c59fbe70afae47d43914d89148cbc49cbd3edb6e3c"
},
{
"path": "src-tauri/src/agent_read_profiles.rs",
"sha256": "f6f07dbcbce22498e4e4e6244cfd19b12bc017749ed9f0a45274f9354e2dba51"
Expand Down Expand Up @@ -397,6 +433,10 @@
"path": "src-tauri/src/agent_vouchers.rs",
"sha256": "721cc3958ddb165da160255aa236c13b1581fcba477382eed5b51e2dff81a9c6"
},
{
"path": "src-tauri/src/axal.rs",
"sha256": "f8b38bd5b1f88b809bd9656ebde8093813c95b7ea7354ec4a5478c75f1f91985"
},
{
"path": "src-tauri/src/commands.rs",
"sha256": "ab5e6dbaf387a239ac20fa7cdeec0785060ca7eb4dda9443c6c2e44c952dc5a7"
Expand Down Expand Up @@ -533,6 +573,14 @@
"path": "src-tauri/src/db/tally_write_store.rs",
"sha256": "23e97c49c533ea67236c13add7972cb3b2654426538427bd35776ca888f0c0fe"
},
{
"path": "src-tauri/src/documents.rs",
"sha256": "3b4bdb23fe0750942fecdf670fd721938064554b5e8083aa0575a66f9a30d2ef"
},
{
"path": "src-tauri/src/endpoint_coordination.rs",
"sha256": "13f5cfdbeafc396fcb7fd1ae2d589dfb8b06159e098cec15fdce3383206ac6dc"
},
{
"path": "src-tauri/src/lib.rs",
"sha256": "e07a1dfa1af1577178ef87d2c5ff46464fb735e5118df26c2538984508bc2c6b"
Expand Down Expand Up @@ -641,6 +689,10 @@
"path": "src-tauri/src/tally/agent_read_request.rs",
"sha256": "ed02b13f739964808844e5aff0684326272963480702cc83b5b16b2e22bb5a77"
},
{
"path": "src-tauri/src/tally/approved_import.rs",
"sha256": "1e47fa1220236102e88eeb2cc84ff281a236c3f66494e6854825feda9a0d26aa"
},
{
"path": "src-tauri/src/tally/canonical_window.rs",
"sha256": "8390164a55d296bf557729df5a807b9797cc1fa51f4df11db2b790c5202b5585"
Expand Down Expand Up @@ -669,6 +721,10 @@
"path": "src-tauri/src/tally/runtime.rs",
"sha256": "9f1e388637760ddb0aa5c4de884c9f9dbc66e5714ace4cdd6bdbd2949888a81b"
},
{
"path": "src-tauri/src/tally/runtime_control.rs",
"sha256": "c6e4ad5d018192dfece1f87696a9c0c7bc4f64a63a12f008b0ff7a99b8adf129"
},
{
"path": "src-tauri/src/tally/runtime_trial_balance.rs",
"sha256": "4bde2ccecbe111273d169cd22e453a491af6e86ae328f419ddea0106ebf24c4a"
Expand Down Expand Up @@ -839,7 +895,7 @@
},
{
"path": "tools/bridge-tally-compatibility/src/lib.rs",
"sha256": "0ea7fb49d64fddab95f148048c92c07d9f9cd162a973912e3a56df2051ee3b99"
"sha256": "8f9840b107e3c14290e66a7e9eeafce09930fb7d17286a35c9475d1af87b6062"
},
{
"path": "tools/bridge-tally-compatibility/src/main.rs",
Expand Down Expand Up @@ -874,5 +930,5 @@
"sha256": "a8ac2714fecf51947f2822c8c46d7ce2e8602c732780ff60566a7771f0836f9a"
}
],
"manifest_sha256": "632ae96b7599ff062311687f9188c8001ec53b655c07cf7986be878f419e7781"
"manifest_sha256": "4dc0c7118372a4bc4a6b3b58346b0b113ce4b6bb07a154f208546f6cd43757a8"
}
81 changes: 81 additions & 0 deletions src-tauri/tests/admission_and_egress_files_stay_pinned.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//! The fourteen files pinned by the raise to 232 (bridge#416) must stay pinned.
//!
//! The compatibility gate cannot notice a pin disappearing. `rehash-surface`
//! updates hashes and never adds paths. `docs/release-process.md` requires the
//! pin list to be merged rather than resolved by taking one side; a resolution
//! that takes the base side anyway drops every entry a branch added while
//! keeping the raised `MAX_SURFACE_FILES`, and the gate passes. So does the cap
//! assertion, which bounds headroom and would pass with all fourteen dropped.
//! `book_presence_tests.rs` guards its own contract's pins the same way.
//!
//! This file is deliberately not pinned itself: a guard that lived in the
//! surface would be resolved away by the same merge it exists to catch.
use std::collections::BTreeSet;

const SURFACE: &str = include_str!("../../docs/tally/compatibility/compatibility-surface.json");

/// Each path was unpinned while a module that declares it was pinned
/// (bridge#416). The reason for each is recorded beside `MAX_SURFACE_FILES` in
/// `tools/bridge-tally-compatibility/src/lib.rs`; it is not repeated here, so
/// the two cannot drift apart.
const ADMISSION_AND_EGRESS: [&str; 14] = [
"src-tauri/crates/bridge-tally-protocol/src/group_ancestry.rs",
"src-tauri/src/agent_company.rs",
"src-tauri/src/agent_delivery.rs",
"src-tauri/src/agent_egress.rs",
"src-tauri/src/agent_import_cash_bank.rs",
"src-tauri/src/agent_import_ledger.rs",
"src-tauri/src/agent_import_persistence.rs",
"src-tauri/src/agent_import_post.rs",
"src-tauri/src/agent_protocol.rs",
"src-tauri/src/axal.rs",
"src-tauri/src/documents.rs",
"src-tauri/src/endpoint_coordination.rs",
"src-tauri/src/tally/approved_import.rs",
"src-tauri/src/tally/runtime_control.rs",
];

fn pinned_paths(surface: &str) -> BTreeSet<String> {
let surface: serde_json::Value = serde_json::from_str(surface).expect("surface json");
surface["files"]
.as_array()
.expect("surface files")
.iter()
.filter_map(|entry| entry["path"].as_str().map(str::to_owned))
.collect()
}

fn unpinned<'a>(pinned: &BTreeSet<String>, required: &[&'a str]) -> Vec<&'a str> {
required
.iter()
.copied()
.filter(|path| !pinned.contains(*path))
.collect()
}

#[test]
fn admission_and_egress_files_are_still_pinned() {
let missing = unpinned(&pinned_paths(SURFACE), &ADMISSION_AND_EGRESS);
assert!(
missing.is_empty(),
"dropped from the compatibility surface: {missing:?}. A merge that took \
the base side of compatibility-surface.json loses added pins while \
keeping the raised cap, and the gate cannot see it. Restore the entries \
and run scripts/reseal.sh --pins-changed."
);
}

/// The check above must be able to fail. Drive the same two functions over the
/// real surface with one entry removed, rather than a hand-built fixture that
/// would only prove `BTreeSet::contains` works.
#[test]
fn the_pin_check_reports_a_dropped_entry() {
let dropped = ADMISSION_AND_EGRESS[0];
let mut surface: serde_json::Value = serde_json::from_str(SURFACE).expect("surface json");
surface["files"]
.as_array_mut()
.expect("surface files")
.retain(|entry| entry["path"].as_str() != Some(dropped));
let pinned = pinned_paths(&surface.to_string());
assert_eq!(unpinned(&pinned, &ADMISSION_AND_EGRESS), vec![dropped]);
}
67 changes: 63 additions & 4 deletions tools/bridge-tally-compatibility/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,16 @@ pub const RESERVED_SURFACE_FILES: usize = 15;
/// and manifest) but makes further unreviewed additions an explicit
/// compatibility-surface decision.
///
/// **Raised five times, the first three by branches that did not see each
/// **Raised six times, the first three by branches that did not see each
/// other.** 210 to 211 on master for `src-tauri/src/agent_ledgers.rs`, 211 to
/// 212 for `src-tauri/crates/bridge-tally-core/src/master_binding.rs`, 212 to
/// 216 in a single commit for the voucher-presence engine, its adapter, its
/// admission-contract assertion, and `agent_catalog.rs` -- the last of those
/// taking the slot a paragraph below had already reserved for it by name, which
/// is why the four pins arrive as one raise and not two -- 216 to 217 for
/// `.github/workflows/dependency-security-scheduled.yml`, and 217 to 218 for
/// `src-tauri/src/agent_import_identity.rs`. Each reason stands; a merge that
/// `.github/workflows/dependency-security-scheduled.yml`, 217 to 218 for
/// `src-tauri/src/agent_import_identity.rs`, and 218 to 232 for fourteen files
/// named individually below. Each reason stands; a merge that
/// keeps a raise but loses its pin would pass the gate with behavior silently
/// outside the evidence boundary, which is the failure this constant exists to
/// make loud.
Expand Down Expand Up @@ -68,7 +69,65 @@ pub const RESERVED_SURFACE_FILES: usize = 15;
/// both halves at once and leave the surface digest unchanged, so a receipt
/// would attest an identity rule the evidence never covered. It is one file for
/// one named reason — not headroom.
pub const MAX_SURFACE_FILES: usize = 218;
///
/// The raise to 232 binds fourteen files at once, which reads like headroom and
/// is not: each is named here with its own reason, and none was chosen to fill
/// space. They were found together (bridge#416) by looking for unpinned
/// production modules declared by pinned ones, then keeping only those whose
/// own body holds a rule about what Bridge posts or prepares for posting, or
/// what may leave the machine. An edit confined to any of them would leave the
/// surface digest unchanged. Each reason says what the file holds, not that it
/// holds all of a guarantee: several guarantees here are shared with pinned
/// files, and a reason that claimed the whole of one would be false.
///
/// What Bridge posts, or prepares for posting:
/// - `tally/approved_import.rs` -- the operator approval dialog, and which
/// choice counts as consent (the named post button, or Yes on Windows).
/// - `agent_import_post.rs` -- the MCP post handler, which admits only a
/// single saved Journal batch, and its part of the refusal to post one batch
/// twice; `agent_import.rs` holds the admission lock and journal append.
/// - `agent_import_ledger.rs` -- the import journal replay: whether a batch was
/// dispatched, derived from its dispatch-intent records, and the refusal of a
/// second dispatch intent for one batch.
/// - `agent_company.rs` -- finding the loaded company whose GUID matches the
/// request and refusing when none or several do; import admission and the
/// company-scoped MCP read tools call it.
/// - `agent_import_cash_bank.rs` -- the reserved-group tables deciding which
/// ledgers may sit on the cash/bank side of a Payment, Receipt or Contra in
/// an import file Bridge builds.
/// - `bridge-tally-protocol/src/group_ancestry.rs` -- the ancestry walk under
/// those tables; its other callers were already pinned and it was not.
/// - `agent_import_persistence.rs` -- whether an earlier import publication has
/// settled, checked every time the import admission lock is taken.
/// - `tally/runtime_control.rs` -- the read retry loop: the attempt limits,
/// including the single-attempt policy, and which failures may repeat a
/// request.
/// - `endpoint_coordination.rs` -- the advisory per-user, per-port lease the
/// shipped post path takes before dispatch, so two of one OS user's Bridge
/// processes cannot both hold it while posting to one Tally port.
///
/// What leaves the machine, and the record of it:
/// - `documents.rs` -- which storage URLs customer documents may be uploaded
/// to, and the file checks made before an upload.
/// - `axal.rs` -- which AXAL API origins may receive credentialed requests,
/// and that its API client follows no redirects.
/// - `agent_protocol.rs` -- the MCP response loop, which records an egress
/// receipt for a tool response before writing it and decides what is sent
/// when recording fails.
/// - `agent_egress.rs` -- the egress log: a failed append is truncated back, or
/// reported as `egress_record_rollback_failed` when that fails, and a torn
/// final row is refused rather than read as evidence.
/// - `agent_delivery.rs` -- the egress receipt record: the fields it carries,
/// the response hash it commits to, and that only a persisted preparation
/// yields a write-completion token.
///
/// Not pinned, and deliberately: files feature-gated out of every shipped build
/// (`agent_lab.rs`, `jsonex*.rs`, `india_tax_observation.rs`), operator filing
/// labels, dead or declaration-only modules, and the read-path files that
/// compute reported figures or decide when a change cursor may advance. Those
/// decide what a read says, not what is admitted or where data may go; they are
/// the next candidates if the boundary widens, and bridge#416 records why.
pub const MAX_SURFACE_FILES: usize = 232;
pub const MAX_OPERATIONS: usize = 16;
pub const MAX_CLAIMS: usize = 128;
pub const MAX_KEYS: usize = 32;
Expand Down