Repository navigation
Docs audit — reference (api, headers, environment variables, glossary) — 2026-08-16 #68
Description
Audited: the reference topic in scoped mode: the API, headers, environment-variables and glossary pages.
Window: the full reference surface at platform main (633455b98, 2026-08-14), plus every merged PR touching it over the last 60 days (#2540, #2566, #2678, #2565, #2485, #2668, #2569, #2623/#2628, #2697, #2539, #2578, and the historical #1407 that removed the 424 sentinel). Docs at 3d0a691.
Pages audited (4): reference/api.mdx, reference/headers.mdx, reference/environment-variables.mdx, reference/glossary.mdx. reference/telemetry.mdx belongs to the request-logs topic and was left out of scope.
10 findings: WRONG x7, MISSING-CASE x3. Four parked backlog items were consumed by this run.
Findings
1 · [WRONG] The rate-limit section says a self-hosted instance allows 100 requests a minute per harness and that two settings change that. The real cap is 200 a minute per workspace, and no setting moves it, on Cloud or self-hosted.
Page: https://manifest.build/docs/reference/api (Rate limits) and https://manifest.build/docs/reference/environment-variables (Network and security, the two rate-limit rows)
What actually happens:
- Your client sends requests through the gateway.
- Manifest allows 200 requests per minute per workspace, 500 requests per minute per IP address, and 10 requests in flight at once. The numbers are the same on Cloud and self-hosted.
- Cross one of them and the request fails with 429: M201 for the workspace cap, M202 for the IP cap, M203 for the concurrency cap.
- On self-hosted you raise the two rate-limit settings and restart. The gateway behaves exactly as before. Those two settings throttle the dashboard's own API calls, not the gateway.
- Your Cloud plan changes your monthly request quota. It does not change any per-minute cap.
Options:
- Rewrite the rate-limit section with the real per-minute and concurrency caps, stated as identical on Cloud and self-hosted and not configurable, and rescope the two settings in the environment-variable reference to the dashboard's own API calls. Recommended.
- Delete the override sentence, link the three rate-limit error pages for the numbers, and rescope the two settings only.
- Leave.
Evidence (for the agent)
reference/api.mdx:212— "Self-hosted instances default to 100 requests per 60 seconds per harness. Override withTHROTTLE_TTLandTHROTTLE_LIMIT(Environment variables)."reference/api.mdx:214— "Cloud rate limits are tied to your plan and shown in the dashboard."reference/environment-variables.mdx:38-39— "THROTTLE_TTL|60000| Rate-limit window in milliseconds" and "THROTTLE_LIMIT|100| Max requests per window per harness".- Code:
proxy.controller.ts:119,123—@Controller('v1')carries@SkipThrottle(), so the Nest throttler never sees/v1/*. - Code:
app.module.ts:78-81—THROTTLE_TTL/THROTTLE_LIMITfeedThrottlerModule.forRootonly, governing the Nest-routed controllers under/api/v1/**. The tracker is the client, not the harness key. - Code:
proxy-rate-limiter.ts:4-9— the real gateway caps are hardcoded module constants: window60_000,RATE_MAX_REQUESTS = 200per tenant (M201 at:47),IP_RATE_MAX_REQUESTS = 500per IP (M202 at:72),CONCURRENCY_MAX = 10in flight (M203 at:85). Checked in order atproxy.controller.ts:378-381. The file reads noprocess.envand noConfigService. - Code:
plan-limits.ts:9,11-16— what varies by Cloud plan is the monthly request quota (Free 10 000, Pro unlimited), not any per-minute cap. - Not a re-raise: issue Docs audit — error catalog (M-codes) — 2026-08-14 #58 finding 2 (still open) says the caps are unconfigurable, on
errors/M201-M203.mdx. This is the opposite-side defect, on the pages that tell users the knob exists. - Impact: a self-hoster hitting M201 or M203 raises the documented setting, restarts, and nothing changes.
2 · [WRONG] Three pages say an exhausted fallback chain returns 424. Manifest returns the status the first model's provider gave, and marks the exhaustion with a response header.
Page: https://manifest.build/docs/reference/api (Errors, the status table and the note below it), https://manifest.build/docs/reference/headers (Response headers, fallback only, the exhausted row) and https://manifest.build/docs/reference/glossary (Fallback chain)
What actually happens:
- Your request goes to the primary model and fails.
- Manifest walks the rest of the chain. Every model fails.
- You receive the status the primary model's provider returned, for example 500 or 429. Never 424.
- The response carries the header that marks the chain as exhausted, set to true. That header is the only reliable signal.
- The body keeps the provider's own error code when the provider sent one, so there is no single code to match on either.
Options:
- Replace the 424 claim on all three pages with header-based detection, and ship it together with the routing-page fix in issue Docs audit — llm gateway (routing, tiers, fallbacks) — 2026-08-09 #53. Recommended.
- Fix the three reference pages now and leave the routing page to Docs audit — llm gateway (routing, tiers, fallbacks) — 2026-08-09 #53.
- Leave until Docs audit — llm gateway (routing, tiers, fallbacks) — 2026-08-09 #53 is decided.
Evidence (for the agent)
reference/api.mdx:6— frontmatter keyword"424 fallback exhausted".reference/api.mdx:204— "|424| Fallback chain exhausted (all configured models failed) |".reference/api.mdx:208— "Status424is the only one that does not trigger a fallback. Manifest returns it itself when the chain is exhausted, so re-routing it would loop forever."reference/headers.mdx:47— "|X-Manifest-Fallback-Exhausted| Set totrue. Response status is424. |"reference/glossary.mdx:53— "When all of them fail, Manifest returns HTTP424withX-Manifest-Fallback-Exhausted: true."- Code: repo-wide grep for
424/FAILED_DEPENDENCYacrosspackages/*/srcat633455b98returns zero production hits. The sentinel was removed by PR #1407 (12ede3c7d, 2026-03-30) and a spec now asserts the opposite (__tests__/proxy-fallback.service.spec.ts:1848-1879). - Code:
proxy.service.ts:1258,1265— the exhausted forward is rebuilt withstatus: primaryStatus, the primary provider's real status;proxy-response-handler.ts:403-405sets that status thenX-Manifest-Fallback-Exhausted: true. - Code:
fallback-status-codes.ts:1-3— the fallback trigger is any status>= 400with no exclusions, soapi.mdx:208's "the only one that does not trigger a fallback" describes a rule that does not exist. - Caveat for whoever writes the fix: the body's code is
providerCode ?? 'fallback_exhausted'(proxy-response-handler.ts:410). When the primary provider supplied its own code,fallback_exhaustednever appears. Do not write "the code is alwaysfallback_exhausted". - Page-echo, not a re-raise: the same concept was raised for
llm-gateway.mdx:6,97,138as issue Docs audit — llm gateway (routing, tiers, fallbacks) — 2026-08-09 #53 finding 2 (still open). Different pages, named here. - Consumes the parked backlog line of 2026-08-10 on
reference/api.mdx:6,204,208, extended to the headers and glossary pages, which the parked line did not list.
3 · [WRONG] The error example shows a numeric code and a limit-exceeded type. No Manifest response contains either, and a spend hard limit arrives as 200, not 429.
Page: https://manifest.build/docs/reference/api (Errors, the example response and the status table)
What actually happens:
- You copy the example and branch on the numeric code, or on the limit-exceeded type.
- Manifest puts a text code, or nothing, in the code field, and keeps the numeric status in a separate field. A number never lands in the code field.
- The type is always one of the standard error types a provider uses, such as an authentication error or a rate-limit error. Limit exceeded is a routing reason, not a type.
- When a spend hard limit trips, Manifest answers 200 (M200) and puts the limit message in the assistant turn. Your error handling never runs.
- A 429 means a gateway cap (M201, M202, M203) or a rate limit the provider itself returned. The gateway ones carry a message and a type, with no code field at all.
Options:
- Replace the example with a real error body (the shape a tool or SDK client gets on a bad key is the most common) and rewrite the 429 row for the gateway rate limits and upstream provider rate limits, with a separate line saying a hard limit arrives as 200. Recommended.
- Drop the example and point to the error catalog for the shapes.
- Leave.
Evidence (for the agent)
reference/api.mdx:191-197— the only error example on the page:{"error":{"message":"Limit exceeded: cost usage ($1.23) exceeds $1.00 per day","type":"limit_exceeded","code":429}}.reference/api.mdx:205— "|429| Hard limit hit (M200), or Manifest rate limit tripped |".- Code:
proxy-response-handler.ts:189-224— the canonical envelope builder emitscode: string | nullalongside a separate numericstatusfield. - Code:
proxy-error-sanitizer.ts:78-82—codepasses througherrorField(), which returnsnullfor anything that is not a non-empty string. A provider sending"code": 429yieldscode: null. - Code:
proxy-error-sanitizer.ts:17-22,169-175—typeis drawn from the closed setinvalid_request_error | authentication_error | permission_error | rate_limit_error | server_error; the Anthropic-modeoverloaded_error/api_errorbranch isproxy-response-handler.ts:207-214.limit_exceededis a routing reason (proxy.service.ts:260), never an error type. - Code: M200 is delivered as an HTTP 200 assistant-message stub to every client (
proxy-friendly-response.ts:89,118, emitted atproxy.service.ts:260). - Code: Manifest's own 429s come only from M201/M202/M203, shaped
{message, type:'rate_limit_error'}with nocodekey (proxy.controller.ts:775). A provider's own 429 is forwarded with its real status and the full envelope (proxy-response-handler.ts:308-310), so the row must cover both sources. - Real pairs for the replacement example: auth on a tool client is
type: 'auth_error',code: 'manifest_auth'(proxy-exception.filter.ts:146); Free-plan quota istype: 'insufficient_quota',code: 'PLAN_LIMIT_REQUESTS'(proxy-exception.filter.ts:120). - Page-echo, not a re-raise: the M200-to-429 half echoes issue Docs audit — llm gateway (routing, tiers, fallbacks) — 2026-08-09 #53 finding 3 (
llm-gateway.mdx:142) and issue Docs audit — error catalog (M-codes) — 2026-08-14 #58 finding 1 (errors.mdx:43,errors/M200.mdx:4,7), both still open. Different page, named here. - Consumes the parked backlog line of 2026-08-10 on
reference/api.mdx:194-195.
4 · [WRONG] The headers page says the tier response header can carry a custom tier's name. It never carries a name, and requests Manifest answers by itself report values the page says cannot occur.
Page: https://manifest.build/docs/reference/headers (Response headers (every request), the tier row and the reason row)
What actually happens:
- You create a custom tier on your own header key and value, then send that header.
- Manifest routes the request to the tier's model.
- The tier response header comes back with a fixed generic value. The reason header is what tells you a header match happened.
- You compare the header against your tier's name, see no match, and start debugging a rule that works.
- When Manifest answers without calling a provider (a spend block, no provider connected, a model it cannot serve), the tier, model and provider headers all report Manifest's own values. A log pipeline keyed on the documented values files those as real model calls.
Options:
- Correct both rows with the values a client can actually receive, and add one sentence: the tier's name appears on the request in the dashboard, never in a header. Recommended.
- Drop the custom-tier-name claim and mark both lists non-exhaustive without enumerating.
- Leave.
Evidence (for the agent)
reference/headers.mdx:27— "|X-Manifest-Tier| The tier that handled the request:default, a custom tier's name, ordirect|default|".reference/headers.mdx:30— "|X-Manifest-Reason| Why that route was picked:default,header-match, ordirect|header-match|".- Code:
resolve.service.ts:325-335— a header-tier match returnstier: 'standard'andreason: 'header-match';header_tier_nameis recorded to the database and never emitted as a header. - Code:
proxy-response-handler.ts:163-171—buildMetaHeaderscopiesmeta.tierverbatim. No branch can produce a tier name. - Code:
proxy-friendly-response.ts:59-63— Manifest-blocked responses emittier: 'simple',model: 'manifest',provider: 'manifest', with reasonslimit_exceeded/no_provider/model_not_available(proxy.service.ts:260,1428,1438), through the same header builder (proxy.controller.ts:406). - Code:
scoring/types.ts:39-51— the reason union also containsscored,tool_detected,large_context,short_message,momentum,ambiguous,heartbeat,specificity,formal_logic_override. - Constraint on the fix: do not introduce the complexity-routing tier vocabulary into the docs. That feature is being retired in-product (
RoutingDeprecationNotice.tsx:4) and no page mentions it. Document only the values a client can receive. - Open point: the reason list above is "confirmed to occur", not proven exhaustive. Option 2 exists partly for that reason.
5 · [WRONG] The chat completions section says the body is forwarded verbatim and that every standard OpenAI field passes through. Manifest rewrites the body for the resolved provider and drops the fields that provider does not accept.
Page: https://manifest.build/docs/reference/api (Chat completions, the paragraph under the request example)
What actually happens:
- You send a routed request with an OpenAI-only field, such as the option that asks for usage totals inside the stream, or the reasoning-effort setting.
- Routing lands on an Anthropic or Google model.
- Manifest converts the payload to that provider's shape, renames the token-limit parameter where the provider expects another name, and drops the fields that only OpenAI and OpenRouter accept.
- You get a normal answer with no usage totals and no reasoning control. No warning, no error.
- Manifest also merges the model parameters saved on your harness into every routed attempt, so a value you never sent can reach the provider.
Options:
- Replace the sentence with what Manifest does to the body (adapts it to the resolved provider, drops unsupported fields, renames parameters, merges harness defaults) and list the fields that survive only on OpenAI and OpenRouter routes. Recommended.
- Say that Manifest adapts the body to the resolved provider, with no list.
- Leave.
Evidence (for the agent)
reference/api.mdx:53— "The body is forwarded verbatim to the resolved provider, withmodelrewritten to the actual model ID. All standard OpenAI fields (temperature,max_tokens,tools,tool_choice,response_format,stream, etc.) pass through."- Code:
provider-client-converters.ts:98-107— the stripped set isstore,metadata,service_tier,stream_options,modalities,audio,prediction,reasoning_effort, dropped for every provider outside the passthrough set{openai, openrouter}(:113, applied at:343,364-372).reasoning_effortis re-admitted forxaianddeepseekonly (:368-371). - Code:
provider-client-converters.ts:122,130,348-349,360-363,374-384—max_tokensis rewritten tomax_completion_tokensand back depending on the target; DeepSeekmax_tokensis clamped to 8192 (:116,387). - Code:
provider-client.ts:724,729— prompt-cache markers are injected;:572(Google),:611(Anthropic) and:647(Responses) convert the payload whole to the target's shape. - Code:
proxy.service.ts:304-317,328-338— per-harness model-parameter defaults are merged into every attempt that is not an explicit-model override. - Impact: the page names
streamas passing through, which makes the siblingstream_optionsdrop maximally surprising. The user debugs the provider instead of the proxy.
6 · [WRONG] The row for the listening interface tells you to open it up for LAN access. On the bundled Docker install that changes nothing: the published port in the compose file decides who reaches the server.
Page: https://manifest.build/docs/reference/environment-variables (Network and security, the row for the listening interface)
What actually happens:
- You want another machine on your network to reach your install.
- You follow the row, set the listening interface to all interfaces, and restart. The container already listened on all interfaces.
- The other machine still cannot connect, because the compose file publishes the port on the loopback address only.
- The host binding lives on a commented line in the install's environment file. Uncomment it, set your address, restart, and the machine connects.
- The other direction breaks too: you restrict exposure by hand-editing the compose file as the row says, then run the upgrade command, which rewrites that file and silently drops your restriction.
Options:
- Rewrite the row for what the variable does on a non-Docker launch, point Docker users at the host-binding variable in the install's environment file, and add that variable's own row in the same PR as the issue Docs audit — self-hosting with Docker — 2026-08-12 #56 fix. Recommended.
- Keep the bind description only and let the self-hosted page own LAN exposure.
- Leave until Docs audit — self-hosting with Docker — 2026-08-12 #56 lands, then fix both pages together.
Evidence (for the agent)
reference/environment-variables.mdx:32— "|BIND_ADDRESS|127.0.0.1| Interface the server binds to. Set to0.0.0.0for LAN access. The Docker image already sets0.0.0.0; restrict a container with the composeportsline instead |".- Code:
docker/Dockerfile:78—ENV BIND_ADDRESS=0.0.0.0. The shipped container already binds every interface, which is why setting the variable is a no-op. The row's second clause is true and makes the first clause dead. - Code:
docker/docker-compose.yml:50— the publish line is"${HOST_BIND_ADDRESS:-127.0.0.1}:${HOST_PORT:-${PORT:-2099}}:${PORT:-2099}". LAN reachability is decided there. - Code:
docker/.env.example:28,31— the upgrade-safe knobs shipped to users are the commentedHOST_BIND_ADDRESSandHOST_PORTlines. - Code:
app.config.ts:22— the127.0.0.1default is real, but only for a non-Docker launch. install.sh --upgradeatomically replacesdocker-compose.ymland never touches.env(evidence recorded with issue Docs audit — self-hosting with Docker — 2026-08-12 #56), so the hand-edit the row recommends is wiped by the documented upgrade path.- Page-echo, not a re-raise: same defect class as issue Docs audit — self-hosting with Docker — 2026-08-12 #56 finding 1 (
self-hosted.mdx:208, still open), on a different page. - Backlog line of 2026-08-12 (missing rows for the compose host-mapping variables) is CLEARED as written, not raised: no
.mdxpage mentions either variable today, so nothing is used-but-undefined and the coherence invariant holds. Option 1 adds the row and pre-satisfies the invariant when the Docs audit — self-hosting with Docker — 2026-08-12 #56 fix introduces the variable into prose.
7 · [WRONG] The request-header table marks the Anthropic API version header as required and says Manifest forwards it. Manifest requires nothing and forwards nothing: it sets the version it sends upstream itself.
Page: https://manifest.build/docs/reference/headers (Request headers, the row for the Anthropic API version) and https://manifest.build/docs/reference/api (Anthropic messages, the example request)
What actually happens:
- You call the Anthropic-format endpoint and leave the version header out.
- Manifest accepts the request and routes it. Nothing checks that header on the way in. A missing key still fails with 401; a missing version header does not.
- Manifest sets the version value on every call it makes to Anthropic.
- You send a different version string. Manifest ignores it and sends its own.
Options:
- Reclassify the row as accepted and ignored: Anthropic SDKs send it on their own, Manifest does not require it, and Manifest chooses the version it sends upstream. Keep the example request unchanged. Recommended.
- Delete the row and remove the header from the example request.
- Leave.
Evidence (for the agent)
reference/headers.mdx:17— "|anthropic-version|2023-06-01| Required for/v1/messages. Forwarded to the upstream. |".reference/api.mdx:61— the Anthropic curl example sends-H "anthropic-version: 2023-06-01".- Code: a grep for
anthropic-versionacrosspackages/backend/srcreturns outbound injection sites only, all with the hardcoded value'2023-06-01':provider-endpoints.ts:105,114,122,subscription-clients.ts:59,custom-provider.service.ts:445,provider-model-fetcher.service.ts:883,921. No inbound validator exists anywhere. - Contract test:
contracts/gateway/tests/routes.test.mjs:85-95posts to/v1/messageswith onlyContent-Type: application/jsonand asserts a 401 auth error, not a 400 for the missing header (request helper:10-31, assertion:33-52). - Consumes the parked backlog line of 2026-08-10 on
reference/headers.mdx:17, which asked exactly this question.
8 · [MISSING-CASE] The glossary says a real model ID goes straight to that provider and skips tiers. A matching custom-tier header wins over the model ID, and the request runs on the tier's model.
Page: https://manifest.build/docs/reference/glossary (Direct routing, and Custom tier) and https://manifest.build/docs/reference/headers (Request headers, the sentence under the table)
What actually happens:
- You configure a custom tier on your own header key and value.
- Your client sends that header along with a concrete model ID, because most SDKs require a model name in the body.
- Manifest checks the tier header first. It matches, so the request goes to the tier's model. The ID you sent is never resolved.
- The tier response header reports a header match, not direct routing, and your Requests page shows the tier's model with its cost.
Options:
- Add the precedence to Direct routing and Custom tier in the glossary, and to the routing sentence on the headers page: a matching custom-tier header takes precedence over an explicit model ID. Recommended.
- Add the precedence to the glossary only, and leave the headers page as it is.
- Leave.
Evidence (for the agent)
reference/glossary.mdx:45— "Sending a real model ID (one thatGET /v1/modelslists) instead ofauto. Manifest forwards the request straight to that provider and skips tiers and fallbacks."reference/headers.mdx:21— "The custom tier header is the only one that changes routing: send the header you configured on a tier and the request goes to that tier's model."- Code:
proxy.service.ts:903-905sends any non-automodel toresolveExplicitModel, which callsresolveHeaderTierat:976-978and returns immediately on a match, before the catalog lookup. The rationale is written at:957-959: the operator's rule is a deliberate override, and the SDK'smodelfield is mandatory, so most harnesses send a name they cannot change. - Code:
resolve.service.ts:325-335— that match then reportstier: 'standard'andreason: 'header-match', which is finding 4's other half. - The rest of the glossary sentence is correct: direct routing does set
fallback_routes: null(proxy.service.ts:1063) and does bypass scoring (:1057-1072). - Impact: the user pays for the tier's model while believing they pinned another one.
9 · [MISSING-CASE] The status table and the "every request" header heading assume one kind of client. Streaming and chat clients receive 200 with the message in the assistant reply, and a request rejected before a provider is picked carries no routing headers.
Page: https://manifest.build/docs/reference/api (Errors, the status table, and Response headers) and https://manifest.build/docs/reference/headers (Response headers (every request), the heading)
What actually happens:
- Claude Code, or any client that streams or asks for an event stream, sends a request with a bad key or an exhausted quota.
- Manifest answers 200 and puts the explanation in the assistant turn. The 401 and 402 rows never reach that client, so its error handling stays silent.
- A tool or SDK client that does not stream gets the statuses the table lists.
- Auth, quota and rate-limit responses carry no routing headers, for either kind of client. Manifest rejects those before routing runs.
- Several Manifest replies (no provider connected, a blocked spend limit, a model it cannot serve) answer 200 to every client and appear in no row of the table.
Options:
- Add one sentence above the table (streaming and chat clients receive 200 with the message inside the assistant turn; the statuses below are what tool and SDK callers see) and retitle the headers section so it stops promising every request. Recommended.
- Do that, and add the missing rows: 400 for a rejected body, 503 and 504 for transport failure and timeout.
- Leave.
Evidence (for the agent)
reference/api.mdx:200-206— the status table (401,402,424,429,5xx), introduced at:188by "The proxy returns a standard JSON error envelope:".reference/api.mdx:218— "Every response carries routing headers so your client can see which model and tier handled the request".reference/headers.mdx:23— the heading "## Response headers (every request)".- Code:
proxy-exception.filter.ts:38-44—isChatRenderingClientis true whenbody.stream === trueorAcceptcontainstext/event-stream. Those callers get HTTP 200 with the message in the assistant turn (:131-149) instead of 401 for auth or 402 for quota. - Code: M100, M101, M102, M200 and M302 return HTTP 200 to every client (
proxy.service.ts:260,411-416,1428,1438;proxy-friendly-response.ts:89,118) and appear in no row of the table. - Code:
proxy-response-handler.ts:309,404,545,861— the header builder runs only on success, SSE init, provider-error and exhausted paths. Auth 401s, quota 402s, rate-limit 429s and internal errors carry noX-Manifest-*headers at all. - Page-echo, not a re-raise: the chat-versus-tool split was raised for
errors.mdx:21against:55,:71as issue Docs audit — error catalog (M-codes) — 2026-08-14 #58 finding 3 (still open). Different page, lower severity here since this is the API reference rather than the error catalog.
10 · [MISSING-CASE] The model-listing section says any model ID missing from the list returns M302. A provider-qualified ID still routes when one of your connected providers serves it, even before the list learns it.
Page: https://manifest.build/docs/reference/api (Listing models, the paragraph under the example)
What actually happens:
- A provider ships a new model. Your model list has not picked it up yet.
- You send that model ID with its provider prefix.
- Manifest works out which connected provider owns it and forwards the request. The provider decides whether the model exists.
- M302 comes back only when no connected provider can serve the ID.
Options:
- Soften the sentence: a model ID that no connected provider can serve returns M302. Recommended.
- Spell out the nuance: a provider-qualified ID can route before the list learns it.
- Leave the simplification, whose only cost is a user not trying a new model ID.
Evidence (for the agent)
reference/api.mdx:80— "If you send a model ID that is not in this harness-specific list, Manifest returns M302: Model not available."- Code:
proxy.service.ts:961-964, verbatim comment: "When discovery has not learned the model yet, a provider-qualified or provider-inferable ID may still route through credentials enabled on this harness; the provider is the authority on whether that model exists." Then at:966: "Returns null when no unambiguous connected provider applies." The routing itself isresolveConnectedExplicitModel(:990-999); M302 is raised only in that null case (:1438). - Page-echo, not a re-raise: third page carrying this concept, after
llm-gateway.mdx:89(issue Docs audit — llm gateway (routing, tiers, fallbacks) — 2026-08-09 #53 finding 4, still open) andself-hosted.mdx(issue Docs audit — introduction (getting started) — 2026-08-07 #49 finding 3, accepted). Severity is lowest of this batch: the failure mode is a user under-using a feature.
Cleared during this audit (recorded so they are not re-derived)
- The model-list query parameters for capabilities and cost (
api.mdx:82-178) are correct on every falsifiable point: exact-string gating, USD per million tokens, per-field and whole-object omission when unknown,autonever carrying metadata,created: 0,-subscriptionIDs directly routable (proxy.controller.ts:104-116,150-168,190,194;openai-model-capabilities.ts:4,10-14,17-34). X-Manifest-ConfidenceandX-Manifest-Specificityare set but absent from the headers table (proxy-response-handler.ts:168,173-175). An unlisted extra header misleads nobody. Acceptable curation.DB_POOL_MAX/AUTH_DB_POOL_MAXdocumented as 30/10 against a real 10/5: re-verified today (app.config.ts:38,auth.instance.ts:33), unchanged since issue Docs audit — 2026-08-07 (PRs #2693–#2697) #48 finding 8 recorded it. Still open there, not re-raised here.- The gateway-tester CORS variable rows (
environment-variables.mdx:33,37, cited as 32/36 before the page shifted a line) are already open as issue Docs audit — 2026-08-07 (PRs #2693–#2697) #48 finding 10. Not re-raised. A sweep for every other internal codename across the four pages returned zero hits, so there is no new leak. STREAM_IDLE_TIMEOUT_MSis a real variable absent from the page, but it appears in no user-facing example file for the Docker install, so nothing is used-but-undefined.AUTOFIX_TIMEOUT_MSdefault10000is correct (autofix.module.ts:19,49).REQUEST_RECORDING_RETENTION_DAYSdefault365is correct for this page's audience: the code default resolves to 365 on any non-billing install (app.config.ts:58-63), and the page is self-hosted-only by its own note.PORT2099,NODE_ENVproduction,BETTER_AUTH_URLand the recordings path: the code defaults differ, but the stated values are the bundled compose file's effective ones, which is the install this page documents. Same call already recorded on 2026-08-12 for the self-hosting page.api.mdx:26sends users to the Harnesses page for a key. The key lives one level in, at the harness's Settings tab (Settings.tsx:247-311). The entry point is right and the retired/agentspath is not used, so nobody lands on a dead screen. Imprecise, not misleading.- The glossary describing only Default and Custom tiers: complexity routing exists in code but is being retired in-product, and no page documents it. Narrating it would break "less beats confusing".
headers.mdx:19on the session key is true as written. The unstated cliff (omitting it disables routing momentum and provider cache affinity,proxy-session-scope.ts:22-37) would require introducing a concept no page defines, and no user acts wrongly on the current sentence.headers.mdx:16marking the content type required: no explicit inbound validator, but body parsing is content-type driven (main.ts:206-207), so it is required in practice. Correct as written.api.mdx:184on streaming and fallback matches the warm-up peek before commit and the no-mid-stream-retry rule (proxy.service.ts:546,589-594;proxy.controller.ts:740-748).glossary.mdx:53"Up to 5 models" is true (routing.dto.ts:201-202,212-213). The uncapped legacy header-tier payload is an API-layer edge the dashboard never produces.- Glossary entries for harness, request, attempt, Autofix and the three auth types all match the platform, and "Autofix" is spelled without a hyphen on all four pages.
Parked for other topics (not findings here)
llm-gateway.mdx:52— the custom-tiers section never says a matching header also overrides an explicit model in the body (proxy.service.ts:970-975). Same gap as finding 8, on the routing topic's page. Both fixes should use the same sentence.self-hosted.mdx:321— "Everything else is optional: rate limits, provider timeouts, ..." implies a self-hoster can configure gateway rate limits by environment variable. None reaches the gateway. Same root cause as finding 1, on the self-hosting topic's page.
Reply with the finding number and the chosen option
(e.g. "3 → option 2", or "3: other idea, let's discuss").
PRs are then made manually with the agent, never by the harness.
Rejected findings: reply "N → reject" and they will never be re-raised.
Activity
docs-sync: scoped audit — reference (10 findings, issue #68), topic s…
Merge origin/main into fix/issue-53-llm-gateway
docs: exhaustion body code is the provider's own, fallback_exhausted …
SebConejo commentedon Aug 18, 2026
Traitement en lot (2026-08-18) : les dix findings → option recommandée, dédoublonnés contre les PRs #62 et #65 déjà mergées (findings 2, 3 et 6 largement pré-réglés). Le finding 4 est vérifié en live (tier simple, model/provider manifest constatés sur une instance locale). Les deux items parqués (llm-gateway:52, self-hosted:321) sont consommés dans la même PR. Pour le finding 1 : les vraies variables de plafonds arriveront avec la release de mnfst/llm-gateway#2724, une PR docs de suivi les documentera.
Merge pull request #74 from mnfst/fix/issue-68-reference