Skip to content

Say where the content sketch is stored, and why it has no table - #133

Merged
pedersen merged 1 commit into
mainfrom
worktree-sketch-storage-note
Sep 5, 2026
Merged

Say where the content sketch is stored, and why it has no table#133
pedersen merged 1 commit into
mainfrom
worktree-sketch-storage-note

Conversation

@pedersen

@pedersen pedersen commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Answers, in the plan itself, the question Step 11 provoked: where does the
content sketch actually live?

Step 11 named the metric and parked its parameters, but never said what the
sketch physically is or where it is stored. A reader arriving at "shingled
MinHash" reasonably expects a table — that is the shape most MinHash
implementations take, because most of them do corpus-wide nearest-neighbour
search and need banding to make it tractable.

Neither holds here, and now the step says so:

  • One opaque BLOB in the note's own catalog row, not a table of its own.
    That is Decision 7's "stored per note in the catalog beside the hash" taken
    literally, and it is the sketch column Step 3 already specifies.
  • The shingles are never stored. The k-grams are transient inputs to the
    hashing; only the fixed-width signature survives. Storing the shingle set
    would amount to a second copy of the note's content, since a k-gram set is
    roughly the size of the text it came from.
  • No banding or LSH index, and that is a consequence of the query rather
    than an omission. Decision 7 compares an unmatched path against the sketches
    of recently-missing notes, so the candidate set is the handful that went
    missing in one scan — loading those rows and comparing pairwise is the whole
    algorithm.
  • The coupling that follows, recorded so nobody has to rediscover it: if a
    later feature ever wants similarity across the whole engram instead of
    across the missing set, the BLOB column becomes a full scan and a band
    table keyed by band hash is the additive escape hatch. Not to be built
    before something needs it.
  • Why the column is untyped BLOB with no fixed length: the sketch width
    is that same bullet's decision to make, and Step 3 round-trips the bytes
    without interpreting them.

Note on ordering

This says "the sketch column that step 3 already created", which matches the
column list in the plan's own Step 3 section. The code behind it is in #131,
still open — if that PR's shape changes in review, this wording is worth a
second look, but it is written against the plan's spec rather than against the
implementation.

Docs only — no code, no user-facing change, so docs/manual-test-plan.md is
untouched: no cases added, changed, or invalidated.

🤖 Generated with Claude Code

Step 11 named the metric and parked its parameters, but never said what the
sketch physically is or where it lives. A reader arriving at the step finds
"shingled MinHash" and reasonably expects a table — the shape most MinHash
implementations take, because most of them do corpus-wide nearest-neighbour
search and need banding to make it tractable.

Neither is true here. The sketch is one opaque BLOB in the note's own
catalog row, which is Decision 7's "stored per note in the catalog beside
the hash" taken literally, and the shingles themselves are never stored at
all: the k-grams are transient inputs to the hashing, and only the
fixed-width signature survives. Storing the shingle set would amount to a
second copy of the note's content.

The absence of banding is a consequence of the query, not an omission.
Decision 7 compares an unmatched path against the sketches of
recently-missing notes, so the candidate set is the handful that went
missing in one scan rather than the engram; loading those rows and comparing
pairwise is the whole algorithm. Records the coupling that follows — a
candidate set that ever widens to the whole engram turns the column into a
full scan, and a band table is the additive escape hatch — so the next
person to want corpus-wide similarity finds the reasoning instead of
rediscovering it.

Also states why the column is an untyped BLOB: the width is this step's to
decide, and step 3 stores the bytes without interpreting them.

Docs only; no code and no user-facing change, so docs/manual-test-plan.md is
untouched — no cases added, changed, or invalidated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

Coverage after merging worktree-sketch-storage-note into main will be

98.35%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
lib
   app.dart96.61%100%100%96.61%142–143
   startup_options.dart100%100%100%100%
   cli_output_io.dart0%100%100%0%10–11, 9
   cli_output_stub.dart0%100%100%0%5
lib/about
   about_screen.dart98.66%100%100%98.66%94–95
lib/commands
   app_commands.dart100%100%100%100%
   app_menu_bar.dart100%100%100%100%
   app_shortcuts.dart97.22%100%100%97.22%161
   text_editing_commands.dart100%100%100%100%
   pending_saves.dart100%100%100%100%
lib/engram
   built_in_engrams.dart100%100%100%100%
   engram_repository.dart98.33%100%100%98.33%311, 49
   engram.dart100%100%100%100%
   engram_scope.dart100%100%100%100%
   engram_startup_gate.dart100%100%100%100%
   repository_scope.dart100%100%100%100%
   asset_engram_store.dart98.15%100%100%98.15%92
   engram_store.dart100%100%100%100%
   desktop_folder_adoption.dart90%100%100%90%70
   engram_file_ops.dart100%100%100%100%
   metadata.dart100%100%100%100%
   id.dart100%100%100%100%
   container_resolver.dart100%100%100%100%
lib/engram/crdt
   app_data_source.dart100%100%100%100%
   app_data_resolver_io.dart100%100%100%100%
   app_data_resolver_stub.dart100%100%100%100%
   metadata_db_stub.dart100%100%100%100%
   metadata_db_io.dart100%100%100%100%
   schema.dart100%100%100%100%
lib/engram/fs
   engram_location.dart100%100%100%100%
   fs_store_io.dart100%100%100%100%
   fs_store_stub.dart100%100%100%100%
lib/engram/ui
   engram_browser.dart98.06%100%100%98.06%195, 197, 199–200, 204–205, 399, 423, 917
   browser_preferences.dart92.31%100%100%92.31%26
   document_edit_controller.dart100%100%100%100%
   engram_switcher.dart93.81%100%100%93.81%102–105, 212, 216
   file_tree.dart100%100%100%100%
   file_tree_node.dart100%100%100%100%
   file_viewer.dart100%100%100%100%
   folder_picker.dart100%100%100%100%
   help_overlay.dart90.91%100%100%90.91%100–102, 72
   file_path_breadcrumb.dart100%100%100%100%
   markdown_editor_pane.dart100%100%100%100%
   markdown_reader.dart100%100%100%100%
   find_in_page.dart100%100%100%100%
   markdown_source_editor.dart100%100%100%100%
lib/settings
   app_settings_controller.dart100%100%100%100%
   settings_scope.dart75%100%100%75%45–46
   device_settings.dart100%100%100%100%
   settings_store.dart98.04%100%100%98.04%206
   settings_screen.dart100%100%100%100%
   engram_pane.dart100%100%100%100%
   housekeeping_pane.dart100%100%100%100%
   setting_control.dart76.47%100%100%76.47%100, 124, 86, 93
   settings_controls.dart100%100%100%100%
   settings_registry.dart85.09%100%100%85.09%215–216, 237, 246–247, 259, 31, 36–37, 41, 52–55, 64, 82–83
   settings_shell.dart99.44%100%100%99.44%244
lib/theme
   app_settings.dart100%100%100%100%
   app_theme.dart90.91%100%100%90.91%14
   design_language.dart100%100%100%100%
lib/widgets
   app_scaffold.dart100%100%100%100%
lib/window
   window_state_stub.dart66.67%100%100%66.67%13

@pedersen
pedersen merged commit 8851f80 into main Sep 5, 2026
2 checks passed
@pedersen
pedersen deleted the worktree-sketch-storage-note branch September 5, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant