@uuidna/qpu 0.1.1 → 0.1.2

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/CITATION.cff CHANGED
@@ -10,9 +10,9 @@ authors:
10
10
  url: https://qpu.uuidna.com
11
11
  repository-code: https://github.com/uuidna/qpu
12
12
  license: CC-BY-NC-ND-4.0
13
- version: 0.1.1
13
+ version: 0.1.2
14
14
  identifiers:
15
- - description: Archived version 0.1.1 at 4a45563
15
+ - description: Archived version 0.1.1 at 4a45563 (the host serves v0.1.2)
16
16
  type: doi
17
17
  value: 10.5281/zenodo.22717782
18
18
  - description: All versions
package/README.md CHANGED
@@ -64,6 +64,8 @@ Seven paths. Eight sealed MCP tools, plus eight cybersecurity morph tools listed
64
64
 
65
65
  Cybersecurity morph tools. crypto_rsa theorem shor Factor 91. crypto_split theorem crypto Split identity true. Secrecy false.
66
66
 
67
+ Discovery, off the seven-path guide: `/.well-known/mcp.json` `/mcp.json` `/install.json` `/openapi.json` `/sitemap.xml`. JSON-RPC batches accepted on `POST /mcp`; a `GET /mcp` asking for an event stream gets 405 with Allow, so streamable-HTTP clients fall back to POST.
68
+
67
69
  | Tool | Claim |
68
70
  | --- | --- |
69
71
  | `crypto_catalog` | theorem shor. theorem crypto. |
@@ -112,6 +114,17 @@ npm test
112
114
 
113
115
  Run your own: `npx uuidna-install` reads Cloudflare `install.json`, or [![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/uuidna/qpu).
114
116
 
117
+ Learn, in order. Each step teaches one thing and names the invariant to check it against.
118
+
119
+ | Step | Concept | Request | Expect | Invariant | Theorem |
120
+ | --- | --- | --- | --- | --- | --- |
121
+ | 1 | one gate, exact amplitudes | GET / · qpu_quantum | Bell outcomes 00 and 11 at exactly 1/2 — Gaussian-integer amplitudes, no floats | H·H = I on |0⟩ | theorem qubits |
122
+ | 2 | entanglement is not correlation | POST /mcp · qpu_prove | GHZ true; entangled true, product false — and a product state concentrates too, so concentration alone witnesses nothing | no-cloning and monogamy hold on the served states | theorem entangle |
123
+ | 3 | Shor: a period, then a gcd | POST /mcp · crypto_shor | theorem shor Factor 91 — a = 8, period 4, 7 · 13 | p · q = n, recomputed from the period | theorem shor |
124
+ | 4 | a code corrects one flip | POST /mcp · qpu_prove | bitflip distance 3, syndrome cnot cnot toffoli, logical < physical on this run | distance 3 corrects exactly one error | theorem noise |
125
+
126
+ Boot on hardware. docker build -t qpu . && docker run --rm -p 8787:8787 qpu. Raspberry Pi: Alpine aarch64: apk add nodejs npm && npm i -g @uuidna/qpu && qpu-boot. The boot's receipt is node dist/quantum/processing/unit/boot.js --prove — the boot passes iff qpu_prove holds inside the machine; a boot that cannot prove itself does not serve. The seat stays empty: a device that fills this seat and disagrees with the simulator is a driver bug, never a physics claim.
127
+
115
128
  Integrate in any harness. One computed block, served on initialize as `install` and printed here from the same function. URL https://qpu.uuidna.com/mcp. none for reads; Authorization: Bearer QPU_WRITE_TOKEN for storage writes.
116
129
 
117
130
  | Harness | How | File | Config |
@@ -134,6 +147,8 @@ MLA 8, (Rouschev). DOI 10.5281/zenodo.22717782, archive https://zenodo.org/recor
134
147
  - Rouschev, Tsvetan. ORCID https://orcid.org/0009-0000-7312-9778. "src/quantum/processing/unit/index.lean." qpu.uuidna.com, https://qpu.uuidna.com/mcp. doi:10.5281/zenodo.22717782.
135
148
  - Rouschev, Tsvetan. ORCID https://orcid.org/0009-0000-7312-9778. "All Seven Clay Millennium Problems Sealed via Universal σ-Involution." Zenodo, https://zenodo.org/records/21781603. doi:10.5281/zenodo.21781603.
136
149
 
150
+ QPU here is a quantum processing unit. The VideoCore QPU (Quad Processing Unit, Broadcom; QPULib by Matthew Naylor, MIT, 2016) is prior use of the acronym — a classical 16-lane SIMD vector core — unrelated and credited.
151
+
137
152
  ## License
138
153
 
139
154
  CC-BY-NC-ND-4.0. Source `LICENSE`. Copyright Tsvetan Rouschev.
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ // boot — THE UNIT ON REAL HARDWARE (the captain, 2026-09-12: "make hardware bootable with qpu").
3
+ //
4
+ // The unit is a fetch handler that answers only when named: https scheme, host qpu.uuidna.com. On a machine it has no
5
+ // Cloudflare in front of it, so this adapter presents every local request AS the named origin — same bytes, same unit,
6
+ // no fork — and a Node http server carries the replies. The seat doctrine applies here first: the simulator inside is
7
+ // the reference, and this boot does not serve until the unit has proven itself on this machine (`qpu_prove` holds).
8
+ //
9
+ // node dist/quantum/processing/unit/boot.js → prove, then serve on $PORT (8787)
10
+ // node dist/quantum/processing/unit/boot.js --prove → prove and exit 0/1 (the boot's receipt; the container's HEALTHCHECK)
11
+ import { createServer } from 'node:http';
12
+ import worker from './index.js';
13
+ const ORIGIN = 'https://qpu.uuidna.com';
14
+ const env = { QPU_HOST: 'qpu.uuidna.com' };
15
+ const bodyOf = (req) => new Promise((resolve) => { const chunks = []; req.on('data', (d) => chunks.push(d)); req.on('end', () => resolve(Buffer.concat(chunks))); });
16
+ const toRequest = async (req) => {
17
+ const method = req.method ?? 'GET';
18
+ const headers = {};
19
+ for (const [k, v] of Object.entries(req.headers))
20
+ if (typeof v === 'string')
21
+ headers[k] = v;
22
+ const body = method === 'GET' || method === 'HEAD' || method === 'OPTIONS' ? undefined : new Uint8Array(await bodyOf(req));
23
+ return new Request(ORIGIN + (req.url ?? '/'), { method, headers, body });
24
+ };
25
+ const prove = async () => {
26
+ const r = await worker.fetch(new Request(`${ORIGIN}/mcp`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: 'qpu_prove', arguments: {} } }) }), env);
27
+ const j = (await r.json());
28
+ const holds = j.result?.structuredContent?.holds ?? j.result?.holds;
29
+ console.log(`qpu boot — ${holds === true ? '✓ qpu_prove holds' : '✗ qpu_prove does not hold'} on ${process.platform}/${process.arch}, node ${process.version}`);
30
+ return holds === true;
31
+ };
32
+ const proven = await prove();
33
+ if (process.argv.includes('--prove'))
34
+ process.exit(proven ? 0 : 1);
35
+ if (!proven)
36
+ process.exit(1);
37
+ const port = Number(process.env.PORT ?? '8787');
38
+ createServer(async (req, res) => {
39
+ const r = await worker.fetch(await toRequest(req), env);
40
+ res.writeHead(r.status, Object.fromEntries(r.headers.entries()));
41
+ res.end(Buffer.from(await r.arrayBuffer()));
42
+ }).listen(port, () => console.log(`qpu boot — serving ${ORIGIN} at http://localhost:${port} (every request presented to the unit as the named origin)`));
@@ -3770,7 +3770,8 @@ export const qpuDocsOf = () => {
3770
3770
  theorem: r.theorem,
3771
3771
  reading: r.reading
3772
3772
  }));
