Files
logos-cpp-sdk/flake.lock
Dario Gabriel LipicarandClaude Opus 5 4778ced7fa feat(cdylib): generic recursive type contract, no silent admissions
The parser mapped a hand-written list of C++ spellings and fell back to the
opaque primitive `any` for everything else; the gate admits `any`. So an
unrecognised spelling was silently accepted and then

  - worked by luck through nlohmann's implicit conversions, or
  - threw at call time (dispatch_failed on a tagged-bytes object where the
    blanket get<>() wanted numbers), or worst
  - emitted a NON-canonical wire value: a vector<vector<vector<uint8_t>>> return
    went out as untagged nested number arrays that no consumer decodes as bytes.

Now there is a leaf set, and composition that is generic and recursive.

  parser  - numbers are 64-bit ONLY: int64_t, uint64_t, double. Narrower
            spellings are NOT auto-widened — widening would let the declared C++
            type and the published LIDL contract disagree about range. uint8_t
            has one meaning: std::vector<uint8_t> = bstr.
          - nlohmann::json is named explicitly. It only ever reached `any` via
            the fallback, so making the fallback an error without this breaks
            test_fullapi_cpp, test_fullapi_proxy and both full_api interface
            headers — the cross-language conformance chain.
          - std::vector<T> and std::map/unordered_map<std::string,T> recurse
            through the same function, so nesting composes to any depth
          - anything left becomes TypeExpr::Named carrying the C++ spelling
  gate    - typeSupported recurses; the message names the offending type and,
            for a narrow numeric, the fix:
              parameter 'depth' has a type outside the cdylib-supported
              (Qt-free) subset (uint32_t — numbers are 64-bit here: use
              uint64_t; uint8_t is only meaningful as std::vector<uint8_t>,
              i.e. bstr)
  emitter - params decode via logos::JsonArg, which converts itself into the
            author's parameter type, so no type name is emitted and no
            LIDL->C++ mapping table has to stay in sync
          - returns and event payloads encode via logos::toJson
          - the ~60-line base64/tagged-bytes codec emitted into EVERY module is
            gone, as are #111's lidlBytesList* helpers and the gating that
            existed only to avoid unused static functions. Modules include
            logos-protocol's logos_codec.h instead.
          - dropped the LogosMap/LogosList "already json" special case: toJson
            of an nlohmann::json is the identity, and inferring it from the LIDL
            kind is wrong now that a plain std::map is also Map-kind (it emitted
            result.dump() on a std::map and failed to compile).

Compatibility, from a scan of every universal module. cdylib-interface modules
(all the Rust ones) and ui_qml backends never reach this parser. Two modules
need a source edit:

  - logos-execution-zone-module: 3 slots spell uint32_t (one scalar, two
    vector<uint32_t>) -> uint64_t / vector<uint64_t>. They silently worked as
    `any` before.
  - logos-libp2p-module: createXpr takes vector<pair<string,string>>, which has
    no canonical JSON form. Wants map<string, vector<uint8_t>> ({tstr: bstr}) —
    the pair's second element carries raw binary, so a string-pair widening
    would be UTF-8-lossy.

Everything else builds unchanged.

Verified end to end, not just as emitted text — a module with bytes at three
nesting depths and a string-keyed map of bytes, driven through logoscore over
the real transport:

  [[bstr]] param  -> "2|2,2:0:255:255,0👎-1:0|0"   (byte-exact, empties kept)
  {tstr: bstr}    -> "2|a=2:128:1:129|b=0👎-1:0"
  [[bstr]] return -> [[{"_bytes":"AP8"},{"_bytes":""}],[]]
  {tstr: bstr} ret-> {"a":{"_bytes":"gAE"},"b":{"_bytes":""}}
  bad element     -> {"code":"dispatch_failed","message":"expected integer at
                      arg1[0], got string"}

Generator probes on real headers: libp2p and lez_core are both rejected by name
with the fix in the message; test_fullapi_cpp keeps echoAny(v: any) -> any.

Tests: 172/172. Re-pin logos-protocol to master once its PR lands.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 22:25:27 -03:00

102 lines
2.4 KiB
JSON

{
"nodes": {
"logos-lidl": {
"inputs": {
"logos-nix": [
"logos-nix"
],
"nixpkgs": [
"logos-lidl",
"logos-nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1781653473,
"narHash": "sha256-8l2tE2K5nY1grcFROQHC1By1jVI0NrfkS3k2v2y6R2I=",
"owner": "logos-co",
"repo": "logos-lidl",
"rev": "8c95d4f0cc6a10195c70ed71e85b7a4cddca02f8",
"type": "github"
},
"original": {
"owner": "logos-co",
"repo": "logos-lidl",
"type": "github"
}
},
"logos-nix": {
"inputs": {
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1774455309,
"narHash": "sha256-3AN7aFnArdysrbQQ2UskWzjNSFADb4hDCsnx69Fa0ng=",
"owner": "logos-co",
"repo": "logos-nix",
"rev": "e637a1f5e871244d1c2df1e3c52a067f2eb406f2",
"type": "github"
},
"original": {
"owner": "logos-co",
"repo": "logos-nix",
"type": "github"
}
},
"logos-protocol": {
"inputs": {
"logos-nix": [
"logos-nix"
],
"nixpkgs": [
"logos-protocol",
"logos-nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1785110737,
"narHash": "sha256-jM5RgMD3KrQKupw3BY/Y2qohmFL+gd+J1j/NjsmLWU8=",
"owner": "logos-co",
"repo": "logos-protocol",
"rev": "8b5b562e9accf3979e24728ecb7dde7dd363f9fb",
"type": "github"
},
"original": {
"owner": "logos-co",
"repo": "logos-protocol",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1759036355,
"narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"logos-lidl": "logos-lidl",
"logos-nix": "logos-nix",
"logos-protocol": "logos-protocol",
"nixpkgs": [
"logos-nix",
"nixpkgs"
]
}
}
},
"root": "root",
"version": 7
}