deepbom 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Copyright (C) 2026 Jun-Hwan Kwon. All rights reserved.
2
+
3
+ This repository and its generated software artifacts are currently provided as
4
+ private research software. No license is granted to copy, modify, distribute,
5
+ sublicense, reverse engineer, or create derivative works from the source code,
6
+ WebAssembly modules, generated JavaScript bindings, or packaged executables,
7
+ except where a separate file or component carries an explicit license.
8
+
9
+ Access to the hosted service does not grant a software or implementation
10
+ license.
11
+
12
+ Future public releases may license selected contracts, conformance fixtures,
13
+ validation data, or automation clients separately. A license applies only to
14
+ the files and versions that explicitly carry it. Third-party dependencies and
15
+ model artifacts remain subject to their respective licenses.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # deepbom
2
+
3
+ Deployment-artifact analysis for on-device neural network models.
4
+
5
+ Answers questions you otherwise have to guess at before shipping a model:
6
+ which operators the XNNPACK delegate will accept, where the graph falls back
7
+ to CPU and how much traffic crosses that boundary, how much of the quantized
8
+ range the weights actually use, and which target profile the numbers apply to.
9
+
10
+ ```console
11
+ $ npx deepbom audit mobilenet_v2_1.0_224_quant.tflite
12
+
13
+ mobilenet_v2_1.0_224_quant.tflite
14
+ sha256 f08d447cde49b4e0446428aa921aff0a14ea589fa9c5817b31f83128e9a43c1d
15
+ format tflite size 3.4 MB
16
+ target android_mid_a55
17
+
18
+ graph
19
+ operators 65
20
+ tensors 173
21
+ total MACs 300,775,552
22
+
23
+ quantization
24
+ quantized tensors 172 / 173 (99%)
25
+ per-axis tensors 0
26
+
27
+ XNNPACK delegate (predicted)
28
+ delegated ops 64 / 65 (98%)
29
+ chain breaks 1 effective / 1 total
30
+ fallback traffic 62.5 KB
31
+
32
+ findings (7)
33
+ MEDIUM 1 XNNPACK predicted partition breaks total
34
+ MEDIUM 17 quantized DEPTHWISE_CONV_2D op(s) use per-tensor weights
35
+ MEDIUM 53 quantized kernel op(s) use asymmetric UINT8 weights
36
+ LOW Input preprocessing contract not encoded in model
37
+ ...
38
+ ```
39
+
40
+ ## Install
41
+
42
+ Nothing to install:
43
+
44
+ ```console
45
+ npx deepbom audit model.tflite
46
+ ```
47
+
48
+ Or add it to a project:
49
+
50
+ ```console
51
+ npm install --save-dev deepbom
52
+ ```
53
+
54
+ Requires Node.js 20 or newer.
55
+
56
+ ## Usage
57
+
58
+ ```console
59
+ deepbom audit <file> [--target <id>] [--json]
60
+ deepbom targets
61
+ deepbom --version
62
+ ```
63
+
64
+ | Option | |
65
+ | --- | --- |
66
+ | `-t, --target <id>` | Target profile, default `android_mid_a55` |
67
+ | `--json` | Emit the complete analysis ledger as JSON |
68
+ | `-q, --quiet` | Suppress the summary header |
69
+
70
+ ### Target profiles
71
+
72
+ Cache pressure and roofline results are profile-bound, not global. Run
73
+ `deepbom targets` for the current list; it includes Cortex-A72/A76/A55/A53
74
+ profiles, an illustrative X3/A715 planning profile, x86 AVX2/SSE4 and browser
75
+ WASM SIMD.
76
+
77
+ ```console
78
+ deepbom audit model.tflite --target rpi5_a76
79
+ ```
80
+
81
+ ### JSON output
82
+
83
+ `--json` emits the full ledger: per-operator MACs, cache payload
84
+ decomposition, predicted delegate placement with reasons, per-tensor
85
+ quantization metadata, and the finding queue. Suitable for CI:
86
+
87
+ ```console
88
+ deepbom audit model.tflite --json > audit.json
89
+ ```
90
+
91
+ ## Privacy
92
+
93
+ Analysis runs locally in WebAssembly. The command performs **no network
94
+ access**. Model bytes, filenames and results are never uploaded.
95
+
96
+ ## Scope and limits
97
+
98
+ This release analyses **TFLite FlatBuffer** artifacts.
99
+
100
+ Delegate placement is a **static projection** derived from the serialized
101
+ graph. It is not observed runtime behaviour: build configuration, device
102
+ capability and runtime partitioning can differ. Roofline and cache figures are
103
+ target-profile projections, not measurements.
104
+
105
+ ONNX, GGUF, SafeTensors and Core ML analysis, runtime benchmarks, CycloneDX
106
+ ML-BOM export and the source-pinned execution-provider evidence packs are
107
+ available in the browser version at <https://deepbom.org>.
108
+
109
+ ## License
110
+
111
+ ISC — see [LICENSE](./LICENSE).
package/bin/deepbom.js ADDED
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env node
2
+ // deepbom — deployment-artifact analysis for on-device neural network models.
3
+ //
4
+ // Runs the browser analyzer's WebAssembly module locally. Model bytes never
5
+ // leave the machine; this command performs no network access.
6
+
7
+ import { readFile } from "node:fs/promises";
8
+ import { fileURLToPath } from "node:url";
9
+ import { dirname, join, basename } from "node:path";
10
+ import { createHash } from "node:crypto";
11
+
12
+ const HERE = dirname(fileURLToPath(import.meta.url));
13
+ const ROOT = join(HERE, "..");
14
+ const pkg = JSON.parse(await readFile(join(ROOT, "package.json"), "utf8"));
15
+
16
+ const argv = process.argv.slice(2);
17
+
18
+ function parseArgs(list) {
19
+ const opts = { _: [] };
20
+ for (let i = 0; i < list.length; i += 1) {
21
+ const a = list[i];
22
+ if (a === "--json") opts.json = true;
23
+ else if (a === "--quiet" || a === "-q") opts.quiet = true;
24
+ else if (a === "--target" || a === "-t") opts.target = list[++i];
25
+ else if (a === "--help" || a === "-h") opts.help = true;
26
+ else if (a === "--version" || a === "-v") opts.version = true;
27
+ else if (a.startsWith("--target=")) opts.target = a.slice(9);
28
+ else if (a.startsWith("-")) { fail(`unknown option: ${a}`); }
29
+ else opts._.push(a);
30
+ }
31
+ return opts;
32
+ }
33
+
34
+ function fail(message, code = 2) {
35
+ process.stderr.write(`deepbom: ${message}\n`);
36
+ process.exit(code);
37
+ }
38
+
39
+ const USAGE = `deepbom ${pkg.version} — deployment-artifact analysis for on-device models
40
+
41
+ USAGE
42
+ deepbom audit <file> [--target <id>] [--json]
43
+ deepbom targets
44
+ deepbom --version
45
+
46
+ COMMANDS
47
+ audit Analyse a model artifact and print a summary
48
+ targets List available target profiles
49
+
50
+ OPTIONS
51
+ -t, --target <id> Target profile (default: android_mid_a55)
52
+ --json Emit the full analysis ledger as JSON
53
+ -q, --quiet Suppress the summary header
54
+ -h, --help Show this help
55
+
56
+ FORMATS
57
+ TFLite (.tflite) is supported in this release. ONNX, GGUF, SafeTensors and
58
+ Core ML are available in the browser version at https://deepbom.org
59
+
60
+ PRIVACY
61
+ Analysis runs locally. No model bytes, filenames or results are uploaded.
62
+ `;
63
+
64
+ async function loadEngine() {
65
+ const mod = await import(new URL("../vendor/tflite_wasm_audit.js", import.meta.url));
66
+ const wasm = await readFile(new URL("../vendor/tflite_wasm_audit_bg.wasm", import.meta.url));
67
+ mod.initSync({ module: wasm });
68
+ return mod;
69
+ }
70
+
71
+ const fmtInt = (n) => Number(n ?? 0).toLocaleString("en-US");
72
+ function fmtBytes(n) {
73
+ const v = Number(n ?? 0);
74
+ if (!Number.isFinite(v) || v <= 0) return "0 B";
75
+ const units = ["B", "KB", "MB", "GB"];
76
+ const i = Math.min(units.length - 1, Math.floor(Math.log(v) / Math.log(1024)));
77
+ return `${(v / 1024 ** i).toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
78
+ }
79
+ const pct = (n, d) => (d > 0 ? `${((n / d) * 100).toFixed(0)}%` : "n/a");
80
+
81
+ async function cmdTargets() {
82
+ const engine = await loadEngine();
83
+ const profiles = engine.target_profiles() || [];
84
+ for (const p of profiles) {
85
+ const id = p?.id ?? p;
86
+ const label = p?.label ? ` — ${p.label}` : "";
87
+ process.stdout.write(`${id}${label}\n`);
88
+ }
89
+ }
90
+
91
+ async function cmdAudit(opts) {
92
+ const file = opts._[0];
93
+ if (!file) fail("audit requires a file path\n\n" + USAGE);
94
+
95
+ let bytes;
96
+ try {
97
+ bytes = new Uint8Array(await readFile(file));
98
+ } catch (error) {
99
+ fail(`cannot read ${file}: ${error.code ?? error.message}`);
100
+ }
101
+ if (bytes.length === 0) fail(`${file} is empty`);
102
+
103
+ const engine = await loadEngine();
104
+ const target = opts.target || "android_mid_a55";
105
+ const known = (engine.target_profiles() || []).map((p) => p?.id ?? p);
106
+ if (known.length && !known.includes(target)) {
107
+ fail(`unknown target "${target}". Run: deepbom targets`);
108
+ }
109
+
110
+ let analysis;
111
+ try {
112
+ analysis = engine.analyze_tflite_for_target(bytes, basename(file), target);
113
+ } catch (error) {
114
+ fail(`analysis failed: ${error?.message ?? error}\n` +
115
+ `This release supports TFLite FlatBuffer artifacts. ` +
116
+ `For ONNX, GGUF, SafeTensors and Core ML see https://deepbom.org`, 1);
117
+ }
118
+
119
+ if (opts.json) {
120
+ process.stdout.write(`${JSON.stringify(analysis, null, 2)}\n`);
121
+ return;
122
+ }
123
+
124
+ const sha = analysis.model_sha256 || createHash("sha256").update(bytes).digest("hex");
125
+ const ops = Array.isArray(analysis.ops) ? analysis.ops : [];
126
+ const delegated = ops.filter((o) => o?.xnnpack_supported === true).length;
127
+ const findings = Array.isArray(analysis.findings) ? analysis.findings : [];
128
+ const out = [];
129
+
130
+ if (!opts.quiet) {
131
+ out.push(`${analysis.filename || basename(file)}`);
132
+ out.push(` sha256 ${sha}`);
133
+ out.push(` format ${analysis.format ?? "unknown"} size ${fmtBytes(analysis.file_size ?? bytes.length)}`);
134
+ out.push(` target ${target}`);
135
+ out.push("");
136
+ }
137
+
138
+ out.push("graph");
139
+ out.push(` operators ${fmtInt(analysis.operator_count)}`);
140
+ out.push(` tensors ${fmtInt(analysis.tensor_count)}`);
141
+ if (analysis.total_macs != null) out.push(` total MACs ${fmtInt(analysis.total_macs)}`);
142
+ out.push("");
143
+
144
+ out.push("quantization");
145
+ out.push(` quantized tensors ${fmtInt(analysis.quantized_tensors)} / ${fmtInt(analysis.tensor_count)} (${pct(analysis.quantized_tensors, analysis.tensor_count)})`);
146
+ out.push(` per-axis tensors ${fmtInt(analysis.per_channel_tensors)}`);
147
+ out.push("");
148
+
149
+ if (ops.length) {
150
+ out.push("XNNPACK delegate (predicted)");
151
+ out.push(` delegated ops ${fmtInt(delegated)} / ${fmtInt(ops.length)} (${pct(delegated, ops.length)})`);
152
+ if (analysis.xnnpack_effective_chain_breaks != null) {
153
+ out.push(` chain breaks ${fmtInt(analysis.xnnpack_effective_chain_breaks)} effective / ${fmtInt(analysis.xnnpack_chain_breaks)} total`);
154
+ }
155
+ if (analysis.fallback_estimated_bytes) {
156
+ out.push(` fallback traffic ${fmtBytes(analysis.fallback_estimated_bytes)}`);
157
+ }
158
+ out.push("");
159
+ }
160
+
161
+ if (findings.length) {
162
+ out.push(`findings (${findings.length})`);
163
+ for (const f of findings.slice(0, 10)) {
164
+ const sev = String(f?.severity ?? f?.priority ?? "info").toUpperCase().padEnd(6);
165
+ const title = f?.title ?? f?.message ?? f?.id ?? "";
166
+ out.push(` ${sev} ${title}`);
167
+ }
168
+ if (findings.length > 10) out.push(` ... ${findings.length - 10} more (use --json)`);
169
+ out.push("");
170
+ }
171
+
172
+ out.push("Predicted delegate placement is a static projection, not observed runtime behaviour.");
173
+ out.push("Full ledger: deepbom audit <file> --json");
174
+ process.stdout.write(`${out.join("\n")}\n`);
175
+ }
176
+
177
+ const opts = parseArgs(argv);
178
+ if (opts.version) { process.stdout.write(`${pkg.version}\n`); process.exit(0); }
179
+ if (opts.help || argv.length === 0) { process.stdout.write(USAGE); process.exit(argv.length === 0 ? 1 : 0); }
180
+
181
+ const command = opts._.shift();
182
+ try {
183
+ if (command === "audit") await cmdAudit(opts);
184
+ else if (command === "targets") await cmdTargets();
185
+ else fail(`unknown command "${command}"\n\n${USAGE}`);
186
+ } catch (error) {
187
+ fail(error?.stack ?? String(error), 1);
188
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "deepbom",
3
+ "version": "0.1.0",
4
+ "description": "Deployment-artifact analysis for on-device neural network models — local static audit of TFLite graphs, quantization contracts and predicted XNNPACK delegate placement",
5
+ "type": "module",
6
+ "bin": {
7
+ "deepbom": "bin/deepbom.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "vendor/",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "license": "ISC",
16
+ "engines": {
17
+ "node": ">=20"
18
+ },
19
+ "keywords": [
20
+ "tflite",
21
+ "litert",
22
+ "onnx",
23
+ "quantization",
24
+ "on-device",
25
+ "edge-ai",
26
+ "xnnpack",
27
+ "ml-bom",
28
+ "cyclonedx",
29
+ "static-analysis"
30
+ ],
31
+ "homepage": "https://deepbom.org",
32
+ "author": "Jun-Hwan Kwon"
33
+ }