mirror of
https://github.com/logos-co/logos-modules-state-module.git
synced 2026-08-27 13:11:12 +00:00
Optional RETURNS are supported now (logos-qt-sdk lifted the gate), so the
contract can be the shape the draft specs describe instead of the shape the
generator allowed.
module_record(module: tstr) -> ? ModuleRecord. A miss is std::nullopt. The
old workaround — a record spelling the miss as state:"absent", seq:0 — is
gone, and so is the essay justifying it. Both of that essay's premises are
now false, and I checked rather than assumed: `?T` keeps its value type
(the generated consumer says std::optional<ModuleRecord>, not a bare
QVariant), and logoscore's core_service no longer turns a null result into
METHOD_FAILED — call_envelope.cpp asks the module for its method list on a
null return and answers METHOD_NOT_FOUND only when introspection proves the
method absent, otherwise status ok with null as the value. Verified by
running it: an unknown module answers {"status":"ok","result":null}.
`absent` was carrying two loads and only one survives. The miss answer is
now the empty optional. The MEMBERSHIP EDGES are the load-bearing half —
absent->unloaded on discovery, unloaded->absent on prune — and without them
a consumer is back to inferring lifecycle from package-install events plus
a 100ms settle, which is what this module exists to stop.
So absent is now EVENT-ONLY: expressible as old_state/new_state, never
carried by a record. A transition into absent ERASES the record, which
makes the never-absent invariant hold by construction rather than by a
filter someone can forget. That erase also destroys the seq the replay rule
compares against, so a seq tombstone keeps a stale delta from resurrecting
a pruned module — the same tombstone the absent record used to be, minus
the fake record.
This shrinks the divergence from logos-lips#317 from a sixth RECORD STATE
to one event-only transition target.
Adds tests/, and they are worth more than the count suggests. Each of the
three invariants was mutated — the erase removed, the tombstone lookup
dropped, the empty-state skip deleted — and each mutation was verified to
APPLY before being trusted, then seen to turn the suite red and back green.
The suite very nearly did not run at all. mkLogosModuleTests executes
`find . -executable \( -name "*_tests" -o -name "*_test" \)` and pipes it
into a while-read loop, so a binary named anything else is built, matched
by nothing, and never executed — while the check still goes green, because
compiling was all that happened. This suite was called
`modules_state_invariants` and passed all three mutations it should have
caught before that was noticed. The CMakeLists says so now.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
30 lines
960 B
Nix
30 lines
960 B
Nix
{
|
|
description = "modules_state - read-only registry of module lifecycle state";
|
|
|
|
inputs = {
|
|
logos-module-builder.url = "github:logos-co/logos-module-builder";
|
|
};
|
|
|
|
outputs = inputs@{ logos-module-builder, ... }:
|
|
let
|
|
module = logos-module-builder.lib.mkLogosModule {
|
|
src = ./.;
|
|
configFile = ./metadata.json;
|
|
flakeInputs = inputs;
|
|
};
|
|
in
|
|
module // {
|
|
# Written as a literal `checks =` on purpose: `ws sync-graph` decides
|
|
# hasTests by grepping the flake for exactly that, so a checks output
|
|
# reached any other way records hasTests=false and `ws test` then reports
|
|
# "no tests" WITHOUT failing — which is the same green-by-absence this
|
|
# module's own invariants are here to stop.
|
|
checks = logos-module-builder.lib.mkLogosModuleTests {
|
|
src = ./.;
|
|
testDir = ./tests;
|
|
configFile = ./metadata.json;
|
|
flakeInputs = inputs;
|
|
};
|
|
};
|
|
}
|