Skip to content

feat(s134): the Tier 3 embedder client and its four gates - #121

Open
HackTuah wants to merge 1 commit into
slice/133-embedder-ladder-static-floorfrom
slice/134-tier3-embedder-client
Open

HackTuah wants to merge 1 commit into
slice/133-embedder-ladder-static-floorfrom
slice/134-tier3-embedder-client

Conversation

@HackTuah

@HackTuah HackTuah commented Oct 8, 2026

Copy link
Copy Markdown
Member

Slice 134, the Tier 3 embedder client and its four gates. Stacked on #119 (slice 133): this PR's base is 133's branch, so the diff shows 134 alone. Merge #119 first; GitHub then retargets this PR to main.

The slice stays in_progress until the owner reruns the gates on the Iron Bank image. registry1 refused the pull without an account, so the gates ran on upstream ollama/ollama:0.40.0, the version Iron Bank's repo pins.

What lands

  • The Ollama client:
    • every request sends truncate:false and the pinned num_ctx;
    • it counts tokens itself, with a pure-Elixir byte-level BPE read from the verified GGUF;
    • a service that truncates silently is detected through prompt_eval_count and turned off;
    • each vector's width and norm are checked.
  • A digest watch on /api/tags: a swapped model turns semantic memory off with :model_digest_changed. Full-text search keeps answering and no other space is selected.
  • mix trinity.tier3.import: a signed import, in order:
    1. cosign verification offline against the operator's key;
    2. every blob's digest checked;
    3. OMS over the model files, and the GGUF digest checked against the OMS statement;
    4. Ollama create, and the resulting digest recorded.
      The verifiers are the reference CLIs, called with an argument list and no shell.
  • Optional callbacks on 133's embedder behaviour, so the locality and configuration checks no longer name an embedder.
  • Docs: docs/tier3-embedder.md, an operator guide; and egress rows in docs/regulated/data-flow.md.

Gates, MEASURED 2026-10-08

Qwen3-Embedding-0.6B f16, CPU only, on an AMD Ryzen AI MAX+ 395.

Gate Result Red
1 parity min cosine 0.99969, 500 of 500 at or over 0.999 num_ctx 256: 440 of 500, FAIL
2 truncation 512 tokens with truncate:false gives HTTP 400, no vector truncate on returns a vector
3 digest pin off 160 ms after the blob swap check removed: still on after 7.4 s
4 offline --network none; /api/embed serves; a pull fails n/a
5 throughput batch 1 p95 57.7 ms; batch 32 p95 1382 ms no pass mark

Q8_0 fails parity (min 0.99854) and is not offered.

Evidence

  • Author's gate: exit 0, 1071 passed (21 properties, 1050 tests), 41 excluded, coverage 80.81%.
  • Reviewer re-run before commit:
    • the 7 changed and new test files: 61 passed, 11 excluded;
    • --only signing_tools with the real cosign v3.1.3 and model_signing 1.1.1: 7 passed;
    • mix format --check-formatted OK; mix credo --strict --all found no issues.
  • CI: cannot run the 7 :signing_tools cases until it installs those two programs. A follow-up.

Slice 134, stacked on slice 133. Every gate passed on this machine
against the upstream ollama/ollama:0.40.0, the version Iron Bank pins.
registry1 refused the pull without an account, so the rerun on the Iron
Bank image is the owner's.

- Trinity.Memory.Embedders.Ollama, the client:
  - every request sends truncate:false and the pinned num_ctx;
  - it counts tokens itself with a pure-Elixir byte-level BPE read from
    the verified GGUF, and refuses an over-length input before sending;
  - a prompt_eval_count below its own count turns it off until restart;
  - each vector's width and norm are checked;
  - the /api/tags digest is the space's revision, and the GGUF and
    tokenizer digests, num_ctx, both prompt templates and the Ollama
    version are fields of their own.
- A supervised watch of /api/tags turns semantic memory off with
  :model_digest_changed within one interval, while full-text search keeps
  answering and no other space is selected.
- The signed import, mix trinity.tier3.import:
  - cosign offline against the operator's key;
  - every blob's digest checked, then OMS over the model files and the
    GGUF digest against the OMS statement;
  - then /api/blobs, /api/create and a /api/show check, and the
    resulting digest recorded.
  The verifiers are the reference CLIs, run with an argument list.
- 133's embedder behaviour gains optional callbacks for the query
  template, the endpoint, the configuration check and children, so
  locality and configuration checks no longer name an embedder.

Measured gates (Qwen3-Embedding-0.6B f16, CPU):
- Gate 1, parity: min cosine 0.99969 on 500 of 500.
- Gate 2: 512 tokens with truncate:false gives HTTP 400, no vector.
- Gate 3: off 160 ms after the blob swap.
- Gate 4: offline start served /api/embed with networking disabled.
Q8_0 fails parity and is not offered. Red evidence R1 to R11 is in the
slice NOTES; the gate reds are in the gate logs.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
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