@miller-tech/uap 2.16.6 → 2.19.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +1 -1
  2. package/config/capacity-policy.json +33 -0
  3. package/config/model-profiles/qwen38.json +32 -33
  4. package/dist/.tsbuildinfo +1 -1
  5. package/dist/bin/cli.js +57 -0
  6. package/dist/bin/cli.js.map +1 -1
  7. package/dist/capacity/policy.d.ts +32 -1
  8. package/dist/capacity/policy.d.ts.map +1 -1
  9. package/dist/capacity/policy.js +123 -4
  10. package/dist/capacity/policy.js.map +1 -1
  11. package/dist/capacity/probe.d.ts +26 -0
  12. package/dist/capacity/probe.d.ts.map +1 -1
  13. package/dist/capacity/probe.js +84 -3
  14. package/dist/capacity/probe.js.map +1 -1
  15. package/dist/cli/inference.d.ts +4 -0
  16. package/dist/cli/inference.d.ts.map +1 -1
  17. package/dist/cli/inference.js +74 -8
  18. package/dist/cli/inference.js.map +1 -1
  19. package/dist/cli/merge-gate.d.ts +59 -0
  20. package/dist/cli/merge-gate.d.ts.map +1 -0
  21. package/dist/cli/merge-gate.js +238 -0
  22. package/dist/cli/merge-gate.js.map +1 -0
  23. package/dist/cli/merge-queue.d.ts +13 -0
  24. package/dist/cli/merge-queue.d.ts.map +1 -1
  25. package/dist/cli/merge-queue.js +48 -2
  26. package/dist/cli/merge-queue.js.map +1 -1
  27. package/dist/cli/mission.d.ts +25 -0
  28. package/dist/cli/mission.d.ts.map +1 -0
  29. package/dist/cli/mission.js +225 -0
  30. package/dist/cli/mission.js.map +1 -0
  31. package/dist/cli/orch.d.ts +27 -0
  32. package/dist/cli/orch.d.ts.map +1 -0
  33. package/dist/cli/orch.js +70 -0
  34. package/dist/cli/orch.js.map +1 -0
  35. package/dist/cli/systemd-services.d.ts.map +1 -1
  36. package/dist/cli/systemd-services.js +44 -0
  37. package/dist/cli/systemd-services.js.map +1 -1
  38. package/dist/delivery/merge-gate.d.ts +168 -0
  39. package/dist/delivery/merge-gate.d.ts.map +1 -0
  40. package/dist/delivery/merge-gate.js +309 -0
  41. package/dist/delivery/merge-gate.js.map +1 -0
  42. package/dist/inference/analysis.d.ts +69 -3
  43. package/dist/inference/analysis.d.ts.map +1 -1
  44. package/dist/inference/analysis.js +123 -7
  45. package/dist/inference/analysis.js.map +1 -1
  46. package/dist/inference/probe.d.ts +38 -1
  47. package/dist/inference/probe.d.ts.map +1 -1
  48. package/dist/inference/probe.js +303 -30
  49. package/dist/inference/probe.js.map +1 -1
  50. package/dist/inference/strata.d.ts +95 -0
  51. package/dist/inference/strata.d.ts.map +1 -0
  52. package/dist/inference/strata.js +167 -0
  53. package/dist/inference/strata.js.map +1 -0
  54. package/dist/mission/database.d.ts +29 -0
  55. package/dist/mission/database.d.ts.map +1 -0
  56. package/dist/mission/database.js +131 -0
  57. package/dist/mission/database.js.map +1 -0
  58. package/dist/mission/ledger.d.ts +109 -0
  59. package/dist/mission/ledger.d.ts.map +1 -0
  60. package/dist/mission/ledger.js +294 -0
  61. package/dist/mission/ledger.js.map +1 -0
  62. package/dist/mission/poll-cycle.d.ts +73 -0
  63. package/dist/mission/poll-cycle.d.ts.map +1 -0
  64. package/dist/mission/poll-cycle.js +100 -0
  65. package/dist/mission/poll-cycle.js.map +1 -0
  66. package/dist/mission/poll-executor.d.ts +91 -0
  67. package/dist/mission/poll-executor.d.ts.map +1 -0
  68. package/dist/mission/poll-executor.js +328 -0
  69. package/dist/mission/poll-executor.js.map +1 -0
  70. package/dist/models/types.d.ts.map +1 -1
  71. package/dist/models/types.js +33 -27
  72. package/dist/models/types.js.map +1 -1
  73. package/dist/self-tuning/profiles/qwen38.d.ts +13 -14
  74. package/dist/self-tuning/profiles/qwen38.d.ts.map +1 -1
  75. package/dist/self-tuning/profiles/qwen38.js +17 -18
  76. package/dist/self-tuning/profiles/qwen38.js.map +1 -1
  77. package/dist/types/mission.d.ts +80 -0
  78. package/dist/types/mission.d.ts.map +1 -0
  79. package/dist/types/mission.js +12 -0
  80. package/dist/types/mission.js.map +1 -0
  81. package/docs/architecture/adr/0003-mission-orchestrator.md +99 -0
  82. package/docs/architecture/adr/0004-deterministic-merge-gate.md +127 -0
  83. package/docs/guides/CAPACITY_POLICY.md +49 -0
  84. package/docs/guides/INFERENCE_HEALTH.md +65 -8
  85. package/docs/guides/MISSIONS.md +170 -0
  86. package/docs/guides/PROXY.md +2 -0
  87. package/docs/reports/2026-10-02-plane-admin-fail-closed.md +70 -0
  88. package/docs/reports/2026-10-02-plane-admin-protect-session.md +116 -0
  89. package/docs/visual/merge-gate.html +404 -0
  90. package/docs/visual/mission-orchestrator.html +472 -0
  91. package/package.json +2 -2
  92. package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
  93. package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
  94. package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
  95. package/src/policies/enforcers/plane_admin_protect.py +133 -0
  96. package/src/policies/schemas/policies/plane-admin-protect.md +55 -0
  97. package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
  98. package/templates/hooks/uap-policy-gate.sh +33 -0
  99. package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
  100. package/tools/agents/scripts/anthropic_proxy.py +522 -45
  101. package/tools/agents/tests/test_anthropic_proxy_streaming.py +171 -0
  102. package/tools/agents/tests/test_gate_failclosed_plane_admin.py +248 -0
  103. package/tools/agents/tests/test_plane_admin_protect.py +124 -0
  104. package/tools/agents/tests/test_repeat_call_guard.py +64 -0
  105. package/tools/agents/tests/test_stream_heartbeat.py +77 -0
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  [![Tests](https://img.shields.io/badge/tests-450%2B_suites-brightgreen)](#testing)
10
10
  [![License](https://img.shields.io/badge/license-MIT-black)](LICENSE)
11
11
 
12
- `v2.11.0` · 367 TypeScript modules across 26 subsystems · 459 vitest suites (+ a ~1,200-test Python enforcer/proxy suite) · 9 agent harnesses
12
+ `v2.16.6` · 367 TypeScript modules across 26 subsystems · 459 vitest suites (+ a ~1,200-test Python enforcer/proxy suite) · 9 agent harnesses
13
13
 
14
14
  [Quickstart](#quickstart) · [Why UAP?](#why-uap) · [The delivery pipeline](docs/guides/DELIVERY_PIPELINE.md) · [`uap deliver`](#the-deliver-harness) · [Docs](docs/INDEX.md)
15
15
 
@@ -39,6 +39,39 @@
39
39
  "knownRestarts": 0,
40
40
  "allowedNew": 0
41
41
  }
42
+ },
43
+ {
44
+ "name": "mission-orchestrator",
45
+ "systemd": {
46
+ "unit": "uap-orchestrator.service",
47
+ "scope": "user"
48
+ },
49
+ "budget": {
50
+ "rssMiB": 512,
51
+ "note": "uap orch poll loop clock over the mission ledger (added 2026-10-03). Polls every 300s; RSS covers node + better-sqlite3."
52
+ },
53
+ "restartBudget": {
54
+ "knownRestarts": 0,
55
+ "allowedNew": 3
56
+ }
57
+ },
58
+ {
59
+ "name": "strata-server",
60
+ "http": {
61
+ "url": "http://127.0.0.1:8080",
62
+ "kind": "strata",
63
+ "metricsMustMatch": {
64
+ "kv": "int8",
65
+ "max_context": 131072
66
+ }
67
+ },
68
+ "budget": {
69
+ "note": "The local Qwen3.8 backend since 2026-10-04 (the gsq-rco llama-server above is its retired predecessor, unit kept for rotation). Unit-less: launched by /home/cogtek/dev/strata/run-iq3_xxs.sh (flash-next IQ3_XXS pack, --expert-cache auto, --vram-reserve-mib 1200, --spec 4, --kv int8, --max-context 131072, single rail). No restartBudget: with no unit, NRestarts does not exist; liveness IS the /metrics probe. metricsMustMatch pins the two load-bearing numbers the note mentions — kv kind and pool size — so a relaunch with different flags reads as RED, the execStartMustContain doctrine applied to a service with no ExecStart."
70
+ },
71
+ "headroom": {
72
+ "gpuMinFreeMiB": 200,
73
+ "_headroom_comment": "200, not the 600 the llama.cpp-era entries use: strata deliberately fills the card (--vram-reserve-mib 1200 is its OWN internal headroom, reported reserve-aware at /metrics), and the measured steady state with the desktop sharing the GPU is ~245 MiB free. A 600 floor would hold the doctor permanently RED at the operator's chosen operating point and train everyone to ignore it. 200 still alerts when something NEW eats the card or strata loses its reserve."
74
+ }
42
75
  }
43
76
  ]
44
77
  }
@@ -1,27 +1,27 @@
1
1
  {
2
2
  "_profile": "qwen38",
3
- "_description": "Qwen3.8 27B GSQ-RCO — local llama.cpp (buun fork) deployment for agentic tool-calling workloads. Successor to qwen36; the default local executor in UAP routing. Routes through the anthropic-proxy for the tool/finalize guardrails, NOT the inference server directly.",
4
- "_engine": "buun-llama-cpp b1261-ed67e11b8 (llama.cpp fork) via uap-gsq-rco-server.service on :8080. Serves /props, /slots, /metrics and /v1. Weights: Qwen3.8-27B-GSQ-RCO-IQ3_S.gguf (ISTA-DASLab non-uniform 3.50 bpw, 10.96 GiB) + mmproj-Qwen3.8-27B-BF16.gguf (vision/video) + Qwen3.8-27B-DFlash2-Q4_K_M.gguf draft.",
5
- "_engine_history": "CORRECTED 2026-09-20. This profile previously described ninfer-serve and asserted that /props, /slots and /metrics did not exist and that chat_template_kwargs was rejected with HTTP 400. That backend is not what is running; all three endpoints are live. Verify against /props before trusting engine claims here.",
6
- "model": "qwen38-gsq-rco-27b",
3
+ "_description": "Qwen3.8 Flash-Next — local Strata serve-layer deployment for agentic tool-calling workloads. Successor to qwen36 and to the 2026-09-20 GSQ-RCO llama.cpp deployment; the default local executor in UAP routing. Routes through the anthropic-proxy for the tool/finalize guardrails, NOT the inference server directly.",
4
+ "_engine": "strata serve layer 0.1.37 (python server + native engine binary) on :8080, no systemd unit — launched by /home/cogtek/dev/strata/run-iq3_xxs.sh. Serves llama.cpp-shaped /props, /slots and /v1, plus a JSON /metrics (engine/live/requests — NOT Prometheus text; `uap inference health` auto-detects it). Weights: strata-data pack iq3_xxs (Qwen3.8-Flash-Next-GSQ-RCO-IQ3_XXS, native experts + PLE shard) with MTP speculative drafts (spec 4, spec-min-p 0.5, mtp_max 4) and an auto-sized expert cache (~14.5 GiB, 91% hit rate observed). Model id advertised at /v1/models: qwen3.8-flash-next-iq3_xxs; the server ignores requested model ids entirely, which is why stale client pins (e.g. a resumed session still naming qwen36 ids) keep working.",
5
+ "_engine_history": "SUPERSEDED 2026-10-04: this profile described buun-llama-cpp behind uap-gsq-rco-server.service (2 rails sharing a 229376-cell VBR pool, DFlash2 draft). That unit is now INACTIVE — the box serves the Strata layer on :8080 instead (tuned 2026-10-03: +15% over the llama.cpp fork on agent workloads). The old description was itself a 2026-09-20 correction of a ninfer-serve description. Verify against /metrics before trusting engine claims here; the dead unit's ExecStart still reports -c 229376 to systemctl, and on 2026-10-04 `uap inference health` printed that stale pool size for the live (131072) backend.",
6
+ "model": "qwen3.8-flash-next-iq3_xxs",
7
7
  "max_tokens": 57344,
8
- "_max_tokens_comment": "Deliberately generous: 50% of the 114688 window, the same ratio the previous 65536/131072 pairing used. The engine returns chain-of-thought in a SEPARATE reasoning_content field (--reasoning-format auto), so reasoning spends completion budget without ever appearing in content. A tight cap therefore does not produce a short answer, it produces an EMPTY one with finish_reason=length — measured previously as ~90% first-turn decode failure that read as bad output format and was really budget truncation. Do not lower this without re-measuring decode compliance.",
8
+ "_max_tokens_comment": "Deliberately generous: 50% of the 114688 window, the same ratio the previous 65536/131072 pairing used. The engine returns chain-of-thought in a SEPARATE reasoning_content field, so reasoning spends completion budget without ever appearing in content. A tight cap therefore does not produce a short answer, it produces an EMPTY one with finish_reason=length — measured previously as ~90% first-turn decode failure that read as bad output format and was really budget truncation. Do not lower this without re-measuring decode compliance. (The proxy additionally clamps tool turns to PROXY_TOOL_TURN_MAX_TOKENS=32768 regardless.)",
9
9
  "temperature": 0.3,
10
10
  "top_p": 0.9,
11
11
  "top_k": 20,
12
12
  "min_p": 0.05,
13
13
  "repetition_penalty": 1.0,
14
- "_sampling_comment": "Carried over from qwen36 unchanged: these are UAP's tool-call-tuned values, not the vendor's chat defaults, and nothing has been re-measured on 3.8. They deliberately differ from the server's own defaults (temp 0.7 / top_p 0.95 / top_k 20 / min_p 0, plus DRY 0.8 allowed_length 16). Left untouched on 2026-09-20 because the 2-rail work measured throughput, not output quality. Re-tune with `uap tune` before changing them.",
14
+ "_sampling_comment": "Carried over from qwen36 unchanged: these are UAP's tool-call-tuned values, not the vendor's chat defaults. They were re-measured only against the llama.cpp GSQ-RCO engine, never against strata — strata's own defaults (spec 4, spec-min-p 0.5) affect drafting, not base sampling, so the values are carried as-is. Re-tune with `uap tune` before changing them.",
15
15
  "stop_sequences": [
16
16
  "<|im_end|>"
17
17
  ],
18
18
  "timeout_ms": 300000,
19
19
  "context_window": 114688,
20
- "_context_window_comment": "THIS IS A PER-SESSION CAP, AND IT IS LOAD-BEARING (set 2026-09-20). The server runs -np 2 -c 229376 with kv_unified=true, which means 229376 is ONE SHARED POOL, not a per-rail allowance: /slots reports n_ctx=229376 for BOTH slots and each rail may address the whole pool. The proxy's own detection (anthropic_proxy.py _maybe_recheck_context_window) reads slots[0].n_ctx and overrides the PROXY_CONTEXT_WINDOW env pin, so without a profile every session would be told it owns 229376 — two concurrent sessions would then demand 458752 cells from a 229376-cell pool and thrash the prefix cache. A profile context_window is the mechanism that applies a per-session cap (anthropic_proxy.py:13933). It is not the only writer of monitor.context_window — :3245 sweeps every live monitor whenever upstream n_ctx changes — but the recheck runs BEFORE the profile override on each request (:13893), so the cap is restored on the next call rather than lost. 114688 x 2 rails = exactly the pool. In practice sessions sit far below it: the proxy prunes at 0.70 (~80k) toward 0.50 (~57k). IMPORTANT GAP: this cap is OPT-IN. _resolve_profile_name returns None when no x-uap-model-profile header (or uap_model_profile body param) is present, and there is no default-profile setting, so a client that does not send it gets the full shared pool. opencode, codex and claude-local are configured to send it; factory/droid custom models have no header field and CANNOT, so keep factory to one local session at a time. Note also that /v1/models advertises the process-wide window (229376), not this cap — a client that sizes itself from discovery rather than its own config will still aim at the pool.",
20
+ "_context_window_comment": "THIS IS A PER-SESSION CAP, AND IT IS LOAD-BEARING. Strata serves ONE rail with a 131072-cell pool (--max-context 131072, /slots reports n_ctx=131072); the proxy's detection reads slots[0].n_ctx and would otherwise tell every session it owns the whole pool. 114688 deliberately sits BELOW the pool (87.5%): the difference (~16k cells) is the engine's own working room (prompt scratch, conversation cache, expert-cache bookkeeping), so a session at the cap cannot crowd the engine out of its own pool. Consequence of the smaller backend: admission is now 1, not 2 — a second hot session at this cap would demand 229376 cells from a 131072-cell pool, the exact overcommit the per-session cap exists to prevent. In practice sessions sit far below it: the proxy prunes at 0.70 (~80k) toward 0.50 (~57k). IMPORTANT GAP (unchanged from the llama.cpp era): this cap is OPT-IN. A client that does not send the x-uap-model-profile header gets the whole pool. opencode, codex and claude-local send it; factory/droid custom models cannot, so keep factory to one local session at a time. /v1/models advertises the process-wide window (131072), not this cap.",
21
21
  "optimize_for_tool_calls": true,
22
22
  "mode_switch_buffer_tokens": 500,
23
23
  "enable_thinking": true,
24
- "_thinking_comment": "Top-level. The previous ninfer engine REJECTED chat_template_kwargs (HTTP 400 chat_template_option_not_supported), which is why qwen36.json carries the nested form and this profile dropped it. The current backend runs llama.cpp --jinja, where chat_template_kwargs is native and supported. The proxy probes the backend once and adapts (PROXY_CHAT_TEMPLATE_KWARGS=auto|on|off), so the top-level form remains correct and safe either way.",
24
+ "_thinking_comment": "Top-level. The proxy probes the backend once and adapts (PROXY_CHAT_TEMPLATE_KWARGS=auto|on|off), so the top-level enable_thinking form remains correct across both the llama.cpp and strata backends.",
25
25
  "dynamic_temperature": {
26
26
  "enabled": true,
27
27
  "decay": 0.5,
@@ -34,45 +34,44 @@
34
34
  "_comment": "Reduces round-trips by encouraging multi-tool emission in one turn."
35
35
  },
36
36
  "concurrency": {
37
- "max_parallel_requests": 2,
38
- "_comment": "Matches the server's 2 rails AND the proxy settings that scripts/sync-local-agent-configs.sh installs in the same change: PROXY_CONCURRENCY_LIMIT=2, UAP_MODEL_SLOTS=2 and — the one that actually protects the shared pool — PROXY_SESSION_ADMISSION_LIMIT=2. Those three must move together with this field: raising it while the proxy still serializes at 1 makes callers fan out and buy latency rather than throughput, and raising admission above the rail count admits more hot sessions than the pool can hold. NOTE this value is aspiration until that script is actually run; the live proxy env is the authority. Whether the second rail is EARNING anything is a separate question — check llamacpp:n_busy_slots_per_decode in /metrics: a prior reading of 1.002 over 139 requests meant the workload never had two concurrent requests at all.",
37
+ "max_parallel_requests": 1,
38
+ "_comment": "Strata runs ONE rail with a 131072-cell pool (its predecessor ran two rails over 229376). One admitted hot session at the 114688 cap is all the pool can hold, so slots, proxy concurrency and session admission all drop to 1 together — exactly the move-together rule the 2-rail comment below codified, in the opposite direction. scripts/sync-local-agent-configs.sh installs the matching PROXY_CONCURRENCY_LIMIT=1, UAP_MODEL_SLOTS=1, PROXY_SESSION_ADMISSION_LIMIT=1. Cost: a mission-deliver run now queues behind opencode instead of overlapping; that is the accepted trade for the 114688 single-session window. NOTE the live proxy env is the authority until that script is run — a profile of 1 against a proxy still admitting 2 overcommits the 131072 pool.",
39
39
  "kv_capacity_shared": true,
40
- "_kv_shared_comment": "true since 2026-09-20: the fork forces --kv-unified whenever VBR runs with -np > 1 ('-np 2 without --kv-unified would disarm the degrade controller'). Rails share one 229376-cell pool rather than owning private slices."
40
+ "_kv_shared_comment": "One rail, one pool: trivially shared, and still true that a rail addresses the WHOLE pool rather than owning a slice. Kept true so consumers that branch on it keep treating the pool as a shared resource."
41
41
  },
42
42
  "server_optimization": {
43
- "kv_dtype": "vbr",
44
- "_kv_dtype_comment": "VBR dynamic turbo: entry tier t8 (~q8_0 quality) degrading toward floor t4 (4.125 bits/value ~ q4_0) only as the pool fills, under an explicit 5120 MiB KV budget (--vbr-vram 5120M). The explicit budget replaced 'auto' on 2026-09-18 after auto resolved 9536 MiB and overcommitted the card through THREE SIGABRT core dumps. A fourth dump followed WITH the 5120M budget already in place; that one was fixed by dropping the pool 262144 -> 229376, not by the budget. Do not fold it into the budget's evidence.",
43
+ "kv_dtype": "int8",
44
+ "_kv_dtype_comment": "Fixed-tier int8 KV (8 bpv) with --kv-resident 32768, NOT the old VBR dynamic degrade — there is no floor to pin at, and the kv-at-floor finding no longer applies. Strata manages pool pressure itself (conversation cache eviction); the profile's job is only to keep the per-session cap below the pool.",
45
45
  "prefill_chunk": 1024,
46
- "max_context": 229376,
47
- "kv_capacity": 229376,
48
- "_capacity_comment": "Shared pool total across both rails, NOT per rail. Per-session allowance is context_window above.",
49
- "parallel_rails": 2,
46
+ "max_context": 131072,
47
+ "kv_capacity": 131072,
48
+ "_capacity_comment": "Whole pool, one rail. Per-session allowance is context_window above (114688, deliberately under the pool).",
49
+ "parallel_rails": 1,
50
50
  "speculative_decoding": {
51
51
  "enabled": true,
52
- "type": "draft-dflash",
53
- "draft_model": "Qwen3.8-27B-DFlash2-Q4_K_M.gguf",
52
+ "type": "mtp",
53
+ "draft_model": "strata-data/mtp/rt (MTP head, not a separate draft model)",
54
54
  "draft_max": 4,
55
- "draft_min": 0,
56
- "_comment": "A real 1.06 GiB draft MODEL, not self-speculation. Replaces the previously recorded '--spec mtp --draft-tokens 3 --lm-head-draft' (that was the ninfer engine's built-in MTP). DFlash2 was measured on this box 2026-09-12 to beat the native MTP head at every depth (45/31/30 vs 36/20/13 t/s at 2k/32k/92k)."
55
+ "draft_min_p": 0.5,
56
+ "_comment": "Strata's native MTP speculative path (--spec 4 --spec-min-p 0.5, mtp_max 4, plus a lookup-3 secondary). Replaces the DFlash2 draft model of the llama.cpp era: observed 2026-10-04 at 84-89% acceptance on agent workloads (vs 62% on one 311-token outlier), which is what carries decode to the observed 46-52 tok/s."
57
57
  },
58
- "_comment": "These are the flags uap-gsq-rco-server.service is actually running under, recorded so a rebuild reproduces the measured behaviour.",
59
- "_budget_tier_comment": "Budget arithmetic worth knowing: 5120 MiB / 229376 cells = 22.86 KiB/token, which is EXACTLY the t4 floor (4.125 bpv). The budget was sized so the full pool fits only at the WORST quality tier; at the t8 entry tier it covers roughly 107k tokens. Consequence of --kv-unified that did not exist at one rail: KV precision is now COUPLED ACROSS SESSIONS. A lone agent at 60k sits at t8; add a second agent at 60k and both degrade toward t4."
58
+ "_comment": "These are the flags run-iq3_xxs.sh actually runs strata with, recorded so a rebuild reproduces the measured behaviour. The load-bearing pair (kv int8, max-context 131072) is pinned in config/capacity-policy.json under the strata-server http entry, where `uap doctor` verifies them against /metrics."
60
59
  },
61
60
  "measured": {
62
- "date": "2026-09-20",
61
+ "date": "2026-10-04",
63
62
  "gpu": "NVIDIA GeForce RTX 3090, 24576 MiB",
64
- "_gpu_comment": "llama-server resident is NOT a constant: VBR maps KV lazily, so it tracks pool occupancy. 16652 MiB was a cold-start reading on an empty pool and should not be quoted as steady state. Measured under real load the same day: ~19.5 GiB resident, ~3.2 GiB free. Budget headroom against the 3.2 GiB figure, not the cold one — and remember a vision request allocates image-encode buffers on top.",
65
- "decode_tokens_per_second": 43,
66
- "_decode_comment": "CODE GENERATION at shallow depth, which is the closest single number to agent work. Decode here is strongly workload- AND depth-dependent, so one number is always a simplification. Measured 3 reps each, greedy, 220 max_tokens, via scripts/bench-decode-reps.sh: code 41.1/45.7/43.0 tok/s | prose 25.4/25.1/32.3 | counting 52.2/52.7/54.2. Depth matters as much: an earlier probe run measured ~72 at ~100 tokens of context but only ~32 at 27k. The DFlash2 rows above (45/31/30 t/s at 2k/32k/92k) remain the best depth-resolved characterisation. An earlier version of this file recorded 72 tok/s from a SINGLE rep on 'count from 1 to 40' — a degenerate, near-perfectly draftable prompt at zero depth. Do not quote a decode number without saying which workload and what depth.",
67
- "draft_acceptance": 0.71,
68
- "_draft_acceptance_comment": "Code generation, 3 reps: 67.8/73.4/71.7%. Strongly prompt-dependent — prose only reaches 30.5-39.8%, while counting hits 93.9-97.7%. The 0.90 previously recorded here came from the counting prompt and is not characteristic of anything an agent does.",
69
- "prefill_tokens_per_second": 900,
70
- "_prefill_comment": "Bulk prefill on unique (uncacheable) prompts: ~927 t/s at 3.5k, ~899 at 13.7k, ~883 at 27.4k, ~751 at 41k. A previously recorded 105 t/s was fixed per-request overhead measured on a ~100-token prompt, not a prefill rate — wrong by roughly 8x. Rough model: ms/token = 1.03 + 6.3e-6*N.",
63
+ "_gpu_comment": "Strata's own reserve-aware /metrics reported ~950 MiB free under live load (--vram-reserve-mib 1200 already held out; arena 40925 MiB across host+device, expert cache ~14.5 GiB). Host-wide free via nvidia-smi is the doctor's number; engine.vram_free_mib is strata's view, and both are checked now.",
64
+ "decode_tokens_per_second": 47,
65
+ "_decode_comment": "CODE GENERATION on real agent traffic, observed 2026-10-04 over the live session: 41.5-51.6 tok/s at 19-20k prompt depth, 36.6 at 38.6k depth, 43.2-47.4 in the 11-12k range, one 45.9 sustained across a 7071-token generation. Depth matters as much as workload: 47 here is a mid-depth code-workload number, not a constant. Do not quote a decode number without saying which workload and what depth.",
66
+ "draft_acceptance": 0.84,
67
+ "_draft_acceptance_comment": "Agent-tool workloads observed 2026-10-04: 84-89% per request (80/93, 66/77, 91/110, 4535/5427 tokens) with one 62% outlier on a 311-token short generation. The prior engine's counting-prompt 0.90 remained dishonest; this figure is from real agent traffic only.",
68
+ "prefill_tokens_per_second": 950,
69
+ "_prefill_comment": "Observed 2026-10-04 on live traffic: 900-1025 tok/s reading 3.7-11.6k unique tokens per turn (with 15.5k+ reused from the conversation cache at 95-99% reuse). Strata reports read-rate only on non-reused tokens, same convention as the old profile.",
71
70
  "concurrent_2_rail_throughput": null,
72
- "_concurrency_comment": "STILL UNMEASURED. Decode on this card is memory-bandwidth-bound, so the expected win from the second rail is OVERLAP (no head-of-line blocking; one session's prefill can proceed during another's decode), NOT 2x throughput. The honest acceptance test is llamacpp:n_busy_slots_per_decode from /metrics: a prior investigation recorded 1.002 over 139 requests, i.e. the workload never actually had two concurrent requests and the second rail bought nothing. Require that metric to exceed 1 under real load before claiming the rail is earning its keep."
71
+ "_concurrency_comment": "Moot at one rail: there is no second rail to measure. Kept null so no concurrent-throughput claim survives from the 2-rail era."
73
72
  },
74
73
  "routing": {
75
74
  "endpoint": "http://127.0.0.1:4000/v1",
76
- "_comment": "Route through the anthropic-proxy, NOT the inference server directly — the proxy applies the tool/finalize guardrails and, via this profile, the per-session context window that clients size their history to. Clients select this profile with the header 'x-uap-model-profile: qwen38' (or a uap_model_profile body param)."
75
+ "_comment": "Route through the anthropic-proxy, NOT the strata port directly — the proxy applies the tool/finalize guardrails and, via this profile, the per-session context window that clients size their history to. Clients select this profile with the header 'x-uap-model-profile: qwen38' (or a uap_model_profile body param)."
77
76
  }
78
77
  }