core: give the pass verdict one definition#72
Merged
Merged
Conversation
"This agent's sessions were not fully seen this pass" (#49) was written out four times in SessionFilesystem — frozen, tombstone_withheld, state_retained and pass_complete each re-derived `incomplete_agents.contains(agent) || resolver.agent_failed(agent)` — and three of them were re-exported through SessionPass for tick_once to remember to call. Forgetting one is silent data loss: a local path-map failure tombstoning healthy sessions on every peer. Name it once as agent_incomplete and express the rest over it. The per-key questions collapse to state_retained; pass_complete keeps its cheap aggregate form. tombstone_withheld goes: frozen already keeps a blind agent's keys out of the reconcile index, and Action::Tombstone needs an index entry, so the guard could never fire — deleting it and running the whole suite changed nothing. Deleting each of the other guards also changed nothing, so pin the consequences at the engine level, where they land: frozen_agent_does_not_tombstone_a_peers_session frozen_agent_keeps_its_carried_state incomplete_pass_does_not_settle_the_recipient_set Each now fails when its mechanism is removed. The fixture runs two agents on purpose: with one, freezing it empties the local snapshot and reconcile's empty-dir wipe guard suppresses tombstones by itself, so the tombstone test passed without the freeze doing any work. The session_filesystem tests that asserted tombstone_withheld now assert frozen — same condition, and the mechanism that actually withholds.
fosskar
enabled auto-merge
July 25, 2026 09:06
auto-merge was automatically disabled
July 25, 2026 09:07
Pull request was closed
fosskar
enabled auto-merge
July 25, 2026 09:08
Merged
fosskar
added a commit
that referenced
this pull request
Jul 25, 2026
Three internal changes landed since v0.20.0 — no features, nothing breaking — so PATCH per the pre-1.0 rule: #71 cli: single-source the systemd hardening set #72 core: give the pass verdict one definition #73 core: give the encrypted session store one owner #71 is the only one that alters a shipped artifact: the unit written by `ssync service install` now lists the sandbox properties alphabetically. The property set is unchanged and systemd is order-insensitive here, so behaviour is identical. Bumping [workspace.package] version is the whole release: nix/effects.nix tags v0.20.1 and generates notes once nixbot goes green on main.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found by an architecture review of the engine loop, then validated by ablation — deleting each guard and running the whole suite — before any code changed.
The problem
One question — "were this agent's sessions fully seen this pass?" (issue #49) — was written out four times in
SessionFilesystem:Three were re-exported through
SessionPasssoEngine::tick_oncecould remember to call each in the right spot — before executing a tombstone, before settling the recipient fingerprint, before pruning carried state. Forgetting one is silent data loss: a local path-map failure tombstoning healthy sessions on every peer, which is the bug class #49 exists to prevent.Validation: every engine-side guard was untested
Delete the guard, run
cargo test --workspace:frozen(projection)excluded_projects_neither_publish_nor_materializetombstone_withheld(lib.rs:353)state_retained(lib.rs:396)pass_complete(lib.rs:387)tombstone_withheldcan never fire:frozenalready strips a blind agent's keys out of the reconcile index, andAction::Tombstoneis only emitted for a key that has an index entry (reconcile.rs:275-286). Sincebegin_passsnapshots before projecting, the two always agree within a pass.The change
Name the predicate once and express the rest over it:
frozenandstate_retainedare now one line over it;pass_completekeeps its cheap aggregate form, documented as the pass-wide form of the same question.tombstone_withheldis removed, along with itsSessionPassforwarder and thetick_onceguard. Dead code that looks load-bearing is worse than no code: no test can exercise it, so it implies a coverage it does not have. The behaviour it nominally protected is now pinned by a test that survives refactors of either mechanism.session_filesystemtests that assertedtombstone_withheldnow assertfrozen— the same condition, and the mechanism that actually withholds.Closing the coverage hole
Three new engine-level tests pin the consequences where they land:
frozen_agent_does_not_tombstone_a_peers_sessionfrozen_agent_keeps_its_carried_stateincomplete_pass_does_not_settle_the_recipient_setEach was verified to fail when its mechanism is removed:
The fixture runs two agents deliberately. With one agent, freezing it empties the local snapshot and reconcile's empty-dir wipe guard suppresses tombstones on its own — the first version of the tombstone test passed without the freeze doing any work. A healthy second agent keeps the snapshot non-empty so the test actually exercises the freeze.
One observation, deliberately not acted on
Ablation also showed the
|| resolver.agent_failed(agent)half ofagent_incompleteis currently redundant:snapshot()mirrors resolver failures intoincomplete_agents(session_filesystem.rs:538) in the same pass, so removing the disjunct changes nothing and no test notices.It stays. It names a real failure mode, and making the verdict depend on that mirroring would couple the definition to an implementation detail of
snapshot. Flagging it in case you disagree.Verification
cargo clippy --workspace --all-targets -- -D warnings— cleancargo test --workspace -- --test-threads=1— 258 passed, 0 failednix fmt -- --ci— 0 changedNo version bump: no user-visible behaviour change (refactor plus test coverage).