Separate common row constraints from established storage sizes. Preserve Q8_1 and K-layout uncertainty, plus numeric IDs and ambiguous textual identities for historically shifted IDs16–25. Keep zero-byte facts and identity limitations independently, and propagate producer facts through totals, cancellation and retained views. Pin released source evidence and document the compatibility cost. Fixes #6848
18 KiB
Model file declarations
Use inspect_model_artifact (CLI: inspect-model-artifact) to inspect a local
GGUF v2/v3 or safetensors file. Detection uses content, including GGUF byte
order, rather than its extension. REA does not load a model, interpret weights,
run inference, import Python, open external-data references or use the network.
Unsupported GGUF versions remain refused. Their diagnostic preserves the four version bytes and both UINT32 interpretations with byte order unknown, rather than inferring big-endian from an unrecognized little-endian value. Little-endian v2/v3 and big-endian v3 remain supported; big-endian v2 remains refused.
rea inspect-model-artifact /absolute/path/model.gguf --json
rea inspect-model-artifact /absolute/path/model.safetensors --hash full --json
The CLI defaults to complete Evidence. For compact delivery with portable access to every retained observation:
rea inspect-model-artifact /absolute/path/model.gguf \
--detail summary --evidence_output /absolute/path/model-evidence.json --json
Identity and reads
The default hash: "header" reads only the metadata and tensor directory. The
result records the exact selected path, file size, header length, header SHA-256,
bytes read and read scope. GGUF alignment padding is outside this prefix.
artifact.sha256 and the Evidence subject are null: a header digest is not a
commitment to the weights. Different files can have identical headers and sizes.
The reported GGUF tensor-data offset follows the aligned tensor directory when
padding is present. For zero-tensor metadata-only files that end at the
directory, it is the directory end; no tensor payload is implied. A partial
alignment gap is rejected. header_length still ends at the directory, before
any padding.
hash: "full" additionally streams the remaining file bytes through SHA-256.
It returns a full-file digest and Evidence subject, while retaining the same
header digest. It uses bounded buffers and does not interpret tensor data, but
it does read the whole file. Cost therefore grows with file size. Both modes
check descriptor and selected-path identity and metadata before completion;
this detects observed replacement or modification, not adversarial modification
that defeats filesystem metadata checks.
If full-file hashing fails or is cancelled after either format's header has been validated, partial Evidence retains the parsed metadata and tensor directory. Header coverage is complete; digests and final file identity remain unknown. Safetensors header parsing is atomic, so interruption before validation does not expose unvalidated JSON rows.
Facts and selected queries
GGUF reports version, byte order, alignment, typed metadata, and each tensor's
name, original type ID, dimensions, relative data offset, file offset and derived
byte length. Alignment accepts every positive UINT32 multiple of eight, including
non-powers of two. Partial Evidence retains explicit alignment once validated;
the default alignment becomes known after metadata completes. Cancellation
retains completed declarations with unknown digests and unverified final file
identity. Metadata keys preserve their spelling and use lowercase
ASCII alphanumeric components separated by dots, underscores or hyphens;
standard numeric components such as general.base_model.0.name are preserved.
Hyphenated components are retained for compatibility with the published
llama.cpp v0.7.0 writer, which emits keys such as
gpt-oss.context_length and wavtokenizer-dec.context_length; the current
GGUF specification
restricts general.architecture values to letters and digits.
This documents producer output that conflicts with that written restriction,
not a claim that the specification permits hyphens. See the pinned
WAVTOKENIZER_DEC
and GPT_OSS
architecture names, context-length key template,
and writer method.
Scalar metadata is complete. Arrays have declared element types,
counts and at most eight preview elements per array, with an explicit
preview_complete flag. This includes tokenizer vocabularies: omitted values
are not silently represented as a complete array. Strings are UTF-8; 64-bit
integer metadata and all shape dimensions use decimal strings without rounding.
Nonfinite floating metadata uses NaN, +Infinity or -Infinity with its
declared float type; negative zero is "-0". Unknown tensor types retain their numeric IDs and null byte
lengths; affected totals and storage validation remain unknown.
Q8_1 (type ID 9) has two released layouts: 40 bytes per 32 elements in
llama.cpp b1500
and 36 bytes in the pinned
modern ggml layout. Both use GGUF v3 and
quantization version 2, so those declarations do not select a storage layout.
REA retains the known type, shape, parameter count and starting offsets, with
byte_length: null, storage_validation: "unknown", partial storage/range
coverage and an explicit limitation for nonempty Q8_1 tensors. Per-type and
overall byte totals remain unknown where affected. Padding, the next tensor's
offset and file size do not establish a layout; retained queries preserve the
same uncertainty. Empty Q8_1 tensors still have a derived zero-byte length,
and the known 32-element row-block constraint remains enforced.
K-quantization IDs 10–15 also have incompatible released layouts. The
b1500 build option
LLAMA_QKK_64 selects GGML_QKK_64; the same release's default and
b3001
use 256-element blocks. The
b1500 structures
give these source-derived sizes:
| ID | Stable name | Bytes per 64 elements, K64 | Bytes per 256 elements, K256 | Padded extent for 256 elements, either layout |
|---|---|---|---|---|
| 10 | Q2_K | 24 | 84 | 96 |
| 11 | Q3_K | 28 | 110 | 128 |
| 12 | Q4_K | 38 | 144 | 160 |
| 13 | Q5_K | 46 | 176 | 192 |
| 14 | Q6_K | 54 | 210 | 224 |
| 15 | Q8_K | 76 | 292 | 320 |
Both builds write GGUF v3 and quantization version 2. The
quantizer
writes general.file_type directly from the selected llama_ftype, without
encoding the K64 build option. GGML_QNT_VERSION_FACTOR is defined in the
header but is not used by this GGUF serialization path. Global file type also
does not identify individual tensor types: the quantizer
retains unselected tensors.
The writer pads each payload
to the default 32-byte alignment; the final column shows why even the same file
extents need not distinguish these layouts.
REA preserves each K type's name and enforces the common 64-element row
multiple, which does not establish a storage block size. Nonempty K tensor
lengths and affected totals are now unknown, including common modern files.
Empty K tensors still have derived zero-byte storage.
Integer IDs also shifted each time IQ types were added. These released
ggml.h snapshots all declare GGUF v3 and quantization version 2:
| Released snapshot | I8 ID | I16 ID | I32 ID |
|---|---|---|---|
| b1500 | 16 | 17 | 18 |
| b1803 | 17 | 18 | 19 |
| b1871 | 18 | 19 | 20 |
| b2100 | 19 | 20 | 21 |
| b2172 | 20 | 21 | 22 |
| b2221 | 21 | 22 | 23 |
| b2253 | 22 | 23 | 24 |
| b2275 | 23 | 24 | 25 |
| b2300 | 24 | 25 | 26 |
Upstream PR 6050 later pinned
integer values explicitly. Modern IDs 16–23 mean IQ2_XXS, IQ2_XS, IQ3_XXS,
IQ1_S, IQ4_NL, IQ3_S, IQ2_S and IQ4_XS, respectively. Thus every ID 16–25 has
multiple released meanings. REA keeps its numeric type_id, uses
AMBIGUOUS_<id> for type, and records the released candidate names in a
limitation. Nonempty byte lengths are unknown. Empty declarations still derive
zero-byte storage, while their textual identity remains ambiguous. Type filters
match the reported AMBIGUOUS_<id> label. ID 26 remains I32 across these
snapshots; later stable entries retain their existing interpretation. This audit
does not establish compatibility with every producer fork or future revision.
The inventory does not select a historical layout from model names, global file types, padding or guessed producer provenance. A source revision together with its build configuration can establish an external layout fact; these headers do not carry that identification, and REA currently has no layout selection input. Authored regression fixtures use the source-derived sizes above; historical executables were not run.
Safetensors reports the header extent, exact string __metadata__ values, dtype,
shape and declared data ranges. A null __metadata__ is treated as omitted;
unknown fields on tensor entries are ignored within the reader's 32-level JSON
nesting limit, while the required dtype, shape and data offsets are still
validated. JSON duplicate keys, invalid UTF-8, out-of-file
ranges, overlaps, gaps, trailing unindexed data and known dtype/shape byte-length
contradictions are rejected with a typed file_format_rejected constraint (public code target_unavailable, category unsupported_target).
A missing, non-regular or otherwise unusable selected path is also target_unavailable;
host I/O or resource failures on a valid selection, such as EMFILE or EIO, are
execution_failure with the path and reason in details.diagnostics. Empty
tensors and scalar shapes are supported. The reader retains shape dimensions as
exact unsigned 64-bit values, including values above JavaScript's safe-integer
range when a zero extent makes storage empty. Shape products are checked in
declaration order, as in the
64-bit upstream reader;
a later zero does not erase an earlier product overflow. Actual file and data
offsets must still fit exact host offset precision. Packed sub-byte types require whole
byte storage. Unknown dtypes retain declared ranges and an explicit limitation
that shape-to-storage validation is unavailable. Each tensor records
storage_validation: "consistent" | "unknown"; coverage.storage_sizes remains
partial when that consistency cannot be checked. Tensor filters accept these
storage_validation states independently of dtype or name.
Parameter counts and per-type totals are derived from declarations, not measurements of effective parameters or inference behavior. Shared or repeated weights are not deduplicated. GGUF dimensions retain their original fastest-first order; safetensors shapes retain JSON order. Safetensors tensor rows use name order; GGUF rows use directory order. An index identifies a declaration within its collection and header digest, not tensor contents or a cross-version match. GGUF supports zero extents and scalar shapes, with at most four dimensions; known quantized types still require complete blocks in the first dimension.
MCP defaults to a compact summary with counts, selected short headline metadata,
chat-template presence (default or named template content) and derived totals.
A names-only tokenizer.chat_templates inventory does not establish template
content. The full type histogram and all rows
remain in complete Evidence. Headline metadata uses short keys/types and scalar
values; long or compound values remain available through explicit metadata
queries. Use the returned parent_evidence_id:
{
"source": {
"kind": "retained-evidence",
"evidence_id": "<parent_evidence_id>"
},
"view": {
"kind": "model-artifact",
"collection": "tensors",
"names": ["token_embd.weight", "output.weight"],
"fields": ["name", "type", "shape", "file_offset", "byte_length"],
"offset": 0,
"limit": 32
}
}
To answer a known question in the initial inspection, pass the same selection
without kind as inspect_model_artifact's optional view, for example
{"path":"/absolute/path/model.gguf","view":{"collection":"tensors","names":["token_embd.weight"],"fields":["type","shape","file_offset"]}}.
This returns one selected page with compact model context and retains the full
source Evidence, avoiding another tool call. view requires summary delivery;
complete detail and a selection are rejected as conflicting choices.
CLI uses --view '{"collection":"tensors","names":["token_embd.weight"]}'
with --detail summary --evidence_output FILE.
Call inspect_analysis_view with the historical query object above for further pages. collection: "metadata" accepts
exact keys, indices, fields and paging; use it for tokenizer.chat_template
or tokenizer array previews. collection: "types" pages derived storage and
parameter totals and accepts exact types. Tensor pages also accept types.
Filters intersect; omitted filters mean all recorded rows and empty arrays mean
none. Every row retains its source-scoped index. Names, keys and type labels
follow field selection; fields: [] returns only indices. Omitted fields return
all recorded columns. Compact warnings use the shared bounded view budget and
link to complete parent Evidence when messages are omitted. Page offsets count filtered
matches, while row indices retain their original scope. Each page carries source
identity, header coverage, array omissions, unknowns and parent Evidence links.
Pages read historical retained facts without reopening the model. Complete
Evidence can also be supplied inline or as a single authenticated Evidence JSON
record through source: {"kind": "evidence-file", "path": "/absolute/path/model-record.json"}.
CLI Evidence bundles contain a records array; import the bundle with
import_evidence_bundle before using retained queries, or save one complete
record as a standalone Evidence file. A bundle is not a single Evidence record.
The session owns validated indexes until that Evidence is released; there is no
live-file result cache or automatic freshness claim.
Imported reports must retain positional indices and unique names, keys and
type identities; malformed reports return a typed input error before indexing.
Bounds and unsupported inputs
The reader admits one active inspection per provider. It enforces a 100,000,000 byte header ceiling (safetensors counts its declared JSON bytes separately from the fixed eight-byte length prefix; GGUF counts the complete header) and a separate 32 MiB retained representation budget before retaining rows or expanding strings. Numeric products use exact integer arithmetic. GGUF follows its four-dimensional tensor layout and limits metadata array nesting to 32 frames. Resource refusals are typed, rather than returned as complete empty inventories. Cancellation joins descriptor finalization; failed cleanup remains owned for retry.
PyTorch pickle and ZIP model deserialization are unsupported; convert using a trusted external workflow and supply GGUF or safetensors. ONNX, TFLite, Core ML, model execution and conversion are outside this operation.
Format references: GGUF specification, ggml tensor layouts, safetensors format.