Repository navigation
refactor(registry): give each format its own files, so that two format PRs never edit the same list - #102
Merged
Conversation
…t PRs never edit the same list Adding a format edited about ten shared, hand-kept lists, all at the same spot, and every profile took a number from one global sequence. Each of those now derives from the format's own files and its registry entry: - The registry is one file per profile, spec/virtualize/profiles/<name>.json, with an explicit `sniff` precedence instead of list position; the Rust core keeps per-profile copies in rust/refkv-ir/profiles/. - Rust dispatch: build.rs generates the format modules' declarations (lib.rs, project/mod.rs), the `Format` enum and the sniff order from the copies, and the source models' table from schema/; each format module declares a `Profile` (`run::FileProfile`: signature, parser, response mode, projection, reads, post-mirror step) and invokes `parser!` itself. `rules::of(name)` replaces the per-format schema statics and accessors. - Sniffing exists once, in the core: Python (`_core.sniff`), the browser (`vz_sniff`) and wasm/run.mjs call it instead of keeping their own copies. - Browser: profiles.ts loads the registry at runtime (`#profiles`: read from the spec under Node, inlined by build.mjs into the bundles); `IrFormat` and the image format are its names, and the file dispatch is the core's sniff. Python reads the registry from the core. - Rejection tests moved from tests/parsers.rs into tests/<format>.rs (tests/common/ holds `reject!`); 687 tests before and after. - Codecs: refkv.zarr.codecs is a package of one module per codec, imported by discovery. - Schemas: spec/generate_schemas.py loads each profile's source-metadata schema from spec/source_metadata/<name>.py; the generated schemas are unchanged. - Spec numbering: each profile document is numbered on its own (Part 2 after Part 1) and cited by name; every reference was rewritten. The §1.2 signature table moved into each profile's document, and spec/virtualize.md states the rule. - Shared prose that enumerated formats (HARNESS.md, compare.py, js/README.md, the justfiles, the demo's examples and credits) is generic or moved into each format's page; the demo's examples are demo/examples/<name>.html, and fixture generators opt out of `just fixtures` with a `# fixtures: on demand` line. The index pages (spec/virtualize.md's, spec/conventions.md's and docs/virtualize/README.md's tables, and the demo page's blocks) stay generated and committed by `just profiles`: they are the one place two format branches can still conflict, when their names sort next to each other, and regenerating resolves it. Outputs are unchanged. Assisted-by: ClaudeCode:claude-opus-5-5
d-v-b
added a commit
that referenced
this pull request
Oct 24, 2026
…jection test in tests/ndpi.rs Merges origin/main (the per-format registry refactor, #102). Its compare.py and fixture generator comments are kept with REVISED's; the NDPI profile is now §7 of spec/virtualize/ndpi.md, so the links this branch added point there; and the rejected level-0 frame fixture gets its reject! case in the new tests/ndpi.rs. Assisted-by: ClaudeCode:claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d-v-b
added a commit
that referenced
this pull request
Oct 24, 2026
…register MP4 and refkv.stream the new way
main gave each format its own files. MP4 now registers through them: the registry file
spec/virtualize/profiles/mp4.json (sniff precedence 85, before MRC's), a Profile and
parser! in src/mp4.rs, rules::of("mp4"), tests/mp4.rs, spec/source_metadata/mp4.py; the
refkv.stream codec is the module refkv.zarr.codecs.stream, in place of main's mp3 module;
the MP3 and MP4 documents number their profile part on their own (§8) and are cited by name.
Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 AI text below 🤖
Adding a format to refkv now touches only that format's own files, its registry file
spec/virtualize/profiles/<name>.json, and the generated index pages. Before, it edited about ten shared, hand-kept lists, and every profile took a section number from one global sequence. PR #99 (MP3) and #88 (FITS) conflicted on every one of those lists and both took §18, a collision git merged silently. Outputs are unchanged.What a format adds now
spec/virtualize/profiles.json, plus generated copies in Python, TypeScript and Rustspec/virtualize/profiles/<name>.json; the Rust core keeps per-profile copies inrust/refkv-ir/profiles/(just profileswrites them)run.rs,lib.rs,rules.rs,project/mod.rs)name,from_name, asniffbranch,AnyParserarms,pub modandparser!lines, a schema static and accessorbuild.rsgenerates the module declarations,Formatand the sniff order; the format module declarespub struct Profile(run::FileProfile) and callscrate::parser!;rules::of(name)readsschema/<name>.jsonwasm/run.mjs)sniffin the registry (ties go by name); sniffing exists only in the core (_core.sniff,vz_sniff)IrFormat,ImageDesc["format"]and anifchain inindex.tsprofiles.tsloads the registry at runtime (#profiles); the format names come from it, and the dispatch is the core's snifftests/parsers.rsrust/refkv-ir/tests/<name>.rs(reject!is intests/common/)zarr/codecs.pyrefkv/zarr/codecs/<codec>.py, imported by discoveryspec/generate_schemas.pyspec/source_metadata/<name>.pysectionin the registry, used as§Neverywheredocs/virtualize/<name>/README.md; demo examples aredemo/examples/<name>.htmlExperiment
Four branches were cut from this PR's commit. Each one added a working stub file format the new way: a parser and its
Profile, a projection, a source model, a rejection test, fixtures, a spec document, a source-metadata module, a docs page and a registry file. Each then ranjust profilesanduv run python spec/generate_schemas.py. Every branch's commit is 16 added files and no edited lines: 13 of the files are the format's own, and the other 3 are generated index pages that each gained one row per table.git mergeaastub,xstub(they sort apart)profiles.py check); Rust core 689 passed;node --test638 passed; spec tools, conventions and IR pytest suites passed;wasm/run.mjssniffs and parses both new formats with no JS changesstuba,stubb(they sort next to each other)just profilesresolves them; Rust core 689 passedThe experiment's first run turned up two places where formats far apart in name still collided: the demo's one-line formats sentence, and the sniff index, which was ordered by precedence so every new format appended at its end. The demo blocks are now filled in by
js/build.mjsat build time, and the sniff index is ordered by name.Checks
cargo test --release): 687 passed, the same count before and after the tests moved into per-format files; the Python bindings crate builds (just ir-rust-test).just test(pytest, with the Rust core built): passed.just js::test: 638 passed.just sections: passed (spec tools tests, the section check, the profiles check).just cli-identical: 4550 conversions, 4550 identical, 0 differ.spec/generate_schemas.pywrites the same 17 schemas byte for byte;js/build.mjsbuilds and inlines the registry.What is left
spec/virtualize.md,spec/conventions.mdanddocs/virtualize/README.md, and the demo's generated blocks, list every profile and stay committed. When two new names sort next to each other, both branches insert at the same spot, and runningjust profilesresolves it. The experiment above shows this case.StoreFormatinstore.rs, the §1.4 root-key table, JSchooseProfile) still dispatch by hand. No format PR in flight adds one.fits_tiles_decodeand_set_chunk_framesinpython/src/lib.rs,vz_fits_tiles_decodeinwasm.rs) and the two per-profile hooks inmirror.rsstay in shared files. A format that needs neither touches neither.pyproject.tomlanduv.lock.just ir-wasm: now reports the VSI sample as rejected. Its file run only rejects, andwasm/run.mjsused to read the file as a TIFF.Notes for review
spec/history/, frozen reference code included (comments only).just sectionspasses.HARNESS.mdandcompare.py(the formats that had a reference) are historical and fixed, so they stay as they are.refkv.virtualize.profilesnow reads the registry fromrefkv._core, sospec/generate_schemas.pyneeds a core built from the same tree (uv runrebuilds it, since the cache keys includerust/refkv-ir/profiles/*.jsonandbuild.rs).🤖 Generated with Claude Code