Logoscore Weekly Update — 2026-08-31

Highlights

  • A module can ask for a signature; only a human can produce one. The keystore’s unlocked-signer cache is gone — unlock, lock and every sign_* were deleted from the contract rather than gated, the key is now derived from the vault password inside approve() and zeroized before the call returns, and admission is tiered by caller identity. The wallet backend became a pure requester, the wallet UI stopped handling the vault password, and signer_ui was proven end-to-end against a live secp256k1 signature that exists only because a password was typed into it logos-evm-keystore-module#6, logos-evm-signer-ui#2, logos-evm-wallet-backend-module#12, logos-evm-wallet-ui#25
  • App-to-app intents shipped. Three deliberately frozen QML symbols (logos.request, logos.intentRequested, logos.respond) over a host-side broker that checks the caller’s own uses declaration and mints a dispatch id the requester never sees — so no app can forge a response or hold a handle on whoever answered. provides landed in the package format and intent names carried through the downloader, the lgx bundler and the module templates logos-view-module-runtime#28, logos-basecamp#363, logos-package#35, logos-package-downloader#34, nix-bundle-lgx#13
  • A grant one way was a grant both ways. TokenManager was one flat map with no direction tag, written from both sides of every relationship — so B could call A purely because A had called B. INBOUND and OUTBOUND are now genuinely separated without moving a single byte of the struct (its layout is a cross-package ABI), and a private token store is created empty instead of being seeded with the host’s own anchor logos-protocol#73, #71, logos-logoscore-cli#104, logos-plugin-qt#26
  • Module state stopped being polled. liblogos turns load, unload and crash into sequenced facts and feeds them to a new modules_state module — retiring Basecamp’s 2s QTimer that inferred module state from package-install events, and the install/uninstall ack handshake between Basecamp and PMUI logos-liblogos#189, logos-modules-state-module#1, logos-basecamp#362, logos-package-manager-ui#74
  • A declared dependency range is now enforced, end to end. A module declaring ^2.0.0 loaded happily against an installed 1.0.0 — module_metadata.cpp dropped the constraint before the registry ever saw it. The range now rides the wire, the package manager evaluates it without masking a deeper mismatch, liblogos refuses at load (fails closed on an unparseable range), and Basecamp finally shows the difference logos-liblogos#196, logos-package-manager#38, logos-package-manager-module#64, logos-basecamp#361

Initiatives

Human-approved signing — the EVM wallet stops holding keys

The week’s largest user-visible security change: signing moved from something a caller can ask for to something a person authorises, once, for a payload they were shown.

  • The hole: once an account was unlocked, any module could sign — sign_* checked only is-unlocked, never who was calling, and unlock passed ttl: None while eviction only fired for Some, making every unlock a permanent, unattributable signing oracle. render == sign was vacuously true: the keystore signed bytes it had never described logos-evm-keystore-module#6
  • What replaced it: three admission tiers by caller identity — the configured approver only, any named module plus a receipt, and ungated account management. Tiers A and B return an identical refusal string so a caller cannot probe which one it failed logos-evm-keystore-module#6
  • The approver: signer_ui made to work and proven end to end; five defects found by running it rather than reading it logos-evm-signer-ui#2
  • The requester: both vault-password passthroughs deleted; signing became a two-phase request that parks the job rather than a dispatch thread; history is written when a transaction is BROADCAST, not when it is requested logos-evm-wallet-backend-module#12, logos-evm-wallet-ui#25
  • Parked, honestly: RAILGUN dropped from the backend and its Private tab removed from the UI until it is migrated off keystore.sign_digest logos-evm-wallet-backend-module#13, logos-evm-wallet-ui#27
  • Also: fees taken from fee_module instead of derived from gasPrice; leaf modules pinned to the backend’s own locked inputs logos-evm-wallet-backend-module#14, logos-evm-wallet-ui#26

App-to-app intents

  • The frozen surface: request() returns void deliberately — the requester never receives a request id, so it cannot forge a respond() for its own request nor hold a handle to whoever answered. That single property is what lets the router underneath be replaced without any app noticing. The bridge does no policy; LogosIntent.h carries the shared vocabulary so a host’s broker and the bridge can never disagree about a legal name or a legal error logos-view-module-runtime#28
  • The broker, on the host/shell split: it checks the caller’s uses declaration, resolves a provider, mints a separate dispatch id, has the presenter load and present the provider, and routes the answer back to that requester alone. The shell is a provider like any other for dispatch — and emphatically not an app, so it must never be loaded logos-basecamp#363
  • Through the packaging chain: a provides field in the package format, intent names in the downloader and the lgx bundler, intents in the module templates, and docs logos-package#35, logos-package-downloader#34, nix-bundle-lgx#13, logos-module-builder#219, logos-modules-release-tool#7, logos-tutorial#85
  • First consumer: PMUI asks for Settings → Repositories via an intent rather than reaching for the shell logos-package-manager-ui#73

Caller identity, put to work

Protocol 0.6’s caller accessor landed the week before; this week it started retiring the tokens it makes unnecessary.