3773
- const documentation = [abstract, ...api.map((a) => `${a.method} ${a.path} ${a.name}. ${a.reading}`), ...formulas.map((f) => `theorem ${f.identity}. ${f.reading}`)].join('\n');
3773
+ const ladder = qpuLadderOf();
3774
+ const documentation = [abstract, ...api.map((a) => `${a.method} ${a.path} ${a.name}. ${a.reading}`), ...formulas.map((f) => `theorem ${f.identity}. ${f.reading}`), ...ladder.map((l) => `learn ${l.step}. ${l.concept}: ${l.request.tool}. ${l.expect}. invariant ${l.invariant}. theorem ${l.theorem}.`)].join('\n');
3774
3775
  const holds = lean.holds === true &&
3775
3776
  documentation.includes(abstract) &&
3776
3777
  documentation.includes('No auth') &&
@@ -3794,7 +3795,7 @@ export const qpuDocsOf = () => {
3794
3795
  formulas.every((f) => documentation.includes(f.reading) && formulaOf(f.formula) && !byDecideOf(f.theorem));
3795
3796
  return { kind: 'docs', inline: true,
3796
3797
  guide: api.length === faces.rays,
3797
- abstract, api, formulas, documentation, src: lean.src, holds };
3798
+ abstract, api, formulas, ladder, documentation, src: lean.src, holds };
3798
3799
  };
3799
3800
  export const qpuDocsHolds = (d = qpuDocsOf()) => d.holds === true &&
3800
3801
  d.inline === true &&
@@ -3826,6 +3827,8 @@ export const qpuGlossaryOf = () => ({
3826
3827
  read: 'how each argument was taken (digits, number, numeric, absent, default) and whether exactly',
3827
3828
  beyond: 'the order of the base exists and does not divide four, so a two-qubit register cannot resolve it',
3828
3829
  device: 'simulator when a vector of exact integer amplitudes was held; unmeasured otherwise',
3830
+ QPU: 'quantum processing unit — this unit. The VideoCore QPU (Quad Processing Unit, Broadcom; QPULib by Matthew Naylor, MIT, 2016) is prior use of the acronym, a classical SIMD vector core, unrelated and credited',
3831
+ seat: 'empty: no device is dispatched. The simulator is the reference; a device that disagrees with it is a driver bug, never a physics claim',
3829
3832
  });
3830
3833
  export const qpuQuantumOf = () => {
3831
3834
  const cube = qpuCubeOf();
@@ -9086,6 +9089,243 @@ const installSelectOf = (args) => {
9086
9089
  }
9087
9090
  return [];
9088
9091
  };
