Dario LipicarandClaude Opus 5 dda5dae1bf test(plain): bound the burst-drain assertion against the burst, not a constant (#56)
BurstThatGoesIdleDrainsWithoutAnotherCall failed on ubuntu-latest at 21, then at
10 on a re-run, against EXPECT_LE(idle, 8u) — having scored 7 against that same
8 the run before. The change under review is not involved: the same source
compiles to a byte-identical object file with and without it.

WHAT THE RESIDUE IS. A waiter reaps only OTHERS, never itself, so what survives
an idle burst is whatever published after the FINAL reap: the last waiter to
finish has nobody behind it, and a waiter sitting in the join loop of its own
reap has not published yet while the batch it did not collect already has. That
is the size of the last exit batch, which is the scheduler's business.

AND NOTHING TAKES IT LATER, so this is not a window that was too short. Sampled
from 100ms to 25.6s after the burst went quiet the count does not move: 5->5 and
17->17 idle, 2->2 under 4x CPU oversubscription, and 24->24, 33->33, 49->49,
82->82, 123->123, 138->138, 168->168 under 32x — 12 runs, every one flat. It is
a residue, not a drain in progress.

MEASURED, 20 runs per cell, this 800-call burst, m_waiters when it goes idle:

                    this code             reaping only on the spawn path
  macOS idle        1 every run           572-723
  Linux idle        1-80  (median 9)      4-168   (median 80)
  Linux 2x CPU      1-145 (median 14)     16-527  (median 275)
  Linux 4x CPU      1-104 (median 28)     10-504  (median 271)

Two things fall out of that, and the second is why this commit says more than
"the number was too small".

  1. 8 WAS READ OFF THE macOS COLUMN. On Linux it sits under the MEDIAN of a
     correct build — 35 of 60 unloaded runs of correct code exceed it — so the
     test was failing correct code in most Linux runs. CI's 7 was luck.

  2. THE ~600 THIS TEST IS DOCUMENTED AGAINST IS macOS-ONLY. On Linux the burst
     is not concurrent: spawning 800 std::threads costs more than a loopback
     ping, so most of it has already been collected by the SPAWN-path reaper
     before the last call is issued, and the defect's own residue collapses
     into the same range as a correct build's (4-168 idle, min 4). The two arms
     overlap there at any bound, 8 included. This assertion is a coarse
     retention check on Linux, not the detector for that defect.

THE NEW BOUND is kBurst/2 — the majority of the burst must have retired itself
with no further call — because the residue has no ceiling for a tighter
fraction to sit under. Worst per load level, 620 runs on a 6-core Linux box:

  idle 152 (n=60)  2x 145 (n=20)  4x 172 (n=80)  8x 175 (n=160)
  16x 278 (n=120)  32x 402 (n=60)  64x 317 (n=40)

Flat out to 8x, climbing after. A quarter of the burst (200) would have been
the original mistake in a new unit: it clears the worst by 1.14x, the same
ratio as 7-against-8. Half clears everything up to 16x by 1.44x and the worst
CI has ever produced (21) by 19x. The single run in 620 that scored 402, at 32x
oversubscription, is recorded in the comment rather than rounded away.

Both assertions in the test take the same expression, the second included: a
residue the follow-up call did not collect is the same retention bug, and a
tighter hard-coded number there would only move the magic constant somewhere
quieter.

Also corrects the retention note in plain_logos_object.h, which quoted "1-2
after a 2000-call burst" as though it were platform-independent.

THE DETECTOR, rebuilt with the defect this test exists to catch — the reap
dropped from the waiter's exit guard, leaving only the spawn path:

  this assertion, macOS          RED 10/10, 550-614 against 400
  this assertion, Linux 16x      RED 4/10, up to 645
  this assertion, Linux idle     GREEN 0/15, 25-208 — see below
  publish-is-last, macOS         RED 5/5
  publish-is-last, Linux         RED 8/8   (green 3/3 with the reap in place)
  nix build '.#tests'            fails its own checkPhase with the defect in

The third line is a real loss of Linux coverage in THIS assertion and it is
stated in the comment rather than glossed: on an unloaded Linux box no bound
that a correct build survives will catch it, because the burst is not
concurrent there. It costs the SUITE nothing — with the exit-guard reap gone,
PublishedWaiterDoesNotTouchTheRegistryAgain is RED deterministically on both
platforms, and it is that test, not this one, that pins the reap. If this one
ever has to be the detector again, the answer is to pace the provider so the
burst is concurrent on every platform, not to tighten the number.

No behaviour change: the only non-comment edit is the bound.

VERIFIED: nix build '.#tests' green on macOS (289/289, 69.6s) and Linux
(289/289, 78.3s).


(cherry picked from commit f147aed2c6)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 10:55:37 -03:00
2026-06-09 23:33:17 -03:00
2026-06-09 23:37:23 -03:00
2026-06-09 23:37:23 -03:00
2026-06-09 23:33:17 -03:00

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 ABIcpp/logos_protocol.h: consumer surface (lp_client_*, lp_invoke[_async], lp_subscribe, tokens, lp_get_methods), provider groundwork (lp_provider_*), 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 coreLogosAPIClient / LogosAPIConsumer including the automatic capability_module.requestModule token-fetch flow (behind the protocol boundary: every language gets it for free).
  • Provider-side plumbingModuleProxy (auth gate the transports publish) and the abstract LogosProviderObject interface (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.

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.

S
Description
No description provided
Readme
1.6 MiB
Languages
C++ 91.5%
C 3.9%
CMake 2.7%
Nix 1.1%
Shell 0.8%