PR-7 of the shared-runtime migration. Comment-only: no non-comment line changes,
and checks.tests passes.
This header is the canonical explanation of the one-runtime invariant, and after
the migration it described a scheme that no longer exists. It still said the
resolution was ONE PROVIDER with liblogos_core exporting types it does not own,
and still pointed at logos-basecamp/cmake/LogosSharedFromDll.cmake -- a file
deleted in logos-basecamp#348 and logos-logoscore-cli#98.
Now states where definitions actually live:
liblogos_protocol TokenManager, LogosAPIClient, the StoreRegistry
liblogos_qt_host LogosAPI
and that liblogos_core defines ZERO runtime symbols, importing them like every
other consumer.
RECORDS THE FIX THAT DID NOT WORK, because it looks obvious and someone will try
it again: hand-marking a class list with __declspec(dllexport) is not a smaller
version of the right answer. It exported 116 symbols and the Qt host runtime
still failed to link with ELEVEN undefined references across five classes, plus
free functions nobody had marked. A curated list is correct only until the next
consumer touches a symbol nobody thought of, and the failure lands in a
downstream repo far from the cause. Hence a .def GENERATED from the objects.
STATES THE IN-PROCESS / OUT-OF-PROCESS SPLIT, which is the distinction that
decides who links what and the one most likely to be "simplified" away by
someone tidying up. In-process images link the SHARED libraries; logos_host,
ui-host, module plugins and ui_qml backends keep linking the STATIC archive, and
that is CORRECT rather than a leftover: each runs in its own process, so its own
copy IS the right per-process singleton -- measured, logos_host and ui-host
define ~100 runtime symbols each and are deliberately exempt from the symbol
gates. Staying static also keeps a .lgx self-contained, since a .lgx records an
EMPTY nix closure and a shared library would not travel with it.
Says plainly not to unify the two, and why: it would couple every .lgx to the
exact runtime build it was packaged against, to fix a duplication that is not a
bug in a separate process.
Ends with what asserts any of this, since nothing did for a long time and that
is how nine images came to define the same singleton: symbol gates in
logos-basecamp, logos-logoscore-cli and logos-standalone-app, each shipped with
a negative control that plants a real duplicate and requires rejection.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
logos-protocol
The Logos protocol layer: transports, token exchange, and the
language-neutral lp_* C ABI (cpp/logos_protocol.h) that every Logos
SDK builds on.
Extracted from logos-cpp-sdk so that non-C++ SDKs (Rust, …) consume the
same transports, capability/token flow and wire behavior through one stable,
versioned boundary instead of re-wrapping the C++/Qt SDK.
What lives here
- Public C ABI —
cpp/logos_protocol.h: consumer surface (lp_client_*,lp_invoke[_async],lp_subscribe, tokens,lp_get_methods), provider groundwork (lp_provider_*), the trust-root surface (lp_grant_host_servicesand the two functions it gates), per-identity token stores (lp_token_isolate_identity,lp_token_get_for,lp_token_save_for,lp_token_reset_identity,lp_token_identity_is_isolated), and the protocol version (LOGOS_PROTOCOL_VERSION_*,lp_protocol_version(),lp_protocol_abi_major()). JSON-in-strings data model; bytes cross the boundary as{"_bytes":"<base64url>"}(lossless, NUL-safe). - Transports — plain TCP / TCP+TLS (Boost.Asio + OpenSSL + nlohmann,
Qt-free),
qt_local, in-memory mock, and Qt Remote Objects (qt_remote— the only Qt-bearing transport). - Consumer core —
LogosAPIClient/LogosAPIConsumerincluding the automaticcapability_module.requestModuletoken-fetch flow (behind the protocol boundary: every language gets it for free). - Provider-side plumbing —
ModuleProxy(auth gate the transports publish) and the abstractLogosProviderObjectinterface (logos_provider_interface.h). - Token manager, transport/registry factories, mode config (remote/local/mock), and the canonical QVariant↔JSON conversion used at the QRO boundary.
Per-identity token stores
TokenManager::instance() is the image's store. In a host that loads
several modules in one image it is also an ambient ring: the host writes
name -> that module's root auth token for every module it loads, and a client
presents a cached token before it ever mints one — so any module in that image
can reach any other with authority it was never granted, and no requestModule
appears in the log. Per-module origin strings do not change that, because
origin was never consulted on the path taken.
TokenManager::forIdentity(origin) makes origin select the store instead of
merely labelling the caller, and isolateIdentity(origin) is how a host opts a
name in (lp_token_isolate_identity and friends from C). Both are additive and
inert by default: until a name is isolated, forIdentity() returns the same
object instance() returns, so a host that knows nothing about this is
unchanged. A private store is seeded with the trust-root bootstrap (core,
capability_module) so first-call requestModule still works, and with nothing
else.
This is a second axis, not a replacement for the per-image split: a module
cdylib links its own copy of this library and therefore has its own
instance(), which stays correct as-is.
logos-cpp-sdk layers the typed C++ developer API (LogosAPI, module
context, code generator, provider base classes) on top of this repo.
Versioning
This repo carries the logos-protocol semver — the single number that governs Logos load/call compatibility. Two participants (modules, hosts, SDKs in any language) interoperate iff they share the same MAJOR. MINOR is additive/back-compatible; PATCH never affects compatibility. SDKs must re-expose the version of the protocol they linked (never mint their own).
Building
# Via workspace
ws build logos-protocol
# Standalone
nix build
# Tests
nix build .#tests
Layering invariant
logos-protocol depends only on Qt / Boost / OpenSSL / nlohmann_json — it
must NEVER depend on logos-cpp-sdk, logos-qt-sdk, logos-rust-sdk, liblogos
or logos-lidl. Everything points inward.