Token direction and consumer admission

  • Direction: inbound and outbound separated without changing TokenManager’s layout — splitting it into three members would have moved m_mutex under QMutex::fastTryLock()’s compare-exchange offset, and host and modules ship as separate .lgx that mix versions at runtime by design logos-protocol#73
  • Empty by default: a private store no longer copies the host’s bootstrap tokens, which had let a sandboxed view present basecamp’s anchor and be answered as HostAnchor. Half of it was live, not latent: reading a caller needed generated glue, writing one didn’t logos-protocol#71
  • One home for admitting a non-module: logos::admitConsumer replaces the same three steps hand-rolled in two applications — the pure-QML identity bug was one of them getting the order wrong. Adopted by Basecamp, the standalone app, and the ui-host adopting its parent’s credential logos-plugin-qt#27, logos-basecamp#359, logos-standalone-app#42, logos-view-module-runtime#27
  • The plumbing and its docs: informModuleToken routed through the INBOUND door, logos_module_accept_inbound_token defined for cdylibs, the CLI daemon filing its client’s token as INBOUND; two-sided load-time token injection and outbound core/capability tokens documented logos-plugin-qt#26, logos-cpp-sdk#151, logos-logoscore-cli#104, logos-liblogos#187, logos-module-loader-qt#10

modules_state — lifecycle as sequenced facts

  • The observer and the feed ship together because the observer alone is inert. Two load-bearing rules: never dispatch under loadMutex() (a sink doing an RPC from inside the load path is the shape of the ui-host startup deadlock and a ~417s Basecamp stall already paid for), and one sequence counter logos-liblogos#189
  • Bundled and auto-loaded in liblogos, Basecamp and logosctl; ready kept across a snapshot logos-liblogos#193, #191, logos-basecamp#362, logos-logoscore-cli#110
  • Consumers stopped guessing: logosctl draws the line at LOADED rather than merely known, for both watch and call; the Basecamp↔PMUI ack handshake for install/uninstall/upgrade is gone logos-logoscore-cli#109, logos-package-manager-ui#74

Dependency ranges, signatures and package identity

Error channel and arity

Last week’s cross-SDK sweep continued into the sites it had missed.

Conformance — the consumer axis

  • The ext table gained the axis its own comment said it lacked: 44 × 2 × 144 × 2 × 3, via a Qt proxy fixture. It found a real defect — a record-bearing contract could not be consumed through a proxy at all, because generated record codecs were file-scope statics named after the record alone and the umbrella amalgamates every <name>_api.cpp into one TU logos-test-modules#50, logos-qt-sdk relock via logos-module-builder#215
  • The same axis in Python, plus the two races two relocks exposed logos-logoscore-py#22
  • Table hygiene: the null-vs-failure classes expressed as cells, one shape for echoOptional and three retirements, the arity work closed on measurement, the isolate rule moved to the table where it belongs, and module-not-loaded answering one token again logos-test-modules#49, #51, #52, #54, #55, #56

Protocol 0.8 / 0.9, and the relock train

Modules and releases

UI — design system rollout

Basecamp test layer (MCP-driven UI tests)

  • Preparation work for MCP-driven UI tests, the first real assertion (welcome → “Install now” navigates to Applications), and a pre-seeded test_qml_only app so integration tests have something to boot logos-basecamp#338, #342, #343

Tooling, diagnostics and docs

  • logosctl: catalog package versions shown; package search gives one version per row with the rest named in package show; releases tagged from VERSION logos-logoscore-cli#106, #111, #107
  • standalone app: logs to stderr by default — its own diagnostics were invisible — and loads the backend library the plugin actually declares logos-standalone-app#43, #44
  • doctests unpinned from logoscore-cli, with the archived accounts module retired logos-liblogos#192
  • tutorials updated so UI modules use QML hot reloading correctly logos-tutorial#86, #78

Appendix: all merged PRs, by repo

lez-explorer-ui, logos-basecamp, logos-blockchain-ui, logos-capability-module, logos-chat-ui, logos-cpp-sdk, logos-delivery-demo, logos-delivery-module, logos-evm-keystore-module, logos-evm-signer-ui, logos-evm-wallet-backend-module, logos-evm-wallet-ui, logos-execution-zone-module, logos-execution-zone-wallet-ui, logos-liblogos, logos-libp2p-module, logos-logoscore-cli, logos-logoscore-py, logos-module, logos-module-builder, logos-module-loader-qt, logos-modules-release, logos-modules-release-tool, logos-modules-state-module, logos-package, logos-package-downloader, logos-package-downloader-module, logos-package-manager, logos-package-manager-module, logos-package-manager-ui, logos-plugin-qt, logos-protocol, logos-qt-sdk, logos-rust-sdk, logos-standalone-app, logos-storage-module, logos-test-framework, logos-test-modules, logos-tutorial, logos-view-module-runtime, nix-bundle-lgx, nix-bundle-logos-module-install

lez-explorer-ui

logos-basecamp

logos-blockchain-ui

logos-capability-module

logos-chat-ui

logos-cpp-sdk

logos-delivery-demo

logos-delivery-module

logos-evm-keystore-module

logos-evm-signer-ui

logos-evm-wallet-backend-module

logos-evm-wallet-ui

logos-execution-zone-module

logos-execution-zone-wallet-ui

logos-liblogos

logos-libp2p-module

logos-logoscore-cli

logos-logoscore-py

logos-module

logos-module-builder

logos-module-loader-qt

logos-modules-release

logos-modules-release-tool

logos-modules-state-module

logos-package

logos-package-downloader

logos-package-downloader-module

logos-package-manager

logos-package-manager-module

logos-package-manager-ui

logos-plugin-qt

logos-protocol

logos-qt-sdk

logos-rust-sdk

logos-standalone-app

logos-storage-module

logos-test-framework

logos-test-modules

logos-tutorial

logos-view-module-runtime

nix-bundle-lgx

nix-bundle-logos-module-install