Searchable metadata, sealed field values
Scheduled4 min read By NT²
A vault that cannot find a title is unusable. A vault that full-text indexes every password on a server is not a vault. The boundary is projected metadata versus sealed field values.
Searchable metadata, sealed field values
Claim: two representations, one honest boundary
Compose domains from one type system explained how packs and templates scale. This essay names the storage boundary those fields must cross: what the list can see versus what only an unlock can see.
The claim: searchable metadata and sealed field values are different layers on purpose. Titles, categories, and carefully projected search text keep a large vault navigable. Sensitive values leave RAM as portable ciphertext—CBF payload blobs addressed by stable field indices—not as JSON keys waiting for the next indexer.
Zero-knowledge is not “we encrypted the database file.” It is a rule about which bytes exist in cleartext for local UX, and which bytes exist only as sealed boxes for disk, backup, and optional sync.
The constraint: index everything or find nothing
Two failure modes dominate structured vaults.
Index everything. Put field maps in plaintext JSON (or decryptable server indexes) so search feels magical. You gain convenience and lose the product. Anyone with the database file, the backup zip, or the sync operator seat can read life data. “Encrypted at rest” becomes a checkbox around a searchable honey pot.
Seal everything, including titles. Store only opaque blobs. Search dies. Users reopen items one by one. The structured model’s list UX—the reason slots beat blank pages—collapses into a mystery archive.
A third failure is subtler: encrypt JSON that still contains free-form string keys. You get ciphertext without evolvable layout. Renames break readers. Synonyms multiply. Blind sync still should not parse fields—but your own future clients must.
NT² needs local search that stays useful at thousands of items, and a wire shape that never asks the edge to understand a password field.
The design: project on save, seal by index
Deliberate plaintext metadata
List rows need a small cleartext surface: title, category, lifecycle flags, list preview text, and other filter columns. Full-text search over titles (and allowed projected text) lives in the local SQLite engine—see FTS5 for titles; table scan when filters win and Never load the whole vault into Svelte state. That metadata is chosen, not “whatever was in the form.”
Capability-gated projection
On save, the Writer tab projects only fields whose semantic types allow search indexing into a local search blob. Secrets stay out. The list subtitle can come from a priority among non-secret fields so a bank row shows an institution-shaped hint without dumping the account number into FTS.
Projection is a client job after unlock. It is not a server-side parse of ciphertext.
Domain id → wire field index
In memory, values are keyed by semantic field ids. Before encryption, the payload encoder maps those ids to stable numeric field indices from the registry manifest, packs them into a payload blob, and seals the blob as CBF under the object’s content key—detailed in CBF is how structured fields leave RAM and the envelope essay One key per object: envelope encryption inside NT² Vault.
flowchart LR
Edit[Field map in RAM] --> Proj[Project safe metadata]
Edit --> Blob[Payload blob by fieldIndex]
Proj --> List[List / FTS columns]
Blob --> Box[CBF ciphertext]
Box --> Disk[SQLite / backup / sync]
Ciphertext does not carry a folklore of password string keys. It carries
indices the registry understands. Template context travels with the blob so
readers know which category schema applies—without inviting the edge to interpret
values.
The edge stays blind
Optional Premium sync relays opaque frames and account metadata. Workers are not handed a field dictionary for your vault. If an operator tool must parse notes to “help,” the boundary already failed. The companion boundary essays— Blind replica sync on the edge and What the Workers are allowed to see—sit beside this one.
The trade-off: secrets are not a global full-text corpus
You cannot paste half a password and expect cloud search to find it. You cannot ask the server to classify your medical fields. Local projection only includes what types allow. Attachment bytes are not a free full-text corpus either; metadata and titles carry the findability load unless a future product surface explicitly says otherwise.
What you keep is stronger: a navigable vault when locked metadata is enough, and sealed values that do not become an offline password oracle for someone else.
| Layer | Cleartext role | Sealed role |
|---|---|---|
| Title / category | List + FTS | — |
| Search projection | Allowed non-secret field text | — |
| Passwords, seeds, account digits | — | CBF field indices |
| Edge sync | Identity / billing / opaque bytes | Relays boxes, does not parse fields |
What we refuse
We refuse server-side plaintext search of vault contents. Convenience that requires the operator to read fields is not a feature.
We refuse free-form string keys scattered through durable ciphertext. Registry indices exist so payloads evolve without synonym soup.
We refuse treating compression or “encrypted disk” as a substitute for sealed payloads. CBF and per-object keys are the item boundary; filesystem encryption is someone else’s layer.
We refuse listing every secret into FTS “just in case.” Searchability is a capability, not a default for every column.
Find the row, open the seal
Structure without findability is a filing cabinet with the labels painted over. Findability without seals is a spreadsheet with a padlock sticker. NT² keeps both layers—and keeps them distinct.
Finish the series arc with Four surfaces, one field set—how edit, view, present, and features read the same active fields without a second data model. For FTS strategy detail, stay with FTS5 for titles; table scan when filters win.
Last updated 2026-11-26
Related stories
- Slots, not a blank page
6 min read
- CBF is how structured fields leave RAM
9 min read
- FTS5 for titles; table scan when filters win
8 min read