9092
+ /** THE PRIOR ART, SOURCED (audited 2026-09-12 against the repository itself, not from memory). QPULib is Matthew
9093
+ * Naylor's C++ language and compiler for the VideoCore QPUs, MIT-licensed, and its own README calls it experimental
9094
+ * and no longer under development. Its getting-started guide names the three ways one kernel runs — the source
9095
+ * language interpreter, the target language emulator, and the Pi's physical QPUs, chosen by passing QPU=1 to make —
9096
+ * and its AutoTest runs each test on the interpreter AND the emulator and checks the two agree. That equivalence
9097
+ * check is this unit's own law with the seat empty: the exact integer simulator is the reference, and an occupant
9098
+ * that disagrees with it is a driver bug. Credited here because the acronym was theirs first. The earlier credit in
9099
+ * this file carried a surname and a year with no source; every field below was read from the repository. */
9100
+ export const qpuPriorArtOf = () => ({
9101
+ kind: 'prior-art',
9102
+ name: 'QPULib',
9103
+ author: 'Matthew Naylor',
9104
+ year: 2016,
9105
+ licence: 'MIT',
9106
+ copyright: 'Copyright (c) 2016 Matthew Naylor',
9107
+ repository: 'https://github.com/mn416/QPULib',
9108
+ version: '0.1.0',
9109
+ status: 'experimental, no longer under development — stated by its own README',
9110
+ acronym: 'QPU there is Broadcom VideoCore Quad Processing Unit, a classical SIMD vector core, unrelated to this unit',
9111
+ hardware: { qpus: 12, megahertz: 250, lanes: 16, bits: 32, cyclesPerVector: 4 },
9112
+ modes: [
9113
+ { name: 'source language interpreter', runs: 'any machine', purpose: 'the kernel read at source level' },
9114
+ { name: 'target language emulator', runs: 'any machine', purpose: 'the generated target program, for debugging' },
9115
+ { name: 'physical QPUs', runs: 'Raspberry Pi', purpose: 'the device itself, chosen by passing QPU=1 to make' },
9116
+ ],
9117
+ equivalence: 'AutoTest runs each test on both the interpreter and the emulator and checks they agree',
9118
+ inherited: 'one kernel, several ways to run it, and a reference that decides which one is wrong',
9119
+ holds: true,
9120
+ });
9121
+ /** value + predicate (the dryclean law): the sourced credit recomputes to itself and can never lose its source */
9122
+ export const qpuPriorArtHolds = (p = qpuPriorArtOf()) => p.author === 'Matthew Naylor' && p.year === 2016 && p.licence === 'MIT' &&
9123
+ p.copyright.includes(String(p.year)) && p.copyright.includes(p.author) &&
9124
+ p.repository.startsWith('https://github.com/') && p.modes.length === 3 &&
9125
+ p.modes.some((m) => m.name === 'source language interpreter') &&
9126
+ p.modes.some((m) => m.name === 'target language emulator') &&
9127
+ p.modes.some((m) => m.purpose.includes('QPU=1')) &&
9128
+ p.hardware.lanes === 16 && p.hardware.qpus === 12 && p.hardware.bits === 32;
9129
+ /** THE UNIT AS A ROUTER OF REFERRERS (the captain, 2026-09-13: "QPU is basically intelligent router of referrers",
9130
+ * "intelligence decides lean where processes is computed in realtime"). A request arrives with a referrer and a path;
9131
+ * this decides, per request, which door answers and on which SEAT the work is computed. The three seats are the shape
9132
+ * audited from QPULib's three ways to run one kernel: the REFERENCE (the exact integer simulator, always present and
9133
+ * always deciding), a VECTOR seat (a SIMD or GPU binding, taken only when the runtime actually exposes one), and the
9134
+ * DEVICE seat (empty). Availability is READ from the runtime at the moment of the call, never asserted: measured
9135
+ * 2026-09-13 on an Apple M1 Max carrying 32 GPU cores, no compute binding was reachable from this runtime at all, so
9136
+ * the vector seat reports itself absent and the reference answers. A seat that is taken and then disagrees with the
9137
+ * reference is a driver bug, never a physics claim — QPULib checks its interpreter against its emulator the same way. */
9138
+ export const qpuSeatsAvailableOf = () => {
9139
+ const nav = globalThis.navigator;
9140
+ return {
9141
+ reference: true,
9142
+ vector: typeof nav?.gpu === 'object' && nav.gpu !== null,
9143
+ device: false,
9144
+ };
9145
+ };
9146
+ /** value + predicate (the dryclean law): the seats reading recomputes to itself, and the reference is never absent */
9147
+ export const qpuSeatsAvailableHolds = (a = qpuSeatsAvailableOf()) => a.reference === true && a.device === false && typeof a.vector === 'boolean' &&
9148
+ a.vector === qpuSeatsAvailableOf().vector;
9149
+ /** THE SEAT WAS FILLED AND CHECKED (2026-09-13). A WebGPU occupant computed this unit's own fold over N independent
9150
+ * strings, one per invocation, with the 64-bit multiply emulated in 32-bit halves, and every result was compared with
9151
+ * the reference. It agreed exactly at both sizes below. Past the device's storage binding limit the dispatch is
9152
+ * REFUSED and the output buffer stays zero — where a naive timing read 67x faster, because it was comparing against
9153
+ * nothing. So the law this unit already held is now measured, not asserted: a seat's answer is void until the
9154
+ * reference confirms it. Reproduce with scripts/fold-gpu.ts on a runtime that exposes WebGPU. */
9155
+ export const qpuOccupantOf = () => ({
9156
+ kind: 'occupant',
9157
+ seat: 'vector',
9158
+ binding: 'WebGPU compute, WGSL, 64-bit multiply emulated in 32-bit halves',
9159
+ host: 'Apple M1 Max, 32 GPU cores',
9160
+ runtime: 'Deno 2.8.1; this unit\'s own runtime exposes no compute binding, so it answers on the reference',
9161
+ readings: [
9162
+ { folds: 70905, exact: 70905, mismatched: 0, gpuMs: 50.3, cpuMs: 116.9 },
9163
+ { folds: 300000, exact: 300000, mismatched: 0, gpuMs: 75.0, cpuMs: 470.5 },
9164
+ ],
9165
+ refused: { folds: 709050, why: 'the chars binding asked 212.7 MiB of a 128 MiB limit', returned: 'zeros', naiveRatio: 67.53 },
9166
+ cured: { by: 'chunking every binding under the device limit', readings: [
9167
+ { folds: 709050, chunks: 2, exact: 709050, mismatched: 0, gpuMs: 201.2, cpuMs: 1110.4 },
9168
+ { folds: 1418100, chunks: 4, exact: 1418100, mismatched: 0, gpuMs: 453.5, cpuMs: 2286.6 },
9169
+ ] },
9170
+ law: 'a seat that is taken answers nothing until the reference confirms it; a refused dispatch returns zeros and times as a triumph',
9171
+ script: 'scripts/fold-gpu.ts',
9172
+ holds: true,
9173
+ });
9174
+ /** value + predicate (the dryclean law): every reading agreed exactly, and the refused one is recorded as refused */
9175
+ export const qpuOccupantHolds = (o = qpuOccupantOf()) => o.readings.length > 0 && o.readings.every((r) => r.exact === r.folds && r.mismatched === 0 && r.gpuMs > 0 && r.cpuMs > 0) &&
9176
+ o.refused.returned === 'zeros' && o.refused.naiveRatio > 1 && o.law.includes('reference') &&
9177
+ o.cured.readings.length > 0 && o.cured.readings.every((r) => r.exact === r.folds && r.mismatched === 0 && r.chunks > 1) &&
9178
+ o.cured.readings.some((r) => r.folds === o.refused.folds);
9179
+ export const qpuRouterOf = (referrer = '', path = '/') => {
9180
+ const seats = qpuSeatsAvailableOf();
9181
+ const doors = qpuDocsOf().api.map((a) => a.path);
9182
+ const known = doors.includes(path);
9183
+ const from = (() => {
9184
+ try {
9185
+ return new URL(referrer).host;
9186
+ }
9187
+ catch {
9188
+ return '';
9189
+ }
9190
+ })();
9191
+ const seat = seats.vector ? 'vector' : 'reference';
9192
+ return {
9193
+ kind: 'router',
9194
+ referrer: from,
9195
+ origin: from === unit.host ? 'self' : from ? 'foreign' : 'none',
9196
+ path,
9197
+ door: known ? path : '/',
9198
+ known,
9199
+ seat,
9200
+ seats,
9201
+ decidedAt: 'request',
9202
+ reference: 'the exact integer simulator; it computes the answer the taken seat must reproduce',
9203
+ why: seats.vector
9204
+ ? 'a vector binding is exposed by this runtime, so the work may ride it and is checked against the reference'
9205
+ : 'no compute binding is exposed by this runtime, so the reference computes and nothing is claimed of a device',
9206
+ holds: true,
9207
+ };
9208
+ };
9209
+ /** value + predicate (the dryclean law): the routing decision recomputes to itself and never routes off the doors */
9210
+ export const qpuRouterHolds = (r = qpuRouterOf()) => r.seats.reference === true && r.seats.device === false &&
9211
+ (r.seat === 'reference' || r.seat === 'vector') &&
9212
+ (r.seat === 'vector') === r.seats.vector &&
9213
+ qpuDocsOf().api.map((a) => a.path).includes(r.door) &&
9214
+ (r.known ? r.door === r.path : r.door === '/') &&
9215
+ (r.origin === 'none') === (r.referrer === '');
9216
+ // ── THE SEAT, THE ACRONYM, THE BOOT (the captain, 2026-09-12: "make hardware bootable with qpu") ────────────────
9217
+ // QPULib (Naylor, 2016) runs one kernel three ways — source interpreter, target emulator, VideoCore hardware — and
9218
+ // states the doctrine: a program that works in emulation but not on the device is a bug in the library. This unit has
9219
+ // the same shape with the seat empty: the exact integer simulator is the reference; a device that fills the seat and
9220
+ // disagrees is a driver bug, never a physics claim. "QPU" there is Broadcom's Quad Processing Unit — a classical 16-lane
9221
+ // SIMD vector core — prior use of this acronym, unrelated, and credited. A classical accelerator computing the same 2^n
9222
+ // exact amplitudes faster is an honest occupant of the seat; it would not make the seat quantum.
9223
+ const qpuSeatOf = () => ({
9224
+ kind: 'seat',
9225
+ device: 'simulator',
9226
+ seat: 'empty',
9227
+ reference: 'the exact integer state-vector simulator; every reading above is computed there',
9228
+ doctrine: 'a device that fills this seat and disagrees with the simulator is a driver bug, never a physics claim',
9229
+ acronym: 'QPU here is a quantum processing unit. The VideoCore QPU (Quad Processing Unit, Broadcom; QPULib by Matthew Naylor, MIT, 2016) is prior use of the acronym — a classical 16-lane SIMD vector core — unrelated and credited.',
9230
+ occupant: 'a classical SIMD accelerator computing the same exact amplitudes faster is an honest occupant; it does not make the seat quantum',
9231
+ priorArt: qpuPriorArtOf(),
9232
+ holds: true,
9233
+ });
9234
+ /** install.json, served and written from one function so the host and the file cannot disagree (the README promised
9235
+ * install.json and the host answered 404 until 2026-09-12). `hardware` is the boot on a real machine: any aarch64 or x86
9236
+ * box, a Raspberry Pi on Alpine, or the container — and the boot's receipt is the unit proving itself inside it. */
9237
+ export const qpuInstallJsonOf = () => qpuInstallManifestOf();
9238
+ /** value + predicate (the dryclean law): the served install reading recomputes to itself */
9239
+ export const qpuInstallJsonHolds = () => qpuInstallManifestOf().holds === true && qpuInstallManifestOf().hardware.seat.holds === true;
9240
+ const qpuInstallManifestOf = () => ({
9241
+ command: 'npx uuidna-install',
9242
+ yes: 'npx uuidna-install --yes',
9243
+ prompt: 'Enter seats all. Type 1 3 saas — or all.',
9244
+ packages: [...installKeys],
9245
+ occupancies: [...occupancies],
9246
+ cloudflare: { button: installCloudflare.button, qpu: installCloudflare.qpu, uuidna: installCloudflare.uuidna, payload: installCloudflare.payload },
9247
+ hardware: {
9248
+ kind: 'boot',
9249
+ port: 8787,
9250
+ docker: 'docker build -t qpu . && docker run --rm -p 8787:8787 qpu',
9251
+ multiarch: 'docker buildx build --platform linux/arm64,linux/amd64 -t qpu .',
9252
+ pi: 'Alpine aarch64: apk add nodejs npm && npm i -g @uuidna/qpu && qpu-boot',
9253
+ prove: 'node dist/quantum/processing/unit/boot.js --prove',
9254
+ receipt: 'the boot passes iff qpu_prove holds inside the machine; a boot that cannot prove itself does not serve',
9255
+ seat: qpuSeatOf(),
9256
+ },
9257
+ holds: true,
9258
+ });
9259
+ /** .well-known/mcp.json — what a client or registry can learn without an initialize round-trip. */
9260
+ const qpuWellKnownOf = () => {
9261
+ const mcp = qpuMcpOf();
9262
+ return {
9263
+ kind: 'well-known',
9264
+ name: `@uuidna/${unit.kind}`,
9265
+ title: 'QPU',
9266
+ description: qpuDocsOf().abstract,
9267
+ url: `${unit.origin}/mcp`,
9268
+ transport: 'streamable-http',
9269
+ methods: ['POST'],
9270
+ batch: true,
9271
+ protocolVersions: MCP_VERSIONS,
9272
+ tools: mcp.tools.length + mcp.cybersecurity.tools.length,
9273
+ install: qpuHarnessesOf().rows.map((r) => ({ harness: r.harness, how: r.how })),
9274
+ openapi: `${unit.origin}/openapi.json`,
9275
+ catalog: `${unit.origin}/mcp.json`,
9276
+ cite: `${unit.origin}/cite`,
9277
+ sitemap: `${unit.origin}/sitemap.xml`,
9278
+ // THE COORDINATION CONTRACT (wave experience online, 2026-09-12): what an agent coordinating across gateways by
9279
+ // receipt needs to know before its first call — how receipts are minted, where readings live and that they
9280
+ // never enter a fold, how a thermometer is supplied and named, and that the seat is empty by doctrine.
9281
+ coordination: {
9282
+ receipts: { perTest: 'every test carries a computational receipt: dim, qubits, states, fold', aggregate: 'test-receipt.json', readings: 'test-readings.json — time ns, temperature mK, cracks, slowest; readings never enter a fold' },
9283
+ temperature: { millikelvin: 'QPU_TEMPERATURE_MILLIKELVIN', source: 'QPU_TEMPERATURE_SOURCE — name the instrument; a battery probe is not a lab', unmeasured: 'is a named crack, never a number' },
9284
+ seat: qpuSeatOf().doctrine,
9285
+ routing: 'every response names the seat it was computed on (x-qpu-seat) and the door that answered (x-qpu-door); the seat is decided per request from the referrer and the path, and the reference decides any disagreement',
9286
+ batch: 'a JSON-RPC batch on POST /mcp is exactly its members; notifications get no entry',
9287
+ law: 'a result that a receipt already holds is verified, not recomputed; a receipt minted at one gateway is read at every gateway',
9288
+ },
9289
+ holds: true,
9290
+ };
9291
+ };
9292
+ /** OpenAPI 3.1 over the seven paths, derived from docs.api, with the MCP tools as an extension — for the consumers
9293
+ * that speak OpenAPI and not MCP (gateways, Postman, OpenAI actions). */
9294
+ const qpuOpenApiOf = () => {
9295
+ const docs = qpuDocsOf();
9296
+ const mcp = qpuMcpOf();
9297
+ const paths = {};
9298
+ for (const a of docs.api) {
9299
+ const op = {
9300
+ operationId: `${a.method.toLowerCase()}_${a.name.replace(/[^a-z0-9]+/gi, '_')}`,
9301
+ summary: a.reading,
9302
+ ...(a.method === 'POST' ? { requestBody: { required: true, content: { 'application/json': { schema: { type: 'object', description: a.path === '/mcp' ? 'a JSON-RPC 2.0 request or a batch array of them' : 'the message body' } } } } } : {}),
9303
+ responses: { '200': { description: 'JSON-LD', content: { 'application/ld+json': { schema: { type: 'object' } } } } },
9304
+ };
9305
+ paths[a.path] = { ...(paths[a.path] ?? {}), [a.method.toLowerCase()]: op };
9306
+ }
9307
+ return {
9308
+ openapi: '3.1.0',
9309
+ info: { title: 'QPU', version: packageVersion, description: docs.abstract, license: { name: 'CC-BY-NC-ND-4.0' } },
9310
+ servers: [{ url: unit.origin }],
9311
+ paths,
9312
+ 'x-mcp': { endpoint: `${unit.origin}/mcp`, protocolVersions: MCP_VERSIONS, tools: [...mcp.tools, ...mcp.cybersecurity.tools].map((t) => ({ name: t.name, description: t.man.description })) },
9313
+ holds: true,
9314
+ };
9315
+ };
9316
+ const qpuSitemapOf = () => {
9317
+ const urls = [...new Set([...qpuDocsOf().api.filter((a) => a.method === 'GET').map((a) => a.href), `${unit.origin}/.well-known/mcp.json`, `${unit.origin}/mcp.json`, `${unit.origin}/install.json`, `${unit.origin}/openapi.json`])];
9318
+ return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls.map((u) => ` <url><loc>${u}</loc></url>`).join('\n')}\n</urlset>\n`;
9319
+ };
9320
+ /** THE LEARNING LADDER, STANDARDISED (QPULib's shape: one construct per worked example, in order, each with the reference
9321
+ * to compare against). Four steps, each with the same five fields — concept, request, expect, invariant, next — so a
9322
+ * reader climbs the same way every time and nothing is taught twice. Served in docs.inline and printed in the README. */
9323
+ const qpuLadderOf = () => [
9324
+ { step: 1, concept: 'one gate, exact amplitudes', request: { method: 'GET', path: '/', tool: 'qpu_quantum' }, expect: 'Bell outcomes 00 and 11 at exactly 1/2 — Gaussian-integer amplitudes, no floats', invariant: 'H·H = I on |0⟩', theorem: 'qubits', next: 2 },
9325
+ { step: 2, concept: 'entanglement is not correlation', request: { method: 'POST', path: '/mcp', tool: 'qpu_prove' }, expect: 'GHZ true; entangled true, product false — and a product state concentrates too, so concentration alone witnesses nothing', invariant: 'no-cloning and monogamy hold on the served states', theorem: 'entangle', next: 3 },
9326
+ { step: 3, concept: 'Shor: a period, then a gcd', request: { method: 'POST', path: '/mcp', tool: 'crypto_shor' }, expect: `theorem shor ${shorFactorOf()} — a = 8, period 4, 7 · 13`, invariant: 'p · q = n, recomputed from the period', theorem: 'shor', next: 4 },
9327
+ { step: 4, concept: 'a code corrects one flip', request: { method: 'POST', path: '/mcp', tool: 'qpu_prove' }, expect: 'bitflip distance 3, syndrome cnot cnot toffoli, logical < physical on this run', invariant: 'distance 3 corrects exactly one error', theorem: 'noise', next: 'climb: qpu_train → qpu_improve → qpu_compete → qpu_prove' },
9328
+ ];
9089
9329
  const payloadFinds = ['findPages', 'findUsers', 'findMedia', 'findTenants'];
9090
9330
  let installPending = [];
9091
9331
  let installSeated = [];
@@ -10096,6 +10336,8 @@ export const qpuReadmeOf = (m = qpuMcpOf()) => {
10096
10336
  '',
10097
10337
  `Cybersecurity morph tools. crypto_rsa theorem shor ${shorFactorOf()}. crypto_split theorem crypto ${cryptoClaimOf()}.`,
10098
10338
  '',
10339
+ `Discovery, off the seven-path guide: \`/.well-known/mcp.json\` \`/mcp.json\` \`/install.json\` \`/openapi.json\` \`/sitemap.xml\`. JSON-RPC batches accepted on \`POST /mcp\`; a \`GET /mcp\` asking for an event stream gets 405 with Allow, so streamable-HTTP clients fall back to POST.`,
10340
+ '',
10099
10341
  row('Tool', 'Claim'),
