Skip to content

merge: reconcile fix/tray-native-windows-rs-062 into b00t-patches - #167

Merged
elasticdotventures merged 36 commits into
b00t-patchesfrom
reconcile/sync-tray-windows-062
Aug 9, 2026
Merged

merge: reconcile fix/tray-native-windows-rs-062 into b00t-patches#167
elasticdotventures merged 36 commits into
b00t-patchesfrom
reconcile/sync-tray-windows-062

Conversation

@elasticdotventures

Copy link
Copy Markdown
Member

Why

b00t's vendor/ledgrrr submodule pin has been tracking fix/tray-native-windows-rs-062 directly (via a series of explicit "bump vendor/ledgrrr for X fix" commits) rather than b00t-patches, which .gitmodules actually declares as the tracked branch. The two branches diverged after b00t-patches was rebased/force-pushed, and kept accumulating independent commits — including two independent fixes for the same bug (windows_registry::* glob-import shadowing std::result::Result), a clear sign these need to be reconciled before more gets lost on either side.

This merges everything from both lineages back together:

  • fix/tray-native-windows-rs-062 (34 commits): desktop-server unification (gh#118), .mcpb packaging (feat: package ledgrrr-mcp desktop controller as .mcpb for Claude Desktop #120), settings HTTP-server refactor, kani-proof downgrades, Windows tray/registry fixes
  • b00t-patches (3 commits it had that the other branch lacked): native Windows tray wiring, opencode MCP compatibility fixes, Result-shadowing fix

Conflicts resolved

  • crates/ledgerr-host/src/tray/native.rs: both branches independently added an identical WM_APP + 1 callback-message constant under different names (WM_TRAY_CALLBACK vs WM_TRAYICON_CALLBACK). Kept WM_TRAYICON_CALLBACK (the pub(crate) one, already referenced by existing doc comments) and removed the duplicate.
  • crates/ledgrrr-settings/src/backend/windows_registry.rs: cosmetic import-order-only conflict, no functional difference.

Verification

  • No conflict markers remain (grep -rn '<<<<<<<\|=======\|>>>>>>>' clean).
  • cargo check --target x86_64-pc-windows-gnu -p ledgerr-host -p ledgrrr-settings (the two touched crates) fails with a pre-existing, unrelated toolchain error (specta needs an unstable debug_closure_helpers feature requiring nightly rustc) — confirmed identical failure on plain b00t-patches before this merge, so not introduced here.
  • Native Linux cargo check --workspace --exclude ledgerr-host hits the same pre-existing specta error workspace-wide (unrelated to this merge).

🤖 Generated with Claude Code

promptexecutionerr and others added 30 commits July 31, 2026 08:04
…drift blocks

Once #162's ledger_ops.rs fix unblocks compilation, `just check-drift`
hits a second, previously-hidden failure: it calls
`cargo run -p xtask-mcpb -- generate-ts-types` and `generate-py-types`,
neither of which exist in xtask-mcpb anymore (only
`generate-type-tables` does), and their target files
(ui/docs/src/iso/generated-types.ts/.py) don't exist in the tree
either. main's CI has never reached this step because it always died
earlier on the conflict-marker compile error, so this drifted
unnoticed.

Removes the two dead blocks. Confirmed via `git log -S` on xtask/src/main.rs
that these subcommands are not present, and the doc comment above
check-drift doesn't reference them either.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…12 tools)

Third latent bug exposed by #162's compile fix: DOC-01 hardcoded the
top-level tool catalog at 10 tools, but BUILTIN_TOOL_NAMES in
mcp_adapter.rs has had 12 since ledgerr_schema/ledgerr_manifest were
added — the test was never updated because main's CI never got past
the ledger_ops.rs conflict-marker compile error to run it.

Confirmed via crates/ledgerr-mcp/src/contract.rs: SCHEMA_TOOL =
"ledgerr_schema", MANIFEST_TOOL = "ledgerr_manifest".

cargo test -p ledgerr-mcp --test mcp_adapter_contract: 4/4 pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…o Task 1's actual deliverable (backend only)

Removes five stub files that Task 1's implementer created to satisfy the given
lib.rs template (model_provider.rs, notification.rs, path.rs, schema.rs, store.rs).
These stubs were placeholders for real modules that Tasks 2–4 will deliver, and their
presence forces unnecessary overwrite/conflict resolution in those tasks.

lib.rs is now scoped to only Task 1's actual deliverable: the backend module and its
public API, with no synthetic re-exports. Later tasks (2, 3, 4) will add their own
modules incrementally as they land their real implementations.

Verification:
- cargo check -p ledgrrr-settings --all-targets: PASS
- cargo test -p ledgrrr-settings: 4/4 backend tests pass
- cargo check --workspace: PASS

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… ledgrrr-settings

Move three notification types from ledgerr-host to the new ledgrrr-settings crate:
- NotificationBackend enum
- NotificationStatus enum
- NotificationTestResult struct

These types are now re-exported from ledgrrr_settings in both ledgerr-host
and ledgrrr-settings for downstream consumption.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Move ModelProviderLabel enum and ProviderReadiness to ledgrrr-settings/model_provider.
Implement display_name() and description() as inherent methods. Methods requiring
ledgerr-host types (chat_settings, readiness) are provided via ModelProviderExt trait
to avoid circular dependencies.

- Creates crates/ledgrrr-settings/src/model_provider.rs with ModelProviderLabel and
  ProviderReadiness enums plus basic inherent methods
- Updates internal_openai.rs to re-export types and implement extension trait
- Maintains API compatibility: trait is automatically in scope via wildcard imports

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… controller

Replaces the two-tool desktop_status/desktop_ping stub from #120 with
the complete PRD-10 desktop controller: two bins (ledgrrr-mcp,
ledgrrr-service) and 9 modules (contract, status, render, simulate,
playbook, office_artifact, service_control, install_plan, state)
implementing all eleven ledgrrr_* tools with real state (b00t CLI,
service liveness via sysinfo, tray binary presence), deterministic
Mermaid/JSON/SVG rendering, a governance-correct non-LLM simulation
engine, and versioned local Office artifact export.

Packaging script/Justfile recipe/README updated to match: binary is
ledgrrr-mcp (not ledgerr-desktop-agent), bundle is ledgrrr-claude.mcpb
per PRD-10 §3.1 naming rather than the placeholder name from #120.

18/18 tests pass; clippy clean; packaging script verified end-to-end
(builds the release binary, assembles the bundle, and the packaged
binary answers a real MCP initialize handshake over stdio).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…colliding PRD-10

task/31-windows-packaging wrote its desktop-agent requirements doc as
PRD-10.md, but main's PRD-10.md is a different, unrelated document
("Financial Pipeline — Ingestion, Workbook Write, and AGT Governance
Wiring", already referenced throughout crates/ledgerr-mcp/src/actor.rs
and gate.rs). Renumbered the desktop-agent spec to PRD-11 and updated
every reference inside crates/ledgerr-desktop-agent/, scripts/, the
Justfile, and README.md accordingly — the ledgerr-mcp governance
PRD-10 references were left untouched.

Adds book/src/desktop-agent-office-playbook.md (wired into SUMMARY.md,
mcp-surface.md, and visualize.md) and the README threads (MECE tables,
capability snapshot, Future Ambitions section) from the original docs
commit, updated to reflect what's actually implemented now (MCPB
packaging works) rather than the "missing" status written before it
existed.

