GrooveSeek

Semantic search over a Markdown knowledge base, served over MCP.

View the Project on GitHub alphabet-h/grooveseek

30. Mark table rows per chunk in a nullable column, and catch up through per-format keys

Context and problem

Since v1.18.0 (.docx) and v1.19.0 (.pptx) a table row is one line of a chunk, its cells separated by tabs. A reader that shows an excerpt, such as grooveseek-desktop, has to guess which lines are table rows from the text alone, and the guess fails both ways: a paragraph outside a table can hold a tab, and a row whose first or last cell is empty starts or ends with a tab that a trim removes. Only the parser knows which lines it wrote as rows, and it knows it per chunk.

ADR-0028 and ADR-0029 kept the schema unchanged and caught existing indexes up through policy keys. .docx now needs a fourth key, which meets ADR-0029’s revisit condition (“one format needs a fourth key of this kind”).

Decision drivers

Options considered

  1. Put a marker in the chunk text. Changes the embedding and full-text input of every .docx and .pptx chunk, so every one of them is re-embedded. Rejected.
  2. A separate table from chunk id to spans. Has to be kept in step with chunks on every write and delete path. Rejected.
  3. A nullable column on chunks. Taken: NULL says “not computed” as it is, and the value goes with its row, which upsert_document already deletes and rewrites as a whole. ADR-0028 and ADR-0029 kept the schema unchanged so that no row had to say which rules wrote it; this column holds what a chunk contains (where its rows are), not a generation of rules, so it does not run against that.

For the catch-up:

  1. Generalise the per-format keys now (ADR-0029’s revisit condition). The tests pin the existing key values and that dropping a key reopens the pass, so a general mechanism would edit them. Rejected.
  2. Use the column’s NULL as the catch-up mark. It says nothing about the rules the chunk text was cut by, so the keys would stay anyway, and two mechanisms would answer one question. Rejected.
  3. One more key per format, on the same predicate. Taken: a constant, a read and a write, and a notice.

Decision

Consequences

References