fix(doctests): unpin logoscore-cli, and retire the archived accounts module

The macOS doc-test job has been red since 2026-08-21: every module call came
back {"__logos_rpc_status__":"unauthorized"}, preceded in the daemon log by
capability_module rejecting the CLI's own requestModule handshake. Linux was
green throughout.

NOT MODULE ROT. A freshly-built test_basic_module failed identically to
accounts_module. Bisected on one macOS box, one variable, same CLI, same module:

    liblogos 3893c833 (parent)   ->  "result":42
    liblogos b2a9a0ba (#182)     ->  unauthorized

MECHANISM, from `nm -mu` on the logoscore binary:

    pre-#182:  TokenManager::instance()  (from liblogos_core)
    at-#182:   TokenManager::instance()  (from liblogos_module_client)

#182 made liblogos_core export ZERO TokenManager symbols -- they moved to
liblogos_protocol. macOS two-level namespace then rebound the CLI's imports to
the next image still statically absorbing a copy, so the CLI wrote its token
into one singleton while the runtime authorized against another. ELF cannot
show this: flat namespace collapses every definition onto the first-loaded
image, so Linux held the invariant by accident.

THE PIN IS THE BUG, not the linkage. The shared-runtime split landed as one pin
SET -- logos-protocol 2e3344a, logos-plugin-qt 1aa3e31, logos-liblogos b2a9a0b
(#182), logoscore-cli 2312a3a. This spec pinned the CLI at b92ade06
(2026-06-10) and overrode only logos-liblogos, manufacturing exactly the
half-migrated pairing the set exists to prevent. That pin's own commit (050f2d3)
called it "Temporary -- drop when the chain PRs merge"; nobody did. Dropping the
rev is the fix. logoscore master had already shed the deprecated
logos-module-client in its #48, so nothing there needs changing.

WHY THIS READ AS ONE FLAKY STEP rather than a total auth outage: "Call a method"
asserted on the bare string '"result"', which the unauthorized envelope also
contains. Both calls now assert values -- '"result":"hello"' and '"result":42'.

ALSO RETIRED: logos-accounts-module was archived on 2026-07-22. Both specs now
drive test_basic_module from logos-test-modules, via the
`#modules.$SYSTEM.<name>.lgx` attribute path the logoscore-cli doc-tests already
use. The module-runtime spec no longer clones a repo at all, so it loses its git
prerequisite and one step.

VERIFIED on aarch64-darwin against 959d11d9 -- the exact commit CI failed on:
34 passed, 0 failed (was 34 passed, 1 failed of 35), and zero "rejecting
unauthorized call" lines in the daemon log.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Dario Gabriel Lipicar
2026-08-26 23:32:20 -03:00
committed by Dario Lipicar
co-authored by Claude Opus 5
parent 2ac002b410
commit f05ed5a899
6 changed files with 176 additions and 176 deletions
+4 -4
View File
@@ -3,11 +3,11 @@ name: liblogos Doc-Tests
# Runs the executable liblogos doc-tests end-to-end via the shared doctest CLI,
# both pinned to the commit of logos-liblogos under test (via --release-for):
# - doctests/liblogos-module-runtime.test.yaml — drives liblogos through the
# logoscore CLI frontend (build logoscore against this commit, install the
# accounts module, start the daemon, load + call methods).
# logoscore CLI frontend (build logoscore against this commit, install
# test_basic_module, start the daemon, load + call methods).
# - doctests/liblogos-as-a-library.test.yaml — embeds liblogos directly:
# builds liblogos_core from this commit, compiles a C++ program that links
# it, installs modules with lgpm, and loads the accounts module via the C API.
# it, installs modules with lgpm, and loads test_basic_module via the C API.
# Both specs run in one invocation, producing a single combined report.
#
# ──────────────────────────────────────────────────────────────────────────────
@@ -230,7 +230,7 @@ jobs:
const body =
`${marker}\n` +
`### 📊 liblogos doc-test report\n\n` +
`The real accounts module, run through a logoscore daemon built against ` +
`A real module, run through a logoscore daemon built against ` +
`this commit of liblogos — rendered alongside the commands actually run ` +
`and their output (updated each run, commit \`${context.sha.slice(0,7)}\`):\n\n` +
`${links}\n\n` +
+33 -31
View File
@@ -18,10 +18,10 @@ intro: |
under test.
2. Build the `lgpm` package manager and install two real modules
([`capability_module`](https://github.com/logos-co/logos-capability-module)
and [`accounts_module`](https://github.com/logos-co/logos-accounts-module))
and [`test_basic_module`](https://github.com/logos-co/logos-test-modules))
into a local modules directory.
3. Write a ~50-line C++ program that links `liblogos_core`, then calls the C
API to start the runtime and load `accounts_module`.
API to start the runtime and load `test_basic_module`.
4. Build that program against this liblogos and run it — watching the module
come up over liblogos' own IPC.
@@ -36,7 +36,7 @@ intro: |
> as `logoscore` and basecamp do. You do **not** need to run Qt's event loop;
> the load calls are synchronous.
what_you_build: "A standalone C++ program that links `liblogos_core` from this commit and loads the real `accounts_module` through the C API."
what_you_build: "A standalone C++ program that links `liblogos_core` from this commit and loads a real module — `test_basic_module` through the C API."
what_you_learn:
- How to build `liblogos_core`, `logos_host`, and `logos_core.h` from a specific liblogos commit
@@ -100,8 +100,8 @@ sections:
text: |
The runtime discovers modules from a directory of installed packages. We
build the `lgpm` package manager and two real modules' `.lgx` packages,
then install them in the next step. `accounts_module` is loaded through the
host's capability layer, so we install `capability_module` alongside it.
then install them in the next step. `test_basic_module` is loaded through
the host's capability layer, so we install `capability_module` alongside it.
steps:
- title: "Build lgpm"
run: "nix build 'github:logos-co/logos-package-manager#cli' -o lgpm"
@@ -114,15 +114,17 @@ sections:
extra_run:
run: "ls cap-lgx/*.lgx"
- title: "Build the accounts module's .lgx"
- title: "Build the test module's .lgx"
text: |
This compiles the module and its SDK dependencies through Nix (the
accounts module wraps the go-wallet-sdk C library), so the first build
is slow.
run: "nix build 'github:logos-co/logos-accounts-module#lgx' -o accounts-lgx"
post_text: "The `.lgx` package is under `./accounts-lgx/`:"
`logos-test-modules` publishes each of its modules under
`modules.<system>.<name>`, so the attribute path carries the Nix system
double — `builtins.currentSystem` supplies it.
run: |
SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem')
nix build "github:logos-co/logos-test-modules#modules.$SYSTEM.test_basic_module.lgx" -o module-lgx
post_text: "The `.lgx` package is under `./module-lgx/`:"
extra_run:
run: "ls accounts-lgx/*.lgx"
run: "ls module-lgx/*.lgx"
- title: "Install the modules with lgpm"
step: true
@@ -137,18 +139,18 @@ sections:
expect_contains:
- "Installed to:"
- title: "Install accounts_module"
run: "./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file accounts-lgx/*.lgx"
- title: "Install test_basic_module"
run: "./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file module-lgx/*.lgx"
expect_contains:
- "Installed to:"
- title: "Confirm both modules are installed"
run: "./lgpm/bin/lgpm --modules-dir ./modules list"
expect_contains:
- "accounts_module"
- "test_basic_module"
- "capability_module"
- "core"
check_file: "modules/accounts_module/manifest.json"
check_file: "modules/test_basic_module/manifest.json"
post_text: |
Both modules now report type `core`, so `logos_core_start()` will
discover them.
@@ -203,7 +205,7 @@ sections:
setvbuf(stdout, nullptr, _IONBF, 0);
const char* modulesArg = (argc > 1) ? argv[1] : "./modules";
const char* moduleName = (argc > 2) ? argv[2] : "accounts_module";
const char* moduleName = (argc > 2) ? argv[2] : "test_basic_module";
// logos_core needs an absolute modules directory: it cannot read
// plugin metadata from a relative path. Resolve it up front.
@@ -300,24 +302,24 @@ sections:
module (here, the one from the library we built).
- `QT_QPA_PLATFORM=offscreen` — so Qt needs no display.
We point it at `./modules` and ask it to load `accounts_module`.
We point it at `./modules` and ask it to load `test_basic_module`.
steps:
- title: "Load accounts_module through the C API"
- title: "Load test_basic_module through the C API"
run: |
LOGOS_HOST_PATH="$PWD/liblogos/bin/logos_host" \
QT_QPA_PLATFORM=offscreen \
./embed-app/build/logos_embed_app ./modules accounts_module
./embed-app/build/logos_embed_app ./modules test_basic_module
code_block: |
export LOGOS_HOST_PATH="$PWD/liblogos/bin/logos_host"
export QT_QPA_PLATFORM=offscreen
./embed-app/build/logos_embed_app ./modules accounts_module
./embed-app/build/logos_embed_app ./modules test_basic_module
expect_contains:
- "Module loaded: capability_module"
- "Module loaded: accounts_module"
- "Module loaded: test_basic_module"
- "Load OK"
post_text: |
The output shows the runtime starting, discovering both modules,
bringing up `capability_module`, then loading `accounts_module` (a real
bringing up `capability_module`, then loading `test_basic_module` (a real
subprocess launched via `logos_host` and wired up over liblogos' IPC):
```
@@ -326,13 +328,13 @@ sections:
Module loaded: capability_module
Discovered modules:
- capability_module
- accounts_module
Loading 'accounts_module' (with dependencies)...
Module loaded: accounts_module
- test_basic_module
Loading 'test_basic_module' (with dependencies)...
Module loaded: test_basic_module
Load OK
Loaded modules:
- capability_module
- accounts_module
- test_basic_module
```
That is your own program — not the `logoscore` CLI — running a real
@@ -343,7 +345,7 @@ sections:
text: |
The C API loads and manages modules; it does not call their methods (that
goes over the typed IPC bridge, which the frontends wrap). To see what
`accounts_module` exposes, introspect the installed plugin with `lm`, the
`test_basic_module` exposes, introspect the installed plugin with `lm`, the
module inspector from [`logos-module`](https://github.com/logos-co/logos-module).
steps:
- title: "Build lm"
@@ -351,10 +353,10 @@ sections:
check_file: "lm/bin/lm"
- title: "List the module's invokable methods"
run: "./lm/bin/lm methods ./modules/accounts_module/accounts_module_plugin.{ext}"
code_block: "lm methods ./modules/accounts_module/accounts_module_plugin.{ext}"
run: "./lm/bin/lm methods ./modules/test_basic_module/test_basic_module_plugin.{ext}"
code_block: "lm methods ./modules/test_basic_module/test_basic_module_plugin.{ext}"
expect_contains:
- "createRandomMnemonic"
- "addInts"
post_text: |
These are the `Q_INVOKABLE` methods the module you just loaded exposes —
the entry points a frontend would call over the IPC bridge once the
+61 -61
View File
@@ -12,18 +12,18 @@ intro: |
commit under test** — so the runtime you exercise is built against the code
in this repository, not the latest published release.
2. Build the `lgpm` local package manager.
3. Build the real [`accounts_module`](https://github.com/logos-co/logos-accounts-module)
3. Build [`test_basic_module`](https://github.com/logos-co/logos-test-modules)
as an `.lgx` package straight from its own flake, and install it into a
`./modules` directory with `lgpm`.
4. Start `logoscore` in daemon mode (`-D`), load `accounts_module`, introspect
it, and call one of its methods — verifying the module actually runs on top
4. Start `logoscore` in daemon mode (`-D`), load `test_basic_module`, introspect
it, and call two of its methods — verifying the module actually runs on top
of this liblogos.
Because every layer (host, module loader, IPC) comes from the liblogos commit
under test, a green run is real evidence that this change keeps the module
runtime working.
what_you_build: "The real `accounts_module`, installed with `lgpm` and called through a `logoscore` daemon running on this liblogos commit."
what_you_build: "A real module — `test_basic_module` installed with `lgpm` and called through a `logoscore` daemon running on this liblogos commit."
what_you_learn:
- How to build `logoscore` against a specific `logos-liblogos` commit via `--override-input`
@@ -41,7 +41,6 @@ prerequisites:
```
Verify: `nix flake --help >/dev/null 2>&1 && echo "Flakes enabled"`
- "**git** — to clone the module repository."
- "A Linux or macOS machine."
sections:
@@ -56,11 +55,18 @@ sections:
> runner expands a release placeholder on it to a concrete ref. Locally that
> is this checkout's `HEAD` (see `run.sh`); in CI it is the commit being
> tested. With no pin it falls back to latest `master`.
> The CLI itself tracks `master`, deliberately. Only `logos-liblogos` is
> overridden, so everything else in the closure must be a revision that
> liblogos' current runtime pairs with — the shared-runtime split landed as
> one pin set across logos-protocol, logos-plugin-qt, logos-liblogos and
> this CLI, and an older CLI rev pinned here silently reintroduces a second
> copy of the runtime in the process.
steps:
- title: "Build the CLI with the liblogos override"
run: "nix build 'github:logos-co/logos-logoscore-cli/b92ade06cdbd3cdf48c8de5b8375cbcc3a6088cf' --override-input logos-liblogos 'github:logos-co/logos-liblogos{release}' --out-link ./logos"
run: "nix build 'github:logos-co/logos-logoscore-cli' --override-input logos-liblogos 'github:logos-co/logos-liblogos{release}' --out-link ./logos"
code_block: |
nix build 'github:logos-co/logos-logoscore-cli/b92ade06cdbd3cdf48c8de5b8375cbcc3a6088cf' \
nix build 'github:logos-co/logos-logoscore-cli' \
--override-input logos-liblogos 'github:logos-co/logos-liblogos' \
--out-link ./logos
check_file: "logos/bin/logoscore"
@@ -84,39 +90,36 @@ sections:
check_file: "lgpm/bin/lgpm"
post_text: "The executable is at `./lgpm/bin/lgpm`."
- title: "Build and install the accounts module"
- title: "Build and install a module"
step: true
text: |
Clone [`logos-accounts-module`](https://github.com/logos-co/logos-accounts-module),
build its `.lgx` straight from its flake's `#lgx` output, and install it
into a local `./modules` directory with `lgpm`. Every module built with
Build [`test_basic_module`](https://github.com/logos-co/logos-test-modules)'s
`.lgx` straight from its flake and install it into a local `./modules`
directory with `lgpm`. Every module built with
[`logos-module-builder`](https://github.com/logos-co/logos-module-builder)
exposes a ready-to-install `#lgx`.
exposes a ready-to-install `lgx` output.
steps:
- title: "Clone the module"
text: |
We clone over HTTPS so the step works in CI; over SSH the URL is
`git@github.com:logos-co/logos-accounts-module.git`.
run: "git clone --depth 1 https://github.com/logos-co/logos-accounts-module.git"
check_file: "logos-accounts-module/flake.nix"
- title: "Build the module's .lgx"
text: |
Build the `#lgx` output and link it as `./accounts-lgx`. (This compiles
the module and its SDK dependencies through Nix, so the first build is
slow.)
run: "nix build 'path:./logos-accounts-module#lgx' -o accounts-lgx"
`logos-test-modules` publishes each of its modules under
`modules.<system>.<name>`, so the attribute path carries the Nix system
double — `builtins.currentSystem` supplies it. Link the result as
`./module-lgx`.
run: |
SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem')
nix build "github:logos-co/logos-test-modules#modules.$SYSTEM.test_basic_module.lgx" -o module-lgx
code_block: |
# From inside the clone this is simply: nix build '.#lgx'
nix build 'path:./logos-accounts-module#lgx' -o accounts-lgx
post_text: "The `.lgx` package is now under `./accounts-lgx/`:"
# From inside a single-module repo this is simply: nix build '.#lgx'
SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem')
nix build "github:logos-co/logos-test-modules#modules.$SYSTEM.test_basic_module.lgx" -o module-lgx
post_text: "The `.lgx` package is now under `./module-lgx/`:"
extra_run:
run: "ls accounts-lgx/*.lgx"
run: "ls module-lgx/*.lgx"
- title: "Seed the modules directory with the bundled capability module"
text: |
`accounts_module` is loaded through the host's capability layer, so the
modules directory also needs the `capability_module` that ships with
Modules are loaded through the host's capability layer, so the modules
directory also needs the `capability_module` that ships with
`logoscore`. Copy it across first.
run: |
mkdir -p modules
@@ -125,10 +128,10 @@ sections:
- title: "Install the .lgx with lgpm"
text: |
Install the freshly-built package into `./modules`. `accounts_module` is
a `core` module, so it goes to `--modules-dir`. The package is unsigned
(a local dev build), so we pass `--allow-unsigned`.
run: "./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file accounts-lgx/*.lgx"
Install the freshly-built package into `./modules`. `test_basic_module`
is a `core` module, so it goes to `--modules-dir`. The package is
unsigned (a local dev build), so we pass `--allow-unsigned`.
run: "./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file module-lgx/*.lgx"
expect_contains:
- "Installed to:"
@@ -136,14 +139,14 @@ sections:
text: "Scan the directory and confirm the module landed:"
run: "./lgpm/bin/lgpm --modules-dir ./modules list"
expect_contains:
- "accounts_module"
check_file: "modules/accounts_module/manifest.json"
- "test_basic_module"
check_file: "modules/test_basic_module/manifest.json"
- title: "Run the daemon and call the module"
step: true
text: |
Start `logoscore` in daemon mode pointed at `./modules`, then use the client
subcommands to load `accounts_module`, introspect it, and call one of its
subcommands to load `test_basic_module`, introspect it, and call two of its
methods. Daemon output is captured in `logs.txt`.
steps:
- title: "Start the daemon"
@@ -168,18 +171,18 @@ sections:
code_block: "logoscore status"
- title: "List discovered modules"
text: "`accounts_module` should be visible in the scan directory:"
text: "`test_basic_module` should be visible in the scan directory:"
run: "./logos/bin/logoscore list-modules"
code_block: "logoscore list-modules"
expect_contains:
- "accounts_module"
- "test_basic_module"
- title: "Load the module"
text: "Load `accounts_module` into the running daemon:"
run: "./logos/bin/logoscore load-module accounts_module"
code_block: "logoscore load-module accounts_module"
text: "Load `test_basic_module` into the running daemon:"
run: "./logos/bin/logoscore load-module test_basic_module"
code_block: "logoscore load-module test_basic_module"
expect_contains:
- "accounts_module"
- "test_basic_module"
- title: "Confirm the module is loaded"
text: |
@@ -188,39 +191,36 @@ sections:
run: "./logos/bin/logoscore status"
code_block: "logoscore status"
expect_contains:
- "accounts_module"
- "test_basic_module"
- '"status":"loaded"'
- title: "Introspect the module with module-info"
text: |
`module-info` lists the `Q_INVOKABLE` methods the module exposes — the
`module-info` lists the methods and events the module exposes — the
same methods you can `call`:
run: "./logos/bin/logoscore module-info accounts_module"
code_block: "logoscore module-info accounts_module"
run: "./logos/bin/logoscore module-info test_basic_module"
code_block: "logoscore module-info test_basic_module"
expect_contains:
- "accounts_module"
- "createRandomMnemonic"
- "addInts"
- "echo"
- title: "Call a method"
text: |
Generate a fresh 12-word BIP-39 mnemonic. `createRandomMnemonic` takes
the word count and returns the phrase — a real round-trip through the
go-wallet-sdk C library wrapped by the module, dispatched over liblogos'
IPC:
run: "./logos/bin/logoscore call accounts_module createRandomMnemonic 12"
code_block: "logoscore call accounts_module createRandomMnemonic 12"
`echo` returns its argument unchanged — a string round-trip out to the
module subprocess and back over liblogos' IPC:
run: "./logos/bin/logoscore call test_basic_module echo hello"
code_block: "logoscore call test_basic_module echo hello"
expect_contains:
- '"result"'
- '"result":"hello"'
- title: "Call a second method"
text: |
`lengthToEntropyStrength` maps a mnemonic word count to its entropy
strength in bits — 12 words is 128 bits. This exercises an `int`
round-trip:
run: "./logos/bin/logoscore call accounts_module lengthToEntropyStrength 12"
code_block: "logoscore call accounts_module lengthToEntropyStrength 12"
`addInts` adds its two arguments. This exercises an `int` round-trip,
where `echo` exercised a string:
run: "./logos/bin/logoscore call test_basic_module addInts 40 2"
code_block: "logoscore call test_basic_module addInts 40 2"
expect_contains:
- '"result":128'
- '"result":42'
- title: "Stop the daemon"
text: "Shut the daemon down cleanly:"
+28 -26
View File
@@ -15,10 +15,10 @@ program**, built against **this** liblogos commit:
under test.
2. Build the `lgpm` package manager and install two real modules
([`capability_module`](https://github.com/logos-co/logos-capability-module)
and [`accounts_module`](https://github.com/logos-co/logos-accounts-module))
and [`test_basic_module`](https://github.com/logos-co/logos-test-modules))
into a local modules directory.
3. Write a ~50-line C++ program that links `liblogos_core`, then calls the C
API to start the runtime and load `accounts_module`.
API to start the runtime and load `test_basic_module`.
4. Build that program against this liblogos and run it — watching the module
come up over liblogos' own IPC.
@@ -33,7 +33,7 @@ an embeddable library, not just through the `logoscore` frontend.
> as `logoscore` and basecamp do. You do **not** need to run Qt's event loop;
> the load calls are synchronous.
**What you'll build:** A standalone C++ program that links `liblogos_core` from this commit and loads the real `accounts_module` through the C API.
**What you'll build:** A standalone C++ program that links `liblogos_core` from this commit and loads a real module — `test_basic_module` through the C API.
**What you'll learn:**
@@ -82,7 +82,7 @@ header, and the `logos_host` binary.
### 1.1 Build the library
```bash
nix build 'github:logos-co/logos-liblogos/5f8139723702a8fff7eee6ae20c042be1c72159f' -o ./liblogos
nix build 'github:logos-co/logos-liblogos' -o ./liblogos
```
The result has three things your program depends on:
@@ -104,8 +104,8 @@ ls liblogos/include/logos_core.h liblogos/lib/liblogos_core.dylib liblogos/bin/l
The runtime discovers modules from a directory of installed packages. We
build the `lgpm` package manager and two real modules' `.lgx` packages,
then install them in the next step. `accounts_module` is loaded through the
host's capability layer, so we install `capability_module` alongside it.
then install them in the next step. `test_basic_module` is loaded through
the host's capability layer, so we install `capability_module` alongside it.
### 2.1 Build lgpm
@@ -127,20 +127,22 @@ The `.lgx` package is under `./cap-lgx/`:
ls cap-lgx/*.lgx
```
### 2.3 Build the accounts module's .lgx
### 2.3 Build the test module's .lgx
This compiles the module and its SDK dependencies through Nix (the
accounts module wraps the go-wallet-sdk C library), so the first build
is slow.
`logos-test-modules` publishes each of its modules under
`modules.<system>.<name>`, so the attribute path carries the Nix system
double — `builtins.currentSystem` supplies it.
```bash
nix build 'github:logos-co/logos-accounts-module#lgx' -o accounts-lgx
SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem')
nix build "github:logos-co/logos-test-modules#modules.$SYSTEM.test_basic_module.lgx" -o module-lgx
```
The `.lgx` package is under `./accounts-lgx/`:
The `.lgx` package is under `./module-lgx/`:
```bash
ls accounts-lgx/*.lgx
ls module-lgx/*.lgx
```
---
@@ -158,10 +160,10 @@ builds, so we pass `--allow-unsigned`.
./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file cap-lgx/*.lgx
```
### 3.2 Install accounts_module
### 3.2 Install test_basic_module
```bash
./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file accounts-lgx/*.lgx
./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file module-lgx/*.lgx
```
### 3.3 Confirm both modules are installed
@@ -222,7 +224,7 @@ int main(int argc, char** argv) {
setvbuf(stdout, nullptr, _IONBF, 0);
const char* modulesArg = (argc > 1) ? argv[1] : "./modules";
const char* moduleName = (argc > 2) ? argv[2] : "accounts_module";
const char* moduleName = (argc > 2) ? argv[2] : "test_basic_module";
// logos_core needs an absolute modules directory: it cannot read
// plugin metadata from a relative path. Resolve it up front.
@@ -321,18 +323,18 @@ Run the program. It needs two things in the environment:
module (here, the one from the library we built).
- `QT_QPA_PLATFORM=offscreen` — so Qt needs no display.
We point it at `./modules` and ask it to load `accounts_module`.
We point it at `./modules` and ask it to load `test_basic_module`.
### 6.1 Load accounts_module through the C API
### 6.1 Load test_basic_module through the C API
```bash
export LOGOS_HOST_PATH="$PWD/liblogos/bin/logos_host"
export QT_QPA_PLATFORM=offscreen
./embed-app/build/logos_embed_app ./modules accounts_module
./embed-app/build/logos_embed_app ./modules test_basic_module
```
The output shows the runtime starting, discovering both modules,
bringing up `capability_module`, then loading `accounts_module` (a real
bringing up `capability_module`, then loading `test_basic_module` (a real
subprocess launched via `logos_host` and wired up over liblogos' IPC):
```
@@ -341,13 +343,13 @@ Starting (modules dir: .../modules)
Module loaded: capability_module
Discovered modules:
- capability_module
- accounts_module
Loading 'accounts_module' (with dependencies)...
Module loaded: accounts_module
- test_basic_module
Loading 'test_basic_module' (with dependencies)...
Module loaded: test_basic_module
Load OK
Loaded modules:
- capability_module
- accounts_module
- test_basic_module
```
That is your own program — not the `logoscore` CLI — running a real
@@ -359,7 +361,7 @@ module on top of this liblogos.
The C API loads and manages modules; it does not call their methods (that
goes over the typed IPC bridge, which the frontends wrap). To see what
`accounts_module` exposes, introspect the installed plugin with `lm`, the
`test_basic_module` exposes, introspect the installed plugin with `lm`, the
module inspector from [`logos-module`](https://github.com/logos-co/logos-module).
### 7.1 Build lm
@@ -371,7 +373,7 @@ nix build 'github:logos-co/logos-module#lm' -o lm
### 7.2 List the module's invokable methods
```bash
lm methods ./modules/accounts_module/accounts_module_plugin.dylib
lm methods ./modules/test_basic_module/test_basic_module_plugin.dylib
```
These are the `Q_INVOKABLE` methods the module you just loaded exposes —
+48 -52
View File
@@ -9,18 +9,18 @@ end-to-end through the headless `logoscore` runtime:
commit under test** — so the runtime you exercise is built against the code
in this repository, not the latest published release.
2. Build the `lgpm` local package manager.
3. Build the real [`accounts_module`](https://github.com/logos-co/logos-accounts-module)
3. Build [`test_basic_module`](https://github.com/logos-co/logos-test-modules)
as an `.lgx` package straight from its own flake, and install it into a
`./modules` directory with `lgpm`.
4. Start `logoscore` in daemon mode (`-D`), load `accounts_module`, introspect
it, and call one of its methods — verifying the module actually runs on top
4. Start `logoscore` in daemon mode (`-D`), load `test_basic_module`, introspect
it, and call two of its methods — verifying the module actually runs on top
of this liblogos.
Because every layer (host, module loader, IPC) comes from the liblogos commit
under test, a green run is real evidence that this change keeps the module
runtime working.
**What you'll build:** The real `accounts_module`, installed with `lgpm` and called through a `logoscore` daemon running on this liblogos commit.
**What you'll build:** A real module — `test_basic_module` installed with `lgpm` and called through a `logoscore` daemon running on this liblogos commit.
**What you'll learn:**
@@ -40,7 +40,6 @@ echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf
Verify: `nix flake --help >/dev/null 2>&1 && echo "Flakes enabled"`
- **git** — to clone the module repository.
- A Linux or macOS machine.
---
@@ -56,10 +55,17 @@ than the latest release. The result is symlinked to `./logos/`.
> is this checkout's `HEAD` (see `run.sh`); in CI it is the commit being
> tested. With no pin it falls back to latest `master`.
> The CLI itself tracks `master`, deliberately. Only `logos-liblogos` is
> overridden, so everything else in the closure must be a revision that
> liblogos' current runtime pairs with — the shared-runtime split landed as
> one pin set across logos-protocol, logos-plugin-qt, logos-liblogos and
> this CLI, and an older CLI rev pinned here silently reintroduces a second
> copy of the runtime in the process.
### 1.1 Build the CLI with the liblogos override
```bash
nix build 'github:logos-co/logos-logoscore-cli/b92ade06cdbd3cdf48c8de5b8375cbcc3a6088cf' \
nix build 'github:logos-co/logos-logoscore-cli' \
--override-input logos-liblogos 'github:logos-co/logos-liblogos' \
--out-link ./logos
```
@@ -89,44 +95,37 @@ The executable is at `./lgpm/bin/lgpm`.
---
## Step 3: Build and install the accounts module
## Step 3: Build and install a module
Clone [`logos-accounts-module`](https://github.com/logos-co/logos-accounts-module),
build its `.lgx` straight from its flake's `#lgx` output, and install it
into a local `./modules` directory with `lgpm`. Every module built with
Build [`test_basic_module`](https://github.com/logos-co/logos-test-modules)'s
`.lgx` straight from its flake and install it into a local `./modules`
directory with `lgpm`. Every module built with
[`logos-module-builder`](https://github.com/logos-co/logos-module-builder)
exposes a ready-to-install `#lgx`.
exposes a ready-to-install `lgx` output.
### 3.1 Clone the module
### 3.1 Build the module's .lgx
We clone over HTTPS so the step works in CI; over SSH the URL is
`git@github.com:logos-co/logos-accounts-module.git`.
`logos-test-modules` publishes each of its modules under
`modules.<system>.<name>`, so the attribute path carries the Nix system
double — `builtins.currentSystem` supplies it. Link the result as
`./module-lgx`.
```bash
git clone --depth 1 https://github.com/logos-co/logos-accounts-module.git
# From inside a single-module repo this is simply: nix build '.#lgx'
SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem')
nix build "github:logos-co/logos-test-modules#modules.$SYSTEM.test_basic_module.lgx" -o module-lgx
```
### 3.2 Build the module's .lgx
Build the `#lgx` output and link it as `./accounts-lgx`. (This compiles
the module and its SDK dependencies through Nix, so the first build is
slow.)
The `.lgx` package is now under `./module-lgx/`:
```bash
# From inside the clone this is simply: nix build '.#lgx'
nix build 'path:./logos-accounts-module#lgx' -o accounts-lgx
ls module-lgx/*.lgx
```
The `.lgx` package is now under `./accounts-lgx/`:
### 3.2 Seed the modules directory with the bundled capability module
```bash
ls accounts-lgx/*.lgx
```
### 3.3 Seed the modules directory with the bundled capability module
`accounts_module` is loaded through the host's capability layer, so the
modules directory also needs the `capability_module` that ships with
Modules are loaded through the host's capability layer, so the modules
directory also needs the `capability_module` that ships with
`logoscore`. Copy it across first.
```bash
@@ -135,17 +134,17 @@ cp -RL ./logos/modules/. ./modules/
```
### 3.4 Install the .lgx with lgpm
### 3.3 Install the .lgx with lgpm
Install the freshly-built package into `./modules`. `accounts_module` is
a `core` module, so it goes to `--modules-dir`. The package is unsigned
(a local dev build), so we pass `--allow-unsigned`.
Install the freshly-built package into `./modules`. `test_basic_module`
is a `core` module, so it goes to `--modules-dir`. The package is
unsigned (a local dev build), so we pass `--allow-unsigned`.
```bash
./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file accounts-lgx/*.lgx
./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file module-lgx/*.lgx
```
### 3.5 Confirm the install
### 3.4 Confirm the install
Scan the directory and confirm the module landed:
@@ -158,7 +157,7 @@ Scan the directory and confirm the module landed:
## Step 4: Run the daemon and call the module
Start `logoscore` in daemon mode pointed at `./modules`, then use the client
subcommands to load `accounts_module`, introspect it, and call one of its
subcommands to load `test_basic_module`, introspect it, and call two of its
methods. Daemon output is captured in `logs.txt`.
### 4.1 Start the daemon
@@ -195,7 +194,7 @@ logoscore status
### 4.4 List discovered modules
`accounts_module` should be visible in the scan directory:
`test_basic_module` should be visible in the scan directory:
```bash
logoscore list-modules
@@ -203,10 +202,10 @@ logoscore list-modules
### 4.5 Load the module
Load `accounts_module` into the running daemon:
Load `test_basic_module` into the running daemon:
```bash
logoscore load-module accounts_module
logoscore load-module test_basic_module
```
### 4.6 Confirm the module is loaded
@@ -220,32 +219,29 @@ logoscore status
### 4.7 Introspect the module with module-info
`module-info` lists the `Q_INVOKABLE` methods the module exposes — the
`module-info` lists the methods and events the module exposes — the
same methods you can `call`:
```bash
logoscore module-info accounts_module
logoscore module-info test_basic_module
```
### 4.8 Call a method
Generate a fresh 12-word BIP-39 mnemonic. `createRandomMnemonic` takes
the word count and returns the phrase — a real round-trip through the
go-wallet-sdk C library wrapped by the module, dispatched over liblogos'
IPC:
`echo` returns its argument unchanged — a string round-trip out to the
module subprocess and back over liblogos' IPC:
```bash
logoscore call accounts_module createRandomMnemonic 12
logoscore call test_basic_module echo hello
```
### 4.9 Call a second method
`lengthToEntropyStrength` maps a mnemonic word count to its entropy
strength in bits — 12 words is 128 bits. This exercises an `int`
round-trip:
`addInts` adds its two arguments. This exercises an `int` round-trip,
where `echo` exercised a string:
```bash
logoscore call accounts_module lengthToEntropyStrength 12
logoscore call test_basic_module addInts 40 2
```
### 4.10 Stop the daemon
+2 -2
View File
@@ -5,10 +5,10 @@
# Two specs run, each exercising THIS liblogos commit a different way:
# - liblogos-module-runtime.test.yaml — drives liblogos through the headless
# `logoscore` CLI frontend (build logoscore against this liblogos, install
# the accounts module, start the daemon, call methods).
# test_basic_module, start the daemon, call methods).
# - liblogos-as-a-library.test.yaml — embeds liblogos directly: builds
# liblogos_core from this commit, compiles a small C++ program that links it,
# installs modules with lgpm, and loads the accounts module through the C API.
# installs modules with lgpm, and loads test_basic_module through the C API.
#
# The runner is the shared `doctest` CLI
# (https://github.com/logos-co/logos-doctest), invoked directly via its flake.