commits
- Add doc comments to Map_int.{map,mem,mem_opt,mem_default,seal} (E325).
- Rewrite uint/int/text/bytes doc comments to lead with [name] (E331).
- Re-export Value.pp / Value.equal at the top of Cbor (E305: type t was
missing pp).
- Refactor Codec.nth into nth_decode_definite + nth_decode_indefinite to
drop below the function-length threshold.
- Add a test_codec.ml smoke suite (round-trips through every major-type
combinator) to satisfy E605 and exercise the codec.ml surface directly.
315 tests pass; merlint clean on ocaml-cbor.
The new error_quality_cases suite asserts that rendered Cbor.Error messages
name the specific path, key, index, or bound where decoding failed — not just
a generic complaint. The first run of these tests caught a real bug in
[Cbor.Codec.mem] / [int_mem]: when the inner codec failed on the matched
value, the stream was left at an unknown position (header consumed but body
not), and the post-match drain loop then read garbage from inside the
previous text/bytes content, surfacing as "unexpected end of input" instead
of the real type mismatch.
Fix: extract a [drain_map_entries] helper used only on the success path; on
inner-decode error, return the error directly without trying to walk the rest
of the map. The trailing-bytes check in [Cbor.of_reader] passes the typed
error through unchanged.
Also wires up the cfdp_eio test sublib that an earlier session left
half-migrated: adds [test/eio/dune], appends [Alcotest.run] to
[test_cfdp_eio.ml], drops the dangling [Test_eio.suite] reference from
[test/test.ml]. The whole monorepo builds clean again.
306 cbor tests pass (9 new error-quality cases).
The codec record drops its Value.t-based [encode] / [decode] fields, leaving
[{ kind; encode_rw; decode_rw }] — codecs now write to a Binary.encoder and
read from a Binary.decoder directly, building 'a from bytes without an
intermediate Value.t. This satisfies the ocaml-encodings skill's "codec.ml
does not depend on value.ml" rule; only cbor.ml bridges the two via
[Binary.read_cbor] / [write_cbor].
Surface follows RFC 8949 spec order: cbor.mli sections walk major types 0-7,
then simple values (3.3) and tags (3.4), each linking to the relevant clause.
Combinators move under [Cbor.Codec] (was top-level on [Cbor]); naming tracks
CDDL: [Cbor.Obj] -> [Cbor.Codec.Map], [Cbor.Obj_int] -> [Cbor.Codec.Map_int],
[Cbor.string] -> [Cbor.Codec.text], [Cbor.string_map] -> [Cbor.Codec.text_map].
Top-level IO verbs follow the parallel naming convention used elsewhere in the
monorepo: [encode_string] / [decode_string] -> [to_string] / [of_string];
[Cbor.Private.{decode,encode}_cbor] collapse into [Cbor.{decode,encode}].
[update_mem] and [delete_mem] move out of [Codec] into [Cbor] as Value.t
patch helpers (they cannot be pure-stream codecs).
Includes a fix to [Binary.skip] for definite-length text/bytes (it was
unconditionally calling [skip_break], which fired on the next item's header).
297 cbor tests + mdx pass; 16 downstream callers (cose, jwt/cwt, mst, scitt,
irmin/cbor) migrated and pass tests.
The old [(o, a) mem] GADT was monadic with [cont : 'x -> ('o, 'a) mem],
which forced [member_names] / [build_decoders] to walk the chain by
calling [cont (Obj.magic ())] — a fake value the continuations were
trusted not to inspect. That trust was implicit, type-system-evading,
and exactly what you don't want in a security-focused codec.
Replace it with [Json.Codec.Object]'s pipeline shape:
Cbor.Obj.map (fun a b c -> { a; b; c })
|> Cbor.Obj.mem "a" (fun r -> r.a) Cbor.string
|> Cbor.Obj.mem "b" (fun r -> r.b) Cbor.int
|> Cbor.Obj.mem_opt "c" (fun r -> r.c) Cbor.string
|> Cbor.Obj.seal
Each [mem] consumes one argument of the curried constructor and reifies
the field as a record carrying its name plus typed encode/decode
closures. [seal] enumerates field names and a name -> field dispatch
table directly from the field list — no chain walking, no [Obj.magic].
The implementation still uses [Stdlib.Obj.repr] / [Stdlib.Obj.obj] to
hold heterogeneously-typed decoded values in a single name-keyed table,
but only with values whose static type is fixed by the field that
produced them (the same [Hmap]-style universal-table contract); never
[Obj.magic ()].
Other changes:
- Apply the same rewrite to [Cbor.Obj_int] (integer-keyed records used
by COSE / CWT).
- Drop [let*], [return], [map], [both], [let+], [and+] from the API —
the pipeline form supersedes them.
- Update mli docs and the README quick-start to the new shape.
- Migrate every caller in the workspace
(ocaml-cbor/test/{test_cbor,test_value}, ocaml-mst/test/test_mst).
[dune build] is clean; [Cbor.encode_string] / [decode_string]
roundtrip remains green across all 298 cbor tests and the 41 mst
tests. [merlint ocaml-cbor] now reports 0 issues — every Obj.magic
flagged by E100 is gone.
- E332: collapse [Error.make] into [Error.v] by making [meta] an
optional argument with [Loc.Meta.none] as the default. The single
primary constructor [v] now serves both the location-aware and
result-only call sites.
- E331: rename the eight result-style helpers from [make_<kind>] to
[<kind>_result], avoiding the collision with the existing raising
helpers ([type_mismatch], [missing_member], etc.) that share the
unprefixed name. Update all 55 call sites in [lib/cbor.ml]
accordingly.
- E605: add [test/test_sort.ml] and [test/test_error.ml] so each
library module has a matching test file. Wire them into [test.ml]
and add [astring] to the test dune.
- E005: factor the duplicated "expected 4-element array" Error
construction in [tuple4] into a local [bad_arity] helper so the
function fits under the 54-line threshold.
Every existing test still passes. The 12 [Obj.magic] sites in
[lib/cbor.ml] are intentionally left untouched: they implement
runtime polymorphic dispatch that wants a typed redesign (GADTs or
explicit per-sort dispatch) and warrants its own thread.
Sweep through 23 more packages flagged by [monopam lint] for
test-stanza references not declared in opam. Each verified by
[dune build] + [dune runtest] before moving on.
- irmin add (astring :with-test)
- ocaml-atproto-oauth add (eio_main :with-test) (nox-crypto-rng :with-test)
- ocaml-auth add (alcotest :with-test) (eio :with-test) (eio_main :with-test)
- ocaml-cam add (odm :with-test)
- ocaml-cbor add (alcotest :with-test) (ohex :with-test)
- ocaml-cfdp add (nox-csv :with-test)
- ocaml-claude add (vlog :with-test)
- ocaml-collision add (alcotest :with-test) (odm :with-test) (ptime :with-test)
- ocaml-cookie add (re :with-test)
- ocaml-cop1 add (nox-csv :with-test)
- ocaml-crc add (nox-csv :with-test) (nox-memtrace :with-test)
- ocaml-dns-eio add (mdx :with-test); also fix a misplaced
paren in the depends list.
- ocaml-gauth add (nox-crypto-rng :with-test)
- ocaml-http add (alcotest :with-test) (eio_main :with-test) (nox-csv :with-test)
- ocaml-ltp add (nox-csv :with-test)
- ocaml-matter add (ohex :with-test) (ptime :with-test)
- ocaml-oauth add (eio_main :with-test) (nox-crypto-ec :with-test)
- ocaml-ocm add (alcotest :with-test) (nox-csv :with-test)
- ocaml-oem add (alcotest :with-test) (nox-csv :with-test)
- ocaml-opm add (alcotest :with-test) (nox-csv :with-test)
- ocaml-pbkdf2 add (ohex :with-test)
- ocaml-requests add (astring :with-test) (nox-csv :with-test)
- ocaml-retry add (re :with-test)
Run mdx on lib/cbor.mli so the two {[ ... ]} odoc blocks now
type-check.
Both blocks referenced `Value.X` paths (`Value.Obj`, `Value.fix`,
`Value.Variant`, `Value.encode_string`) -- those don't exist; the
codec API lives at the top level (`Cbor.Obj`, `Cbor.fix`,
`Cbor.Variant`, `Cbor.encode_string`).
Cbor.Obj.mem also takes a getter `('o -> 'a)` between the field name
and the codec -- the example was missing that argument. Restructured
the record-codec block as a real Obj.seal expression with concrete
getters, and added a roundtrip assert (decode of encode equals the
input). The Variant fix block now uses the right module path; the
flow was already correct.
The Value example used 'Cbor.Map'/'Cbor.Text' (top-level constructors
that don't exist) and 'Cbor.int 30' (no such smart constructor). Open
Cbor at the top of the block, qualify the constructors as
Value.Map/Value.Text, and replace 'Cbor.int 30' with 'Value.Int
(Z.of_int 30)' which is the actual variant + zarith int. Add an
'assert false'-guarded match so the build catches drift in the Value.t
shape.
The READMEs all share the standard install/overlay snippet, but the
sh blocks lacked the "<!-- $MDX skip -->" directive. `dune test`
would shell out to `opam install` against the live switch, which
either prompts interactively or fails with a package conflict —
either way diffing as a test failure.
Bulk-add skip directives in front of every install/overlay block.
Also collapse the doubled "non-deterministic + skip" stack on three
READMEs (memtrace, ocaml-dpop, ocaml-pid1, ocaml-yaml, merlint) where
`skip` already implies the runtime is bypassed.
Each README's 'opam install <pkg>' instructions now match the post-rename
opam package names. Auto-generated by 'monopam lint --fix' after the
nox-* prefix landed on the underlying packages.
Renames 35 packages to make blacksun forks distinguishable from their
opam-repository upstreams. Module names (Git.x, Tls.x, ...) stay bare;
opam package names and dune (public_name) findlib references move to
nox-X. After this commit, zero local package names overlap with
opam-repository.
Renamed:
- nox-git, nox-irmin
- nox-crypto, nox-crypto-pk, nox-crypto-rng, nox-crypto-ec
- nox-tls, nox-tls-eio, nox-tar, nox-tar-eio, nox-tty, nox-tty-eio
- nox-arp, nox-ca-certs, nox-cbor, nox-cookie, nox-crc, nox-csv
- nox-gpt, nox-hkdf, nox-http, nox-jwt, nox-kdf, nox-loc
- nox-memtrace, nox-pds, nox-sexp, nox-slack, nox-toml
- nox-websocket, nox-x509, nox-xdge, nox-yaml
Also drops orphan tar-mirage and tar-unix opam templates that had no
matching package stanza.
Each fork's dune-project (source ...) now matches the canonical
upstream URL recorded in sources.toml, so the generated dev-repo:
in opam-repository points users at the real home rather than the
in-monorepo collaboration fork. Where Thomas is doing maintenance
on the fork but isn't yet listed, add him to the relevant author
or maintainer fields.
ca-certs -> github mirage/ca-certs
(added Thomas to authors and maintainers)
ocaml-cbor -> tangled anil.recoil.org/ocaml-cbort
ocaml-cookie -> tangled anil.recoil.org/ocaml-cookeio
ocaml-json -> github dbuenzli/jsont
ocaml-jwt -> tangled anil.recoil.org/ocaml-jsonwt
ocaml-tar -> github mirage/ocaml-tar
(added Thomas to maintainers)
ocaml-toml -> tangled anil.recoil.org/ocaml-tomlt
ocaml-yaml -> tangled anil.recoil.org/ocaml-yamlt
Pure formatting changes from `dune fmt`: doc comment placement moves
from above the binding to below it for `type`s, multi-line `match`
expressions collapse onto one line where they fit, and infix operator
applications pick up spaces (`Soup.($?)` -> `Soup.( $? )`). No
semantic changes.
Object combinators: [Object.mem] -> [Object.member], [Object.opt_mem]
-> [Object.opt_member], [Object.case_mem] -> [Object.case_member]. The
sibling submodules [Object.Mem] / [Object.Mems] become
[Object.Member] / [Object.Members]. RFC 8259 §4 calls these
"name/value pairs, referred to as the members", so mirror the spec
name rather than the shortened [mem].
[Object.finish] -> [Object.seal]. "Seal" reads as "close the map, no
more members added", which is what the operation does.
Value constructors/queries: [Value.mem] (function) -> [Value.member];
[Value.mem_find] -> [Value.member_key]; [Value.mem_names] ->
[Value.member_names]; [Value.mem_keys] -> [Value.member_keys].
[type mem = ...] -> [type member = ...]; [type object'] still points
at [member list].
Downstream (~80 files across slack, sbom, stripe, sigstore, requests,
claude, irmin, freebox) updated via perl-pie. dune build clean,
dune test ocaml-json clean.
This reverts commit 58d9592128efa768a384d69bcb6a544fa3b753ca.
Expose only what's actually called. kinded' / or_kind were added
speculatively across libraries that don't use them; revert.
- toml, xml, csv: keep to_string, pp, kinded (kinded has callers —
csv 3, toml 2, xml 1). Drop kinded' and or_kind.
- cbor, protobuf: keep to_string, pp only. Drop kinded, kinded',
or_kind (no callers).
- json keeps the full API — 38 callers including kinded' (16) and
or_kind (11).
Factor [kinded] through [kinded' ~kind s = if kind = "" then s else
kind ^ " " ^ s], matching the shape of json's and toml's Sort
modules. Consistent API across every encoding library's Sort: every
module exposes [to_string], [pp], [or_kind], [kinded'], [kinded].
protobuf previously lacked [or_kind] and [kinded] entirely; add them
alongside [kinded'].
Replace the inline custom Error module with a proper facade over
Loc.Error, following the ocaml-encodings skill:
- Typed kinds extend Loc.Error.kind (Type_mismatch, Missing_member,
Unknown_member, Duplicate_member, Out_of_range, Invalid_value,
Parse_error, Custom, Sort_mismatch, Kinded_sort_mismatch). Printers
registered at module init. Callers pattern-match on Loc.Error.kind.
- CBOR-native path steps Cbor_key (non-string map keys) and Cbor_tag
(tagged-value boundary) extend Loc.Path.step, printed via the step
registry. Mem/Nth cover string keys and array indices.
- Error.t = Loc.Error.t; custom Error.Decode exception deleted (raise
Loc.Error.Error instead). Paths use Loc.Context.t throughout the
codec interpreters.
- Context builders ctx_with_index / ctx_with_key / ctx_with_cbor_key /
ctx_with_tag descend one step in a context; replace the old cons-on-
list path threading (Error.Index i :: path → Error.ctx_with_index i
path).
- Typed raising helpers (type_mismatch, missing_member, ...) and the
shape-error menu (sort, kinded_sort, expected, missing_mems, ...)
match the other encoding libraries' facade shape.
Update ocaml-bpsec fuzz harness to catch Loc.Error instead of
Cbor.Error.Decode. External callers (cose, jwt, scitt, mst, space-dtn)
only use Cbor.Error.pp / to_string, which still work through the
facade.
Move Sort out of cbor.ml into its own sort.ml at the top level. Sort is
a public type labelling error contexts and Loc.Path frames; inlining it
in cbor.ml hid that role.
Replace Sort.of_cbor with Value.sort, following json's convention
(Value converts into Sort, not the other way). Sort stays dependency-
free.
Warning 69 (unused-field, mutable-never-assigned). Four independent
record fields were flagged as mutable but the code only mutates their
referents in place, never rebinds the record slot itself:
- ocaml-wal/lib/wal.ml: [t.file] (the Eio file resource; methods call
Eio.File.pwrite_all etc., the slot is set once at open time).
- ocaml-block/lib/block.ml: [Memory.state.data] (the backing bytes,
written via Bytes.blit_string; [Bytes.t] is already mutable).
- ocaml-sse/lib/sse.ml: [Parser.t.data_buf] (a Buffer.t, written via
Buffer.add_*; the slot never changes).
- ocaml-zephyr/lib/zephyr.ml: drop [mode : Read | Write] entirely —
set at open-time, read nowhere. The open_read / open_write
constructors already distinguish the two call shapes, so mode
tracking was redundant.
- Rename test/test_cbor_rw.{ml,mli} to test/test_binary.{ml,mli} to
match the lib/binary.ml rename (E605).
- Drop the (modules ...) field from fuzz/dune (E523).
12 Obj.magic usages in cbor.ml remain — they encode the record codec's
CPS continuation walk (extracting names/decoders without having a value
in hand). A refactor to explicit field-list + Dict-based assembly is
tracked as follow-up work; the Obj.magic calls are isolated to codec
construction and never touched at runtime.
Previously the eight git-x subcommands sat flat at top level (split,
check, fix, verify, filter-paths, split-commit, drop-commit, reword),
with 'split' ambiguous between the subtree split and the per-directory
commit split.
Regrouped into two namespaces that mirror the object they act on:
git-x tree
split (was: git-x split)
add (new — inject a standalone history under a prefix)
drop (was: git-x filter-paths)
check (was: git-x check)
fix (was: git-x fix)
verify (was: git-x verify)
git-x commit
split (was: git-x split-commit)
drop (was: git-x drop-commit)
reword (was: git-x reword)
Each subcommand lives in cmd_<group>_<verb>.{ml,mli}; cmd_tree.ml and
cmd_commit.ml are the Cmd.group wrappers. git_x.ml registers just the
two groups.
'tree add' is a thin wrapper over Git.Subtree.add, which already
existed in the library but had no CLI exposure. It accepts a ref (e.g.
FETCH_HEAD after 'git fetch URL REF') and a --prefix, then builds a
subtree-merge commit with the current user's git config identity.
Log source names are updated to match (git-x.tree.split,
git-x.tree.fix). The cram test under test/cram/tree_split.t is
updated to use the new 'git-x tree split' invocation throughout.
Drops the "t" suffix. Internal raw CBOR module moves to Value (was
Cbor in lib/cbor.ml), matching the value/codec/<pkg> layout from the
other codec packages. Low-level byte R/W moved to lib/binary.ml (was
lib/cbor_rw.ml). Library name cbor; main module Cbor via lib/cbor.ml
(was cbort.ml).
Downstream packages (ocaml-bundle, ocaml-cose, ocaml-bpsec, ocaml-scitt,
ocaml-crow, irmin) partially migrated: Cbort.Cbor -> Cbor.Value, the
internal Cbor alias shadowing in each file renamed to V to free the
top-level Cbor for the library facade. Some downstream build errors
remain because many callsites conflated raw value constructors
(Cbor.int, Cbor.int64) with schema codecs and need manual triage.
The lib/binary.ml R/W primitives are NOT re-exported through Cbor.Binary
due to OCaml's lazy module alias elision when the aliased module isn't
referenced by any type/value in the parent signature. A separate
cbor.bytesrw library (ocaml-cbor/lib/bytesrw/) is the right home for
that, matching json.bytesrw / toml.bytesrw; left as a follow-up.
- Add doc comments to Map_int.{map,mem,mem_opt,mem_default,seal} (E325).
- Rewrite uint/int/text/bytes doc comments to lead with [name] (E331).
- Re-export Value.pp / Value.equal at the top of Cbor (E305: type t was
missing pp).
- Refactor Codec.nth into nth_decode_definite + nth_decode_indefinite to
drop below the function-length threshold.
- Add a test_codec.ml smoke suite (round-trips through every major-type
combinator) to satisfy E605 and exercise the codec.ml surface directly.
315 tests pass; merlint clean on ocaml-cbor.
The new error_quality_cases suite asserts that rendered Cbor.Error messages
name the specific path, key, index, or bound where decoding failed — not just
a generic complaint. The first run of these tests caught a real bug in
[Cbor.Codec.mem] / [int_mem]: when the inner codec failed on the matched
value, the stream was left at an unknown position (header consumed but body
not), and the post-match drain loop then read garbage from inside the
previous text/bytes content, surfacing as "unexpected end of input" instead
of the real type mismatch.
Fix: extract a [drain_map_entries] helper used only on the success path; on
inner-decode error, return the error directly without trying to walk the rest
of the map. The trailing-bytes check in [Cbor.of_reader] passes the typed
error through unchanged.
Also wires up the cfdp_eio test sublib that an earlier session left
half-migrated: adds [test/eio/dune], appends [Alcotest.run] to
[test_cfdp_eio.ml], drops the dangling [Test_eio.suite] reference from
[test/test.ml]. The whole monorepo builds clean again.
306 cbor tests pass (9 new error-quality cases).
The codec record drops its Value.t-based [encode] / [decode] fields, leaving
[{ kind; encode_rw; decode_rw }] — codecs now write to a Binary.encoder and
read from a Binary.decoder directly, building 'a from bytes without an
intermediate Value.t. This satisfies the ocaml-encodings skill's "codec.ml
does not depend on value.ml" rule; only cbor.ml bridges the two via
[Binary.read_cbor] / [write_cbor].
Surface follows RFC 8949 spec order: cbor.mli sections walk major types 0-7,
then simple values (3.3) and tags (3.4), each linking to the relevant clause.
Combinators move under [Cbor.Codec] (was top-level on [Cbor]); naming tracks
CDDL: [Cbor.Obj] -> [Cbor.Codec.Map], [Cbor.Obj_int] -> [Cbor.Codec.Map_int],
[Cbor.string] -> [Cbor.Codec.text], [Cbor.string_map] -> [Cbor.Codec.text_map].
Top-level IO verbs follow the parallel naming convention used elsewhere in the
monorepo: [encode_string] / [decode_string] -> [to_string] / [of_string];
[Cbor.Private.{decode,encode}_cbor] collapse into [Cbor.{decode,encode}].
[update_mem] and [delete_mem] move out of [Codec] into [Cbor] as Value.t
patch helpers (they cannot be pure-stream codecs).
Includes a fix to [Binary.skip] for definite-length text/bytes (it was
unconditionally calling [skip_break], which fired on the next item's header).
297 cbor tests + mdx pass; 16 downstream callers (cose, jwt/cwt, mst, scitt,
irmin/cbor) migrated and pass tests.
The old [(o, a) mem] GADT was monadic with [cont : 'x -> ('o, 'a) mem],
which forced [member_names] / [build_decoders] to walk the chain by
calling [cont (Obj.magic ())] — a fake value the continuations were
trusted not to inspect. That trust was implicit, type-system-evading,
and exactly what you don't want in a security-focused codec.
Replace it with [Json.Codec.Object]'s pipeline shape:
Cbor.Obj.map (fun a b c -> { a; b; c })
|> Cbor.Obj.mem "a" (fun r -> r.a) Cbor.string
|> Cbor.Obj.mem "b" (fun r -> r.b) Cbor.int
|> Cbor.Obj.mem_opt "c" (fun r -> r.c) Cbor.string
|> Cbor.Obj.seal
Each [mem] consumes one argument of the curried constructor and reifies
the field as a record carrying its name plus typed encode/decode
closures. [seal] enumerates field names and a name -> field dispatch
table directly from the field list — no chain walking, no [Obj.magic].
The implementation still uses [Stdlib.Obj.repr] / [Stdlib.Obj.obj] to
hold heterogeneously-typed decoded values in a single name-keyed table,
but only with values whose static type is fixed by the field that
produced them (the same [Hmap]-style universal-table contract); never
[Obj.magic ()].
Other changes:
- Apply the same rewrite to [Cbor.Obj_int] (integer-keyed records used
by COSE / CWT).
- Drop [let*], [return], [map], [both], [let+], [and+] from the API —
the pipeline form supersedes them.
- Update mli docs and the README quick-start to the new shape.
- Migrate every caller in the workspace
(ocaml-cbor/test/{test_cbor,test_value}, ocaml-mst/test/test_mst).
[dune build] is clean; [Cbor.encode_string] / [decode_string]
roundtrip remains green across all 298 cbor tests and the 41 mst
tests. [merlint ocaml-cbor] now reports 0 issues — every Obj.magic
flagged by E100 is gone.
- E332: collapse [Error.make] into [Error.v] by making [meta] an
optional argument with [Loc.Meta.none] as the default. The single
primary constructor [v] now serves both the location-aware and
result-only call sites.
- E331: rename the eight result-style helpers from [make_<kind>] to
[<kind>_result], avoiding the collision with the existing raising
helpers ([type_mismatch], [missing_member], etc.) that share the
unprefixed name. Update all 55 call sites in [lib/cbor.ml]
accordingly.
- E605: add [test/test_sort.ml] and [test/test_error.ml] so each
library module has a matching test file. Wire them into [test.ml]
and add [astring] to the test dune.
- E005: factor the duplicated "expected 4-element array" Error
construction in [tuple4] into a local [bad_arity] helper so the
function fits under the 54-line threshold.
Every existing test still passes. The 12 [Obj.magic] sites in
[lib/cbor.ml] are intentionally left untouched: they implement
runtime polymorphic dispatch that wants a typed redesign (GADTs or
explicit per-sort dispatch) and warrants its own thread.
Sweep through 23 more packages flagged by [monopam lint] for
test-stanza references not declared in opam. Each verified by
[dune build] + [dune runtest] before moving on.
- irmin add (astring :with-test)
- ocaml-atproto-oauth add (eio_main :with-test) (nox-crypto-rng :with-test)
- ocaml-auth add (alcotest :with-test) (eio :with-test) (eio_main :with-test)
- ocaml-cam add (odm :with-test)
- ocaml-cbor add (alcotest :with-test) (ohex :with-test)
- ocaml-cfdp add (nox-csv :with-test)
- ocaml-claude add (vlog :with-test)
- ocaml-collision add (alcotest :with-test) (odm :with-test) (ptime :with-test)
- ocaml-cookie add (re :with-test)
- ocaml-cop1 add (nox-csv :with-test)
- ocaml-crc add (nox-csv :with-test) (nox-memtrace :with-test)
- ocaml-dns-eio add (mdx :with-test); also fix a misplaced
paren in the depends list.
- ocaml-gauth add (nox-crypto-rng :with-test)
- ocaml-http add (alcotest :with-test) (eio_main :with-test) (nox-csv :with-test)
- ocaml-ltp add (nox-csv :with-test)
- ocaml-matter add (ohex :with-test) (ptime :with-test)
- ocaml-oauth add (eio_main :with-test) (nox-crypto-ec :with-test)
- ocaml-ocm add (alcotest :with-test) (nox-csv :with-test)
- ocaml-oem add (alcotest :with-test) (nox-csv :with-test)
- ocaml-opm add (alcotest :with-test) (nox-csv :with-test)
- ocaml-pbkdf2 add (ohex :with-test)
- ocaml-requests add (astring :with-test) (nox-csv :with-test)
- ocaml-retry add (re :with-test)
Run mdx on lib/cbor.mli so the two {[ ... ]} odoc blocks now
type-check.
Both blocks referenced `Value.X` paths (`Value.Obj`, `Value.fix`,
`Value.Variant`, `Value.encode_string`) -- those don't exist; the
codec API lives at the top level (`Cbor.Obj`, `Cbor.fix`,
`Cbor.Variant`, `Cbor.encode_string`).
Cbor.Obj.mem also takes a getter `('o -> 'a)` between the field name
and the codec -- the example was missing that argument. Restructured
the record-codec block as a real Obj.seal expression with concrete
getters, and added a roundtrip assert (decode of encode equals the
input). The Variant fix block now uses the right module path; the
flow was already correct.
The Value example used 'Cbor.Map'/'Cbor.Text' (top-level constructors
that don't exist) and 'Cbor.int 30' (no such smart constructor). Open
Cbor at the top of the block, qualify the constructors as
Value.Map/Value.Text, and replace 'Cbor.int 30' with 'Value.Int
(Z.of_int 30)' which is the actual variant + zarith int. Add an
'assert false'-guarded match so the build catches drift in the Value.t
shape.
The READMEs all share the standard install/overlay snippet, but the
sh blocks lacked the "<!-- $MDX skip -->" directive. `dune test`
would shell out to `opam install` against the live switch, which
either prompts interactively or fails with a package conflict —
either way diffing as a test failure.
Bulk-add skip directives in front of every install/overlay block.
Also collapse the doubled "non-deterministic + skip" stack on three
READMEs (memtrace, ocaml-dpop, ocaml-pid1, ocaml-yaml, merlint) where
`skip` already implies the runtime is bypassed.
Renames 35 packages to make blacksun forks distinguishable from their
opam-repository upstreams. Module names (Git.x, Tls.x, ...) stay bare;
opam package names and dune (public_name) findlib references move to
nox-X. After this commit, zero local package names overlap with
opam-repository.
Renamed:
- nox-git, nox-irmin
- nox-crypto, nox-crypto-pk, nox-crypto-rng, nox-crypto-ec
- nox-tls, nox-tls-eio, nox-tar, nox-tar-eio, nox-tty, nox-tty-eio
- nox-arp, nox-ca-certs, nox-cbor, nox-cookie, nox-crc, nox-csv
- nox-gpt, nox-hkdf, nox-http, nox-jwt, nox-kdf, nox-loc
- nox-memtrace, nox-pds, nox-sexp, nox-slack, nox-toml
- nox-websocket, nox-x509, nox-xdge, nox-yaml
Also drops orphan tar-mirage and tar-unix opam templates that had no
matching package stanza.
Each fork's dune-project (source ...) now matches the canonical
upstream URL recorded in sources.toml, so the generated dev-repo:
in opam-repository points users at the real home rather than the
in-monorepo collaboration fork. Where Thomas is doing maintenance
on the fork but isn't yet listed, add him to the relevant author
or maintainer fields.
ca-certs -> github mirage/ca-certs
(added Thomas to authors and maintainers)
ocaml-cbor -> tangled anil.recoil.org/ocaml-cbort
ocaml-cookie -> tangled anil.recoil.org/ocaml-cookeio
ocaml-json -> github dbuenzli/jsont
ocaml-jwt -> tangled anil.recoil.org/ocaml-jsonwt
ocaml-tar -> github mirage/ocaml-tar
(added Thomas to maintainers)
ocaml-toml -> tangled anil.recoil.org/ocaml-tomlt
ocaml-yaml -> tangled anil.recoil.org/ocaml-yamlt
Object combinators: [Object.mem] -> [Object.member], [Object.opt_mem]
-> [Object.opt_member], [Object.case_mem] -> [Object.case_member]. The
sibling submodules [Object.Mem] / [Object.Mems] become
[Object.Member] / [Object.Members]. RFC 8259 §4 calls these
"name/value pairs, referred to as the members", so mirror the spec
name rather than the shortened [mem].
[Object.finish] -> [Object.seal]. "Seal" reads as "close the map, no
more members added", which is what the operation does.
Value constructors/queries: [Value.mem] (function) -> [Value.member];
[Value.mem_find] -> [Value.member_key]; [Value.mem_names] ->
[Value.member_names]; [Value.mem_keys] -> [Value.member_keys].
[type mem = ...] -> [type member = ...]; [type object'] still points
at [member list].
Downstream (~80 files across slack, sbom, stripe, sigstore, requests,
claude, irmin, freebox) updated via perl-pie. dune build clean,
dune test ocaml-json clean.
Expose only what's actually called. kinded' / or_kind were added
speculatively across libraries that don't use them; revert.
- toml, xml, csv: keep to_string, pp, kinded (kinded has callers —
csv 3, toml 2, xml 1). Drop kinded' and or_kind.
- cbor, protobuf: keep to_string, pp only. Drop kinded, kinded',
or_kind (no callers).
- json keeps the full API — 38 callers including kinded' (16) and
or_kind (11).
Factor [kinded] through [kinded' ~kind s = if kind = "" then s else
kind ^ " " ^ s], matching the shape of json's and toml's Sort
modules. Consistent API across every encoding library's Sort: every
module exposes [to_string], [pp], [or_kind], [kinded'], [kinded].
protobuf previously lacked [or_kind] and [kinded] entirely; add them
alongside [kinded'].
Replace the inline custom Error module with a proper facade over
Loc.Error, following the ocaml-encodings skill:
- Typed kinds extend Loc.Error.kind (Type_mismatch, Missing_member,
Unknown_member, Duplicate_member, Out_of_range, Invalid_value,
Parse_error, Custom, Sort_mismatch, Kinded_sort_mismatch). Printers
registered at module init. Callers pattern-match on Loc.Error.kind.
- CBOR-native path steps Cbor_key (non-string map keys) and Cbor_tag
(tagged-value boundary) extend Loc.Path.step, printed via the step
registry. Mem/Nth cover string keys and array indices.
- Error.t = Loc.Error.t; custom Error.Decode exception deleted (raise
Loc.Error.Error instead). Paths use Loc.Context.t throughout the
codec interpreters.
- Context builders ctx_with_index / ctx_with_key / ctx_with_cbor_key /
ctx_with_tag descend one step in a context; replace the old cons-on-
list path threading (Error.Index i :: path → Error.ctx_with_index i
path).
- Typed raising helpers (type_mismatch, missing_member, ...) and the
shape-error menu (sort, kinded_sort, expected, missing_mems, ...)
match the other encoding libraries' facade shape.
Update ocaml-bpsec fuzz harness to catch Loc.Error instead of
Cbor.Error.Decode. External callers (cose, jwt, scitt, mst, space-dtn)
only use Cbor.Error.pp / to_string, which still work through the
facade.
Move Sort out of cbor.ml into its own sort.ml at the top level. Sort is
a public type labelling error contexts and Loc.Path frames; inlining it
in cbor.ml hid that role.
Replace Sort.of_cbor with Value.sort, following json's convention
(Value converts into Sort, not the other way). Sort stays dependency-
free.
Warning 69 (unused-field, mutable-never-assigned). Four independent
record fields were flagged as mutable but the code only mutates their
referents in place, never rebinds the record slot itself:
- ocaml-wal/lib/wal.ml: [t.file] (the Eio file resource; methods call
Eio.File.pwrite_all etc., the slot is set once at open time).
- ocaml-block/lib/block.ml: [Memory.state.data] (the backing bytes,
written via Bytes.blit_string; [Bytes.t] is already mutable).
- ocaml-sse/lib/sse.ml: [Parser.t.data_buf] (a Buffer.t, written via
Buffer.add_*; the slot never changes).
- ocaml-zephyr/lib/zephyr.ml: drop [mode : Read | Write] entirely —
set at open-time, read nowhere. The open_read / open_write
constructors already distinguish the two call shapes, so mode
tracking was redundant.
- Rename test/test_cbor_rw.{ml,mli} to test/test_binary.{ml,mli} to
match the lib/binary.ml rename (E605).
- Drop the (modules ...) field from fuzz/dune (E523).
12 Obj.magic usages in cbor.ml remain — they encode the record codec's
CPS continuation walk (extracting names/decoders without having a value
in hand). A refactor to explicit field-list + Dict-based assembly is
tracked as follow-up work; the Obj.magic calls are isolated to codec
construction and never touched at runtime.
Previously the eight git-x subcommands sat flat at top level (split,
check, fix, verify, filter-paths, split-commit, drop-commit, reword),
with 'split' ambiguous between the subtree split and the per-directory
commit split.
Regrouped into two namespaces that mirror the object they act on:
git-x tree
split (was: git-x split)
add (new — inject a standalone history under a prefix)
drop (was: git-x filter-paths)
check (was: git-x check)
fix (was: git-x fix)
verify (was: git-x verify)
git-x commit
split (was: git-x split-commit)
drop (was: git-x drop-commit)
reword (was: git-x reword)
Each subcommand lives in cmd_<group>_<verb>.{ml,mli}; cmd_tree.ml and
cmd_commit.ml are the Cmd.group wrappers. git_x.ml registers just the
two groups.
'tree add' is a thin wrapper over Git.Subtree.add, which already
existed in the library but had no CLI exposure. It accepts a ref (e.g.
FETCH_HEAD after 'git fetch URL REF') and a --prefix, then builds a
subtree-merge commit with the current user's git config identity.
Log source names are updated to match (git-x.tree.split,
git-x.tree.fix). The cram test under test/cram/tree_split.t is
updated to use the new 'git-x tree split' invocation throughout.
Drops the "t" suffix. Internal raw CBOR module moves to Value (was
Cbor in lib/cbor.ml), matching the value/codec/<pkg> layout from the
other codec packages. Low-level byte R/W moved to lib/binary.ml (was
lib/cbor_rw.ml). Library name cbor; main module Cbor via lib/cbor.ml
(was cbort.ml).
Downstream packages (ocaml-bundle, ocaml-cose, ocaml-bpsec, ocaml-scitt,
ocaml-crow, irmin) partially migrated: Cbort.Cbor -> Cbor.Value, the
internal Cbor alias shadowing in each file renamed to V to free the
top-level Cbor for the library facade. Some downstream build errors
remain because many callsites conflated raw value constructors
(Cbor.int, Cbor.int64) with schema codecs and need manual triage.
The lib/binary.ml R/W primitives are NOT re-exported through Cbor.Binary
due to OCaml's lazy module alias elision when the aliased module isn't
referenced by any type/value in the parent signature. A separate
cbor.bytesrw library (ocaml-cbor/lib/bytesrw/) is the right home for
that, matching json.bytesrw / toml.bytesrw; left as a follow-up.