18/18 tests pass; clippy clean; packaging script re-verified after the
rename (builds, bundles, and the packaged binary still answers a real
MCP initialize handshake).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…auri) that doesn't exist

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Move resolve_chat_settings above the #[cfg(test)] mod tests block
(clippy::items_after_test_module) and drop the unnecessary ::default()
call on the Phi4LocalFallbackBackend unit struct
(clippy::default_constructed_unit_structs).
…test

Same drift as fix/119-retire-actor-gate's 5c053fc: tool catalog grew
from 10 to 12 (schema/manifest tools), this e2e test's tools/list
assertion wasn't updated. Inherited here because this branch is based
on #162's tip, which predates that fix landing on the shared branch.
…st invariant

xtask/src/viz_manifest.rs only registered 20 of the 28 existing
`impl HasVisualization` types in ledger_core::iso_objects (missing MetaCtx,
Disposition, AuRdActivity, AuRdOffset, QreActivity, UsRdcCredit, CryptoTx,
CryptoWallet). The checked-in ui/docs/public/viz-manifest.json stub had never
been regenerated and was still the empty placeholder from before this feature
existed.

pipe_viz_manifest_entry_count_is_32 asserted a count of 32 and the presence of
"Classification" / "GovernanceState<Closed>" entries — neither type exists
anywhere in the codebase, so this invariant was unreachable. Renamed to
pipe_viz_manifest_entry_count_matches_registered_types, asserting the real
count (28) and representative entries that actually exist.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014WXX8Nx14N3QJ8jcxmcfnr
invoice_required_pass_iff_arithmetic_holds was the only proof in this
crate using f64 with more than one magnitude-unbounded symbolic operand
(subtotal/gst were only constrained by is_finite()). CBMC's bit-precise
floating-point theory scales very poorly across multiple interacting
unbounded doubles, which lines up with this being the one CI job that
has repeatedly run 3-6+ hours before the runner loses communication
with the GitHub Actions server (see recent Kani Proofs run history on
this branch and #162).

Bounding subtotal/gst to the same practical amount range already used
for total doesn't weaken the proof: solver.validate() and the test's
arith_ok both compute the identical (total - subtotal - gst).abs() <
0.01 formula, so the assertion is an unconditional tautology regardless
of the bound — this only shrinks the search space CBMC has to explore.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014WXX8Nx14N3QJ8jcxmcfnr
… drift/push guardrails

Local investigation (cargo kani installed + run directly, bypassing the 5-6h
blind CI round trip) found invoice_required_pass_iff_arithmetic_holds was the
actual cause of every "Kani model checking" CI failure on #164/#165. The
property is a syntactic tautology (solver.validate() and the test compute the
identical (total - subtotal - gst).abs() < 0.01 formula), but CBMC's default
CaDiCaL bit-blasting solver can't discharge the auto-generated NaN
safety-checks for three interacting f64 operands in bounded time. Native SMT
solvers (Z3, Bitwuzla) solve the same harness in ~0.1s but the CBMC/kani-driver
integration reports those checks as ERROR rather than SUCCESS — not a genuine
pass, so not a safe substitute. Downgraded to concrete/edge-case #[test]s
(un-gated from #[cfg(kani)] so they run under plain `cargo test` on every
push); the other 4 kani-proofs harnesses (all f32) remain full symbolic
proofs and verify in seconds.

Also closes two other gaps surfaced this session:
- check-drift never covered ui/docs/public/viz-manifest.json, the exact
  artifact that silently rotted for six weeks. Added it alongside the
  existing bindings.ts/mcp-capability-contract.md checks, in CI too.
- A prior session claimed PRs #164/#165 were "pushed" when they weren't
  (verified after the fact via manual git fetch/rev-parse). Added
  `just verify-pushed` so that's a one-line check instead of trusting a
  push command's exit code.
- Added `just kani-setup`/`just kani-check` so local Kani iteration
  (cargo install kani-verifier && cargo kani setup) doesn't have to be
  rediscovered next time.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014WXX8Nx14N3QJ8jcxmcfnr
Ran the full remaining kani-proofs suite locally (cargo kani, no --harness
filter) after the invoice_arithmetic downgrade and confirmed the other four
harnesses (vendor_constraints, z3_result x3, meta_ctx) genuinely verify in
under a second each. commit_gate_is_total was the one still hanging — and
was almost certainly the actual root cause of every historical CI timeout on
this workflow (it's the first harness Kani reaches alphabetically, so it
would block before invoice_arithmetic was ever reached).

evaluate_commit_gate()'s PendingOperator branch builds `reason` via
format!("... {:.2} ...", ...); CBMC can't bound the data-dependent loops in
Rust's float formatting internals (flt2dec::round_up), and switching to
unprecision-specified Display just traded that for an equally unbounded
Unicode table lookup (core::unicode::unicode_data::skip_search) — confirmed
locally, not guessed. This is a known general Kani limitation: format!/
Display in code reachable from a proof harness defeats automatic unwinding.

The proof's actual assertion — that the return value matches one of
CommitGate's three variants — is also a tautology of Rust's type system
(any CommitGate trivially matches its own variants), and the harness's use
of new_for_kani (always empty issues) meant the Blocked variant was never
even reachable from it. Downgraded to four concrete tests covering all three
real branches, including Blocked, which the original proof never exercised.

Remaining kani-proofs suite (4 harnesses) verified clean: `cargo kani` ->
"Complete - 5 successfully verified harnesses, 0 failures, 5 total" in ~2s
(5 because z3_result contributes 3 harnesses from one file).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014WXX8Nx14N3QJ8jcxmcfnr
…ed proofs

The concrete edge-case tests added when invoice_arithmetic and commit_gate
were downgraded from symbolic Kani proofs run in milliseconds and only cover
a handful of hand-picked cases — real correctness coverage, but not the
breadth a formal proof was providing.

Adds a second, #[ignore]'d tier per module:
- invoice_arithmetic: dense (total, subtotal) grid in $0.01 steps up to
  $2,000, x6 representative gst deltas per pair — 50.4M concrete checks.
- commit_gate: every confidence value on a 5,000,001-step grid across
  [0.0, 1.0], checked both with and without an unrecoverable issue present
  (10M evaluations) — this concretely exercises the format!() call in the
  PendingOperator branch millions of times, the exact workload that
  defeated Kani's symbolic unwinding, just run natively instead of
  symbolically.

Both run in ~6.5s combined (measured) and are excluded from the default
fast `cargo test` suite so normal iteration stays fast; run explicitly via
the new `just exhaustive-check` recipe before a release or when auditing
either invariant.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014WXX8Nx14N3QJ8jcxmcfnr
promptexecutionerr and others added 6 commits August 8, 2026 22:59
…esult::Result

The glob import brought in windows_registry's re-exported Result<T>
type alias (single generic parameter, error type hardcoded to
windows_result::Error), shadowing std::result::Result used throughout
this file's Result<T, SettingsBackendError> signatures. Only surfaced
on a native windows-latest build; this crate has no compile coverage
on non-Windows dev hosts.
First real CI compile of this file (PR #911, windows-latest) surfaced 24
errors, all API-mismatch or plain type-system issues against windows 0.62.2 /
windows-core 0.62.2 (this crate has never built here before now):

- BOOL and PCWSTR moved out of the Win32::Foundation glob re-export; both now
  live in windows::core (windows-result::BOOL, windows-strings::PCWSTR) and
  need an explicit `use windows::core::{w, BOOL, PCWSTR};`. Same story for the
  `w!` literal macro (one bare use wasn't fully qualified).
- HBITMAP -> HGDIOBJ and HMODULE -> HINSTANCE are now distinct newtypes
  instead of being interchangeable; added `.into()` at each DeleteObject,
  WNDCLASSW.hInstance, and CreateWindowExW call site.
- BI_RGB is now a BI_COMPRESSION newtype, not a bare u32; use `.0`.
- PostMessageW's hwnd parameter is `Option<HWND>` in 0.62; wrap in `Some`.
- `WM_APP + 1` used directly as a match pattern is invalid Rust (arbitrary
  expressions aren't patterns) regardless of windows-rs version; extracted to
  a named const `WM_TRAYICON_CALLBACK` used both as the match arm and the
  NOTIFYICONDATAW.uCallbackMessage value.
- std::sync::mpsc::Sender has no `is_closed`; dropped the probe and rely on
  `send` returning Err on a disconnected receiver instead, which also
  required changing run_tray_pump's ready_tx parameter from an owned Sender
  to `&Sender` so the caller can still use it after the call for error
  reporting (the owned param was silently moved into the call, which would
  have been its own separate "use of moved value" error once the missing
  method issue was fixed).
- create_icon_from_rgba and build_tray_menu (plus its nested push_info /
  push_action / push_check helpers) returned Box<dyn Error> while their
  caller's `?` needs Box<dyn Error + Send + Sync>; aligned all of their
  return types to match rather than map_err at each call site.

Verified every API shape against the locally cached windows-core-0.62.2 and
windows-0.62.2 crate sources (registry checkout) rather than against memory
of older windows-rs majors, per the task's caution that this file has no
prior working revision to trust.
Nested fn items (push_info/push_action/push_check) don't inherit
unsafety from the enclosing unsafe fn build_tray_menu -- each needs
its own explicit unsafe block around the AppendMenuW call.
specta::specta-annotated Tauri commands returning Result<CytoscapeGraph, String>
require CytoscapeGraph (and its field types) to implement specta's Type trait
via the blanket FunctionResult impl. Add the derive to CytoscapeNodeData,
CytoscapeNode, CytoscapeEdgeData, CytoscapeEdge, and CytoscapeGraph, and add
specta as a holon-viz dependency (pinned to the same =2.0.0-rc.25 version
ledgerr-host already uses, with the derive feature enabled).

Fixes E0277 FunctionResult<_> not satisfied at commands.rs:541 and :649.
Recovers 34 commits that diverged from b00t-patches after a rebase/force-push
separated the two lineages: desktop-server unification (gh#118), MCP .mcpb
packaging (#120), settings HTTP-server refactor, kani-proof downgrades, and
Windows tray/registry fixes (specta::Type derive, AppendMenuW unsafe blocks,
windows-rs 0.62 migration).

b00t's vendor/ledgrrr submodule pin has been tracking fix/tray-native-windows-rs-062
directly (not b00t-patches, despite .gitmodules declaring that branch) via a
series of explicit bump commits — this merge reunifies the two so the
declared tracking branch matches what is actually depended on.

# Conflicts:
#	crates/ledgerr-host/src/tray/native.rs
#	crates/ledgrrr-settings/src/backend/windows_registry.rs
@elasticdotventures
elasticdotventures merged commit 310a91f into b00t-patches Aug 9, 2026
4 checks passed
@elasticdotventures
elasticdotventures deleted the reconcile/sync-tray-windows-062 branch August 9, 2026 13:00
elasticdotventures added a commit to elasticdotventures/_b00t_ that referenced this pull request Aug 9, 2026
check-submodule-drift.sh's existing checks only ever compared a
submodule's checked-out HEAD against the recorded .gitmodules pin —
they had no way to notice the pin itself becoming unreachable from
the branch .gitmodules declares (branch = ...) after that branch gets
force-pushed/rebased upstream. That's exactly how vendor/ledgrrr
silently stranded 34 commits on an orphan lineage for weeks (see
PromptExecution/ledgrrr#167 and `b00t lfmf ledgrrr-sync` for the full
incident) — every existing check reported "ok" the whole time.

Adds a branch_status field (ok/stale/unknown/n/a) per submodule,
local-only by design (never fetches over the network at check time —
see the same day's WSL2 + Cloudflare WARP MTU-blackhole incident for
why a per-submodule network call on every `b00t doctor check` is a bad
idea). `stale` is counted as a doctor-check failure; `unknown` (branch
not fetched locally yet) is not. Threaded through doctor_cmd.rs's JSON
detail/unresolved-count and human-readable output, plus three new bats
regression tests (ok/stale/unknown) mirroring the real incident's
shape via a force-pushed fixture branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
elasticdotventures added a commit to elasticdotventures/_b00t_ that referenced this pull request Aug 9, 2026
* chore(vendor): sync ledgrrr to reconciled b00t-patches (PromptExecution/ledgrrr#167)

The submodule pin had been tracking fix/tray-native-windows-rs-062
directly (via a series of one-off "bump vendor/ledgrrr for X fix"
commits) rather than b00t-patches, the branch .gitmodules actually
declares — the two diverged after b00t-patches was rebased/force-pushed
upstream, and each accumulated independent commits, including two
independent fixes for the same windows_registry Result-shadowing bug.

PromptExecution/ledgrrr#167 reconciled both lineages back into
b00t-patches (34 commits from the tray branch: desktop-server
unification gh#118, .mcpb packaging #120, settings HTTP-server
refactor, kani-proof downgrades, Windows tray/registry fixes; 3 from
b00t-patches: native tray wiring, opencode MCP compat, an independent
Result-shadowing fix — deduplicated during merge). This bump points
the pin back at what .gitmodules actually declares, with nothing lost.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat(doctor): detect submodule pins stranded off their declared branch

check-submodule-drift.sh's existing checks only ever compared a
submodule's checked-out HEAD against the recorded .gitmodules pin —
they had no way to notice the pin itself becoming unreachable from
the branch .gitmodules declares (branch = ...) after that branch gets
force-pushed/rebased upstream. That's exactly how vendor/ledgrrr
silently stranded 34 commits on an orphan lineage for weeks (see
PromptExecution/ledgrrr#167 and `b00t lfmf ledgrrr-sync` for the full
incident) — every existing check reported "ok" the whole time.

Adds a branch_status field (ok/stale/unknown/n/a) per submodule,
local-only by design (never fetches over the network at check time —
see the same day's WSL2 + Cloudflare WARP MTU-blackhole incident for
why a per-submodule network call on every `b00t doctor check` is a bad
idea). `stale` is counted as a doctor-check failure; `unknown` (branch
not fetched locally yet) is not. Threaded through doctor_cmd.rs's JSON
detail/unresolved-count and human-readable output, plus three new bats
regression tests (ok/stale/unknown) mirroring the real incident's
shape via a force-pushed fixture branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(vendor): bump ledgrrr for get_webview_window fix (PromptExecution/ledgrrr#168)

Follow-up to the earlier reconciliation bump in this branch: updating
rustup's stable toolchain (1.91.1 -> 1.97.1) unblocked the specta
unstable-feature build error that had been silently masking the rest
of the dependency graph on the Windows target -- which turned up one
real, pre-existing bug (Tauri renamed get_window to
get_webview_window). Fixed upstream and verified
`cargo check --workspace --target x86_64-pc-windows-gnu` clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants