Field counts come from inspect, not memory: record_llm_call takes 36
parameters, COLUMNS has 36 entries, the physical table has 37.
- README: capability table says 36 fields and names the three row kinds;
new section covers reading call_stats, the five SQL migration items,
the attribution query and the storage-side upgrade
- README/.env.example/ARCHITECTURE: error_body follows the summarize_body
limit and the structured-exhaustion error carries its own bounded
explanation, so neither is inside PGW_TELEMETRY_TEXT_CAP coverage
- ARCHITECTURE 7.8: the ten columns with per-column semantics, the I3/I4
invariants, operation versus exc.operation, and the assembly gate
- CHANGELOG: unreleased section listing the four public changes and what
downstream must do, in particular counting failures by event_kind and
the assembly-time error for custom recorders
- schemas/llm-calls: the ten columns plus a three-row-kind section
- metrics/call-telemetry-coverage: 1.3.5 coverage contract, real live
baselines left unfilled rather than stating a fake percentage
Validation record records the T4 evidence: mechanical migration red then
green, the four PG acceptance cases, the seven-item mutation matrix with
all seven killed and the copy restored to an identical digest, plus the
PYTHONPATH pitfall that made the first mutation round silently test the
original source.
Version numbers and release steps are deliberately untouched.
The behaviour section described round trips that only ever existed inside the
branch. Verified every claim against `git show 6ec9ec7:<file>` plus a 300-combo
side-by-side run (4 old provider slots x 25 models x three ENABLE_THINKING
states); exactly two differences exist.
- glm-5.3 / glm-5.3-flash / gemini-3.1-pro are newly registered as unable to
stop reasoning. They were unregistered in 1.3.2, so ENABLE_THINKING=false
passed; now it fails at assembly. That is the one change that breaks an
existing config, so it leads the table.
- The openai slot moves from "shape unknown, refuse at assembly" to the standard
OpenAI shapes in both directions. Neither openai nor anthropic nor google ever
injected medium; minimax did and still does, byte for byte.
- kimi-k3 was never registered before, so it changes nothing for anyone. Moved
to new capabilities as a first registration.
- Both keyword and positional ThinkingCapability construction break, not just
positional; spell out the migration form.
.env.example: name all eight registry slots, and say that "on" injects nothing
on the three slots whose on_base is empty.
ARCHITECTURE 7.8 gains the pool resource semantics, the two-sentence
failure verdict and the two config keys; the ownership rule lands in a
new 4.5 because it is a cross-subsystem discipline, not a telemetry
convention. CHANGELOG leads with the three items downstream must read
first: the 3.12 floor, the connection count going from 10 per client to
on demand, and aclose no longer closing injected components.
README gains the key with the reason a single-source scope wants wait,
and the price of choosing it. .env.example carries the same warning
since README points at it as the full key list. ARCHITECTURE 7.4 records
why the missing cell is unrelated to source count -- and why keying on
len(sources) would be the worse debt -- plus the six-exit retry_after_s
contract and the admission convergence; 9 registers the key.
CHANGELOG stays unreleased per the release checklist: the version bump
belongs to the release run, not here. Its "read this first" section
covers the half-open retry_after_s change, which is visible even on the
default fail_fast setting.
`PGW_TELEMETRY_TEXT_CAP` now reaches the emitter on every assembly path.
Unset means no truncation, which stays the default: a truncated row is
no longer audit evidence and cannot be replayed, and downstreams rely on
that today. The flip side — contracts and bids sitting in `llm_calls`
indefinitely, multi-tenant — is spelled out in `.env.example` so readers
can weigh both.
All three `from_settings` paths are wired (chat, embedding, OCR): they
write the same table, so capping only chat would leave half of it
uncontrolled. `TelemetryEmitter.__init__` now rejects `text_cap <= 0`;
it is the single point where the three clients converge, so the direct
construction path — a public assembly route the settings guard never
sees — is covered too. `0` would otherwise reduce every body to a bare
elision marker.
_validate_stall still guards stall_window_s >= max ttft_timeout_s, but its
stated reason no longer holds: TTFT waiting is productive time and never
reaches the stall account. The check is harmless and stays, so the
docstring now says why it is kept rather than implying a live hazard.
.env.example dropped the "must be >= max TTFT" advice for what the window
actually measures.
AIMD ceiling now respects per-source max_concurrency and the pacer is
assembled explicitly in the client; MIN_CALLS parses as strict int;
acceptance doc corrects source-5 attempt count to 549; design and
migration notes aligned with implemented 429/stall/suppression
semantics and AIMD constants documented.
Round 5 left three residual failure classes; ladder exhaustion (3.2%
of structured calls with a single re-ask) and 429 leakage (5.8%, AIMD
oscillating above the sustainable point) are addressable: re-ask
default goes 1 to 2 (conservative vs instructor's 3) and the AIMD cut
factor drops to 0.5.
Includes config aggregation for multi-source env keys, from_env and
from_settings factories with explicit shared-backend injection,
gather_bounded, top-level exports, tightened import-linter layers with
the gate removed from the Makefile, and the finalized .env.example.