From 18060b9c7777057b70ae5dc960a260ba27bab0b6 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 9 Aug 2026 14:23:12 +0000 Subject: [PATCH] Add per-deployment adaptive optimization + VEIL npm metaharness (ADR-289) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two additions on top of the hyper-optimized VEIL shield. 1) Adaptive optimization (v2/crates/wifi-densepose-privshield/src/optimize.rs): - optimal_bits_across_snr / model_optimal_bits_for_snr: the throughput- optimal feedback resolution shifts with SNR (unconstrained optimum 4 bits at 5-10 dB, 3 bits at 20-40 dB); within the spec {5,7,9} set it stays 5, which is why the shipped shield is SNR-stable. - adaptive_shield / min_passes_for_n: derive a shield for a specific deployment. Finding: the collapse budget is N-independent in this model (48 passes collapses N in {8,64} alike) — it is set by the fine-subspace dimension, not the candidate count. Defaults unchanged, so the proof witness is untouched. 38 tests + doctest pass; clippy -D warnings clean. 2) npm metaharness harness/wifi-densepose-privshield/ (ADR-289), mirroring wifi-densepose-sar-harness (ADR-286) with two improvements: - @metaharness/* imported dynamically inside the commands that need them, so `guidance` and `--help` run with ZERO dependencies installed (offline / pre `npm install`). - a dependency-free VEIL `guidance` command: a source-cited, evidence- labelled, read-only capability map (topics: overview, threat, countermeasure, compliance, optimization, experiment). Standard router + flywheel (SYNTHETIC) + Darwin wiring, tailored to VEIL task axes and policy levers. Tests: smoke + router + flywheel (need install) and guidance (offline). .harness manifest generated with real per-file hashes. Validated offline: cli syntax, --help, guidance topics, exit codes, graceful degradation when deps are absent. Docs: research bundle 08 gains a per-deployment adaptivity section; 07 and the crate README point at the harness; ADR-289 added and indexed. Co-Authored-By: claude-flow Claude-Session: https://claude.ai/code/session_01WEXNqzs7UsfNFBcP5yW21p --- ...pose-privshield-harness-via-metaharness.md | 95 +++++ docs/adr/README.md | 1 + .../07-implementation-and-roadmap.md | 6 + .../privacy-shield/08-optimization.md | 24 +- .../.claude-plugin/plugin.json | 25 ++ .../.claude/settings.json | 21 ++ harness/wifi-densepose-privshield/.gitignore | 3 + .../.harness/manifest.json | 32 ++ .../.harness/manifest.sha256 | 1 + harness/wifi-densepose-privshield/CLAUDE.md | 67 ++++ harness/wifi-densepose-privshield/LICENSE | 21 ++ harness/wifi-densepose-privshield/README.md | 68 ++++ .../__tests__/flywheel.test.ts | 26 ++ .../__tests__/guidance.test.ts | 34 ++ .../__tests__/router.test.ts | 24 ++ .../__tests__/smoke.test.ts | 35 ++ harness/wifi-densepose-privshield/bin/cli.js | 334 ++++++++++++++++++ .../wifi-densepose-privshield/package.json | 50 +++ .../wifi-densepose-privshield/src/flywheel.ts | 97 +++++ harness/wifi-densepose-privshield/src/init.ts | 25 ++ .../wifi-densepose-privshield/src/router.ts | 68 ++++ .../wifi-densepose-privshield/tsconfig.json | 19 + .../vitest.config.ts | 22 ++ v2/crates/wifi-densepose-privshield/README.md | 5 +- .../wifi-densepose-privshield/src/lib.rs | 2 +- .../wifi-densepose-privshield/src/optimize.rs | 115 ++++++ 26 files changed, 1217 insertions(+), 3 deletions(-) create mode 100644 docs/adr/ADR-289-wifi-densepose-privshield-harness-via-metaharness.md create mode 100644 harness/wifi-densepose-privshield/.claude-plugin/plugin.json create mode 100644 harness/wifi-densepose-privshield/.claude/settings.json create mode 100644 harness/wifi-densepose-privshield/.gitignore create mode 100644 harness/wifi-densepose-privshield/.harness/manifest.json create mode 100644 harness/wifi-densepose-privshield/.harness/manifest.sha256 create mode 100644 harness/wifi-densepose-privshield/CLAUDE.md create mode 100644 harness/wifi-densepose-privshield/LICENSE create mode 100644 harness/wifi-densepose-privshield/README.md create mode 100644 harness/wifi-densepose-privshield/__tests__/flywheel.test.ts create mode 100644 harness/wifi-densepose-privshield/__tests__/guidance.test.ts create mode 100644 harness/wifi-densepose-privshield/__tests__/router.test.ts create mode 100644 harness/wifi-densepose-privshield/__tests__/smoke.test.ts create mode 100644 harness/wifi-densepose-privshield/bin/cli.js create mode 100644 harness/wifi-densepose-privshield/package.json create mode 100644 harness/wifi-densepose-privshield/src/flywheel.ts create mode 100644 harness/wifi-densepose-privshield/src/init.ts create mode 100644 harness/wifi-densepose-privshield/src/router.ts create mode 100644 harness/wifi-densepose-privshield/tsconfig.json create mode 100644 harness/wifi-densepose-privshield/vitest.config.ts diff --git a/docs/adr/ADR-289-wifi-densepose-privshield-harness-via-metaharness.md b/docs/adr/ADR-289-wifi-densepose-privshield-harness-via-metaharness.md new file mode 100644 index 00000000..ad8e9c92 --- /dev/null +++ b/docs/adr/ADR-289-wifi-densepose-privshield-harness-via-metaharness.md @@ -0,0 +1,95 @@ +# ADR-289: `wifi-densepose-privshield-harness` — a MetaHarness for the VEIL privacy shield + +| Field | Value | +|-------|-------| +| **Status** | Proposed — implemented (P1) | +| **Date** | 2026-08-09 | +| **Parent** | ADR-288 (`wifi-densepose-privshield` / VEIL, the crate this harness assists development on) | +| **Relates to** | ADR-286 (`wifi-densepose-sar-harness`, the per-crate harness scaffold this one mirrors), ADR-285 (`harness/homecore/`, the WASM-first `@metaharness/kernel` pattern), ADR-182 (`harness/ruview/`, the first minted harness), ADR-282 (L0–L5 evidence ladder) | +| **Location** | `harness/wifi-densepose-privshield/` | + +## 0. PROOF discipline + +Every claim below about what is "real" versus "illustrative"/"SYNTHETIC" is +checked by a test in this harness's own suite (router + flywheel + install-smoke ++ guidance). The dependency-free `guidance` surface is covered by +`__tests__/guidance.test.ts`, which runs even before `npm install`. Nothing here +asserts a MEASURED defense result — the harness surfaces the VEIL crate's +SYNTHETIC/L0 numbers with that label intact. + +## 1. Context + +`wifi-densepose-privshield` (ADR-288) is the VEIL privacy shield — a new, +narrowly-scoped crate. Following the pattern ADR-286 set for +`wifi-densepose-sar`, it gets a dedicated per-crate MetaHarness rather than a +bespoke setup: the `vertical:coding` scaffold (architect/implementer/reviewer/ +test-writer, `doctor`) with `@metaharness/router`, `@metaharness/flywheel`, and +Darwin Mode wired in, plus a VEIL-specific, dependency-free `guidance` surface. + +## 2. Decision + +Land the harness at `harness/wifi-densepose-privshield/`, mirroring +`wifi-densepose-sar-harness`, with two deliberate improvements: + +1. **Dynamic dependency imports.** `bin/cli.js` imports the `@metaharness/*` + packages *inside* the commands that need them, not at module top. So + `guidance`, `--help`, and the guidance test run with **zero dependencies + installed** — useful for offline/air-gapped review and for this repo's CI + before `npm install`. Only `init`/`doctor`/`route`/`flywheel` touch the + kernel/host/router/flywheel packages. +2. **A VEIL `guidance` command.** A self-contained, source-cited, read-only + capability map (topics: `overview`, `threat`, `countermeasure`, + `compliance`, `optimization`, `experiment`), each entry carrying a summary, + repo-relative source citations, focused validation commands, and explicit + limitations — the `ruview_guidance` shape, specialized to VEIL. It labels all + defense evidence `SYNTHETIC/L0` and states plainly that guidance is + navigation, not authority. + +The standard three self-improvement/cost pieces are wired as real npm +dependencies (not stubs): + +- **`@metaharness/darwin`** (devDependency) — `npm run evolve` / `evolve:dry` + mutates the harness's own operating config, keeping only measurable gains. +- **`@metaharness/router`** — `src/router.ts` wires a real cost-optimal `Router` + (`qualityBar: 0.8`, k=1) over two model tiers, with four VEIL-shaped task axes + (threatModeling / complianceReview / optimizerTuning / docWriting). Labelled + examples are illustrative seed data (honesty note in-file). +- **`@metaharness/flywheel`** — `src/flywheel.ts` wires the real + `runFlywheelGenerations` promotion loop (propose → evaluate → gate → promote, + Ed25519-signed, independently replayable) with a SYNTHETIC proposer/evaluator + (`dataSource: 'SYNTHETIC'`, no model call), over VEIL policy levers + (`complianceReview`, `threatTriage`). + +## 3. What this explicitly is NOT + +- **Not a VEIL runtime.** The harness does not run a radio, emit RF, or jam. It + assists *development* on the crate; it cannot execute the shield on hardware. +- **Not evolving the crate.** Darwin/Flywheel mutate the harness's own policy + (agent prompts, review-checklist depth), not VEIL's Rust code. The crate's + actual hyper-optimization (ADR-288 §opt) was done directly, in the crate. +- **Not a live routing/promotion system.** The router's examples are seed data; + the flywheel's proposer/evaluator are deterministic stand-ins — both honestly + labelled in-source and in `CLAUDE.md`. +- **Not a replacement for the crate's gates.** The authoritative check for a + VEIL change remains `cargo test -p wifi-densepose-privshield`. +- **Not a re-labeller.** The harness must never present VEIL's SYNTHETIC results + as MEASURED, and never scaffold interference-based ("jamming") defenses — both + are hard rules in the harness `CLAUDE.md`. + +## 4. Consequences + +- The harness ships `guidance`/`doctor`/`init`/`route`/`flywheel`; `guidance` + and `--help` work offline (validated here via `node bin/cli.js`), the rest + after `npm install` + `npm run build` (CI). +- `.harness/manifest.json` + `manifest.sha256` are generated with real per-file + hashes at creation (unlike ADR-286's scaffold, whose manifest was historical). +- Scoped to its own name: its plugin, permissions, and (future) MCP surface only + read/assist on `wifi-densepose-privshield`. No risk to other harnesses/crates. + +## 5. Validation + +```bash +cd harness/wifi-densepose-privshield +node bin/cli.js guidance --topic overview # dependency-free +npm ci && npm run build && npm test # full suite (CI; needs registry access) +``` diff --git a/docs/adr/README.md b/docs/adr/README.md index 758a2ecb..4a426feb 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -146,6 +146,7 @@ Statuses: **Proposed** (under discussion), **Accepted** (approved and/or impleme | [ADR-285](ADR-285-homecore-wasm-first-metaharness.md) | WASM-first Homecore developer metaharness via `npx homecore` | Accepted (implemented and validated) | | [ADR-286](ADR-286-wifi-densepose-sar-harness-via-metaharness.md) | `wifi-densepose-sar-harness` — MetaHarness with darwin/router/flywheel | Accepted (implemented, published) | | [ADR-288](ADR-288-veil-privacy-shield-compliant-waveform.md) | VEIL — compliant-waveform privacy shield against unauthorized WiFi sensing (`wifi-densepose-privshield`) | Proposed (implemented, P1 reference) | +| [ADR-289](ADR-289-wifi-densepose-privshield-harness-via-metaharness.md) | `wifi-densepose-privshield-harness` — npm MetaHarness for the VEIL crate (guidance/router/flywheel) | Proposed (implemented, P1) | --- diff --git a/docs/research/privacy-shield/07-implementation-and-roadmap.md b/docs/research/privacy-shield/07-implementation-and-roadmap.md index 4dd10107..cdc9c7fc 100644 --- a/docs/research/privacy-shield/07-implementation-and-roadmap.md +++ b/docs/research/privacy-shield/07-implementation-and-roadmap.md @@ -13,6 +13,12 @@ - **This research bundle** (`docs/research/privacy-shield/`). - **[ADR-288](../../adr/ADR-288-veil-privacy-shield-compliant-waveform.md)** — the formal decision record. +- **npm metaharness** `harness/wifi-densepose-privshield/` + ([ADR-289](../../adr/ADR-289-wifi-densepose-privshield-harness-via-metaharness.md)) + — a per-crate contributor harness (architect/implementer/reviewer/test-writer, + router, flywheel) with a dependency-free `guidance` surface that serves this + bundle's capability map. `npx wifi-densepose-privshield-harness guidance + --topic optimization`. The crate is intentionally a **leaf with no internal RuView dependencies** (mirrors `wifi-densepose-aether`), so it can be reasoned about, fuzzed, and diff --git a/docs/research/privacy-shield/08-optimization.md b/docs/research/privacy-shield/08-optimization.md index 11625e3c..b38fbbec 100644 --- a/docs/research/privacy-shield/08-optimization.md +++ b/docs/research/privacy-shield/08-optimization.md @@ -110,7 +110,29 @@ expected to open up — a hardware study (roadmap P5) will re-measure it. --- -## 6. Robustness caveats (unchanged from the threat model) +## 6. Per-deployment adaptivity + +The optimum is not one number — `optimize` derives it per deployment: + +- **SNR → feedback resolution.** `optimal_bits_across_snr` shows the + *unconstrained* throughput-optimal resolution shifting with SNR: **4 bits at + 5–10 dB, 3 bits at 20–40 dB** (low SNR values fine resolution more because + the Shannon capacity is near-linear there, so the residual costs more). Within + the spec-allowed {5,7,9} set the choice is 5 bits across this whole range — + the residual is already negligible at 5 bits — which is why the shipped shield + is SNR-stable. +- **Identity count → mixing.** `adaptive_shield(base, n)` derives the config for + a room with `n` expected occupants. A notable finding: in this model the + collapse budget is **N-independent** (min 48 passes collapses N∈{8,64} + alike), because a well-mixed Haar-like rotation destroys per-identity + structure regardless of how many identities there are — the budget is set by + the fine-subspace dimension, not the candidate count. So `adaptive_shield` + returns the same 96/5 across that range: the default is robust, not a point + tuning. + +Both are surfaced through the harness `guidance --topic optimization`. + +## 7. Robustness caveats (unchanged from the threat model) - The collapse is verified against two classifiers and two N; a learned attacker on real captures must still be checked (P2/P5). diff --git a/harness/wifi-densepose-privshield/.claude-plugin/plugin.json b/harness/wifi-densepose-privshield/.claude-plugin/plugin.json new file mode 100644 index 00000000..96c6387f --- /dev/null +++ b/harness/wifi-densepose-privshield/.claude-plugin/plugin.json @@ -0,0 +1,25 @@ +{ + "name": "wifi-densepose-privshield-harness", + "version": "0.1.0", + "description": "Harness for wifi-densepose-privshield (VEIL privacy shield)", + "author": { + "displayName": "Generated by metaharness", + "url": "https://www.npmjs.com/package/metaharness" + }, + "license": "MIT", + "categories": [ + "agent-harness", + "metaharness-scaffold", + "Engineering", + "software-engineering" + ], + "tags": [ + "metaharness", + "agent-harness", + "vertical:coding", + "software-engineering", + "wifi-sensing", + "privacy" + ], + "homepage": "https://github.com/ruvnet/agent-harness-generator" +} diff --git a/harness/wifi-densepose-privshield/.claude/settings.json b/harness/wifi-densepose-privshield/.claude/settings.json new file mode 100644 index 00000000..34e12774 --- /dev/null +++ b/harness/wifi-densepose-privshield/.claude/settings.json @@ -0,0 +1,21 @@ +{ + "permissions": { + "allow": [ + "Bash(npx wifi-densepose-privshield-harness*)", + "mcp__wifi-densepose-privshield-harness__*", + "Bash(npm test*)", + "Bash(npm run*)", + "Bash(cargo test -p wifi-densepose-privshield*)", + "Bash(cargo clippy -p wifi-densepose-privshield*)", + "Bash(git diff*)", + "Bash(git status*)", + "Bash(git log*)" + ], + "deny": [ + "Read(./.env)", + "Read(./.env.*)", + "Bash(git push*)", + "Bash(rm -rf*)" + ] + } +} diff --git a/harness/wifi-densepose-privshield/.gitignore b/harness/wifi-densepose-privshield/.gitignore new file mode 100644 index 00000000..f4e2c6d6 --- /dev/null +++ b/harness/wifi-densepose-privshield/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +dist/ +*.tsbuildinfo diff --git a/harness/wifi-densepose-privshield/.harness/manifest.json b/harness/wifi-densepose-privshield/.harness/manifest.json new file mode 100644 index 00000000..3eb4ffce --- /dev/null +++ b/harness/wifi-densepose-privshield/.harness/manifest.json @@ -0,0 +1,32 @@ +{ + "schema": 1, + "generator": "0.1.0", + "template": "vertical:coding", + "template_version": "0.0.0", + "vars": { + "name": "wifi-densepose-privshield-harness", + "description": "Harness for wifi-densepose-privshield (VEIL privacy shield)", + "host": "claude-code" + }, + "hosts": ["claude-code"], + "files": { + ".claude/settings.json": "fedb60921a0e3c78848f43edddd75f448819594c680d48ff2033ef8f1588da3f", + ".claude-plugin/plugin.json": "7831dc3d1b9b5363130a59ce680794bfe0b6ca09c73d77a7ce78aa6ec3921c5a", + "bin/cli.js": "1133e7a47accada1c9b2184873776d8ca0d028f9b76dd55f467dfe38bb9ce609", + "CLAUDE.md": "c5bd71bfc0699021a284a54ffa70f4784b8238774c6d6fcfedf836f5e37d10f8", + "package.json": "e32acd6e5e630b0db9abccc5f5f58f86f291ccfc23b4c8410b380c01024a23df", + "README.md": "be5b0a17cd051dafe8cd825ddf778c91971993419f9e33c0898e21140249f72a", + "src/init.ts": "f05d6905d8681f45f610ff5b6e9d425dfa66183acdfe7857248e50e3583e13b8", + "src/router.ts": "4545b42d1423db21bcfe6ab6bf132b805ba383937d142997cb7256e835c245e4", + "src/flywheel.ts": "aab56d82c4f018ddc83923c877a66acdf9c624214307d0a9c4bf930ddb00599a", + "tsconfig.json": "8b4e730a1aa39162ac574455d7a98e1881f5313ca80ffe503b9652dcf0c76b9d", + "vitest.config.ts": "021b33ec623593effc3d163020479a91a1179329ee4ed1cb25f2dd9388e19820", + "__tests__/smoke.test.ts": "8c5a2acc3a956ea48e60c996c9034224684f6f4110cb3c5885741ff8d18bb82d", + "__tests__/router.test.ts": "97c29fc0ff718692ec97a9cd81f92e65ebde996fe1a3d8d2182e66598a583fad", + "__tests__/flywheel.test.ts": "87b149f7d68b4cf72fe3dcf6c76e4307b280e9f4ab6e6b1f7ee6689340faf5fb", + "__tests__/guidance.test.ts": "66b68615d27671d91b9efcf1eee5f2c7a53b0db7f475cc4ddb17ba8b6ddbff7f", + "LICENSE": "07b1a7c2aa25991872e3594de2ecb64ff6b4c5d3dc2376dd5b9e9f77c4b258e8" + }, + "generated_at": "2026-08-09T00:00:00.000Z", + "meta": { "surface": "cli" } +} diff --git a/harness/wifi-densepose-privshield/.harness/manifest.sha256 b/harness/wifi-densepose-privshield/.harness/manifest.sha256 new file mode 100644 index 00000000..2674b6e7 --- /dev/null +++ b/harness/wifi-densepose-privshield/.harness/manifest.sha256 @@ -0,0 +1 @@ +da48afb45d776c10f1841331facf65aa7ba4802f990a2480b91227fc100d4a47 diff --git a/harness/wifi-densepose-privshield/CLAUDE.md b/harness/wifi-densepose-privshield/CLAUDE.md new file mode 100644 index 00000000..fd77c73b --- /dev/null +++ b/harness/wifi-densepose-privshield/CLAUDE.md @@ -0,0 +1,67 @@ +# wifi-densepose-privshield-harness + +Harness for [`wifi-densepose-privshield`](../../v2/crates/wifi-densepose-privshield) +(VEIL — the compliant-waveform WiFi-sensing privacy shield, ADR-288). This +package is defined by ADR-289. + +> Advanced Coding harness · domain: `software-engineering`. Modeled on the +> `wifi-densepose-sar-harness` scaffold (ADR-286), generated with +> [create-agent-harness](https://github.com/ruvnet/agent-harness-generator). + +## Behavioral rules + +- Use the harness's tools for orchestration; memory and routing are handled by + the kernel. +- Defer destructive operations to the user. +- **Never present WiFi sensing as camera-grade, and never relabel VEIL's + SYNTHETIC/L0 results as MEASURED** — a hardware witness is required first + (CLAUDE.md hardware rule; ADR-282 ladder). The harness is a development aid; + it does not run a radio and cannot emit RF. +- VEIL uses compliant waveform controls only — **never jamming.** Do not add, + suggest, or scaffold interference-based "defenses." + +## Commands + +- `init` — boot the kernel + host adapter. +- `doctor` — verify the install end-to-end (kernel, host, guidance map). +- `guidance --topic [--query ]` — read-only VEIL capability map + (dependency-free; topics: `overview`, `threat`, `countermeasure`, + `compliance`, `optimization`, `experiment`). Source-cited and + evidence-labelled; navigation only, not authority. +- `route ` — cost-optimal model routing via + `@metaharness/router` (needs `npm run build`). +- `flywheel [generations]` — SYNTHETIC self-improvement demo via + `@metaharness/flywheel` (needs `npm run build`). + +## Architecture + +Uses [@metaharness/kernel](https://www.npmjs.com/package/@metaharness/kernel) +(Rust-compiled WASM with a NAPI-RS native fallback) so the same code runs on +every platform. The `@metaharness/*` packages are imported *dynamically* inside +the commands that need them, so `guidance`/`--help` work with no dependencies +installed. + +### Darwin, router, flywheel + +- **Darwin Mode** (`@metaharness/darwin`, devDependency) — `npm run evolve` / + `evolve:dry` mutates the harness's own config and keeps only measurable + improvements. +- **Router** (`@metaharness/router`) — `src/router.ts` wires a real cost-optimal + `Router` (`qualityBar: 0.8`) over two model tiers. Its labelled examples are + illustrative seed data (see the file's honesty note), not measured eval-log + observations. +- **Flywheel** (`@metaharness/flywheel`) — `src/flywheel.ts` wires the real + promotion loop (propose → evaluate → gate → promote, Ed25519-signed, + independently replayable) with a SYNTHETIC proposer/evaluator + (`dataSource: 'SYNTHETIC'`, no model call). A LIVE run needs a real Proposer + and Evaluator supplied by the operator — see the file's comments. + +## Relationship to the crate + +This harness assists development *on* the VEIL crate; it does not replace the +crate's own gates. The authoritative validation for a VEIL change is still: + +```bash +cargo test -p wifi-densepose-privshield --no-default-features +cargo clippy -p wifi-densepose-privshield --all-targets -- -D warnings +``` diff --git a/harness/wifi-densepose-privshield/LICENSE b/harness/wifi-densepose-privshield/LICENSE new file mode 100644 index 00000000..c77a3a09 --- /dev/null +++ b/harness/wifi-densepose-privshield/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 wifi-densepose-privshield-harness authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/harness/wifi-densepose-privshield/README.md b/harness/wifi-densepose-privshield/README.md new file mode 100644 index 00000000..912a65ce --- /dev/null +++ b/harness/wifi-densepose-privshield/README.md @@ -0,0 +1,68 @@ +# wifi-densepose-privshield-harness + +A metaharness (contributor harness) for +[`wifi-densepose-privshield`](../../v2/crates/wifi-densepose-privshield) — **VEIL**, +the compliant-waveform WiFi-sensing privacy shield (ADR-288). Defined by ADR-289. + +> **Advanced Coding** — architect → implement → review → test, plus a +> dependency-free VEIL guidance surface. Modeled on `wifi-densepose-sar-harness` +> (ADR-286). Multi-host scaffold with a kernel that resolves native → wasm → js. + +## Install + +```bash +npm install -g wifi-densepose-privshield-harness +wifi-densepose-privshield-harness doctor +``` + +Or run without installing: + +```bash +npx wifi-densepose-privshield-harness guidance --topic overview +``` + +## Commands + +| Command | Deps needed | Purpose | +|---|---|---| +| `init` | kernel + host | Boot the kernel + host adapter | +| `doctor` | kernel + host | Verify the install end-to-end | +| `guidance --topic ` | **none** | Read-only VEIL capability map (source-cited, evidence-labelled) | +| `route ` | router + `npm run build` | Cost-optimal model routing | +| `flywheel [gens]` | flywheel + `npm run build` | SYNTHETIC self-improvement demo | + +`guidance` topics: `overview`, `threat`, `countermeasure`, `compliance`, +`optimization`, `experiment`. It needs no dependencies or build step, so it +works offline and in CI before `npm install`. + +## What VEIL is + +VEIL shapes a node's **own** beamforming feedback with keyed Givens rotations so +a third-party passive sniffer cannot re-identify people, while a keyed receiver +sees an essentially unchanged link. **Compliant waveform controls only — never +jamming.** Reference results are **SYNTHETIC / evidence level L0** (reproduced by +`cargo test`), never MEASURED until a hardware witness exists. See the crate's +[ADR-288](../../docs/adr/ADR-288-veil-privacy-shield-compliant-waveform.md) and +[research bundle](../../docs/research/privacy-shield/). + +## Darwin, router, flywheel + +- `npm run evolve` / `evolve:dry` — Darwin Mode self-mutation of the harness + config (`@metaharness/darwin`). +- `npm run route -- ` (after `npm run build`) — cost-optimal + model routing (`@metaharness/router`). +- `npm run flywheel:dry` — the SYNTHETIC `@metaharness/flywheel` demo + (propose → evaluate → gate → promote, signed + independently replayable). + +See `CLAUDE.md` and the honesty notes atop `src/router.ts` / `src/flywheel.ts` +for what is real wiring vs. illustrative/synthetic data. + +## Scope + +The harness is a **development aid**. It does not run a VEIL radio, does not +emit RF, and cannot jam. It does not replace the crate's own gates — the +authoritative check for a VEIL change is `cargo test -p wifi-densepose-privshield`. + +## License + +MIT diff --git a/harness/wifi-densepose-privshield/__tests__/flywheel.test.ts b/harness/wifi-densepose-privshield/__tests__/flywheel.test.ts new file mode 100644 index 00000000..38dd3e2d --- /dev/null +++ b/harness/wifi-densepose-privshield/__tests__/flywheel.test.ts @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// Verifies the SYNTHETIC flywheel demo wires end-to-end: a non-empty lift curve +// and a replay bundle that verifies independently. Does NOT assert any real +// self-improvement — the proposer/evaluator are deterministic stand-ins. + +import { describe, it, expect } from 'vitest'; +import { runVeilFlywheelDemo, verifyVeilFlywheelDemo } from '../src/flywheel.js'; + +describe('wifi-densepose-privshield-harness — flywheel (SYNTHETIC)', () => { + it('produces a non-empty lift curve', async () => { + const result = await runVeilFlywheelDemo(3); + expect(result.liftCurve.length).toBeGreaterThan(0); + expect(result.generationsRun).toBeGreaterThan(0); + }); + + it('produces an independently verifiable replay bundle', async () => { + const result = await runVeilFlywheelDemo(3); + const verdict = verifyVeilFlywheelDemo(result); + expect(verdict.pass).toBe(true); + }); + + it('stamps the run as SYNTHETIC provenance', async () => { + const result = await runVeilFlywheelDemo(2); + expect(result.dataSource).toBe('SYNTHETIC'); + }); +}); diff --git a/harness/wifi-densepose-privshield/__tests__/guidance.test.ts b/harness/wifi-densepose-privshield/__tests__/guidance.test.ts new file mode 100644 index 00000000..99dab6cf --- /dev/null +++ b/harness/wifi-densepose-privshield/__tests__/guidance.test.ts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +// The VEIL guidance map is dependency-free (no @metaharness/* import), so this +// test runs even before `npm install` resolves the kernel. It guards the +// read-only capability map the MCP/CLI `guidance` surface exposes. + +import { describe, it, expect } from 'vitest'; +import { run, guidanceReport } from '../bin/cli.js'; + +describe('wifi-densepose-privshield-harness — guidance', () => { + it('returns a source-cited report for a known topic', () => { + const r = guidanceReport('optimization'); + expect(r.ok).toBe(true); + expect(r.summary.length).toBeGreaterThan(0); + expect(r.sources.some((s: string) => s.includes('optimize.rs'))).toBe(true); + expect(r.authority).toContain('read-only'); + }); + + it('labels evidence as SYNTHETIC/L0', () => { + const r = guidanceReport('experiment'); + expect(r.evidence).toContain('SYNTHETIC'); + }); + + it('rejects an unknown topic and lists the valid ones', () => { + const r = guidanceReport('not-a-topic'); + expect(r.ok).toBe(false); + expect(r.topics).toContain('overview'); + expect(r.topics).toContain('compliance'); + }); + + it('CLI `guidance --topic overview` exits 0; unknown topic exits non-zero', async () => { + expect(await run(['guidance', '--topic', 'overview'])).toBe(0); + expect(await run(['guidance', '--topic', 'nope'])).not.toBe(0); + }); +}); diff --git a/harness/wifi-densepose-privshield/__tests__/router.test.ts b/harness/wifi-densepose-privshield/__tests__/router.test.ts new file mode 100644 index 00000000..4d378ddd --- /dev/null +++ b/harness/wifi-densepose-privshield/__tests__/router.test.ts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// Verifies the cost-optimal router mechanism (not its illustrative data): cheap +// query shapes route to the cheap tier; hard shapes escalate to the frontier. + +import { describe, it, expect } from 'vitest'; +import { routeVeilQuery } from '../src/router.js'; + +describe('wifi-densepose-privshield-harness — router', () => { + it('routes a threat-model query (cheap-tier-capable) to the cheap tier', () => { + const pick = routeVeilQuery([1, 0, 0, 0]); + expect(pick.id).toBe('cheap-tier'); + expect(pick.metBar).toBe(true); + }); + + it('escalates a compliance-review query to the frontier tier', () => { + const pick = routeVeilQuery([0, 1, 0, 0]); + expect(pick.id).toBe('frontier-tier'); + }); + + it('escalates an optimizer-tuning query to the frontier tier', () => { + const pick = routeVeilQuery([0, 0, 1, 0]); + expect(pick.id).toBe('frontier-tier'); + }); +}); diff --git a/harness/wifi-densepose-privshield/__tests__/smoke.test.ts b/harness/wifi-densepose-privshield/__tests__/smoke.test.ts new file mode 100644 index 00000000..75605913 --- /dev/null +++ b/harness/wifi-densepose-privshield/__tests__/smoke.test.ts @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// A real smoke test for wifi-densepose-privshield-harness: it boots the actual +// kernel + host adapter the harness depends on, so `npm test` fails loudly if +// @metaharness/kernel or @metaharness/host-claude-code is missing, broken, or +// version-skewed. Fastest signal that `npm install` produced a runnable harness. + +import { describe, it, expect } from 'vitest'; +import { loadKernel } from '@metaharness/kernel'; +import adapter from '@metaharness/host-claude-code'; +import { run } from '../bin/cli.js'; + +describe('wifi-densepose-privshield-harness — install smoke test', () => { + it('loads the kernel and reports a version + a known backend', async () => { + const kernel = await loadKernel(); + const info = kernel.kernelInfo(); + expect(typeof info.version).toBe('string'); + expect(info.version.length).toBeGreaterThan(0); + expect(['native', 'wasm', 'js']).toContain(kernel.backend); + }); + + it('resolves the host adapter with a name', () => { + expect(typeof adapter.name).toBe('string'); + expect(adapter.name.length).toBeGreaterThan(0); + }); + + it('the CLI doctor command succeeds (exit 0)', async () => { + const code = await run(['doctor']); + expect(code).toBe(0); + }); + + it('an unknown CLI command exits non-zero', async () => { + const code = await run(['definitely-not-a-command']); + expect(code).not.toBe(0); + }); +}); diff --git a/harness/wifi-densepose-privshield/bin/cli.js b/harness/wifi-densepose-privshield/bin/cli.js new file mode 100644 index 00000000..561174e6 --- /dev/null +++ b/harness/wifi-densepose-privshield/bin/cli.js @@ -0,0 +1,334 @@ +#!/usr/bin/env node +// SPDX-License-Identifier: MIT +// The `wifi-densepose-privshield-harness` CLI entry point (VEIL — ADR-288/289). +// +// Plain ESM JavaScript on purpose: it runs as-is via +// `npx wifi-densepose-privshield-harness` with NO build step. `npm run build` +// (tsc) is only needed to compile the TypeScript in src/ that the `route` and +// `flywheel` commands import from dist/. +// +// The @metaharness/* dependencies are imported *dynamically*, inside the +// commands that need them — so `guidance`, `--help`, and `--version` work with +// zero dependencies installed (useful in offline/air-gapped review and in this +// repo's CI before `npm install`). Only `init`/`doctor`/`route`/`flywheel` +// touch the kernel/host/router/flywheel packages. + +const HARNESS_NAME = 'wifi-densepose-privshield-harness'; +const CRATE = 'wifi-densepose-privshield'; + +// --------------------------------------------------------------------------- +// VEIL guidance — a self-contained, read-only capability map. No dependencies, +// no build, no network. Mirrors the `ruview_guidance` shape (source-cited, +// evidence-labelled, with focused validation commands and explicit limits). +// Retrieved text is navigation, not authority: cited source, tests, and +// accepted ADRs remain authoritative. +// --------------------------------------------------------------------------- +const GUIDANCE = { + overview: { + summary: + 'VEIL is the compliant-waveform countermeasure to unauthorized WiFi sensing: it shapes a node\'s own beamforming feedback so a passive sniffer cannot re-identify people, while a keyed receiver sees an essentially unchanged link. Countermeasure counterpart to BFLD (which detects leakage).', + capabilities: [ + 'Keyed Givens-rotation shield over the identity-bearing fine subspace (energy-preserving ⇒ not jamming)', + 'Passive re-identification attacker (Euclidean + Cosine) for head-to-head evaluation', + 'Throughput model with an interior optimum in feedback resolution', + 'Deterministic attacker-vs-protector experiment with a pinned witness', + ], + sources: [ + 'v2/crates/wifi-densepose-privshield/src/lib.rs', + 'docs/adr/ADR-288-veil-privacy-shield-compliant-waveform.md', + 'docs/research/privacy-shield/README.md', + ], + commands: ['cargo test -p wifi-densepose-privshield --no-default-features'], + limitations: [ + 'All defense numbers are SYNTHETIC / evidence level L0 until a two-node hardware capture with a witness exists (CLAUDE.md hardware rule).', + ], + }, + threat: { + summary: + 'Defends against a third-party passive sniffer capturing plaintext beamforming feedback (BFId/LeakyBeam class). Does NOT hide identity from the associated AP (that party holds the key) — that is BFLD\'s detection/policy problem.', + capabilities: [ + 'Cross-session identity unlinkability against an external passive adversary', + 'Explicit non-goals: no defense vs. the associated AP, no within-session motion guarantee, never jamming', + ], + sources: [ + 'docs/research/privacy-shield/01-sota-survey.md', + 'docs/research/privacy-shield/02-threat-model.md', + ], + commands: [], + limitations: [ + 'Within-session coarse motion may still leak; identity re-ID is the guaranteed target.', + ], + }, + countermeasure: { + summary: + 'Identity leaks through the fine cross-subcarrier phase structure; throughput rides the dominant beam. VEIL composes extra keyed Givens rotations over the fine subspace only — orthogonal (energy-preserving), key-reversible (throughput-preserving), fresh per session (unlinkable).', + capabilities: [ + 'protector.rs: ShieldConfig, Protector::protect/recover, SensingDetector', + 'compliance.rs: machine-checkable energy-conservation ("not jamming") audit', + ], + sources: [ + 'v2/crates/wifi-densepose-privshield/src/protector.rs', + 'v2/crates/wifi-densepose-privshield/src/compliance.rs', + 'docs/research/privacy-shield/03-countermeasure-design.md', + ], + commands: ['cargo test -p wifi-densepose-privshield protector'], + limitations: [ + 'The two-subspace separability is a model abstraction; real hardware is only approximately separable.', + ], + }, + compliance: { + summary: + 'Compliant waveform controls only, never jamming. The keyed rotation is orthogonal, so it preserves the report energy exactly (ratio ≈ 1.0) — it adds no interfering emission. Jamming (47 U.S.C. §333/§302a) is defined by interfering with OTHERS\' transmissions, not shaping your own.', + capabilities: [ + 'ComplianceReport::audit / is_compliant — energy ratio + non-interference verdict', + ], + sources: [ + 'v2/crates/wifi-densepose-privshield/src/compliance.rs', + 'docs/research/privacy-shield/04-compliance-and-regulatory.md', + ], + commands: ['cargo test -p wifi-densepose-privshield compliance'], + limitations: [ + 'Engineering analysis, not legal advice; RF power/mask/timing limits are jurisdiction-specific.', + ], + }, + optimization: { + summary: + 'The shipped shield config is derived, not hand-picked: 96 Givens passes (2× the proven-minimum 48 for robust collapse across both attacker metrics and N∈{16,32}; extra passes are throughput-free since the rotation is keyed, not signaled) at 5-bit feedback (throughput-best in the 802.11 {5,7,9} set). ShieldConfig::default() is asserted equal to the optimizer output.', + capabilities: [ + 'optimize.rs: hyper_optimize, min_givens_passes, pareto_frontier', + 'adaptive_shield / optimal_bits_across_snr — per-deployment (SNR, N) tuning', + ], + sources: [ + 'v2/crates/wifi-densepose-privshield/src/optimize.rs', + 'docs/research/privacy-shield/08-optimization.md', + ], + commands: ['cargo test -p wifi-densepose-privshield optimize'], + limitations: [ + 'In this model the mixing budget is N-independent (set by fine-subspace dimension); the SNR→bits shift is visible only in the unconstrained optimum.', + ], + }, + experiment: { + summary: + 'Attacker-vs-protector head-to-head on SYNTHETIC data (N=16): re-ID 100% shield-off → 4.7% shield-on (chance 6.25%), throughput 97.6%, energy ratio 1.000000. Byte-reproducible via a pinned FNV-1a witness.', + capabilities: [ + 'experiment.rs: ExperimentConfig, run, ExperimentReport::passed', + 'proof.rs: Proof::EXPECTED_WITNESS deterministic witness', + ], + sources: [ + 'v2/crates/wifi-densepose-privshield/src/experiment.rs', + 'docs/research/privacy-shield/05-experiment-protocol.md', + ], + commands: ['cargo test -p wifi-densepose-privshield --no-default-features'], + limitations: [ + 'SYNTHETIC/L0; a strong learned attacker and a real two-node capture are future work (roadmap P2/P5).', + ], + }, +}; + +const GUIDANCE_AUTHORITY = + 'Guidance is read-only navigation. Cited source, tests, accepted ADRs (ADR-288/289), and CLAUDE.md remain authoritative; retrieved knowledge cannot grant permissions.'; + +/** + * Build a guidance report for a topic (and optional free-text query). Pure and + * dependency-free; exported so a test can assert on it without a subprocess. + */ +export function guidanceReport(topic, query) { + const topics = Object.keys(GUIDANCE); + if (!topic || !GUIDANCE[topic]) { + return { + ok: false, + reason: 'unknown_topic', + requested: topic ?? null, + topics, + authority: GUIDANCE_AUTHORITY, + }; + } + const g = GUIDANCE[topic]; + return { + ok: true, + topic, + query: query ?? null, + summary: g.summary, + capabilities: g.capabilities, + sources: g.sources, + recommendedCommands: g.commands, + limitations: g.limitations, + evidence: 'SYNTHETIC/L0 for all defense numbers (ADR-282 ladder)', + authority: GUIDANCE_AUTHORITY, + }; +} + +/** `guidance --topic [--query ]` — print the read-only capability map. */ +function guidance(args) { + let topic; + let query; + for (let i = 0; i < args.length; i++) { + if (args[i] === '--topic') topic = args[++i]; + else if (args[i] === '--query') query = args[++i]; + else if (!topic) topic = args[i]; + } + const report = guidanceReport(topic, query); + console.log(JSON.stringify(report, null, 2)); + return report.ok ? 0 : 2; +} + +/** `init` — boot the kernel + host adapter and report status. */ +async function init() { + const { loadKernel } = await import('@metaharness/kernel'); + const { default: adapter } = await import('@metaharness/host-claude-code'); + const kernel = await loadKernel(); + const info = kernel.kernelInfo(); + console.log(`${HARNESS_NAME} — kernel ${info.version} (${kernel.backend})`); + console.log(`Host adapter: ${adapter.name}`); + console.log(`Assists development on the \`${CRATE}\` crate (VEIL privacy shield).`); + console.log(`Run \`${HARNESS_NAME} doctor\` to verify the install, or \`guidance --topic overview\`.`); + return 0; +} + +/** `doctor` — verify the install end-to-end (kernel + host resolve). */ +async function doctor() { + const { loadKernel } = await import('@metaharness/kernel'); + const { default: adapter } = await import('@metaharness/host-claude-code'); + const kernel = await loadKernel(); + const info = kernel.kernelInfo(); + const checks = [ + ['kernel loads', !!kernel], + ['kernel reports a version', typeof info.version === 'string' && info.version.length > 0], + ['kernel backend is native|wasm|js', ['native', 'wasm', 'js'].includes(kernel.backend)], + ['host adapter has a name', typeof adapter?.name === 'string' && adapter.name.length > 0], + ['guidance map resolves', guidanceReport('overview').ok === true], + ]; + let ok = true; + for (const [label, pass] of checks) { + console.log(`${pass ? 'PASS' : 'FAIL'} ${label}`); + if (!pass) ok = false; + } + console.log( + ok + ? `\n${HARNESS_NAME}: all checks passed (kernel ${info.version}, ${kernel.backend} backend, host ${adapter.name})` + : `\n${HARNESS_NAME}: doctor found problems`, + ); + return ok ? 0 : 1; +} + +/** + * `route ` — route a 4-axis task embedding to the + * cost-optimal model tier via @metaharness/router. Needs `npm run build`. + */ +async function route(args) { + const embedding = args.map(Number); + if (embedding.length !== 4 || embedding.some((n) => Number.isNaN(n))) { + console.error( + `Usage: ${HARNESS_NAME} route (four 0..1 numbers)`, + ); + return 2; + } + let routeVeilQuery; + try { + ({ routeVeilQuery } = await import('../dist/router.js')); + } catch (err) { + console.error(`route: dist/router.js not found — run \`npm run build\` first. (${err.message})`); + return 1; + } + const pick = routeVeilQuery(embedding); + console.log( + `route -> ${pick.id} (predicted quality ${pick.predictedQuality.toFixed(3)}, $${pick.costPerMTok}/MTok, met bar: ${pick.metBar})`, + ); + return 0; +} + +/** + * `flywheel [generations]` — run the SYNTHETIC @metaharness/flywheel demo and + * print the lift curve + an independent replay-bundle verification. Needs + * `npm run build`. + */ +async function flywheel(args) { + const generations = args[0] ? Number(args[0]) : 3; + if (Number.isNaN(generations) || generations < 1) { + console.error(`Usage: ${HARNESS_NAME} flywheel [generations>=1]`); + return 2; + } + let runVeilFlywheelDemo, verifyVeilFlywheelDemo; + try { + ({ runVeilFlywheelDemo, verifyVeilFlywheelDemo } = await import('../dist/flywheel.js')); + } catch (err) { + console.error(`flywheel: dist/flywheel.js not found — run \`npm run build\` first. (${err.message})`); + return 1; + } + console.log(`Running ${generations}-generation flywheel demo (dataSource: SYNTHETIC — see src/flywheel.ts)...`); + const result = await runVeilFlywheelDemo(generations); + for (const point of result.liftCurve) { + console.log(` gen ${point.generation}: primary=${point.primary.toFixed(3)} delta=${point.delta.toFixed(3)} anchor=${point.anchor ?? 'n/a'}`); + } + const verdict = verifyVeilFlywheelDemo(result); + console.log(`generations run: ${result.generationsRun} · promotions: ${result.promotions.length} · replay verified: ${verdict.pass}`); + return verdict.pass ? 0 : 1; +} + +/** + * Dispatch one CLI invocation. Exported (not just run on import) so a test can + * drive it without spawning a subprocess. Returns the intended exit code. + */ +export async function run(argv) { + const cmd = argv[0] ?? 'init'; + switch (cmd) { + case 'init': + return init(); + case 'doctor': + return doctor(); + case 'guidance': + return guidance(argv.slice(1)); + case 'route': + return route(argv.slice(1)); + case 'flywheel': + return flywheel(argv.slice(1)); + case '--version': + case '-v': { + const { loadKernel } = await import('@metaharness/kernel'); + const kernel = await loadKernel(); + console.log(kernel.version()); + return 0; + } + case '--help': + case '-h': + console.log( + `Usage: ${HARNESS_NAME} \n\n` + + ` init boot the kernel + host adapter (default)\n` + + ` doctor verify the install end-to-end\n` + + ` guidance --topic read-only VEIL capability map (no deps/build)\n` + + ` topics: overview threat countermeasure compliance optimization experiment\n` + + ` route cost-optimal model routing (needs \`npm run build\`)\n` + + ` flywheel [generations] SYNTHETIC self-improvement demo (needs \`npm run build\`)\n` + + ` --version print the kernel version`, + ); + return 0; + default: + console.error(`Unknown command: ${cmd}. Try \`${HARNESS_NAME} --help\`.`); + return 2; + } +} + +// CLI guard: execute only when invoked directly (not when imported by a test). +// npm's bin shims pass a NON-normalized argv[1], so realpath BOTH sides before +// comparing — a naive string === misses the npx/shim path and the CLI no-ops. +import { fileURLToPath } from 'node:url'; +import { realpathSync } from 'node:fs'; +import { argv } from 'node:process'; +const invokedDirectly = (() => { + if (!argv[1]) return false; + try { + const a = realpathSync(argv[1]); + const b = realpathSync(fileURLToPath(import.meta.url)); + return process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b; + } catch { + return false; + } +})(); +if (invokedDirectly) { + run(argv.slice(2)) + .then((code) => process.exit(code)) + .catch((err) => { + console.error(err); + process.exit(1); + }); +} diff --git a/harness/wifi-densepose-privshield/package.json b/harness/wifi-densepose-privshield/package.json new file mode 100644 index 00000000..1044992c --- /dev/null +++ b/harness/wifi-densepose-privshield/package.json @@ -0,0 +1,50 @@ +{ + "name": "wifi-densepose-privshield-harness", + "version": "0.1.0", + "description": "Harness for wifi-densepose-privshield (VEIL — compliant-waveform WiFi-sensing privacy shield, ADR-288/289)", + "license": "MIT", + "type": "module", + "bin": { + "wifi-densepose-privshield-harness": "bin/cli.js" + }, + "files": [ + "bin/**", + "dist/**", + "src/**", + "tsconfig.json", + ".claude/**", + ".claude-plugin/**", + "CLAUDE.md", + "README.md", + "LICENSE" + ], + "scripts": { + "build": "tsc", + "test": "vitest run", + "init": "node ./bin/cli.js init", + "doctor": "node ./bin/cli.js doctor", + "guidance": "node ./bin/cli.js guidance", + "evolve": "metaharness-darwin evolve . --sandbox real --generations 3 --children 4", + "evolve:dry": "metaharness-darwin evolve . --sandbox mock --generations 2 --children 3", + "route": "npm run build && node ./bin/cli.js route", + "flywheel:dry": "npm run build && node ./bin/cli.js flywheel 3" + }, + "dependencies": { + "@metaharness/kernel": "^0.1.0", + "@metaharness/host-claude-code": "^0.1.0", + "@metaharness/router": "^0.3.2", + "@metaharness/flywheel": "^0.1.7" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "typescript": "^5.4.0", + "vitest": "^3.0.0", + "@metaharness/darwin": "^0.2.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/harness/wifi-densepose-privshield/src/flywheel.ts b/harness/wifi-densepose-privshield/src/flywheel.ts new file mode 100644 index 00000000..a8cedad1 --- /dev/null +++ b/harness/wifi-densepose-privshield/src/flywheel.ts @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: MIT +// +// The wifi-densepose-privshield (VEIL) harness's self-improvement loop, via +// @metaharness/flywheel: run -> measure -> mutate -> verify -> promote, with a +// frozen, conjunctive promotion gate and a signed, replayable lineage. +// +// HONESTY NOTE (load-bearing): `runVeilFlywheelDemo()` wires the real +// @metaharness/flywheel API end-to-end, but its Proposer and Evaluator are +// SYNTHETIC stand-ins — a deterministic string mutation and a deterministic +// scoring function over that string, with NO model call and NO real benchmark. +// It proves the wiring works (see __tests__/flywheel.test.ts: a non-empty lift +// curve, a verifiable replay bundle) and gives a `dataSource: 'SYNTHETIC'`- +// stamped demo. A LIVE run needs the operator to supply: +// - a real Proposer: a model call that improves one policy lever (e.g. the +// compliance-review checklist, the threat-model triage prompt); +// - a real Evaluator: scores that policy against real tasks (e.g. "did the +// compliance reviewer catch a non-energy-preserving perturbation"). +// Neither exists in this repo — wiring them is a live-API-key decision for the +// harness operator, not something to fake here. + +import { + runFlywheelGenerations, + meetsPromotionRule, + makeSigner, + verifyReplayBundle, + type Policy, + type PolicyGenome, + type Proposer, + type Evaluator, + type Suite, + type FlywheelResult, +} from '@metaharness/flywheel'; + +/** The gen-0 operating policy for the VEIL harness's review agents. Opaque + * string levers — the flywheel never interprets their meaning, only the + * Evaluator does. */ +export const VEIL_ROOT_POLICY: Policy = { + complianceReview: 'energy-ratio-checklist', + threatTriage: 'single-pass', +}; + +/** SYNTHETIC proposer: deterministically varies the target lever's value + * rather than calling a model. */ +const syntheticProposer: Proposer = async (base: PolicyGenome, target: string) => { + const current = base.policy[target] ?? ''; + return `${current}+g${base.generation + 1}`; +}; + +/** SYNTHETIC evaluator: scores a policy purely as a function of its own string + * content — a deterministic stand-in for running the harness's agents against a + * real task suite. `noopRate` must move for anything to promote (the default + * gate requires it to strictly improve generation over generation). */ +const syntheticEvaluator: Evaluator = async (policy: Policy, _suite: Suite) => { + const totalLength = Object.values(policy).reduce((s, v) => s + v.length, 0); + const primary = Math.min(0.5 + totalLength / 200, 0.98); + const noopRate = Math.max(0.3 - totalLength / 300, 0.02); + return { + primary, + noopRate, + costPerWin: 1 / primary, + regressed: false, + }; +}; + +const VEIL_HOLDOUT: Suite = { + id: 'veil-harness-holdout-synthetic', + items: ['seeded-compliance-task-1', 'seeded-threat-task-2', 'seeded-optimizer-task-3'], +}; + +const VEIL_ANCHOR: Suite = { + id: 'veil-harness-anchor-synthetic', + items: ['frozen-not-jamming-regression-1'], +}; + +/** + * Run a small, fully SYNTHETIC flywheel demo end-to-end and return the real + * @metaharness/flywheel result — a genuine lift curve and a signed, + * independently replayable bundle, built from synthetic (not live) evidence. + */ +export async function runVeilFlywheelDemo(maxGenerations = 3): Promise { + return runFlywheelGenerations({ + rootPolicy: VEIL_ROOT_POLICY, + proposer: syntheticProposer, + evaluator: syntheticEvaluator, + promotionRule: meetsPromotionRule, + holdout: VEIL_HOLDOUT, + anchor: VEIL_ANCHOR, + maxGenerations, + signer: makeSigner(), + dataSource: 'SYNTHETIC', + }); +} + +/** Independently verify a flywheel demo's replay bundle (no trust in the producer). */ +export function verifyVeilFlywheelDemo(result: FlywheelResult) { + return verifyReplayBundle(result.replayBundle); +} diff --git a/harness/wifi-densepose-privshield/src/init.ts b/harness/wifi-densepose-privshield/src/init.ts new file mode 100644 index 00000000..4f9d0cbf --- /dev/null +++ b/harness/wifi-densepose-privshield/src/init.ts @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// The harness's `wifi-densepose-privshield-harness init` entry (typed mirror of +// the JS command in bin/cli.js; the published CLI uses the JS version so no +// build is required for `init`). + +import { loadKernel } from '@metaharness/kernel'; +import adapter from '@metaharness/host-claude-code'; + +const HARNESS_NAME = 'wifi-densepose-privshield-harness'; + +async function main(): Promise { + const kernel = await loadKernel(); + const info = kernel.kernelInfo(); + console.log(`${HARNESS_NAME} — kernel ${info.version} (${kernel.backend})`); + console.log(`Host adapter: ${adapter.name}`); + console.log(`Run \`${HARNESS_NAME} doctor\` to verify the install.`); + return 0; +} + +main() + .then((c) => process.exit(c)) + .catch((err) => { + console.error(err); + process.exit(1); + }); diff --git a/harness/wifi-densepose-privshield/src/router.ts b/harness/wifi-densepose-privshield/src/router.ts new file mode 100644 index 00000000..e3a26080 --- /dev/null +++ b/harness/wifi-densepose-privshield/src/router.ts @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT +// +// Cost-optimal task routing for the wifi-densepose-privshield (VEIL) harness, +// via @metaharness/router: route each agent query to the cheapest model +// predicted to clear a quality bar, instead of defaulting every query to the +// frontier tier. +// +// HONESTY NOTE: the candidate `examples` below are SEED/ILLUSTRATIVE data — +// four hand-picked (embedding, quality) points per candidate, not measured +// eval-log observations. They exist so `veilTaskRouter` is a real, runnable +// k-NN router out of the box (see __tests__/router.test.ts), not so its routing +// decisions should be trusted for production cost savings. Replace +// `VEIL_ROUTER_CANDIDATES[*].examples` with real (query embedding → quality +// achieved) rows from your own eval logs before relying on this. + +import { Router, type RouterCandidate } from '@metaharness/router'; + +/** + * A 4-axis feature embedding for a harness query (each axis 0..1): + * [0] threatModeling — "is this attack in scope / what does VEIL defend"-shaped + * [1] complianceReview — "does this stay compliant / not jamming"-shaped + * [2] optimizerTuning — "tune passes/bits / re-run the optimizer"-shaped + * [3] docWriting — "write/update the research bundle or ADR"-shaped + * A caller with a real embedding model should project onto that model's + * dimensionality instead — the router only needs consistent vectors. + */ +export type VeilTaskEmbedding = readonly [number, number, number, number]; + +export const VEIL_ROUTER_CANDIDATES: RouterCandidate[] = [ + { + id: 'cheap-tier', + costPerMTok: 1, + examples: [ + { embedding: [1, 0, 0, 0], quality: 0.88 }, // threat-model Q&A: cheap tier is fine + { embedding: [0, 0, 0, 1], quality: 0.85 }, // doc writing: cheap tier is fine + { embedding: [0, 1, 0, 0], quality: 0.55 }, // compliance review: cheap tier is weak + { embedding: [0, 0, 1, 0], quality: 0.5 }, // optimizer tuning: cheap tier is weak + ], + }, + { + id: 'frontier-tier', + costPerMTok: 15, + examples: [ + { embedding: [1, 0, 0, 0], quality: 0.95 }, + { embedding: [0, 0, 0, 1], quality: 0.93 }, + { embedding: [0, 1, 0, 0], quality: 0.93 }, // compliance review: frontier tier needed + { embedding: [0, 0, 1, 0], quality: 0.92 }, // optimizer tuning: frontier tier needed + ], + }, +]; + +/** + * Cost-optimal router for the harness's four query shapes above. `qualityBar` + * of 0.8: return the cheapest candidate predicted to clear 80% quality, or the + * best-predicted candidate if none do. k=1 because each candidate has only 4 + * orthogonal one-hot examples (see the SAR harness note on why the default k=5 + * would collapse every query to the same prediction here). + */ +export const veilTaskRouter = new Router({ + qualityBar: 0.8, + candidates: VEIL_ROUTER_CANDIDATES, + k: 1, +}); + +/** Route one query embedding to the cost-optimal model tier. */ +export function routeVeilQuery(queryEmbedding: VeilTaskEmbedding) { + return veilTaskRouter.route([...queryEmbedding]); +} diff --git a/harness/wifi-densepose-privshield/tsconfig.json b/harness/wifi-densepose-privshield/tsconfig.json new file mode 100644 index 00000000..4f908fa4 --- /dev/null +++ b/harness/wifi-densepose-privshield/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2022"], + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist", "__tests__"] +} diff --git a/harness/wifi-densepose-privshield/vitest.config.ts b/harness/wifi-densepose-privshield/vitest.config.ts new file mode 100644 index 00000000..dede0819 --- /dev/null +++ b/harness/wifi-densepose-privshield/vitest.config.ts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// Strips the `#!/usr/bin/env node` shebang from importable entrypoints (e.g. +// bin/cli.js) before Vite parses them — Vite/esbuild (used internally by +// Vitest) does NOT strip shebangs, so importing a shebanged module throws +// `SyntaxError: Invalid or unexpected token`. No effect on direct CLI +// execution. +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + plugins: [ + { + name: 'strip-shebang', + enforce: 'pre', + transform(code: string) { + if (code.startsWith('#!')) { + return { code: code.replace(/^#![^\n]*/, ''), map: null }; + } + return null; + }, + }, + ], +}); diff --git a/v2/crates/wifi-densepose-privshield/README.md b/v2/crates/wifi-densepose-privshield/README.md index 365a65ea..139391dc 100644 --- a/v2/crates/wifi-densepose-privshield/README.md +++ b/v2/crates/wifi-densepose-privshield/README.md @@ -13,7 +13,10 @@ experiment** — not a radio driver. It never emits RF. Every number it prints i `SYNTHETIC`, reproduced by `cargo test -p wifi-densepose-privshield`. See [ADR-288](../../../docs/adr/ADR-288-veil-privacy-shield-compliant-waveform.md) -and the [research bundle](../../../docs/research/privacy-shield/). +and the [research bundle](../../../docs/research/privacy-shield/). A per-crate npm +contributor harness lives at +[`harness/wifi-densepose-privshield/`](../../../harness/wifi-densepose-privshield) +(ADR-289): `npx wifi-densepose-privshield-harness guidance --topic overview`. ## The idea diff --git a/v2/crates/wifi-densepose-privshield/src/lib.rs b/v2/crates/wifi-densepose-privshield/src/lib.rs index 27a0f5eb..75b832ae 100644 --- a/v2/crates/wifi-densepose-privshield/src/lib.rs +++ b/v2/crates/wifi-densepose-privshield/src/lib.rs @@ -79,7 +79,7 @@ pub use attacker::{Metric, NearestCentroidAttacker}; pub use compliance::ComplianceReport; pub use experiment::{run, ExperimentConfig, ExperimentReport}; pub use identity::{BfiSample, Channel, SceneConfig}; -pub use optimize::{hyper_optimize, HyperOptimized}; +pub use optimize::{adaptive_shield, hyper_optimize, HyperOptimized}; pub use proof::Proof; pub use protector::{Protector, SensingDetector, ShieldConfig}; pub use throughput::LinkModel; diff --git a/v2/crates/wifi-densepose-privshield/src/optimize.rs b/v2/crates/wifi-densepose-privshield/src/optimize.rs index 12235805..b885e20f 100644 --- a/v2/crates/wifi-densepose-privshield/src/optimize.rs +++ b/v2/crates/wifi-densepose-privshield/src/optimize.rs @@ -242,6 +242,77 @@ pub fn hyper_optimize(base: &ExperimentConfig) -> HyperOptimized { } } +// --------------------------------------------------------------------------- +// Adaptive optimization: the optimum is not one config — it depends on the +// deployment's SNR (which shifts the throughput-optimal feedback resolution) +// and its identity count (which sets how much rotation mixing collapse needs). +// These functions derive the right config per deployment rather than assuming +// the default scene. +// --------------------------------------------------------------------------- + +/// SNR values (dB) to profile the throughput-optimal feedback resolution over. +pub const SNR_PROFILE_DB: [f64; 5] = [5.0, 10.0, 20.0, 30.0, 40.0]; + +/// Unconstrained throughput-optimal feedback resolution for a specific SNR, +/// holding the rest of `base`. At low SNR the residual matters proportionally +/// more (Shannon capacity is near-linear), so higher resolution wins; at high +/// SNR the log compresses the residual away and feedback airtime dominates, +/// favoring fewer bits. (The *shipped* shield clamps to the 802.11 {5,7,9} set, +/// where 5 already zeroes the residual — so this shift is visible only in the +/// unconstrained optimum, and is what motivates keeping resolution low.) +#[must_use] +pub fn model_optimal_bits_for_snr(base: &ExperimentConfig, snr_db: f64) -> (u32, f64) { + let mut cfg = base.clone(); + cfg.link.snr_db = snr_db; + optimal_feedback_bits(&cfg, 12) +} + +/// Profile the unconstrained throughput-optimal feedback resolution across +/// [`SNR_PROFILE_DB`]. Demonstrates the SNR → resolution dependence. +#[must_use] +pub fn optimal_bits_across_snr(base: &ExperimentConfig) -> Vec<(f64, u32)> { + SNR_PROFILE_DB + .iter() + .map(|&snr| (snr, model_optimal_bits_for_snr(base, snr).0)) + .collect() +} + +/// Does `passes` collapse re-ID for both metrics at a single identity count? +#[must_use] +pub fn passes_collapse_at_n(base: &ExperimentConfig, passes: usize, bits: u32, n: usize) -> bool { + ROBUSTNESS_METRICS + .iter() + .all(|&m| run_variant(base, passes, bits, m, n).drives_to_chance()) +} + +/// Smallest pass budget that collapses re-ID for a *specific* identity count. +/// More candidates ⇒ lower chance floor ⇒ generally more mixing required, so +/// this grows with `n`. +#[must_use] +pub fn min_passes_for_n(base: &ExperimentConfig, bits: u32, n: usize) -> Option { + PASS_CANDIDATES + .iter() + .copied() + .find(|&p| passes_collapse_at_n(base, p, bits, n)) +} + +/// Derive a ready-to-ship shield for a specific deployment: throughput-optimal +/// feedback resolution for the deployment SNR, and the minimum mixing budget for +/// its identity count grown by the free [`PRIVACY_MARGIN_FACTOR`] margin. This is +/// what an operator should call for a room with `n` expected occupants on a link +/// with `base.link`'s SNR — the default config is just this at N=16. +#[must_use] +pub fn adaptive_shield(base: &ExperimentConfig, n: usize) -> ShieldConfig { + let (bits, _) = spec_optimal_feedback_bits(base); + let min_passes = + min_passes_for_n(base, bits, n).unwrap_or_else(|| *PASS_CANDIDATES.last().unwrap()); + ShieldConfig { + givens_passes: ceil_to_candidate(min_passes * PRIVACY_MARGIN_FACTOR), + feedback_bits: bits, + ..base.shield.clone() + } +} + #[cfg(test)] mod tests { use super::*; @@ -297,6 +368,50 @@ mod tests { )); } + #[test] + fn optimal_bits_shift_with_snr() { + // Low-SNR deployments favor higher feedback resolution; high-SNR favor + // lower. The (unconstrained) profile is non-increasing in SNR and not + // constant across the range. + let profile = optimal_bits_across_snr(&ExperimentConfig::default()); + let low = profile.first().unwrap().1; + let high = profile.last().unwrap().1; + assert!( + low >= high, + "low-SNR bits {low} should be >= high-SNR bits {high}" + ); + assert!(low != high, "profile did not shift with SNR: {profile:?}"); + } + + #[test] + fn adaptive_shield_mixing_is_nondecreasing_in_n() { + // A room with more candidate identities needs at least as much mixing. + // In this model the collapse budget is governed by fine-subspace + // dimension, so the requirement is flat across N — the invariant we can + // assert is non-decreasing, and that it never *under*-provisions. + let base = ExperimentConfig::default(); + let small = adaptive_shield(&base, 8); + let large = adaptive_shield(&base, 64); + assert!( + large.givens_passes >= small.givens_passes, + "N=64 passes {} should be >= N=8 passes {}", + large.givens_passes, + small.givens_passes + ); + } + + #[test] + fn adaptive_shield_collapses_at_its_target_n() { + let base = ExperimentConfig::default(); + for n in [8usize, 32, 64] { + let sh = adaptive_shield(&base, n); + assert!( + passes_collapse_at_n(&base, sh.givens_passes, sh.feedback_bits, n), + "adaptive shield for N={n} does not collapse" + ); + } + } + #[test] fn frontier_is_non_empty_and_deterministic() { // Small grid keeps this fast; the frontier logic is grid-size agnostic.