GrooveSeek

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

View the Project on GitHub alphabet-h/grooveseek

25. Skip inputs the embedding endpoint rejects, and retry the failures that pass

Context and problem

With provider = "openai-compatible" (ADR-0022), every file that rebuild_index (grooveseek/src/indexer.rs) re-embeds is one or more HTTP requests. Until this record, any failed request stopped the whole run with failed to embed chunks for <file>. The walk visits files in the same order every time, so the next run stopped at the same file, and the files after it were never indexed. The steps that follow the loop never ran either: the sweep that removes rows for deleted files, and the recording of the declared-field set.

Two kinds of failure did this, and they are different in kind:

The question is how groove index, MCP rebuild_index and the watcher should treat each, without hiding a configuration error behind a run that looks successful.

Decision drivers

Options considered

  1. Which failures skip a file.
    • Skip the file on any failure. Rejected: a 401 or a wrong dimension would turn every file into a skip, and the run would report success.
    • Skip only on a failure caused by the input: HTTP 400, 413 and 422. Taken.
    • Stop on every failure, as before. Rejected: it is the problem above.
  2. How to bound a long input before it is sent.
    • By tokens. Rejected: groove holds no tokenizer for the model behind an alias, and cannot know which one the endpoint uses.
    • By bytes. Rejected: a byte limit cuts inside a multi-byte character and means a different amount of text per script.
    • By characters (Unicode scalar values). Taken. The unit does not match the server’s token limit, and an input that is still too long falls to the skip above.
  3. What the retry exposes as configuration.
    • The wait times as keys as well. Rejected: more frozen keys, and nobody has asked to tune them.
    • max_retries alone; the waits are constants. Taken.
    • No key at all. Rejected: a latency-sensitive daemon needs a way to turn the retries off (see Consequences).
  4. What a run with rejections reports.
    • Always exit 0. Rejected: a configuration error that the endpoint answers with 400 would look like a clean run with many skips.
    • Exit non-zero on any rejection. Rejected: one oversized chunk in a large, healthy knowledge base would fail every run.
    • Exit non-zero only when the run had a rejection and the endpoint accepted nothing. Taken. That pattern points at model / document_model or endpoint rather than at the files. A file refused only after the endpoint accepted an earlier batch of it counts as accepted, not as such a rejection: the accepted batch shows the configuration works.

Decision

A rejected input skips its file; a transient failure is retried; a run that only saw rejections fails after it has finished.

Consequences

References