Skip to content

Commit 1281b38

Browse files
committed
Merge remote-tracking branch 'origin/yolo' into yolo
# Conflicts: # PLAN.md
2 parents 1c9bfba + 6c2055f commit 1281b38

12 files changed

Lines changed: 570 additions & 48 deletions

PLAN.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,51 @@ maintained_by: agent
1919
a webhook HTTP response proves delivery, not queue admission or a passing
2020
build.
2121

22+
## Container honors `--spaces` (legible-markdown containers) — DONE (2026-07-21 EDT)
23+
24+
Goal (Peter): put a markdown file into a `.pbf.json` container but keep it legible;
25+
`--spaces` was silently ignored in container mode. Fixed across all 5 container
26+
surfaces (Lua, Node, Zig, standalone-C, FFI-C) + shared `test/test_container`.
27+
28+
- [x] `--spaces` honored in container encode: literal spaces in the JSON `data`
29+
value (letters/digits/`. @ ^ _` already pass through, so markdown reads
30+
naturally; newlines stay `` glyphs → still valid single-line JSON). (2026-07-21 03:00 PM EDT)
31+
- [x] **Flagless** design (Peter's call): NO `spaces` schema field, `version` stays 1.
32+
Decode uses a **crc-probe** — try keeping literal spaces; if `crc32_encoded`
33+
mismatches, strip them as transport noise. The crc is the disambiguation oracle. (2026-07-21 03:00 PM EDT)
34+
- [x] Ambiguity warning: a non-spaces container (space-glyph present) with a
35+
transport-injected literal space → recover by stripping + WARN that literal
36+
spaces were assumed formatting because the space glyph was also present.
37+
Space glyph read from the map (DRY), never hardcoded. (2026-07-21 03:00 PM EDT)
38+
- [x] `--tabs`/`--crlf`/`-w`/`--preserve` + `--container` = HARD ERROR (would break
39+
JSON-validity + transport-resistance). (2026-07-21 03:00 PM EDT)
40+
- [x] Corrected `character_map.txt` header comment: documents the 66/94 printable-ASCII
41+
passthrough (the legibility property), verified behavior-neutral. (2026-07-21 03:00 PM EDT)
42+
- [x] Guard #4 (map redefines space→space) proven UNNECESSARY: the "first
43+
whitespace-delimited token" parser + 256-glyph-count check make a literal-space
44+
glyph structurally unloadable (physics over policy). (2026-07-21 03:00 PM EDT)
45+
- [x] Fixed FFI NULL-deref: `preserve_chars` is `char *` (NULL) in FFI opts, not an
46+
array — guard now NULL-checks. Caught by hermetic nix check, not exit code. (2026-07-21 03:00 PM EDT)
47+
48+
## Integrated compression (z7z/LZMA in `-C`) — DECLINED (2026-07-21 EDT)
49+
50+
Considered then dropped (Peter): a user can compress in a pipe chain *before*
51+
printable-binary and stay truer to the Unix philosophy — no need to bake it in.
52+
Also, z7z is an archive tool (no raw stdin→stdout stream; `.7z` header +
53+
nondeterministic mtime would sink a stable "compressed hash"; max level 9), so
54+
integration would be awkward anyway. If ever revived, the open question is
55+
LZMA2-library-vs-CLI cross-impl parity (Zig/C could link z7z's core in-process;
56+
Lua/Node/Rust/Elixir could not without shelling out or their own LZMA).
57+
58+
## Container metadata injection (`-k`/`-v`/`--kv`/`--key-namespace`) — SPEC'd, FUTURE (2026-07-21 EDT)
59+
60+
Design approved by Peter (all forks ruled), NOT yet implemented — a future
61+
nice-to-have. Attach arbitrary key/value metadata to a container for other
62+
tooling to read first (xattr / HTTP-`X-`-header analogue). Full spec + TDD plan:
63+
`docs/plans/2026-07-21-container-metadata-injection-design.md`.
64+
- [ ] Implement TDD-first (Lua reference → Node → Zig → standalone-C → FFI-C) +
65+
extend the shared `test/test_container` guard. Reserved-key rejection is an
66+
MFIC cross-impl contract.
2267
## Docs and benchmark parity — active (2026-07-17 EDT)
2368

2469
- [x] Document every supported implementation—especially Rust, WebAssembly, and

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,25 @@ paste) and restores the file under its original name. Optional metadata
214214
(timestamps, POSIX permissions/owner) is included when the tool can read it and
215215
omitted otherwise; decode never fails on a missing optional field.
216216

217+
**Legible-text containers with `-s`/`--spaces`.** Add `--spaces` to keep literal
218+
spaces in the `data` value instead of encoding them to the space glyph. Since
219+
letters, digits and `. @ ^ _` already pass through as themselves, a text file —
220+
e.g. Markdown — reads naturally inside the container while staying valid,
221+
single-line JSON (newlines remain `` glyphs):
222+
223+
```bash
224+
./bin/printable-binary -C --spaces notes.md > notes.md.pbf.json
225+
# data value reads like: "♯ Title¶¶Some ⁎⁎bold⁎⁎ text.¶˗ a list item¶"
226+
```
227+
228+
No schema flag records this — the format stays `version: 1`. Decode disambiguates
229+
with the `crc32_encoded` oracle: it keeps literal spaces if they check out as
230+
data, otherwise strips them as transport formatting (and warns if the space glyph
231+
was also present, i.e. the spaces were injected into a non-`--spaces` container).
232+
`--spaces` is the only preserve flag allowed with `-C`; `--tabs`/`--crlf`/`-w`/
233+
`--preserve` are rejected, since raw tab/CR/LF would break both JSON validity and
234+
the whitespace-stripping transport-resistance.
235+
217236
### Hexlike Mode (`-X`)
218237

219238
`-X`/`--hexlike` is a hybrid view: printable ASCII passes through untouched while

bin/printable-binary

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@ local function crc32_hex(data)
2121
return bit.tohex(bit.bxor(crc, 0xFFFFFFFF))
2222
end
2323

24-
-- Strip transport whitespace (space/tab/CR/LF) from an encoded payload.
25-
local function canonical_payload(s)
24+
-- Strip transport whitespace from an encoded payload. Normally all of space/tab/
25+
-- CR/LF are transport noise. When keep_spaces is set (container --spaces), literal
26+
-- spaces are DATA, so only tab/CR/LF are stripped as noise.
27+
local function canonical_payload(s, keep_spaces)
28+
if keep_spaces then
29+
return (s:gsub("[\t\r\n]", ""))
30+
end
2631
return (s:gsub("[ \t\r\n]", ""))
2732
end
2833

