Skip to content

CRUX slice 4 (#3739): the serve verb — apr serve, llama-server and ollama through ONE OpenAI client, streaming + non-streaming, plus hf/llamafile servers #3797

Closed as not planned

Description

@noahgift

Child of #3739: slice 4, the serve verb. The issue's done_when, verbatim: "serve: apr serve · llama-server · ollama serve, all through the SAME OpenAI /v1/chat/completions client, streaming + non-streaming".

done_when

  • scripts/crux_inference_dogfood.sh <version> --verbs run,serve runs ONE serve cell per model under one hold of the GPU lock:

    • apr serve run and llama-server each load the model once, next to the running ollama daemon;
    • every golden prompt goes through scripts/lib/crux_openai_client.py, non-streaming and streaming;
    • then the servers stop, and ollama unloads (keep_alive 0, plus the unload wait).
  • One client for every server. crux_openai_client.py sends the same body (model, messages, max_tokens, temperature, seed, stream) and writes the row-contract JSON {"text", "reported": {device, stream, finish_reason, usage, chunks}}. It reads no clock and computes no rate.

  • Plugin engines (hf, llamafile) run gen --verb 'serve run', starting their own server per call (non-streaming).

  • The judge reads every serve row through the client JSON and applies the same RED rule.

    • The key gains an additive mode (nonstream | stream) for serve cells only.
    • apr serve's cells carry backend_verified: false, because the server's responses report no backend.
  • The case table covers:

    • stream and non-stream as distinct GREEN cells;
    • an apr serve that answered nothing while llama-server answered (RED).

    Mutants: drop the mode from the key; drop the backend flag.

  • A real run on lambda (cpu lane, qwen2.5-coder-1.5b Q4_K_M): apr serve, llama-server and ollama each answer every golden prompt in both modes.

  • Not in this slice, named in not_covered: TTFT and decode rate through apr test llm bench (the canonical client, PERF-009), and max accepted context.

Activity

  1. added this to the 0.69.1 milestone on Sep 21, 2026
  2. added a commit that references this issue on Sep 22, 2026
  3. noahgift commented on Sep 22, 2026

    @noahgift
    MemberAuthor

    AMENDMENT (operator, 2026-09-22): three comparators and a user-story test case

    Operator instruction: each verb MUST have two, preferably three CRUX comparators, and a "test case" user story for each. Recorded on all four verb slices (#3829 run, #3795 chat, #3797 serve, #3830 code) and on the epic #3739.

    Comparators for serve — three, all through ONE client

    # server why it is a distinct oracle
    1 llama-server (llama.cpp @ pinned d1d3c3396) the reference OpenAI-compatible server on the same GGUF
    2 ollama serve (0.33.2) a different OpenAI-compatible implementation with its own streaming framing and its own finish_reason conventions
    3 hf / llamafile servers (#3778 drivers) a non-GGUF server, so a wire-protocol defect cannot hide behind a shared runtime

    The load-bearing constraint is already in this slice and is what makes three engines meaningful: crux_openai_client.py is the only client, sending the same body to all three. A per-engine client would compare our clients, not our servers.

    Test case — user story

    As an application developer with a working OpenAI client, I change the base URL to apr serve and change nothing else. My app keeps working — streaming and non-streaming — and I get the same answers I got from llama-server.

    Acceptance, falsifiable: the same request body (model, messages, max_tokens, temperature, seed, stream) sent to all three servers returns, for each golden prompt: a 200, a non-empty choices[0].message.content (non-streaming) and a reassembled non-empty content from the chunks (streaming), containing the golden pattern. stream: true and stream: false are distinct cells — an implementation that answers one and not the other has broken half the contract, which is why the key carries mode.

    The RED rule, stated for this story: apr serve answering nothing while llama-server answers the same body is RED. This is not hypothetical — #3791 shipped a serve path that returned HTTP 500 Invalid token ID at temperature 0 and "HHHHHHHH…" at 0.8, on a model llama.cpp serves correctly.

    Known limitation, already in this slice: apr serve's responses report no backend, so cells carry backend_verified: false; TTFT and decode rate are not_covered here and belong to apr test llm bench (PERF-009).

  4. noahgift commented on Sep 22, 2026

    @noahgift
    MemberAuthor

    CORRECTION: the comparator table I posted here was wrong — llama.cpp works on BOTH hosts

    aprender-c7, 2026-09-22. Full correction with the measurements: #3829 (comment)

    I reported lambda's llama-cli broken and gx10's absent. Both readings were of PATH, not of llama.cpp:

    lambda  /home/noah/src/llama.cpp-d1d3c3396/build/bin/llama-cli   version: 0.4.1-dev (build 10987, commit d1d3c3396)
    gx10    /home/noah/src/llama.cpp-d1d3c3396/build/bin/llama-cli   version: 0.4.1-dev (build 2423,  commit d1d3c339)
    

    llama-cli, llama-server and llama-tokenize all run at the pinned sha, and bash scripts/llama_bin.sh resolves them (#3740). On lambda ~/.local/bin/llama-cli is a dead copy of the UNPINNED checkout and shadows the working one; on gx10 nothing is on PATH at all, so a lookup reports absence while the pinned build exists. CLAUDE.md Verification Discipline #8, the ~/.local/bin/apr instance, one directory over.

    So nothing needs building, and this slice is landable on both hosts. The comparator must be resolved through scripts/llama_bin.sh, never by bare name.

    Two bounds from that inventory do survive, and they are real:

  5. added a commit that references this issue on Sep 22, 2026
  6. modified the milestones: 0.69.1, 0.70.0 on Sep 24, 2026
  7. noahgift commented on Sep 24, 2026

    @noahgift
    MemberAuthor

    triage 2026-09-24 (aprender-dd, issues owner; proposal #4159, approved by the cop aprender-cf): milestoned to 0.70.0 — 0.69.x leftover, not done at the tag: release-process / CRUX release gate / comparator pin — 0.70 Fast Train. It was 0.69.1 (released). Open PR / live branch: PR#3835.

  8. modified the milestones: 0.70.0, 0.70.1 on Sep 24, 2026
  9. noahgift commented on Sep 24, 2026

    @noahgift
    MemberAuthor

    Milestone 0.70.0 → 0.70.1 (gate triage). 0.70.0 now holds only the operator's release gate: "FULL ontology spec and all aprender binary working" + "0.70 to crates.io" (ONT-001, every [[bin]] build+smoke, the publish cascade), plus P0s and operator-ruled rows. This issue isn't needed for any of those. Evidence: evidence/m070-gate-triage-1835.md. If that's wrong, move it back to 0.70.0 and say which gate it serves.

  10. noahgift commented on Sep 24, 2026

    @noahgift
    MemberAuthor

    done_when audit (apr-features): items 1-5 and 7 are met. Item 5 gains 2 mutants on feat/3797-crux-serve-verify @6ab17f9b4, which folds after merge-back #4224. Item 6 (real GREEN run) cannot be met as written: qwen2.5-coder-1.5b is not in prompt-certification.json and there is no hf/vllm ground truth. Proposed amendment: run on a certified Qwen3.5-4B-family sha, or certify coder-1.5b first. The real run found #4339 (/v1/completions stop overrun, 13/13), #4340 (im_end stream leak) and #4341 (sweep timeout discards rows). Receipt: cop-inbox/evidence/apr-features-3797-audit.md

  11. added 2 commits that reference this issue on Sep 24, 2026
  12. 14 remaining items

  13. added
    P2Medium priority
    and removed
    P0Critical priority
    on Oct 14, 2026
  14. noahgift commented on Oct 14, 2026

    @noahgift
    MemberAuthor

    P0 to P2 (2026-10-14 P0 triage): P0 now means it blocks the next release or carries the operator's own words on it; this issue does neither, and its milestone is 0.73.0.

  15. noahgift commented on Oct 14, 2026

    @noahgift
    MemberAuthor

    merged into #5313 (master ticket for epic #3999; triage rule 7b, 2026-10-14). It is a checklist row there; reopen this issue when work on it starts or its PR opens.

  16. noahgift commented on Oct 14, 2026

    @noahgift
    MemberAuthor

    Moved: this sub-ticket is now a row in #5336 (CRUX verb parity: chat, serve and perf receipts against llama.cpp and ollama), split out of #5313 by theme.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions