From dc103d44d9f5fca46ef8e0e3abb27d2b6987017c Mon Sep 17 00:00:00 2001 From: t Date: Wed, 16 Sep 2026 13:46:23 +0530 Subject: [PATCH 1/3] Pin the admission and egress files whose pinned siblings already were bridge#416. Thirteen files decide, in their own bodies, what Bridge admits into a customer's book or lets leave the machine, and each was the unpinned half of a pair whose other half was pinned: `agent_import.rs` pinned while `agent_import_post.rs`, which holds the only POST and its double-post guard, was not; `agent_catalog.rs` pinned for argument admission while `agent_company.rs` did company-identity admission unsealed; every other caller of `group_ancestry.rs` pinned while the walk itself was not. Raises MAX_SURFACE_FILES from 218 to 231. The constant's rule is one file for one named reason, not headroom, so each of the thirteen is named beside it with its own reason. Every reason was checked at its cited function before being written, and two were narrowed when the check did not support the first wording. Deliberately not pinned, and recorded beside the constant: feature-gated files absent from every shipped build, 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. Adds src-tauri/tests/admission_and_egress_files_stay_pinned.rs, following the guard book_presence_tests.rs keeps for its own contract. The gate cannot see a pin disappear: rehash-surface never adds paths, so a merge that takes the base side of the surface drops these entries while keeping the raised cap. Measured, not asserted: with axal.rs removed from the surface and resealed, `reseal.sh --verify` exits 0 and the compatibility tool's cap assertion passes, while this guard fails naming the dropped path. It lives in an unpinned file so the same merge cannot resolve it away. Co-Authored-By: Claude Opus 5 --- .../compatibility/compatibility-matrix.json | 2 +- .../compatibility/compatibility-surface.json | 56 ++++++++++++- .../admission_and_egress_files_stay_pinned.rs | 80 +++++++++++++++++++ tools/bridge-tally-compatibility/src/lib.rs | 54 ++++++++++++- 4 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 src-tauri/tests/admission_and_egress_files_stay_pinned.rs diff --git a/docs/tally/compatibility/compatibility-matrix.json b/docs/tally/compatibility/compatibility-matrix.json index c23761128..b8a11240d 100644 --- a/docs/tally/compatibility/compatibility-matrix.json +++ b/docs/tally/compatibility/compatibility-matrix.json @@ -1,7 +1,7 @@ { "schema_version": 1, "bridge_commit_sha": "be1c20cc3fd66fa1ece196505c69f26e555e4b8e", - "compatibility_surface_sha256": "632ae96b7599ff062311687f9188c8001ec53b655c07cf7986be878f419e7781", + "compatibility_surface_sha256": "9dac6dec6f582f1335535f0ea02709d0fb947c230c8af655470d1edb8dd3c8b5", "claims": [ { "claim_id": "erp9-6-6-3-windows-education-xml-one-company", diff --git a/docs/tally/compatibility/compatibility-surface.json b/docs/tally/compatibility/compatibility-surface.json index b854d0091..b62a51065 100644 --- a/docs/tally/compatibility/compatibility-surface.json +++ b/docs/tally/compatibility/compatibility-surface.json @@ -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" @@ -337,18 +341,42 @@ "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_persistence.rs", + "sha256": "50fdab872d872759fe4b093c67f4b120f8eac4060fc501cefd39d70b097581d4" + }, + { + "path": "src-tauri/src/agent_import_post.rs", + "sha256": "f23d9b2c535a8dea5a2bdcc41e2852a1994562aeda1bb7338b3ce47f7e3d4541" + }, { "path": "src-tauri/src/agent_ledgers.rs", "sha256": "a891e4ac51addc9dc17ae28ce4634bd2cfeb8f3f0df78e072290771d29a3131b" @@ -361,6 +389,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" @@ -397,6 +429,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" @@ -533,6 +569,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" @@ -641,6 +685,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" @@ -669,6 +717,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" @@ -839,7 +891,7 @@ }, { "path": "tools/bridge-tally-compatibility/src/lib.rs", - "sha256": "0ea7fb49d64fddab95f148048c92c07d9f9cd162a973912e3a56df2051ee3b99" + "sha256": "6953b2b2a1ee1bd75d895e88543acc98dd85b308febe22f3c31acced9350e0ff" }, { "path": "tools/bridge-tally-compatibility/src/main.rs", @@ -874,5 +926,5 @@ "sha256": "a8ac2714fecf51947f2822c8c46d7ce2e8602c732780ff60566a7771f0836f9a" } ], - "manifest_sha256": "632ae96b7599ff062311687f9188c8001ec53b655c07cf7986be878f419e7781" + "manifest_sha256": "9dac6dec6f582f1335535f0ea02709d0fb947c230c8af655470d1edb8dd3c8b5" } \ No newline at end of file diff --git a/src-tauri/tests/admission_and_egress_files_stay_pinned.rs b/src-tauri/tests/admission_and_egress_files_stay_pinned.rs new file mode 100644 index 000000000..6973e1d6f --- /dev/null +++ b/src-tauri/tests/admission_and_egress_files_stay_pinned.rs @@ -0,0 +1,80 @@ +//! The thirteen files pinned by the raise to 231 (bridge#416) must stay pinned. +//! +//! The compatibility gate cannot notice a pin disappearing. `rehash-surface` +//! updates hashes and never adds paths, and the only correct way to resolve a +//! conflict in a generated artifact is to take one side and regenerate -- so a +//! merge that takes the base side of `compatibility-surface.json` drops every +//! entry a branch added while keeping the raised `MAX_SURFACE_FILES`, and the +//! gate passes. `book_presence_tests.rs` guards its own contract's pins the same +//! way, for the same reason. +//! +//! 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 is the unpinned half of a pair whose other half was already +/// pinned. 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; 13] = [ + "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_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 { + 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, 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]); +} diff --git a/tools/bridge-tally-compatibility/src/lib.rs b/tools/bridge-tally-compatibility/src/lib.rs index 785ed7626..986d746ae 100644 --- a/tools/bridge-tally-compatibility/src/lib.rs +++ b/tools/bridge-tally-compatibility/src/lib.rs @@ -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 231 for thirteen 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. @@ -68,7 +69,52 @@ 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 231 binds thirteen 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) because each is the unpinned +/// half of a pair whose other half was already pinned -- the pinned module +/// declares them, or the pinned caller depends on the rule they hold -- so the +/// reasoning that pinned one half never reached the other. Each decides, in its +/// own file, what Bridge admits into a book or lets leave the machine; an edit +/// confined to it would leave the surface digest unchanged. +/// +/// Admission into a book: +/// - `tally/approved_import.rs` -- whether the operator's dialog counts as +/// consent to post, and that only the explicit post button does. +/// - `agent_import_post.rs` -- the only POST path, and the guard that stops one +/// approved batch posting twice. +/// - `agent_company.rs` -- that exactly one loaded company matches the +/// requested identity; import admission and the company-scoped read tools +/// rely on it. +/// - `agent_import_cash_bank.rs` -- the reserved-group tables deciding which +/// ledgers may sit on the money leg of a Payment, Receipt or Contra. +/// - `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` -- refuses a new import while an earlier +/// publication is unsettled. +/// - `tally/runtime_control.rs` -- which read failures are retryable; widening +/// it re-sends a request `tally/runtime.rs` marked single-attempt. +/// - `endpoint_coordination.rs` -- the exclusive per-listener lease taken +/// before a post, so two processes cannot post to one Tally at once. +/// +/// What leaves the machine, and the record of it: +/// - `documents.rs` -- the origin allowlist for uploading customer documents. +/// - `axal.rs` -- where credentialed requests may go, and that a redirect never +/// carries the credentials onward. +/// - `agent_protocol.rs` -- that the egress receipt is persisted before the +/// response is written. +/// - `agent_egress.rs` -- the append-only egress log, and its refusal to read a +/// torn final row as evidence. +/// - `agent_delivery.rs` -- what a receipt hashes, which is what it attests. +/// +/// 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 = 231; pub const MAX_OPERATIONS: usize = 16; pub const MAX_CLAIMS: usize = 128; pub const MAX_KEYS: usize = 32; From 294bf4bc434258aa25d3e466f6f3f06e8cef50ed Mon Sep 17 00:00:00 2001 From: t Date: Wed, 16 Sep 2026 14:10:21 +0530 Subject: [PATCH 2/3] Say what each pinned file holds, not a guarantee it only shares Review found 11 of the 13 reasons beside MAX_SURFACE_FILES overstated what the code does, and one causal claim false. Each was checked against the code before rewriting: - runtime_control.rs: "widening retryable re-sends a request runtime.rs marked single-attempt" was false. SINGLE_ATTEMPT is defined in this file with maximum_attempts: 1, and the loop stops at the attempt limit regardless of class. The file still holds the attempt limits. - agent_import_post.rs was "the only POST path"; every Tally read is an HTTP POST, and the double-post refusal is split with agent_import.rs. It admits only a single saved Journal batch. - agent_company.rs matches on GUID; "exactly one loaded company matches the requested identity" claimed the full tuple. - agent_protocol.rs does not guarantee a receipt precedes every response: a failed receipt can still send a recovery or build-failure response. - axal.rs: the no-redirect client is its own; documents.rs builds another. - approved_import.rs: Windows consent is Yes, not a post button. - agent_import_persistence.rs refuses nothing itself; its check runs whenever the import admission lock is taken. - endpoint_coordination.rs: an advisory lease, per user and per port, taken by the shipped post path. - agent_egress.rs, documents.rs, agent_import_cash_bank.rs: narrowed to what each holds. The framing also claimed each was "the unpinned half of a pair"; that is not true of agent_delivery.rs, whose caller was unpinned. It now says how the files were found. The guard's doc comment said taking one side is the correct way to resolve a generated artifact, contradicting release-process.md, which requires the pin list to be merged. Corrected, and it now notes the cap assertion would pass with all thirteen pins dropped. The report-only coverage script is removed from this PR and moves to its own: review showed it misses a child declared in any #[path]-loaded file, which rustc resolves beside the file rather than under its stem. Co-Authored-By: Claude Opus 5 --- .../compatibility/compatibility-matrix.json | 2 +- .../compatibility/compatibility-surface.json | 4 +- .../admission_and_egress_files_stay_pinned.rs | 12 ++-- tools/bridge-tally-compatibility/src/lib.rs | 66 +++++++++++-------- 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/docs/tally/compatibility/compatibility-matrix.json b/docs/tally/compatibility/compatibility-matrix.json index b8a11240d..f9a080c0d 100644 --- a/docs/tally/compatibility/compatibility-matrix.json +++ b/docs/tally/compatibility/compatibility-matrix.json @@ -1,7 +1,7 @@ { "schema_version": 1, "bridge_commit_sha": "be1c20cc3fd66fa1ece196505c69f26e555e4b8e", - "compatibility_surface_sha256": "9dac6dec6f582f1335535f0ea02709d0fb947c230c8af655470d1edb8dd3c8b5", + "compatibility_surface_sha256": "f0b2893363c0e655cf0cdcbd29e74d76d5d93df569da399ee808352b5c794151", "claims": [ { "claim_id": "erp9-6-6-3-windows-education-xml-one-company", diff --git a/docs/tally/compatibility/compatibility-surface.json b/docs/tally/compatibility/compatibility-surface.json index b62a51065..0ffa3ffd4 100644 --- a/docs/tally/compatibility/compatibility-surface.json +++ b/docs/tally/compatibility/compatibility-surface.json @@ -891,7 +891,7 @@ }, { "path": "tools/bridge-tally-compatibility/src/lib.rs", - "sha256": "6953b2b2a1ee1bd75d895e88543acc98dd85b308febe22f3c31acced9350e0ff" + "sha256": "5b36ff900a964586a5eb0a7cc39fe5bc0429e558a8e7deb833e33945097c2e0d" }, { "path": "tools/bridge-tally-compatibility/src/main.rs", @@ -926,5 +926,5 @@ "sha256": "a8ac2714fecf51947f2822c8c46d7ce2e8602c732780ff60566a7771f0836f9a" } ], - "manifest_sha256": "9dac6dec6f582f1335535f0ea02709d0fb947c230c8af655470d1edb8dd3c8b5" + "manifest_sha256": "f0b2893363c0e655cf0cdcbd29e74d76d5d93df569da399ee808352b5c794151" } \ No newline at end of file diff --git a/src-tauri/tests/admission_and_egress_files_stay_pinned.rs b/src-tauri/tests/admission_and_egress_files_stay_pinned.rs index 6973e1d6f..66eeff84d 100644 --- a/src-tauri/tests/admission_and_egress_files_stay_pinned.rs +++ b/src-tauri/tests/admission_and_egress_files_stay_pinned.rs @@ -1,12 +1,12 @@ //! The thirteen files pinned by the raise to 231 (bridge#416) must stay pinned. //! //! The compatibility gate cannot notice a pin disappearing. `rehash-surface` -//! updates hashes and never adds paths, and the only correct way to resolve a -//! conflict in a generated artifact is to take one side and regenerate -- so a -//! merge that takes the base side of `compatibility-surface.json` drops every -//! entry a branch added while keeping the raised `MAX_SURFACE_FILES`, and the -//! gate passes. `book_presence_tests.rs` guards its own contract's pins the same -//! way, for the same reason. +//! 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 thirteen 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. diff --git a/tools/bridge-tally-compatibility/src/lib.rs b/tools/bridge-tally-compatibility/src/lib.rs index 986d746ae..cb75c9d29 100644 --- a/tools/bridge-tally-compatibility/src/lib.rs +++ b/tools/bridge-tally-compatibility/src/lib.rs @@ -72,41 +72,49 @@ pub const RESERVED_SURFACE_FILES: usize = 15; /// /// The raise to 231 binds thirteen 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) because each is the unpinned -/// half of a pair whose other half was already pinned -- the pinned module -/// declares them, or the pinned caller depends on the rule they hold -- so the -/// reasoning that pinned one half never reached the other. Each decides, in its -/// own file, what Bridge admits into a book or lets leave the machine; an edit -/// confined to it would leave the surface digest unchanged. +/// 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. /// -/// Admission into a book: -/// - `tally/approved_import.rs` -- whether the operator's dialog counts as -/// consent to post, and that only the explicit post button does. -/// - `agent_import_post.rs` -- the only POST path, and the guard that stops one -/// approved batch posting twice. -/// - `agent_company.rs` -- that exactly one loaded company matches the -/// requested identity; import admission and the company-scoped read tools -/// rely on it. +/// 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 half of the refusal to post one batch +/// twice; the other half is in `agent_import.rs`. +/// - `agent_company.rs` -- finding the loaded company whose GUID matches the +/// request and refusing when none or several do; import admission and the +/// MCP read tools call it. /// - `agent_import_cash_bank.rs` -- the reserved-group tables deciding which -/// ledgers may sit on the money leg of a Payment, Receipt or Contra. +/// 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` -- refuses a new import while an earlier -/// publication is unsettled. -/// - `tally/runtime_control.rs` -- which read failures are retryable; widening -/// it re-sends a request `tally/runtime.rs` marked single-attempt. -/// - `endpoint_coordination.rs` -- the exclusive per-listener lease taken -/// before a post, so two processes cannot post to one Tally at once. +/// - `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 Bridge processes do not +/// post to one Tally listener at once. /// /// What leaves the machine, and the record of it: -/// - `documents.rs` -- the origin allowlist for uploading customer documents. -/// - `axal.rs` -- where credentialed requests may go, and that a redirect never -/// carries the credentials onward. -/// - `agent_protocol.rs` -- that the egress receipt is persisted before the -/// response is written. -/// - `agent_egress.rs` -- the append-only egress log, and its refusal to read a -/// torn final row as evidence. -/// - `agent_delivery.rs` -- what a receipt hashes, which is what it attests. +/// - `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 rolled back, and a +/// torn final row is refused rather than read as evidence. +/// - `agent_delivery.rs` -- what an egress receipt hashes, which is what it +/// attests. /// /// Not pinned, and deliberately: files feature-gated out of every shipped build /// (`agent_lab.rs`, `jsonex*.rs`, `india_tax_observation.rs`), operator filing From 315782aac24bee26ec4c71184763527459140272 Mon Sep 17 00:00:00 2001 From: t Date: Wed, 16 Sep 2026 14:17:34 +0530 Subject: [PATCH 3/3] Pin the import journal replay, and finish narrowing the reasons Second review of the reasons found one file the stated criterion covers but the list left out, and five wordings still broader than the code. agent_import_ledger.rs derives whether a batch was dispatched from its dispatch-intent records (line 127) and refuses a second dispatch intent for one batch (import_ledger_duplicate_dispatch). That is part of the refusal to post one batch twice, in a production module declared by the pinned agent_import.rs, so the criterion already covered it. Pinned, and the cap raised to 232. Narrowed: - agent_import_post.rs held "its half" of the double-post refusal; it is one part of three, with the ledger replay and agent_import.rs. - agent_company.rs is called by the company-scoped read tools, not all of them: list_companies, read_evidence, egress_log and status do not. - endpoint_coordination.rs: the lease directory is per OS user, so it holds between one user's processes, not any two. - agent_egress.rs: a failed rollback is reported as egress_record_rollback_failed rather than rolled back. - agent_delivery.rs: a receipt attests more than a hash -- its fields, the response hash, and that only a persisted preparation yields a write-completion token. The guard test still described each path as "the unpinned half of a pair whose other half was already pinned", which the previous commit removed from lib.rs as untrue of agent_delivery.rs. It now says what was measured: each was unpinned while a module declaring it was pinned. Co-Authored-By: Claude Opus 5 --- .../compatibility/compatibility-matrix.json | 2 +- .../compatibility/compatibility-surface.json | 8 +++-- .../admission_and_egress_files_stay_pinned.rs | 11 +++---- tools/bridge-tally-compatibility/src/lib.rs | 29 +++++++++++-------- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/docs/tally/compatibility/compatibility-matrix.json b/docs/tally/compatibility/compatibility-matrix.json index f9a080c0d..7a55f200c 100644 --- a/docs/tally/compatibility/compatibility-matrix.json +++ b/docs/tally/compatibility/compatibility-matrix.json @@ -1,7 +1,7 @@ { "schema_version": 1, "bridge_commit_sha": "be1c20cc3fd66fa1ece196505c69f26e555e4b8e", - "compatibility_surface_sha256": "f0b2893363c0e655cf0cdcbd29e74d76d5d93df569da399ee808352b5c794151", + "compatibility_surface_sha256": "4dc0c7118372a4bc4a6b3b58346b0b113ce4b6bb07a154f208546f6cd43757a8", "claims": [ { "claim_id": "erp9-6-6-3-windows-education-xml-one-company", diff --git a/docs/tally/compatibility/compatibility-surface.json b/docs/tally/compatibility/compatibility-surface.json index 0ffa3ffd4..4030a2a4a 100644 --- a/docs/tally/compatibility/compatibility-surface.json +++ b/docs/tally/compatibility/compatibility-surface.json @@ -369,6 +369,10 @@ "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" @@ -891,7 +895,7 @@ }, { "path": "tools/bridge-tally-compatibility/src/lib.rs", - "sha256": "5b36ff900a964586a5eb0a7cc39fe5bc0429e558a8e7deb833e33945097c2e0d" + "sha256": "8f9840b107e3c14290e66a7e9eeafce09930fb7d17286a35c9475d1af87b6062" }, { "path": "tools/bridge-tally-compatibility/src/main.rs", @@ -926,5 +930,5 @@ "sha256": "a8ac2714fecf51947f2822c8c46d7ce2e8602c732780ff60566a7771f0836f9a" } ], - "manifest_sha256": "f0b2893363c0e655cf0cdcbd29e74d76d5d93df569da399ee808352b5c794151" + "manifest_sha256": "4dc0c7118372a4bc4a6b3b58346b0b113ce4b6bb07a154f208546f6cd43757a8" } \ No newline at end of file diff --git a/src-tauri/tests/admission_and_egress_files_stay_pinned.rs b/src-tauri/tests/admission_and_egress_files_stay_pinned.rs index 66eeff84d..6296dc482 100644 --- a/src-tauri/tests/admission_and_egress_files_stay_pinned.rs +++ b/src-tauri/tests/admission_and_egress_files_stay_pinned.rs @@ -1,11 +1,11 @@ -//! The thirteen files pinned by the raise to 231 (bridge#416) must stay pinned. +//! 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 thirteen dropped. +//! 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 @@ -14,16 +14,17 @@ use std::collections::BTreeSet; const SURFACE: &str = include_str!("../../docs/tally/compatibility/compatibility-surface.json"); -/// Each path is the unpinned half of a pair whose other half was already -/// pinned. The reason for each is recorded beside `MAX_SURFACE_FILES` in +/// 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; 13] = [ +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", diff --git a/tools/bridge-tally-compatibility/src/lib.rs b/tools/bridge-tally-compatibility/src/lib.rs index cb75c9d29..76c2509f7 100644 --- a/tools/bridge-tally-compatibility/src/lib.rs +++ b/tools/bridge-tally-compatibility/src/lib.rs @@ -39,7 +39,7 @@ pub const RESERVED_SURFACE_FILES: usize = 15; /// 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`, 217 to 218 for -/// `src-tauri/src/agent_import_identity.rs`, and 218 to 231 for thirteen files +/// `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 @@ -70,7 +70,7 @@ pub const RESERVED_SURFACE_FILES: usize = 15; /// would attest an identity rule the evidence never covered. It is one file for /// one named reason — not headroom. /// -/// The raise to 231 binds thirteen files at once, which reads like headroom and +/// 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 @@ -84,11 +84,14 @@ pub const RESERVED_SURFACE_FILES: usize = 15; /// - `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 half of the refusal to post one batch -/// twice; the other half is in `agent_import.rs`. +/// 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 -/// MCP read tools call it. +/// 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. @@ -100,8 +103,8 @@ pub const RESERVED_SURFACE_FILES: usize = 15; /// 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 Bridge processes do not -/// post to one Tally listener at once. +/// 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 @@ -111,10 +114,12 @@ pub const RESERVED_SURFACE_FILES: usize = 15; /// - `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 rolled back, and a -/// torn final row is refused rather than read as evidence. -/// - `agent_delivery.rs` -- what an egress receipt hashes, which is what it -/// attests. +/// - `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 @@ -122,7 +127,7 @@ pub const RESERVED_SURFACE_FILES: usize = 15; /// 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 = 231; +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;