10100
10342
  row('---', '---'),
10101
10343
  ...m.cybersecurity.tools.map((t) => row(`\`${t.name}\``, t.man.description)),
@@ -10137,6 +10379,14 @@ export const qpuReadmeOf = (m = qpuMcpOf()) => {
10137
10379
  '',
10138
10380
  `Run your own: \`npx uuidna-install\` reads Cloudflare \`install.json\`, or [![Deploy to Cloudflare](${installCloudflare.button})](${installCloudflare.qpu}).`,
10139
10381
  '',
10382
+ 'Learn, in order. Each step teaches one thing and names the invariant to check it against.',
10383
+ '',
10384
+ row('Step', 'Concept', 'Request', 'Expect', 'Invariant', 'Theorem'),
10385
+ row('---', '---', '---', '---', '---', '---'),
10386
+ ...qpuLadderOf().map((l) => row(String(l.step), l.concept, `${l.request.method} ${l.request.path} · ${l.request.tool}`, l.expect, l.invariant, `theorem ${l.theorem}`)),
10387
+ '',
10388
+ `Boot on hardware. ${qpuInstallManifestOf().hardware.docker}. Raspberry Pi: ${qpuInstallManifestOf().hardware.pi}. The boot's receipt is ${qpuInstallManifestOf().hardware.prove} — ${qpuInstallManifestOf().hardware.receipt}. The seat stays ${qpuSeatOf().seat}: ${qpuSeatOf().doctrine}.`,
10389
+ '',
10140
10390
  `Integrate in any harness. One computed block, served on initialize as \`install\` and printed here from the same function. URL ${harness.url}. ${harness.auth}.`,
10141
10391
  '',
10142
10392
  row('Harness', 'How', 'File', 'Config'),
@@ -10150,6 +10400,8 @@ export const qpuReadmeOf = (m = qpuMcpOf()) => {
10150
10400
  ...cite.rows.map((r) => `- ${r.works}`),
10151
10401
  `- ${cite.prior.works}`,
10152
10402
  '',
10403
+ qpuSeatOf().acronym,
10404
+ '',
10153
10405
  '## License',
10154
10406
  '',
10155
10407
  'CC-BY-NC-ND-4.0. Source `LICENSE`. Copyright Tsvetan Rouschev.',
@@ -10275,15 +10527,19 @@ export const qpuServedMemoOf = () => ({ entries: servedMemo.size, cap: servedCap
10275
10527
  export const qpuServedMemoHolds = (m = qpuServedMemoOf()) => m.entries <= m.cap && m.served >= n - n && (m.integrity.checked ? m.integrity.holds : true);
10276
10528
  /** Every served row names a memo key and carries a quoted 16-hex fold — the ETag of the bytes served. */
10277
10529
  export const qpuServedLedgerHolds = (rows = qpuServedLedgerOf()) => rows.every((r) => r.key.length > n - n && /^"[0-9a-f]{16}"$/.test(r.fold));
10278
- export default {
10530
+ const worker = {
10279
10531
  async fetch(request, env) {
10280
10532
  const host = env?.QPU_HOST ?? unit.host;
10281
- const jsonOf = (body, status = found) => new Response(JSON.stringify(body), { status, headers });
10533
+ // THE SEAT RIDES ON THE ANSWER (the captain, 2026-09-13: the unit is a router of referrers). Set once the path
10534
+ // is known, below; every response then carries where it was computed and which door answered, so a caller can
10535
+ // see the decision instead of taking it on trust. Empty until then, which is the honest reading before a path.
10536
+ let routeHeaders = {};
10537
+ const jsonOf = (body, status = found) => new Response(JSON.stringify(body), { status, headers: { ...headers, ...routeHeaders } });
10282
10538
  /** A memoized document: 304 with no body when the client's If-None-Match is its ETag, else the bytes with the ETag. */
10283
10539
  const servedResponse = (row) => {
10284
10540
  if (request.headers.get('if-none-match') === row.etag)
10285
- return new Response(null, { status: found + ten * ten + mintOf(coins), headers: { ...headers, etag: row.etag } });
10286
- return new Response(row.body, { status: found, headers: { ...headers, etag: row.etag } });
10541
+ return new Response(null, { status: found + ten * ten + mintOf(coins), headers: { ...headers, ...routeHeaders, etag: row.etag } });
10542
+ return new Response(row.body, { status: found, headers: { ...headers, ...routeHeaders, etag: row.etag } });
10287
10543
  };
10288
10544
  if (host !== unit.host || host.includes('*') || !unit.holds || !integrityOnceOf()) {
10289
10545
  return jsonOf(JSON.parse(dead), lost);
@@ -10291,12 +10547,20 @@ export default {
10291
10547
  const url = new URL(request.url);
10292
10548
  const raw = url.pathname.replace(/\/$/, '') || '/';
10293
10549
  const path = raw === '/index.html' ? '/' : raw;
10550
+ const route = qpuRouterOf(request.headers.get('referer') ?? '', path);
10551
+ routeHeaders = { 'x-qpu-seat': route.seat, 'x-qpu-door': route.door };
10294
10552
  const named = url.protocol === 'https:' && url.hostname === unit.host;
10295
10553
  if (!named)
10296
10554
  return jsonOf(JSON.parse(dead), lost);
10297
10555
  if (request.method === 'OPTIONS')
10298
10556
  return new Response(null, { status: found + coins + coins, headers });
10299
10557
  if (path === '/mcp') {
10558
+ // STREAMABLE HTTP, HONESTLY (measured 2026-09-12): this unit answers every JSON-RPC request in its POST and opens no
10559
+ // server-initiated stream, so a GET asking for text/event-stream gets the spec's other allowed answer — 405 with
10560
+ // Allow — and the client falls back to POST instead of parsing a JSON-LD catalog as an event stream.
10561
+ if (request.method === 'GET' && (request.headers.get('accept') ?? '').includes('text/event-stream')) {
10562
+ return new Response(null, { status: lost + seed, headers: { ...headers, allow: 'POST, OPTIONS' } });
10563
+ }
10300
10564
  if (request.method === 'POST') {
10301
10565
  let parsed;
10302
10566
  try {
@@ -10305,7 +10569,22 @@ export default {
10305
10569
  catch {
10306
10570
  return jsonOf(rpcErrorOf(null, rpcCodes.parse, 'Parse error: the body is not JSON'), badRequest);
10307
10571
  }
10308
- if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
10572
+ if (Array.isArray(parsed)) {
10573
+ // JSON-RPC BATCH. MCP 2025-03-26 allowed batches and 2025-06-18 removed them; a server advertising both accepts
10574
+ // them. Every member is re-dispatched through this same door, so a batch is exactly its members; a notification
10575
+ // (no id) gets no entry, per JSON-RPC 2.0; an empty array is the spec's Invalid Request.
10576
+ const members = parsed;
10577
+ if (members.length === n - n || !members.every((m) => m !== null && typeof m === 'object' && !Array.isArray(m)))
10578
+ return jsonOf(rpcErrorOf(null, rpcCodes.invalid, 'Invalid Request: a batch must be a non-empty array of request objects'), badRequest);
10579
+ const auth = request.headers.get('authorization');
10580
+ const replies = await Promise.all(members.map(async (m) => {
10581
+ const one = new Request(request.url, { method: 'POST', headers: { 'content-type': 'application/json', accept: 'application/json', ...(auth ? { authorization: auth } : {}) }, body: JSON.stringify(m) });
10582
+ const r = await worker.fetch(one, env);
10583
+ return m.id === undefined ? null : (await r.json());
10584
+ }));
10585
+ return jsonOf(replies.filter((r) => r !== null));
10586
+ }
10587
+ if (parsed === null || typeof parsed !== 'object') {
10309
10588
  return jsonOf(rpcErrorOf(null, rpcCodes.invalid, 'Invalid Request: expected one JSON-RPC 2.0 request object'), badRequest);
10310
10589
  }
10311
10590
  const body = parsed;
@@ -10357,6 +10636,19 @@ export default {
10357
10636
  return servedResponse(servedOf(`/${unit.path}`, () => qpuLeanOf()));
10358
10637
  if (path === '/cite')
10359
10638
  return servedResponse(servedOf('/cite', () => qpuCiteOf()));
10639
+ // DISCOVERY DOORS — extras off the seven-path guide (the README names extras as allowed). What an MCP client, a
10640
+ // registry, an OpenAPI consumer or a crawler asks for by convention, each derived from the readings above. Measured
10641
+ // 2026-09-12: all five answered 404 while the README promised install.json.
10642
+ if (path === '/.well-known/mcp.json')
10643
+ return servedResponse(servedOf(path, () => qpuWellKnownOf()));
10644
+ if (path === '/mcp.json')
10645
+ return servedResponse(servedOf(path, () => qpuMcpOf()));
10646
+ if (path === '/install.json')
10647
+ return servedResponse(servedOf(path, () => qpuInstallManifestOf()));
10648
+ if (path === '/openapi.json')
10649
+ return servedResponse(servedOf(path, () => qpuOpenApiOf()));
10650
+ if (path === '/sitemap.xml')
10651
+ return new Response(qpuSitemapOf(), { status: found, headers: { ...headers, 'content-type': 'application/xml; charset=utf-8' } });
10360
10652
  if (path === '/server' || path.startsWith('/server/')) {
10361
10653
  if (request.method === 'POST') {
10362
10654
  const body = (await request.json().catch(() => ({})));
@@ -10424,3 +10716,4 @@ export default {
10424
10716
  return jsonOf(JSON.parse(dead), lost);
10425
10717
  }
10426
10718
  };
10719
+ export default worker;
@@ -0,0 +1,69 @@
1
+ // publish — THE VERDICT A PUSH DESERVES, as a pure function. The network lives in scripts/post-push.mjs; the law
2
+ // lives here so the receipted suite can test it against crafted rows instead of a live forge.
3
+ //
4
+ // WHY THIS EXISTS (measured 2026-09-13). Publishing this unit was verified by hand with `gh run list --limit 1`,
5
+ // which is a WINDOW over the newest runs, not the runs of a commit. The run for the pushed commit did not exist
6
+ // yet, so the newest row belonged to the PREVIOUS push, it read `success`, and a deploy that had not happened was
7
+ // reported as verified — the live doors then answered with the old bytes. Asking by head sha is exact, and an
8
+ // absent run is UNMEASURED, never a pass. The sibling tree met this conflation four times before naming it; this
9
+ // is the same law carried across rather than invented a second time.
10
+ const PASSED = new Set(['success', 'neutral']);
11
+ const DID_NOT_JUDGE = new Set(['skipped', 'cancelled']);
12
+ /** pushVerdictOf(sha, runs) → what the forge says about THIS commit. Pure; the caller fetches the rows. */
13
+ export const pushVerdictOf = (sha, runs) => {
14
+ if (sha.length < 7)
15
+ throw new Error(`post-push: "${sha}" is too short to name a commit — seven hex characters is git's own floor`);
16
+ const onSha = runs.filter((r) => r.headSha === sha || r.headSha.startsWith(sha));
17
+ // ONLY A PUSH JUDGES A PUSH. A schedule or a manual dispatch can sit on the same commit and answer something else.
18
+ const mine = onSha.filter((r) => r.event === 'push');
19
+ const notThisPush = onSha.filter((r) => r.event !== 'push').map((r) => `${r.workflowName} (${r.event}: ${r.conclusion ?? r.status})`).sort();
20
+ const pending = mine.filter((r) => r.status !== 'completed').map((r) => r.workflowName).sort();
21
+ const done = mine.filter((r) => r.status === 'completed');
22
+ const failing = done.filter((r) => !PASSED.has(r.conclusion ?? '') && !DID_NOT_JUDGE.has(r.conclusion ?? ''))
23
+ .map((r) => `${r.workflowName} (${r.conclusion ?? 'no conclusion'})`).sort();
24
+ const didNotJudge = done.filter((r) => DID_NOT_JUDGE.has(r.conclusion ?? '')).map((r) => `${r.workflowName} (${r.conclusion})`).sort();
25
+ const passed = done.filter((r) => PASSED.has(r.conclusion ?? '')).map((r) => r.workflowName).sort();
26
+ // A VERDICT NEEDS A JUDGE: absence of failure over a set where nothing judged is not a pass.
27
+ const measured = passed.length > 0 || failing.length > 0;
28
+ const settled = mine.length > 0 && pending.length === 0;
29
+ const ok = settled && passed.length > 0 && failing.length === 0;
30
+ const short = sha.slice(0, 9);
31
+ const aside = (didNotJudge.length ? ` — and did NOT judge: ${didNotJudge.join(', ')}` : '')
32
+ + (notThisPush.length ? ` — and NOT this push: ${notThisPush.join(', ')}` : '');
33
+ const reason = pending.length
34
+ ? `still running for ${short}: ${pending.join(', ')}${aside}`
35
+ : failing.length
36
+ ? `FAILED for ${short}: ${failing.join(', ')}${aside}`
37
+ : !onSha.length
38
+ ? `UNMEASURED: the forge reports no run at all for ${short} — this is NOT a pass. It may not be queued yet; wait, never conclude.`
39
+ : !mine.length
40
+ ? `UNMEASURED: ${onSha.length} run(s) sit on ${short} and none was a push — ${notThisPush.join(', ')}. Another event answers another question.`
41
+ : !passed.length
42
+ ? `UNMEASURED: every run on ${short} declined to judge${aside}`
43
+ : `green for ${short}: ${passed.join(', ')}${aside}`;
44
+ return { sha, ok, settled, measured, passed, failing, pending, didNotJudge, notThisPush, reason };
45
+ };
46
+ /** value + predicate: a verdict may never be ok without a run that actually passed, and never ok while one fails. */
47
+ export const pushVerdictHolds = (v) => (!v.ok || (v.settled && v.passed.length > 0 && v.failing.length === 0)) &&
48
+ (!v.ok || v.measured) && v.reason.length > 0;
49
+ /** THE FORGE CANNOT ANSWER, versus THE FORGE ANSWERED "NOTHING". Asking for the runs of a commit the forge has not
50
+ * indexed returns 422 and the tool exits non-zero, so an arm that does not catch it DIES where the honest answer is
51
+ * UNMEASURED — and the seconds after a push are exactly when that happens. Only a refusal that names the commit may
52
+ * become an empty row set; a missing credential or an absent tool must stay loud, because reading those as "no runs"
53
+ * is the conflation this whole law refuses. A bare "Not Found" is NOT the pattern: `command not found` contains it. */
54
+ export const isUnknownCommit = (message) => /No commit found for SHA|\(HTTP (?:404|422)\)/i.test(String(message));
55
+ /** THE PUSH THAT REPORTED SUCCESS AND LANDED NOTHING. git can exit 0 while the remote branch sits elsewhere — a
56
+ * concurrent push, a protected ref, a retry that went to another branch. The forge is then asked about a commit
57
+ * the remote does not carry, and "no run yet" reads as patience when the truth is that nothing landed. The sibling
58
+ * tree compares the remote's head against the sha it pushed and refuses; the same guard belongs here. */
59
+ export const landedVerdictOf = (pushed, remoteHead) => {
60
+ if (pushed.length < 7)
61
+ throw new Error(`post-push: "${pushed}" is too short to name a commit — seven hex characters is git's own floor`);
62
+ const landed = remoteHead.trim() === pushed.trim();
63
+ return {
64
+ landed,
65
+ reason: landed
66
+ ? `origin carries ${pushed.slice(0, 9)}`
67
+ : `NOTHING LANDED: origin is ${remoteHead.trim().slice(0, 9) || 'unreadable'}, not ${pushed.slice(0, 9)} — the push reported success and the remote is elsewhere`,
68
+ };
69
+ };
@@ -1,2 +1,2 @@
1
1
  /** GENERATED by scripts/embed-lean.mjs from package.json. Do not edit; bump package.json and rerun `npm run lean:embed`. */
2
- export const packageVersion = "0.1.1";
2
+ export const packageVersion = "0.1.2";
package/install.json CHANGED
@@ -2,12 +2,81 @@
2
2
  "command": "npx uuidna-install",
3
3
  "yes": "npx uuidna-install --yes",
4
4
  "prompt": "Enter seats all. Type 1 3 saas — or all.",
5
- "packages": ["qpu-mcp", "payload-mcp", "vitepress-payload"],
6
- "occupancies": ["personal", "business", "corporate", "saas", "paas"],
5
+ "packages": [
6
+ "qpu-mcp",
7
+ "payload-mcp",
8
+ "vitepress-payload"
9
+ ],
10
+ "occupancies": [
11
+ "personal",
12
+ "business",
13
+ "corporate",
14
+ "saas",
15
+ "paas"
16
+ ],
7
17
  "cloudflare": {
8
18
  "button": "https://deploy.workers.cloudflare.com/button",
9
19
  "qpu": "https://deploy.workers.cloudflare.com/?url=https://github.com/uuidna/qpu",
10
20
  "uuidna": "https://deploy.workers.cloudflare.com/?url=https://github.com/uuidna/uuidna",
11
21
  "payload": "https://deploy.workers.cloudflare.com/?url=https://github.com/uuidna/uuidna-payload"
12
- }
22
+ },
23
+ "hardware": {
24
+ "kind": "boot",
25
+ "port": 8787,
26
+ "docker": "docker build -t qpu . && docker run --rm -p 8787:8787 qpu",
27
+ "multiarch": "docker buildx build --platform linux/arm64,linux/amd64 -t qpu .",
28
+ "pi": "Alpine aarch64: apk add nodejs npm && npm i -g @uuidna/qpu && qpu-boot",
29
+ "prove": "node dist/quantum/processing/unit/boot.js --prove",
30
+ "receipt": "the boot passes iff qpu_prove holds inside the machine; a boot that cannot prove itself does not serve",
31
+ "seat": {
32
+ "kind": "seat",
33
+ "device": "simulator",
34
+ "seat": "empty",
35
+ "reference": "the exact integer state-vector simulator; every reading above is computed there",
36
+ "doctrine": "a device that fills this seat and disagrees with the simulator is a driver bug, never a physics claim",
37
+ "acronym": "QPU here is a quantum processing unit. The VideoCore QPU (Quad Processing Unit, Broadcom; QPULib by Matthew Naylor, MIT, 2016) is prior use of the acronym — a classical 16-lane SIMD vector core — unrelated and credited.",
38
+ "occupant": "a classical SIMD accelerator computing the same exact amplitudes faster is an honest occupant; it does not make the seat quantum",
39
+ "priorArt": {
40
+ "kind": "prior-art",
41
+ "name": "QPULib",
42
+ "author": "Matthew Naylor",
43
+ "year": 2016,
44
+ "licence": "MIT",
45
+ "copyright": "Copyright (c) 2016 Matthew Naylor",
46
+ "repository": "https://github.com/mn416/QPULib",
47
+ "version": "0.1.0",
48
+ "status": "experimental, no longer under development — stated by its own README",
49
+ "acronym": "QPU there is Broadcom VideoCore Quad Processing Unit, a classical SIMD vector core, unrelated to this unit",
50
+ "hardware": {
51
+ "qpus": 12,
52
+ "megahertz": 250,
53
+ "lanes": 16,
54
+ "bits": 32,
55
+ "cyclesPerVector": 4
56
+ },
57
+ "modes": [
58
+ {
59
+ "name": "source language interpreter",
60
+ "runs": "any machine",
61
+ "purpose": "the kernel read at source level"
62
+ },
63
+ {
64
+ "name": "target language emulator",
65
+ "runs": "any machine",
66
+ "purpose": "the generated target program, for debugging"
67
+ },
68
+ {
69
+ "name": "physical QPUs",
70
+ "runs": "Raspberry Pi",
71
+ "purpose": "the device itself, chosen by passing QPU=1 to make"
72
+ }
73
+ ],
74
+ "equivalence": "AutoTest runs each test on both the interpreter and the emulator and checks they agree",
75
+ "inherited": "one kernel, several ways to run it, and a reference that decides which one is wrong",
76
+ "holds": true
77
+ },
78
+ "holds": true
79
+ }
80
+ },
81
+ "holds": true
13
82
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uuidna/qpu",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -35,7 +35,13 @@
35
35
  "exports": {
36
36
  ".": {
37
37
  "types": "./qpu.d.ts",
38
- "import": "./dist/quantum/processing/unit/index.js"
38
+ "import": "./dist/quantum/processing/unit/index.js",
39
+ "default": "./dist/quantum/processing/unit/index.js"
40
+ },
41
+ "./boot": {
42
+ "types": "./dist/quantum/processing/unit/boot.d.ts",
43
+ "import": "./dist/quantum/processing/unit/boot.js",
44
+ "default": "./dist/quantum/processing/unit/boot.js"
39
45
  }
40
46
  },
41
47
  "files": [
@@ -74,11 +80,16 @@
74
80
  "verify:live": "node scripts/verify-live.mjs https://qpu.uuidna.com",
75
81
  "test:live": "QPU_LIVE=https://qpu.uuidna.com node --test --test-reporter=spec dist/quantum/processing/unit/live.test.js",
76
82
  "proof": "git diff --exit-code -- test-receipt.json",
77
- "examine": "node scripts/examine.mjs https://qpu.uuidna.com"
83
+ "examine": "node scripts/examine.mjs https://qpu.uuidna.com",
84
+ "post-push": "node scripts/post-push.mjs",
85
+ "land": "npm test && git push && node scripts/post-push.mjs --wait && npm run verify:live"
78
86
  },
79
87
  "devDependencies": {
80
88
  "@types/node": "26.5.1",
81
89
  "typescript": "7.0.2",
82
90
  "wrangler": "4.131.0"
91
+ },
92
+ "bin": {
93
+ "qpu-boot": "./dist/quantum/processing/unit/boot.js"
83
94
  }
84
95
  }