Sanitization by Construction: Bounded Context Before the Network
Regex redaction on arbitrary broker exports fails the moment a column renames, a locale shifts decimal separators, or a merged cell appears. We chose structural exclusion: the Ask AI path never serializes a free-form ledger string because we never build one for the model.
The mechanism is buildPortfolioContext in app/lib/ai/contextBuilder.ts.
Edge Compiler = function contract, not a package
Edge Compiler is a term of art for this deterministic reduction. There is no EdgeCompiler npm module — only a pure function with a fixed output template:
const TOP_HOLDINGS_COUNT = 10;
// ...
lines.push('Portfolio summary (for personalization only):');
lines.push(`Total positions: ${totals.totalPositions}`);
lines.push(`Total trades: ${trades.length}`);
// Top holdings: ticker, shares, currency, value %, P/L %
Source comment (accurate):
// No raw ledger rows, no PII, no account identifiers—sanitization by construction.
Two pipelines — do not conflate
| Stage |
Input → output |
What crosses the network for Ask AI |
| Import |
Broker CSV → Trade[] via packages/importer |
Not the default Ask AI body (Part 5) |
| Context build |
Trade[] + positions → template string |
Yes — bounded aggregate only |
Import may touch account-ish columns while parsing; the inference boundary is the second stage. By the time buildPortfolioContext runs, only template fields can appear in the output lines.
What the LLM receives
Approved: “The LLM receives a bounded, user-approved aggregate context payload.”
Prohibited: “AI never sees your data.” The model also receives the user message, optional attachment content (explicit user action), and route-defined server injections (e.g. live quotes) per app/api/ai/chat/route.ts and docs/IP-TECHNICAL-MECHANISMS.md.
Approved: No PII and no account identifiers on the Pocket Analyst inference path as designed in contextBuilder.ts.
On a typical allocation question:
- Client calls
buildPortfolioContext(trades, positions).
- Network tab shows a short
context field in the POST body — not 10,000 trade rows.
- Compare to guest
localStorage or Firebase-backed trade count in application state — orders of magnitude larger than the payload.
Reduction is O(n) over trades for position derivation plus sort of position list for top-N — typically milliseconds on-device. Publish latency numbers only after measurement on target hardware.
Part 2 of Sovereign Ingestion & Stateless Inference.
Read the full Sovereign Intelligence book, explore Open Portfolio, or try Pocket Portfolio.