@gracek1459/whitespace-prior-art

0
1
flwr new @gracek1459/whitespace-prior-art

Whitespace: private prior-art triage on Flower

Ask whether your idea is novel without showing the whole idea to every source. Each source is a Flower node (a ClientApp on its own SuperNode) holding its own data.

uv sync # builds .venv from uv.lock (flwr 1.39.0) .venv/bin/python app.py # live web app on http://127.0.0.1:8765 (stdlib only) .venv/bin/python run.py --auto-approve # CLI demo; drop the flag for the interactive approval gate .venv/bin/python eval.py # sanity checks on the synthetic corpus open out/report.html

Everything in this app is SYNTHETIC demo data (fictional papers, patents and company portfolios in nodes_data.py). No external data or flwr-datasets download is needed.

Run with flwr run (Simulation Runtime)

The app needs exactly 8 virtual SuperNodes (one per source in nodes_data.py; partition-id 0..7 picks the source). The default local simulation has 2, so set the size on the command line:

flwr run . --federation-config "num-supernodes=8" --run-config "approved=true" --stream

Nothing is sent unless approved=true: that flag is the approval gate for flwr run. Review the elements in [tool.flwr.app.config] (one element per line) before setting it. Other run-config keys:

keydefaultmeaning
elementsthe four example elementstext sent to every node, one element per line
approvedfalseapproval gate; the ServerApp refuses to send anything while false
approved-design-aroundfalsealso allow automatic rewrites of approved elements to be sent
design-around-rounds3maximum design-around rounds
num-nodes8SuperNodes the ServerApp waits for (up to 90 s) before sending
out""path to write results.json; empty prints the result only

Example with design-around and a custom idea:

flwr run . --federation-config "num-supernodes=8" --stream
--run-config 'approved=true approved-design-around=true elements="first element\nsecond element"'

The result (matrix, mediator notes, conflicts per round, audit count) is printed by the ServerApp.

Run on the Deployment Runtime

Start one SuperNode per source and give each a distinct node-index from 0 to 7 (0-2 papers, 3-5 patents, 6-7 confidential portfolios, in the order of nodes_data.py):

flower-supernode --insecure --superlink <superlink-host>:9092 --node-config "node-index=0"

... repeat with node-index=1 .. 7

Then flwr run . <your-superlink-connection> --run-config "approved=true" --stream. The code is the same in both runtimes; only the node config key differs (partition-id vs node-index).

60-second demo script (web app)

Start: .venv/bin/python app.py, open http://127.0.0.1:8765, press ? for shortcuts. Everything shown is synthetic demo data; latencies and counts come from the run itself.

  1. Run demo (or R). The approval gate opens with the four example elements. Untick one to show it drop out of "What leaves your machine"; tick it back. Expand a private node to show it may only return {name, kind, element_id, signal}.
  2. Approve and send (or Ctrl/⌘+Enter). Pulses go out to all eight nodes; replies come back and colour each node. The first row takes a few seconds (it includes simulation start-up); later rows took about 50 to 110 ms per reply in our test runs. Expected result: E1 covered by Paper 1 and Patent 1, E3 covered by Paper 2 with Private Co. X high, E4 covered by Patent 2 with Private Co. Y high, E2 open.
  3. Trust tab (1): all five invariants turn PASS as the run completes.
  4. Click the E1 × Paper 1 cell: the quoted evidence is highlighted in the paper's text. Click E3 × Private Co. X: only the high signal, no text.
  5. Design-around tab (2): conflicts per round 6 → 5 → 4 → 3, each rewrite with its accept/reject reason, and the before/after wording.
  6. Export report (E) downloads the HTML report for the run.

Fallback if the live run misbehaves: switch to Replay (L), pick "demo_backup (known-good run)", press Replay. It re-plays a saved live run with the same animations; nothing is sent and Flower is not started. .venv/bin/python app.py --replay demo_backup opens straight into it, and --replay out/results.json replays a CLI run (latency shown as "not recorded").

Troubleshooting:

  • Use the project venv (uv sync, then .venv/bin/python, flwr 1.39.0); a system Python with an older flwr will fail.
  • Ray on small machines: keep client_resources at num_cpus=1 (run.py --cpus 1, the default).
  • Nodes register asynchronously; the ServerApp polls grid.get_node_ids() for up to 90 s before sending. A slow first row is start-up, not a hang.
  • "a run is already in progress": wait for the current run to finish (one run at a time).
  • Port in use: .venv/bin/python app.py --port 9000.
  • A run that dies shows an error in the event stream; the Flower log is in runs/<id>/log.txt.

Flower pieces used (checked against flwr 1.39.0 in the sandbox)

  • ClientApp with @app.query("ask"): each node answers one element per message
  • ServerApp with @app.main(): coordinator, mediator and design-around loop
  • Grid.create_message(..., "query.ask", node_id, group) + Grid.push_messages / Grid.pull_messages (replies are timed individually as they arrive)
  • context.node_config["partition-id"] (simulation) or ["node-index"] (deployment) picks a node's data
  • context.run_config carries the job under flwr run
  • flwr.simulation.run_simulation(...): used by run.py, eval.py and the web app (8 SuperNodes)

Layout

  • nodes_data.py SYNTHETIC papers, patents, private portfolios (client side only)
  • matching.py simple deterministic matching (swap for embeddings or an LLM judge)
  • client_app.py node behaviour; private nodes may only reply {signal: high|low}
  • server_app.py coordinator, mediator notes, design-around loop, audit log
  • run.py planner stub, human approval gate, simulation, HTML report
  • eval.py recall, false conflicts, unsupported "covered", private-text leaks
  • app.py local web app: launches run.py --job as a subprocess, streams events.jsonl (SSE)
  • ui_page.py the single-page UI as one HTML string (no build step, no CDN; works offline)
  • pyproject.toml, uv.lock Flower app metadata and locked dependencies (managed with uv)
  • invariants.py safety checks recomputed from a run's files (python invariants.py runs/<id>)
  • labels.py hand-written synthetic labels shared by eval.py and invariants.py
  • demo_backup/ one known-good live run (events, results, gate, job, report) for Replay mode

Safety properties (enforced in code)

  • The ServerApp refuses to run unless the approval gate passed; unapproved elements are never sent.
  • A public node may answer covered only with a quoted span from its own document.
  • Private nodes cannot return text; eval.py checks their replies have no extra fields.
  • Every outbound query is logged in results.json under audit.

Honest limits

  • Matching is keyword overlap, not understanding. The planner and design-around proposer are rule-based stand-ins for LLM agents (see plan() and propose()).
  • The corpus and eval labels are synthetic and hand-written: eval.py is a regression check, not evidence of accuracy on real patents.
  • Coarse signals can still leak information; this is reduced exposure, not privacy.
  • The Simulation Runtime path (flwr run, run.py, the web app) is tested; the Deployment Runtime instructions follow the flwr 1.39 CLI but have not been run end-to-end with real SuperNodes.
  • run_simulation is deprecated in flwr 1.39 in favour of flwr run; run.py, eval.py and the web app still use it (it works on 1.39); flwr run is supported as described above.
  • Screening triage only. Not legal advice.

License

Apache-2.0, see LICENSE.