From d9dc89c9339fe70b9954062d45999d10df75e51a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 13:37:40 +0000 Subject: [PATCH] docs: close the project, and correct what the docs got wrong Development has ended. The READMEs now say so, and record what worked and what did not, rather than leaving a green test badge to imply the first and hide the second. Why it ended, stated in the root README: two load-bearing premises failed while the engineering was succeeding. P3 -- the economics do not close; scripts/economics.py puts a realistic host at $2.256/1M tokens against a $0.150 commodity price, ~15x, with break-even utilisation unreachable. P2 -- the desk review found the NAT-traversal falsifier true as written, which relocates the whole claim onto cross-party pooling (P1), for which there was never any evidence. D7 never got its human reviewer. Discrepancies found by reading the code and fixed here: - packages/website/README.md called the project "a globally distributed, community-owned AI infrastructure" -- the thing D6 decided not to build and D2 priced out of existence. The site's own landing component had been corrected; this file had not. It also listed 5 of 9 pages, omitting dashboard, playground and status (the functional ones), and described the sibling packages as separate repositories a year after the migration. - packages/node/README.md claimed the Ollama proxy was "the only backend runtime.py assigns". It is not a runtime.py backend at all. runtime.py:282 assigns EchoBackend and nothing else, ever; OllamaBackend is never constructed outside a test; nothing in src ever enqueues onto task_queue. The live path is api/inference.py -> clients/ollama.py, a different class. So Runtime._worker_loop -> InferenceBackend -> ArtifactStore is dead code kept alive by a test named test_end_to_end_pipeline that feeds the queue by hand. Recorded in the node README and in ROADMAP's closure header. - The "155-word vocabulary" figure for LocalBoundaryEngine was wrong and had propagated to five files: ROADMAP.md, CLAUDE.md, experimental/README.md, .claude/rules/node.md and the root README. The list holds 116 words plus 4 special tokens, against a declared vocab_size of 32000. Counted, not recalled. CLAUDE.md warns that prose cannot notice when it goes stale; this number was never in scope of the mechanism built to act on that warning. - The v1.0.1 tag names a tree that declares itself 1.0.0 in all four packages. test_every_package_declares_the_same_version compares the four to each other and never to the tag, so V3's fix converged them on the previous version and the ratchet passed. Left as found and documented: bumping now would produce a tree claiming to be v1.0.1 that is not the released v1.0.1. - "Python 3.11-3.14" in ROADMAP implied four interpreters; ci.yml names three (3.11, 3.12, 3.14). 3.13 is not in the matrix. STATUS.md regenerated with the script, not by hand: 906 passed, 1 skipped across the three suites. It still reads CI UNVERIFIABLE because there is no gh CLI here; the root README explains that and cites run #33 on main at e5d1e7c, read through the API, which concluded success. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01PgHmwMuw5ivVZTCdiUaEmN --- .claude/rules/node.md | 2 +- CLAUDE.md | 3 +- README.md | 423 ++++++++++++++++++++++------------- ROADMAP.md | 37 ++- STATUS.md | 32 ++- experimental/README.md | 7 +- packages/node/README.md | 52 ++++- packages/scheduler/README.md | 37 +-- packages/shared/README.md | 3 + packages/website/README.md | 77 ++++--- 10 files changed, 447 insertions(+), 226 deletions(-) diff --git a/.claude/rules/node.md b/.claude/rules/node.md index 34fc5d9..99bcf04 100644 --- a/.claude/rules/node.md +++ b/.claude/rules/node.md @@ -13,7 +13,7 @@ inference. - **The distributed inference path is not implemented.** `runtime.py` never assigns `self.inference_backend` anything but `EchoBackend`. The working path is the non-split one that proxies to Ollama. Do not describe split inference as working, - and do not wire `LocalBoundaryEngine` into anything — it is a 155-word vocabulary + and do not wire `LocalBoundaryEngine` into anything — it is a 120-token vocabulary over seeded random matrices. - **Hardware figures are measured, never assumed.** Registration once hardcoded 16 GB of VRAM for every node, so matchmaking filtered against fiction. Every probe diff --git a/CLAUDE.md b/CLAUDE.md index 9943fdc..3a4e60b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -112,7 +112,8 @@ lower its budget so the ratchet holds. **The distributed inference path is not implemented.** `packages/node/src/node/runtime.py` never assigns `self.inference_backend` anything but `EchoBackend`. `LocalBoundaryEngine` -uses a 155-word vocabulary and seeded random matrices. The working inference path is +uses a 120-token vocabulary (116 words plus 4 special tokens) and seeded random +matrices. The working inference path is the non-split one that proxies to Ollama. Don't describe split inference as working. **`VERIFY.md` step 3's known-issues table is EMPTY, and the greps still return diff --git a/README.md b/README.md index f9f821c..885412e 100644 --- a/README.md +++ b/README.md @@ -1,156 +1,246 @@ # Public Intelligence -**An OpenAI-compatible control plane for hardware you already own.** - -Point it at machines you or people you trust control — a workstation with a GPU, a -lab's spare box, three laptops in a research group — and it gives you one -authenticated `/v1/chat/completions` endpoint that routes across all of them. Nodes -dial *out* to the coordinator and answer over that connection, so a node behind NAT -needs no inbound port forwarding of its own — the coordinator is the one machine that -has to be reachable. How well that traverses a *real* NAT boundary is still unproven; -see "What is actually true" below. - -It is not a marketplace and there is no network to join. You run both halves — it is -**self-hosted infrastructure for hardware you own**, not a service. See -[`docs/decisions/D8-the-wedge.md`](docs/decisions/D8-the-wedge.md) for why that is the -product, and [D2](docs/decisions/D2-economics.md) for the arithmetic that ruled out -the alternative. - -**This is the v1.0.1 feature-complete milestone — not a maturity claim.** It means the -v1 scope is built and the gate is green on every supported platform, not that anyone -has run this in anger. Read "What is actually true" before relying on anything here. - -## What is actually true, as of 2026-08-17 - -Verified, not aspirational. `STATUS.md` is generated from real test runs; this -section summarises it in prose. - -**Works:** a node registers with the Scheduler, heartbeats over an authenticated -Zenoh mesh, advertises the models Ollama actually has, and survives the Scheduler -being unreachable. The Scheduler matchmakes, dispatches over the mesh (which is how -a node behind NAT is reachable at all), and exposes an OpenAI-shaped gateway behind -RS256 JWT auth. State can persist across restarts. - -CI runs the gate on Linux, macOS and Windows across Python 3.11–3.14 — ten jobs — and -as of `25fe60c` all ten pass. Worth stating plainly rather than as a badge: **they did -not, from 2026-08-09 to 2026-08-17.** The three Windows legs were red for eight days, -across the `v1.0.0` release commit, and nothing in this repository noticed. See -"What we cannot see" below, because that gap is more instructive than the bug was. - -**If `STATUS.md` and the paragraph above disagree, they are both right.** That claim -comes from reading the run directly; `STATUS.md` reports `UNVERIFIABLE` whenever it is -generated on a machine without the `gh` CLI, because that is the only way it knows how -to ask. Regenerate it where `gh` is installed and authenticated and the line resolves. - -**Does not work, and is not claimed to:** - -- **No node has served a request across a real NAT boundary.** On 2026-08-11 a node on - a *second physical machine* registered and served a real request over the mesh — but - both machines were on one LAN, so no NAT was crossed (`ROADMAP.md`, 1.5). A later - attempt to test across a real NAT was blocked by the coordinator sitting on a managed - network with no inbound reachability. The path is architecturally correct for NAT - (nodes dial out) and works on a LAN; it is **unproven on genuinely separate - networks**. This is the most load-bearing unproven claim in the project — see - [`docs/PREMISES.md`](docs/PREMISES.md), P2. -- **Split inference, layer sharding, FP8 compression, speculative decoding and - KV-cache checkpointing are not implemented.** They are cut from v1. The gateway - answers **501** if you ask for split inference. It used to answer 200 with invented - text; that was removed on 2026-08-07. -- **Credits are an accounting unit, not a currency.** They are not redeemable and - there is no payout path — not "not yet", but a decision +**Archived on 2026-08-21. Development has ended. This repository is a record, not a +product.** + +It was an OpenAI-compatible control plane for hardware you already own: point it at +machines you or people you trust control, and get one authenticated +`/v1/chat/completions` endpoint that routes across all of them. Nodes dial *out* to a +coordinator and answer over that connection, so a node behind NAT needs no inbound port +forwarding. + +The code works, within the limits set out below. Nobody ever used it. Both of those are +findings, and this file exists to state them plainly rather than leave a green test +badge to imply the first and hide the second. + +Nothing here is maintained. There is no support, no roadmap, and no security response — +`SECURITY.md` describes a process that is no longer staffed. If you run this, you own +it. + +--- + +## Why it ended + +Not because it broke. Because the question underneath it was answered, and the answer +was no. + +The project rested on a register of stated, falsifiable premises +([`docs/PREMISES.md`](docs/PREMISES.md)). Two of the load-bearing ones failed while the +engineering was succeeding: + +- **P3 — the economics do not close.** `scripts/economics.py`, tested by + `tests/test_economics.py`, puts a realistic host at **~$2.26 per 1M tokens against a + ~$0.15 commodity price** — roughly 15×. The conclusion survives doubling every power + and throughput input and tripling utilisation. That killed the marketplace, and with + it the reason a stranger would contribute hardware ([D2](docs/decisions/D2-economics.md)). -- **There is no content filtering, no meaningful rate limiting, and no backups**, and - nothing verifies that a node ran the model it claims. The rate limiter is a - per-instance abuse dampener, not a quota. Canary checks catch a host running *no* - model; they cannot catch a host running the *wrong* one. - [`docs/OPERATING.md`](docs/OPERATING.md) lists what you take on by running this. -- **`/v1/batch` is not implemented** — it answers 501. It is authenticated and - tenant-scoped, because those were real fixes to a real hole, but it dispatches - nothing. -- **JWTs cannot be revoked.** They are stateless by design; the mitigations are a - server-enforced TTL cap and key rotation. There is no revoke button and this is - said plainly rather than implied away. -- **Nodes installed before [D9](docs/decisions/D9-admission-is-not-identity.md) keep - the old weakness** — one header meaning both fleet admission and node identity — - until they are upgraded. That is a deliberate compatibility choice, not an - oversight: refusing them would strand every running host. - -## What we cannot see - -Distinct from the list above, which is what does not *work*. This is what this -project's own verification **cannot observe** — the gaps where a defect would not be -caught by anything here. It is written down because -[`docs/PREMISES.md`](docs/PREMISES.md) P8 records that every falsification of "the -gate is the definition of does this pass" has arrived by **absence rather than -failure**, and an unlisted absence is indistinguishable from an all-clear. - -- **`install.ps1` has never been executed, by anything, ever.** `install.sh` gets a - real run against a throwaway tree (`scripts/verify_install.sh`); the PowerShell - installer is only ever *read* — `scripts/audit_system.py` greps it for strings and - `tests/test_installer_parity.py` ratchets its structure. Every Windows install - defect to date (W1–W5, W8) was therefore found by a person on a real machine, not - by the gate. Assume the next one will be too. -- **The repository cannot read its own CI.** `scripts/generate_status.py` shells out - to `gh`; where `gh` is absent it reports `UNVERIFIABLE — cannot query run history`. - That is honest, and it reads like "no known problem". It is the mechanism by which - a red build sat under a published release for eight days. **The fix is known and - not yet made:** fall back to the GitHub REST API so the answer does not depend on - which machine regenerated the file. -- **Work on a branch is unverified until it becomes a pull request.** The workflow - triggers only on `push` to `main` and on PRs, so a feature branch gets no CI at all. -- **The local gate is one operating system and one interpreter.** CI is nine legs; a - developer's run is one. Platform-specific defects are structurally invisible - locally, and there have now been three: a cp1252 text encoding (2.9), CRLF line - endings (V1), and wall-clock resolution (V2). A local `PASS` is a weaker claim than - a CI `PASS` and the gate says so in its own output. -- **The gate skips checks it cannot run**, naming them as `DID NOT RUN`: a missing - interpreter, `shellcheck` if absent, the website suite without `node_modules`. The - honesty is real; the coverage still is not there. -- **`docker-compose.test.yml` has never run.** Two defects were found in it by - reading (`tests/test_compose_env_matches_settings.py`) rather than by executing it. -- **Four module pairs in `experimental/` remain duplicated** — `quantization`, - `local_boundary`, `kv_cache`, `transport`. Drift is ratcheted, not eliminated. -- **No human outside this project has reviewed any of it.** Two independent AI desk - reviews of the market premises are in [`docs/review/`](docs/review/) and they - converged, which is evidence but not independence. - -## What this project has decided, and what it hasn't - -The eight product questions this code had been assuming answers to are answered in -[`docs/decisions/`](docs/decisions/README.md). The short version: invite-only trusted -hosts, no marketplace, no operated network, one coordinator, and a self-hosted pitch. - -**One question is still open and cannot be closed from inside:** -[D7](docs/decisions/D7-second-pair-of-eyes.md) asks for a second pair of eyes. Every -judgement here has been made by one party, and the verification process — strong as it -is — is structurally incapable of catching a wrong premise. The assumptions are laid -out in [`docs/PREMISES.md`](docs/PREMISES.md) specifically so they can be attacked. -**If you disagree with one, that is the contribution.** - -A first external pass — two independent AI desk reviews of the market premises — is -recorded in [`docs/review/`](docs/review/). It found the demand for *cross-party -pooling* unevidenced and the *remote-access* problem already well solved by Tailscale, -which is why the honest framing of this project is self-hosted infrastructure for your -own trusted hardware, not a network to join. That is still not the human second -opinion D7 asks for. - -## Host a node - -One command fetches the project, installs it, and leaves a **running** node: +- **P2 — NAT traversal is not a differentiator.** An external desk review + ([`docs/review/desk-review-2026-08-14.md`](docs/review/desk-review-2026-08-14.md)) + found the falsifier true as written: single-user remote access to a home GPU is a + solved, SEO-saturated problem, and Tailscale is the free answer. What survives is + *cross-party pooling*, which Tailscale is single-tenant-shaped and does not do — but + that relocates the whole load onto P1 (*someone wants to serve inference from hardware + they own, across parties*), for which there is **no evidence at all**, only assumption. -```bash -curl -fsSL https://raw.githubusercontent.com/Epichlo/Public-Intelligence/main/scripts/bootstrap.sh \ - | bash -s -- --scheduler-url https://your-scheduler --fleet-token TOKEN --invite-code CODE -``` +So the remaining pitch was: a thing that costs 15× the alternative, solving a problem +that is already solved for the single-machine case, for a multi-party demand nobody had +demonstrated. The correct response to that is to stop, and write down why, which is what +this is. + +The one question that could have changed the answer — +[D7](docs/decisions/D7-second-pair-of-eyes.md), *a second pair of eyes* — never got a +human reviewer. Every judgement in this repository, including this one, was made by a +single party. That is itself part of what went wrong. + +--- + +## What worked + +Evidence, not recollection. Test counts below were produced by running the suites in the +session that wrote this file; the CI result was read from the GitHub API, not inferred. + +**The core loop runs.** A node registers with the Scheduler, heartbeats over an +authenticated Zenoh mesh, advertises the models Ollama actually has (measured hardware, +never a hardcoded guess), and survives the Scheduler being unreachable. The Scheduler +matchmakes, dispatches over the mesh, meters usage, and serves an OpenAI-shaped gateway +behind RS256 JWT auth. On 2026-08-11 a node on a **second physical machine** registered, +held a mesh session, and served a real completion dispatched over that mesh. + +**The tests pass, and they were run here.** + +| Suite | Result | +|---|---| +| `packages/scheduler/tests` | 397 passed | +| `packages/node/tests` | 260 passed, 1 skipped | +| `tests` (cross-package) | 249 passed | +| **Total** | **906 passed, 1 skipped** | + +**CI is green.** Run **#33** on `main` at `e5d1e7c` completed **success**. The matrix is +3 operating systems × Python 3.11, 3.12 and 3.14, plus a fresh-clone job — 10 jobs. + +*`STATUS.md` says CI is `UNVERIFIABLE`, and both are right.* That file asks the `gh` +CLI, and reports `UNVERIFIABLE` wherever `gh` is absent — which is the honest word for +"I did not look", and is also the word that reads like "probably fine". The run above +was read straight from the GitHub API instead. That gap is listed under what failed +below; it is the mechanism by which a red build sat under a published release for eight +days, and it was never fixed. + +**Persistence does what it says.** SQLite backs the registry, node credentials, the +credit ledger, the usage meter and invites. Observations — heartbeats, telemetry, mesh +reachability — are deliberately *not* restored, because reviving them would make dispatch +prefer a Zenoh session that died with the process. Persist facts, not observations. + +**Real security holes were found and closed**, most of them by moving cut features out of +live paths rather than by a scanner: + +- Streamed completions were being republished onto the shared mesh **in plaintext**, on a + key any peer could subscribe to with a `**` wildcard — while a whole protocol change had + been spent AES-encrypting *telemetry* on that same mesh. +- The same router deadlocked after four chunks, because nothing in the repository has ever + sent an ACK. Streaming was broken on precisely the deployment this was built for. +- Every Scheduler boot started an **unauthenticated Raft consensus plane** on a wildcard + key. A crafted `AppendEntries` could evict any host or inject one — and an injected node + receives other people's prompts. +- Every node opened an unauthenticated wildcard subscriber that deserialised + attacker-controlled bytes and, for a `shm://` payload, unlinked host shared memory by + attacker-supplied name. +- One header carried two meanings, so every node's "per-node" credential was the fleet + secret ([D9](docs/decisions/D9-admission-is-not-identity.md)). + +**Fabricated output was removed rather than hidden.** The gateway used to answer +`x-split-inference: true` with **HTTP 200** and text from a toy engine — asking it for the +capital of France returned `token_556`, which every OpenAI-compatible client renders as +the model's answer. It now answers **501**, and the ~250-line execution block was deleted +rather than left behind a flag, because dead code behind a disabled flag is how it shipped +in the first place. `/v1/batch` likewise answers 501 instead of pretending to queue. -Everything after `bash -s --` is forwarded to `install.sh` (`install.sh --help` lists the -flags). It clones into `~/public-intelligence` (override with `PI_DIR`), starts the -daemon, and re-running it updates in place. Prefer to read what runs first? Clone the -repo and run `./install.sh --start` yourself — the two paths are identical. Manage the -daemon with `./scripts/launch_host_node.sh {status,logs,stop}`. +**The verification layer is the part worth keeping.** One gate (`scripts/verify.sh`) is +the only definition of "does this pass", and CI invokes that file and nothing else — with +a test that fails if CI ever grows a second list. Around it: ratchets on source parity, +route inventory (an unguarded route fails the build), line endings read from the git +index, environment-variable binding, version parity, and the experimental quarantine +boundary. Agent-written claims go to `zones/claimed/`; only the gate writes +`zones/verified/`, because writing it requires having run the checks. -You need Ollama running with at least one model pulled; and, against a Scheduler that -sets them, a fleet token and an invite code from its operator. +**Decisions were written down with their costs.** [`docs/decisions/`](docs/decisions/README.md) +(D1–D9) records what was chosen, what it cost, and what changed in the code. When a +premise was falsified, the roadmap changed rather than the story. + +--- + +## What failed + +**The differentiator was never proven.** No request has ever been served across a real +NAT boundary. The 2026-08-11 two-machine test put both machines on adjacent private +subnets of one network — no NAT was crossed. [D8](docs/decisions/D8-the-wedge.md) makes +traversal *the* product, so the single most load-bearing claim in the project stayed +unearned for its entire life. A phone hotspot would have tested it. That test was never +run. + +**Split inference never existed.** `LocalBoundaryEngine` is a **120-token vocabulary — +116 words plus 4 special tokens — against a declared `vocab_size` of 32,000, with two +seeded `random.gauss` matrices**; its "speculative candidates" are +`(prev * 7 + 13) % vocab_size`. It produces plausible-looking tensors and no inference +happens. For weeks it was wired to the live gateway and its output was served as a +successful completion. The distance from it to real sharding is a rewrite, not a fix. + +**An entire node execution path is dead code, and the tests conceal it.** +`Runtime._worker_loop` consumes a `task_queue`, runs an `InferenceBackend`, saves to an +`ArtifactStore` and reports over Zenoh. **Nothing in `src` ever enqueues a task** — only +tests do. `self.inference_backend` is only ever assigned `EchoBackend` +(`packages/node/src/node/runtime.py:282`), and `OllamaBackend` is never constructed +outside a test file. The real serving path is the FastAPI route +`packages/node/src/node/api/inference.py`, which uses a *different* class +(`clients/ollama.py`). So the backend abstraction has one implementation, zero production +callers, and a test named `test_end_to_end_pipeline` that feeds the queue by hand — an +end-to-end test of a path production never takes. + +**The gate's failures arrived by absence, never by a red test.** Every falsification of +"the gate is the definition of does this pass" was something the gate did not look at: +`tests/` were not linted, then the website, then `scripts/`, then `.claude/`, then +`install.ps1`. + +- **`install.ps1` has never been executed, by anything, ever.** `install.sh` gets a real + run against a throwaway tree; the PowerShell installer is only ever *read*. Every + Windows install defect to date (W1–W5, W8) was therefore found by a person on a real + machine. One of them reported *"Installation Complete! Host Node is Ready"* over a + failed install and exited 0 — the third time this repository shipped that defect, in a + third language. +- **`docker-compose.test.yml` has never run.** Two defects were found in it by reading. +- **The repository could not read its own CI.** `STATUS.md` shells out to `gh` and reports + `UNVERIFIABLE` where it is absent — which is honest, and reads like "probably fine". It + is the mechanism by which **CI was red on `main` for eight days, across the `v1.0.0` + release commit**, and nothing noticed. Confirmed from the API: runs #26–#29 all failed; + the last green before them was #25 on 2026-08-07. +- **A branch gets no CI at all** — the workflow triggers only on `push` to `main` and on + PRs. +- **A local gate is one OS and one interpreter** against CI's nine. Three defects were + structurally invisible locally: a cp1252 encoding, CRLF line endings, and wall-clock + resolution. Python **3.13 is not in the matrix**, despite "3.11–3.14" reading as a + contiguous range. + +**A ratchet that cannot see the thing it names is worse than no ratchet.** Two happened +here: + +- `test_compose_env_matches_settings.py` claimed in its own docstring that it "would have + caught" the `NODE_ID` / `NODE_NODE_ID` bug. Its helper blessed the broken variable. The + file was fixed by hand and the test took the credit. +- **The `v1.0.1` tag names a tree that declares itself `1.0.0`.** All four packages agree + with each other at `25fe60c`, so `test_every_package_declares_the_same_version` passes — + it only compares the packages to *each other*, never to the tag that names them. V3's + own stated principle was "a tag names one tree"; the fix converged the four packages on + the *previous* version and stopped there. Left as found: bumping it now would produce a + tree claiming to be `v1.0.1` that is not the released `v1.0.1`, which is the same + confusion wearing a different hat. + +**A number nobody checked propagated across five documents.** Every doc in this +repository described `LocalBoundaryEngine` as having a "155-word vocabulary" — +`ROADMAP.md`, `CLAUDE.md`, `experimental/README.md`, `.claude/rules/node.md`, and the +first draft of this file. The actual list holds **116 words plus 4 special tokens**, +against a declared `vocab_size` of 32,000. Counted at closure, in one command. The +figure was wrong from its first use and was copied outward four times, including into +the rules file that governs how agents work here. `CLAUDE.md` warns in its own words +that "prose cannot notice when it goes stale" and moves measurements into a generated +`STATUS.md` for exactly this reason; this number was never in scope of that mechanism, +so nothing measured it. It is corrected everywhere as of this commit. + +**The rest of what is missing, stated without softening.** No content filtering. No +meaningful rate limiting — what exists is a per-instance abuse dampener, not a quota. No +backups. No way to revoke a JWT; they are stateless by design, and the mitigations are a +TTL cap and key rotation. Nothing verifies a node ran the model it *claims* — canaries +catch a host running no model, not one running the wrong one. Credits are an accounting +unit with no payout path, by decision. Nodes installed before D9 keep the old +credential weakness until upgraded, deliberately, so that no running host is stranded. +Four module pairs in `experimental/` remain duplicated, with drift ratcheted rather than +eliminated. + +**And there was never a fleet.** No hosts, no traffic, no users. `docs/PREMISES.md` puts +it exactly right: *"Nobody has metered a real node in this fleet, because there is no +fleet."* Every green test exercised this system talking to itself. + +--- + +## What we would tell someone starting this + +1. **Test the load-bearing claim first, with the cheapest possible experiment.** The NAT + crossing was the entire product and it needed a phone hotspot and an afternoon. It was + never done, across four months, while 906 tests were written around it. +2. **Do the arithmetic before the architecture.** `scripts/economics.py` is about a + hundred lines. Run at the start, it would have redirected the project. Run at month + three, it ended it. +3. **A test suite measures regression, never premise.** A ratchet asks "did this get + worse"; a test asks "does it still do what I said". Neither can ask "should this exist + at all". 906 passing tests said nothing about whether anyone wanted this. +4. **Absence is the failure mode, not failure.** Everything that went wrong here was + outside what the gate looked at. When adding a check, the useful question is not "does + this pass" but "what is still unwatched". +5. **Never let unfinished plumbing touch a live path.** Every serious security defect in + this repository came from cut-feature code left wired in. A disabled flag is not a + boundary; a different directory with an enforced import ban is. +6. **Get the second pair of eyes early.** D7 was open from the start and stayed open. A + process that is rigorous and self-contained is still self-contained. + +--- ## Repository layout @@ -158,28 +248,47 @@ sets them, a fleet token and an invite code from its operator. |---|---| | `packages/scheduler/` | FastAPI control plane: registry, matchmaking, OpenAI gateway, Zenoh router | | `packages/node/` | FastAPI host agent: local control API, telemetry, Ollama-backed inference | -| `packages/website/` | Next.js dashboard and playground | +| `packages/website/` | Next.js dashboard, playground, and public pages | +| `packages/shared/` | The modules both services must agree on byte for byte (`pi_shared`) | +| `experimental/` | Quarantined cut features. **Nothing here is part of the shipped system.** | | `specs/` | One document per change: what it does, why, and what is out of scope | -| `docs/decisions/` | The product decisions, and what each one costs | +| `docs/decisions/` | The product decisions (D1–D9), and what each one costs | +| `docs/PREMISES.md` | Every load-bearing assumption, with its falsifier | | `docs/historical/` | Superseded design documents. **They describe intentions as if built.** | +| `zones/` | `claimed/` is what an agent believed; `verified/` is what the gate measured | -## Developing it +## Running it anyway -One venv for everything: +The code still runs. One venv for everything: ```bash python3 -m venv .venv .venv/bin/python -m pip install -e packages/shared \ -e "packages/node[dev]" -e "packages/scheduler[dev]" -./scripts/install-hooks.sh ./scripts/verify.sh # the single gate: lint, types, tests, security, installer ``` -`scripts/verify.sh` is the only definition of "does this pass"; CI runs that file -and nothing else. See `CONTRIBUTING.md` for how to work here and `VERIFY.md` for what -a completion claim has to be backed by. +The three suites must be invoked separately — a single `pytest` across all of them fails +on a conftest path collision: + +```bash +.venv/bin/python -m pytest packages/scheduler/tests -q +.venv/bin/python -m pytest packages/node/tests -q +.venv/bin/python -m pytest tests -q +``` + +Hosting a node needs Ollama running with at least one model pulled, and — against a +Scheduler that sets them — a fleet token and an invite code: + +```bash +./install.sh --start # or scripts/bootstrap.sh for the one-line path +``` + +`STATUS.md` is generated by `python3 scripts/generate_status.py` and should never be +edited by hand. ## Licence -[Apache-2.0](LICENSE). Patent grant included; warranty disclaimed. Security reports go -through [`SECURITY.md`](SECURITY.md), not the issue tracker. +[Apache-2.0](LICENSE). Patent grant included; warranty disclaimed. The project is +archived and unmaintained: there is no security response process, and issues and pull +requests are not being monitored. diff --git a/ROADMAP.md b/ROADMAP.md index 15be180..54fdff8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,7 +1,39 @@ # ROADMAP — v1 +> ## CLOSED — 2026-08-21 +> +> **The project is archived and this roadmap is no longer a plan.** It is kept as the +> record of what was built and in what order. Nothing below will be worked on. +> +> It ended because two load-bearing premises failed while the engineering was +> succeeding: the economics do not close (~15× against commodity pricing, +> [D2](docs/decisions/D2-economics.md)), and NAT traversal turned out not to be a +> differentiator for the single-machine case that is actually solved — relocating the +> whole claim onto cross-party pooling, for which there was never any evidence +> (`docs/PREMISES.md` P1/P2). 1.5 and D7 below stayed open to the end, and 1.5 was the +> product. See the root [`README.md`](README.md) for the full account. +> +> **Two findings recorded at closure, both from reading the code rather than a failing +> test:** +> +> - **The `v1.0.1` tag names a tree that declares itself `1.0.0`.** All four packages +> agree with each other at `25fe60c`, so `test_every_package_declares_the_same_version` +> passes — it compares the packages to *each other*, never to the tag. V3 below fixed +> "the release shipped two version numbers" by converging them on the *previous* one. +> Deliberately not bumped now: a tree claiming `v1.0.1` that is not the released +> `v1.0.1` is the same confusion in a different hat. +> - **A whole node execution path is dead code.** `Runtime._worker_loop` → +> `InferenceBackend` → `ArtifactStore` is never fed: nothing in `src` enqueues onto +> `task_queue`, `inference_backend` is only ever `EchoBackend` +> (`packages/node/src/node/runtime.py:282`), and `OllamaBackend` is never constructed +> outside a test. The live path is `api/inference.py` → `clients/ollama.py`, a +> different class. `test_end_to_end_pipeline` feeds the queue by hand — an end-to-end +> test of a path production never takes. + Status: **Stages 0–4, C and D are complete. Released as `v1.0.1` on 2026-08-17, with -CI green on all ten jobs (Linux/macOS/Windows × Python 3.11–3.14) at `25fe60c`. +CI green on all ten jobs (Linux/macOS/Windows × Python 3.11, 3.12 and 3.14, plus a +fresh-clone job) at `25fe60c` — 3.13 is not in the matrix, and the range notation used +here previously implied four interpreters where `.github/workflows/ci.yml` names three. 1.5 is half earned — a second machine served a real request over the mesh on 2026-08-11, but not across a real NAT. D7 is open. W1–W10 are done; W7 is done in code and unexercised on real hardware. V1–V3 closed the Windows CI failure that had @@ -152,7 +184,8 @@ cutting it means this isn't v1. I concluded it is not, for four reasons: expands the catalogue; it is not what makes the exchange work. 2. **What exists today is a simulation, not an implementation.** `LocalBoundaryEngine` - is a 155-word vocabulary and two seeded `random.gauss` matrices; "speculative + is a 120-token vocabulary (116 words plus 4 special tokens, against a declared + `vocab_size` of 32,000) and two seeded `random.gauss` matrices; "speculative candidates" are `(prev * 7 + 13) % vocab_size`. Real sharding needs real weights, real tensor ops, and a real runtime. The distance from here to there is a rewrite, not a fix. Betting v1 on it means v1 does not ship. diff --git a/STATUS.md b/STATUS.md index d01385a..9266b7c 100644 --- a/STATUS.md +++ b/STATUS.md @@ -4,16 +4,16 @@ -**Generated:** 2026-08-17 05:19 UTC +**Generated:** 2026-08-21 13:36 UTC **Test status:** PASSING ## Tests | Suite | Status | Passed | Failed | Skipped | Time | | --- | --- | --- | --- | --- | --- | -| Scheduler | PASS | 397 | 0 | 0 | 13.39s | -| Node | PASS | 260 | 0 | 1 | 3.85s | -| Root E2E | PASS | 249 | 0 | 0 | 28.35s | +| Scheduler | PASS | 397 | 0 | 0 | 11.51s | +| Node | PASS | 260 | 0 | 1 | 3.10s | +| Root E2E | PASS | 249 | 0 | 0 | 26.90s | | **Total** | **PASSING** | **906** | **0** | **1** | | Reproduce: @@ -26,12 +26,24 @@ Reproduce: ## Git -- **Last commit:** `214bcb8` docs: record the real state, including what we cannot see -- **Author / date:** Claude — 2026-08-17 05:18:43 +0000 -- **Branch:** claude/v1-wrap-up-checklist-6uadua -- **Total commits:** 52 +- **Last commit:** `e5d1e7c` docs: record the real state, including what we cannot see (#2) +- **Author / date:** attu308 — 2026-08-17 11:35:15 +0530 +- **Branch:** claude/project-closure-readme-4iwry3 +- **Total commits:** 53 - **Remote:** origin https://github.com/Epichlo/Public-Intelligence (fetch) -- **Working tree:** clean +- **Working tree:** 9 uncommitted change(s) + +``` + M .claude/rules/node.md + M CLAUDE.md + M README.md + M ROADMAP.md + M experimental/README.md + M packages/node/README.md + M packages/scheduler/README.md + M packages/shared/README.md + M packages/website/README.md +``` ## CI @@ -47,7 +59,7 @@ _Measured, not asserted. Re-run to refresh._ | Repo | Remote | Branch | Tracking | | --- | --- | --- | --- | -| root | `https://github.com/Epichlo/Public-Intelligence` | claude/v1-wrap-up-checklist-6uadua | origin/claude/v1-wrap-up-checklist-6uadua | +| root | `https://github.com/Epichlo/Public-Intelligence` | claude/project-closure-readme-4iwry3 | **none** | - **`.gitmodules`:** absent, which is correct — `packages/` are ordinary directories since the 2026-08-04 monorepo migration, and CI's fresh-clone job asserts this file does not come back. - **root venv interpreter:** Python 3.11.15 diff --git a/experimental/README.md b/experimental/README.md index cb15776..f9c89e8 100644 --- a/experimental/README.md +++ b/experimental/README.md @@ -71,7 +71,7 @@ while an unimportable quarantined test still fails the gate. | Module | Feature | Lines | |---|---|---| | `transport.py` | Shared-memory IPC, backpressured tensor streaming | 541 × 2 | -| `local_boundary.py` | Embedding/unembedding across a split boundary — a 155-word vocabulary and seeded `random.gauss` matrices, **not a model** | 378 × 2 | +| `local_boundary.py` | Embedding/unembedding across a split boundary — a 120-token vocabulary (116 words + 4 special) against a declared `vocab_size` of 32,000, and seeded `random.gauss` matrices, **not a model** | 378 × 2 | | `boundary_engine.py` | Re-export shim for the above | 5 × 2 | | `kv_cache.py` | KV-cache checkpointing and restitching | ~98 × 2 | | `quantization.py` | FP8/FP4 activation compression | 49 × 2 | @@ -122,8 +122,9 @@ of that returns. ## If you are reading this because you want to build on it -Don't, yet. `LocalBoundaryEngine` in particular is a simulation: a 155-word -vocabulary and two seeded random matrices. It produces plausible-looking tensors and +Don't, yet. `LocalBoundaryEngine` in particular is a simulation: a 120-token +vocabulary — 116 words plus 4 special tokens, against a declared `vocab_size` of +32,000 — and two seeded random matrices. It produces plausible-looking tensors and no inference happens. Returning its output to a caller as a completion is precisely the bug ROADMAP N1 removed, where `token_556` was served as the capital of France with HTTP 200. diff --git a/packages/node/README.md b/packages/node/README.md index 4df5add..633dde8 100644 --- a/packages/node/README.md +++ b/packages/node/README.md @@ -1,5 +1,8 @@ # Public Intelligence Node +**Archived on 2026-08-21 along with the rest of the project. See the root +[`README.md`](../../README.md) for what worked, what failed, and why it stopped.** + A Public Intelligence Node is a compute worker that registers with the Scheduler, advertises the models Ollama actually has, executes inference locally, and holds an authenticated Zenoh mesh session so it is reachable even from behind NAT — it dials @@ -9,8 +12,25 @@ Part of the **`public-intelligence` monorepo** (Scheduler, Node, and Website wer into `packages/` on 2026-08-04). This document describes `packages/node`. Version 1 establishes the complete lifecycle of a compute node. The distributed -(split) inference path is **not** implemented; the working path proxies to Ollama, and -that is the only backend `runtime.py` assigns. +(split) inference path is **not** implemented. + +## Which path actually serves a request + +Worth stating precisely, because this file got it wrong until 2026-08-21. It used to say +the Ollama proxy was "the only backend `runtime.py` assigns". It is not a `runtime.py` +backend at all, and there are two separate Ollama integrations: + +- **The live path** is the FastAPI route `src/node/api/inference.py`, which calls + `clients/ollama.py` (`OllamaClient`). This is what serves every real request. +- **The `backends/` abstraction is dead code in production.** `runtime.py:282` assigns + `self.inference_backend` an `EchoBackend` and nothing else, ever; `OllamaBackend` is + never constructed outside a test file. `Runtime._worker_loop` consumes a `task_queue` + that **nothing in `src` ever enqueues onto** — only tests do, including the one named + `test_end_to_end_pipeline`, which is an end-to-end test of a path production never + takes. + +So `backends/base.py` is an interface with one implementation and zero production +callers. It was written to make a second backend survivable and never got one. --- @@ -86,20 +106,28 @@ A local end-to-end text demonstration is also available in [examples/demo.md](ex ## Version -Current Release - -``` -v1.0.0 -``` +`pyproject.toml` declares **`1.0.0`**. The last release tag is **`v1.0.1`** — the two do +not match. That discrepancy is recorded rather than papered over in the root +[`README.md`](../../README.md); the version-parity ratchet compares the four packages to +each other, never to the tag that names them. --- -## Future Work +## What was never finished + +There is no future work — the project is archived. What did not get done: + +- **A proven real-NAT path.** The mesh works on a LAN, and on 2026-08-11 a node on a + second physical machine served a real request over it. Both machines were on adjacent + subnets of one network, so **no NAT boundary was ever crossed** — and NAT traversal was + the differentiator the whole project rested on. +- **Split / distributed inference.** Cut from v1; the node runs whole models, never + shards. The gateway answers `501` rather than fabricating a completion. +- **A second inference backend.** `backends/base.py` exists to make one survivable and + never got one, so the abstraction is untested against reality. -Automatic hardware discovery shipped in v1 — the installer probes CPU, RAM, and GPU, -and registration advertises the measured figures rather than a hardcoded guess. What is -**not** in v1: split/distributed inference (the node runs whole models, not shards), and -a proven real-NAT path (the mesh works on a LAN; crossing a real NAT is unverified). +Automatic hardware discovery *did* ship: the installer probes CPU, RAM and GPU, and +registration advertises the measured figures rather than a hardcoded guess. --- diff --git a/packages/scheduler/README.md b/packages/scheduler/README.md index 7ab036e..3ef3157 100644 --- a/packages/scheduler/README.md +++ b/packages/scheduler/README.md @@ -1,5 +1,8 @@ # Public Intelligence Scheduler +**Archived on 2026-08-21 along with the rest of the project. See the root +[`README.md`](../../README.md) for what worked, what failed, and why it stopped.** + The Scheduler is the control plane. It maintains a registry of compute nodes, receives heartbeats over an authenticated Zenoh mesh, matchmakes requests to a node that has the requested model, dispatches over the mesh (which is how a node behind NAT is reachable), @@ -91,25 +94,33 @@ uvicorn scheduler.main:app --reload ## Version -Current Release - -``` -v1.0.0 -``` +`pyproject.toml` declares **`1.0.0`**. The last release tag is **`v1.0.1`** — the two do +not match. That discrepancy is recorded rather than papered over in the root +[`README.md`](../../README.md); the version-parity ratchet compares the four packages to +each other, never to the tag that names them. --- -## Roadmap +## What was never finished -Request routing, mesh dispatch, and OpenAI-compatible serving — once listed here as -future work — shipped in v1. What is **deliberately not** in v1, and is not pretended -to be (see the root `README.md` and `docs/PREMISES.md`): +There is no roadmap — the project is archived. Request routing, mesh dispatch and +OpenAI-compatible serving all shipped. What did not, and was never pretended to (see the +root [`README.md`](../../README.md) and [`docs/PREMISES.md`](../../docs/PREMISES.md)): +- **A proven real-NAT path.** The mesh works on a LAN; crossing a real NAT boundary was + never demonstrated (`ROADMAP.md`, 1.5) — and it was the differentiator the project + rested on. - **Split / distributed inference** (sharding one model across nodes). Cut from v1; the - gateway answers `501`, it does not fabricate a completion. -- **A proven real-NAT path.** The mesh works on a LAN; crossing a real NAT boundary is - unverified (`ROADMAP.md`, 1.5). -- **Any payout / marketplace.** Credits are an accounting unit, not a currency (D2). + gateway answers `501`, it does not fabricate a completion. It used to answer `200` with + text from a toy engine. +- **`/v1/batch`.** Authenticated and tenant-scoped, because those were real fixes to a + real hole — but it answers `501` and dispatches nothing. +- **Any payout / marketplace.** Credits are an accounting unit, not a currency + ([D2](../../docs/decisions/D2-economics.md)). +- **Execution integrity beyond admission control.** Canaries catch a host running *no* + model; nothing catches one running the *wrong* one. +- **Revocable tokens, content filtering, real quotas, or backups.** None of these exist. + JWTs are stateless by design; the mitigations are a TTL cap and key rotation. --- diff --git a/packages/shared/README.md b/packages/shared/README.md index a15a418..9245c9d 100644 --- a/packages/shared/README.md +++ b/packages/shared/README.md @@ -1,5 +1,8 @@ # packages/shared +**Archived on 2026-08-21 along with the rest of the project. See the root +[`README.md`](../../README.md) for what worked, what failed, and why it stopped.** + The stated follow-up to the 2026-08-04 monorepo migration (ROADMAP C8), and the answer to the question `CLAUDE.md` has been asking contributors to hold in their heads: *"before adding a module, check whether its twin exists; if you change one of diff --git a/packages/website/README.md b/packages/website/README.md index 49a99c4..380f046 100644 --- a/packages/website/README.md +++ b/packages/website/README.md @@ -1,49 +1,72 @@ # Public Intelligence Website -The official website for **Public Intelligence** — a globally distributed, community-owned AI infrastructure. +**Archived on 2026-08-21 along with the rest of the project. See the root +[`README.md`](../../README.md) for what worked, what failed, and why it stopped.** -The website communicates the project's vision, architecture, research, roadmap, and development progress. +The Next.js front end for **Public Intelligence**: a dashboard over a running Scheduler, +an interactive playground against its OpenAI-compatible gateway, and the public pages +that describe the project. -## Demo +Part of the **`public-intelligence` monorepo** (the Scheduler, Node and Website were +merged into `packages/` on 2026-08-04). This document describes `packages/website`. -A walkthrough of the first working prototype is available on YouTube: -[Public Intelligence v1 Demo](https://www.youtube.com/watch?v=cGDWpOArB5I) +> **This README described the project as "a globally distributed, community-owned AI +> infrastructure" until 2026-08-21.** That was never true and had been explicitly decided +> against: [D6](../../docs/decisions/D6-is-there-a-network.md) records that there is no +> network and one will not be operated, and [D2](../../docs/decisions/D2-economics.md) +> that the marketplace economics do not close. The site's own landing page +> (`src/components/landing/unredacted-truth.tsx`) had been corrected; this file had not. +> It is fixed here because a stale README is how a claim outlives the decision that +> retired it. -This video demonstrates the end-to-end integration of the Website, Scheduler, Node, registration, heartbeats, and local inference. +--- -## Tech Stack +## Pages -- Next.js -- TypeScript -- Tailwind CSS +Nine routes under `src/app`: -## Pages +| Route | What it does | +|---|---| +| `/` | Landing page, including the "Unredacted Truth" panel listing what is and is not proven | +| `/dashboard` | Live view of registered nodes, telemetry and credit, proxied to the Scheduler | +| `/playground` | Interactive chat against `/v1/chat/completions`, with a bearer token you supply | +| `/status` | Fleet and request status | +| `/vision`, `/architecture`, `/research`, `/roadmap`, `/contribute` | Static project pages | + +`/dashboard`, `/playground` and `/status` are the functional ones — they proxy to a +running Scheduler and do nothing useful without one. The earlier version of this file +listed only the five static pages and omitted all three. -- Home -- Vision -- Architecture -- Research -- Roadmap -- Contribute +## Tech stack + +- Next.js 16 / React 19 +- TypeScript +- Tailwind CSS ## Development ```bash npm install -npm run dev +npm run dev # http://localhost:3000 ``` -Visit: +The dashboard and playground need a Scheduler to talk to; see +[`packages/scheduler`](../scheduler/README.md). -``` -http://localhost:3000 -``` +## Version + +`package.json` declares **`1.0.0`**. The last release tag is **`v1.0.1`** — the two do not +match, and that discrepancy is recorded rather than papered over in the root +[`README.md`](../../README.md) ("A ratchet that cannot see the thing it names"). The +version-parity ratchet compares the four packages to each other, never to the tag. -## Related Repositories +## Related components -- Public Intelligence Scheduler -- Public Intelligence Node +Part of the `public-intelligence` monorepo, alongside `packages/scheduler` (control +plane), `packages/node` (host agent) and `packages/shared`. They are directories, not +separate repositories — the pre-monorepo standalone repos are archived and tagged +`pre-monorepo-2026-08-04`. -## License +## Licence -Apache 2.0 \ No newline at end of file +Apache 2.0