@@ -32,8 +37,6 @@ end
3237
local function json_get_string(json, key)
3338
return json:match('"' .. key .. '"%s*:%s*"(.-)"')
3439
end
35-
36-
3740
-- PrintableBinary: A utility to encode/decode binary data into human-readable UTF-8
3841
-- Module definition
3942
local PrintableBinary = {}
@@ -1028,19 +1031,45 @@ if arg then
10281031
-- Container (.pbf.json) mode (issue #1): assemble/parse the flat-JSON envelope
10291032
-- over the shared encode/decode + crc32 (A2). Transport-resistant.
10301033
if container_mode then
1034+
-- Only --spaces is honored in container mode. --tabs/--crlf/-w/--preserve would
1035+
-- put raw tab/CR/LF (or arbitrary chars) into the JSON value, breaking both
1036+
-- single-line-JSON validity and the tab/CR/LF-stripping transport-resistance.
1037+
if tabs_mode or crlf_mode or preserve_chars ~= "" then
1038+
io.stderr:write("Error: --tabs/--crlf/-w/--preserve are not supported with "
1039+
.. "--container (only --spaces is honored; other whitespace stays encoded)\n")
1040+
os.exit(1)
1041+
end
10311042
if decode_mode then
10321043
local data_raw = json_get_string(input_data, "data")
10331044
if not data_raw then
10341045
io.stderr:write("Error: not a printable-binary-file container (missing 'data')\n")
10351046
os.exit(1)
10361047
end
1037-
local clean = canonical_payload(data_raw)
1048+
-- Flagless crc-probe: no schema flag records whether --spaces was used; the
1049+
-- crc32_encoded oracle disambiguates. Try keeping literal spaces (they're DATA
1050+
-- in a --spaces container); if the crc mismatches, strip them as transport noise.
1051+
local clean = canonical_payload(data_raw, true)
1052+
local spaces = true
10381053
local ce = json_get_string(input_data, "crc32_encoded")
10391054
if ce and crc32_hex(clean) ~= ce then
1040-
io.stderr:write("Error: container crc32_encoded mismatch (data corrupted)\n")
1041-
os.exit(1)
1055+
local stripped = canonical_payload(data_raw, false)
1056+
if crc32_hex(stripped) == ce then
1057+
-- Literal spaces were noise. If the space glyph is ALSO present, the payload
1058+
-- mixed real (glyph) spaces with formatting spaces -> warn we dropped them.
1059+
local space_glyph = encode_map[32]
1060+
if space_glyph and clean:find(space_glyph, 1, true) then
1061+
io.stderr:write("Warning: literal spaces in container data were assumed to be "
1062+
.. "ignorable formatting because the space glyph " .. space_glyph
1063+
.. " was also present; stripping them\n")
1064+
end
1065+
clean = stripped
1066+
spaces = false
1067+
else
1068+
io.stderr:write("Error: container crc32_encoded mismatch (data corrupted)\n")
1069+
os.exit(1)
1070+
end
10421071
end
1043-
local decoded = PrintableBinary.decode(clean, {})
1072+
local decoded = PrintableBinary.decode(clean, { spaces = spaces })
10441073
local co = json_get_string(input_data, "crc32")
10451074
if co and crc32_hex(decoded) ~= co then
10461075
io.stderr:write("Error: container crc32 mismatch (decoded data corrupted)\n")
@@ -1049,8 +1078,8 @@ if arg then
10491078
io.write(decoded)
10501079
os.exit(0)
10511080
else
1052-
local data = PrintableBinary.encode(input_data, {})
1053-
local clean = canonical_payload(data)
1081+
local data = PrintableBinary.encode(input_data, { spaces = spaces_mode })
1082+
local clean = canonical_payload(data, spaces_mode)
10541083
local crc_orig = crc32_hex(input_data)
10551084
local crc_enc = crc32_hex(clean)
10561085
local fname = ""

bin/printable-binary-node.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,13 @@ async function main() {
361361
}
362362

363363
if (containerMode) {
364+
// Only --spaces is honored in container mode; --tabs/--crlf/-w/--preserve
365+
// would put raw tab/CR/LF (or arbitrary chars) into the JSON value, breaking
366+
// single-line-JSON validity and the tab/CR/LF-stripping transport-resistance.
367+
if (tabsMode || crlfMode || preserveChars) {
368+
process.stderr.write('Error: --tabs/--crlf/-w/--preserve are not supported with --container (only --spaces is honored; other whitespace stays encoded)\n');
369+
process.exit(1);
370+
}
364371
if (decodeMode) {
365372
const res = pb.decodeText(input.toString('utf8'));
366373
stats(`Decoded ${res.kind} container${res.filename && res.filename !== 'decoded.bin' ? ' (' + res.filename + ')' : ''}: ${res.bytes.length} bytes`);
@@ -376,7 +383,7 @@ async function main() {
376383
meta.mode = '0' + (st.mode & 0o777).toString(8);
377384
} catch (_e) { /* metadata is best-effort */ }
378385
}
379-
const container = pb.encodeToContainer(new Uint8Array(input), meta);
386+
const container = pb.encodeToContainer(new Uint8Array(input), meta, { spaces: spacesMode });
380387
stats(`Encoded ${input.length} bytes -> .pbf.json container (crc32 ${container.crc32})`);
381388
process.stdout.write(JSON.stringify(container, null, 2) + '\n');
382389
}

character_map.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
## is the glyph for byte N. Exactly 256 glyph lines. The glyph is the FIRST
66
## whitespace-delimited token on the line.
77
##
8+
## ASCII passthrough (the core point): letters (A–Z, a–z), digits (0–9), and
9+
## . @ ^ _ map to THEMSELVES — 66 of the 94 printable non-space bytes — so ASCII
10+
## text stays legible in the encoded form even when mixed with control/high bytes.
11+
## The other printable bytes take look-alike glyphs to stay unambiguous: 0x20
12+
## space -> ␣, plus the 28 punctuation ! " # $ % & ' ( ) * + , - / : ; < = > ? [ \ ] ` { | } ~
13+
## (see per-line trailing notes). Byte 0x23 '#' -> ♯ is discussed below.
14+
##
815
## Comments:
916
## - A line beginning with `##` (two or more '#') is a full-line comment, skipped.
1017
## - A trailing `<glyph> ## comment` is ignored (only the first token is taken).

0 commit comments

Comments
 (0)