Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions adoption/templates/systemd/omniroute.service
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@
# Generate it without printing any value: evidence/artifacts/omniroute-gateway-20260927/scripts/make_server_env.py.txt.
# Values in that file override the Environment= lines below (systemd.exec(5), EnvironmentFile=).
#
# The lsof shim. shim/ on PATH holds evidence/artifacts/omniroute-gateway-20260927/scripts/lsof-shim.sh.txt. Without
# it, serve's port preflight (bin/cli/commands/serve.mjs L252-261 at a58000c7 and 81c9b6da) reads null.length on a free
# port whenever lsof exits 1, and serve exits. Upstream 8183e9b79 (#14812, resolveServeBusyPids in serve.mjs) fixes this
# and is in 2f42a9ac1, so the shim is redundant on that build; it stays only for continuity with the recorded units.
# Drop the shim/ segment at the next rebuild after a free-port start passes without it.
# The lsof shim. shim/ on PATH holds evidence/artifacts/omniroute-sol-max-20260930/scripts/lsof-shim-v2.sh.txt (v2, sha256
# b6ae900224df3dc7...; v1, the 2026-09-27 shim, is evidence/artifacts/omniroute-gateway-20260927/scripts/lsof-shim.sh.txt). Upstream's
# port preflight (bin/cli/utils/pid.mjs findListeningPids, used by serve.mjs resolveServeBusyPids) runs `lsof -ti :PORT`, which
# lists CLIENT sockets too: a client's dead pooled connection (CLOSE-WAIT) makes a restart, or systemd's restart after a crash,
# fail with "Port is already in use" although nothing listens. v2 answers that one query with exit status 2, which upstream's own
# fallback for an unusable discovery tool (#14518) turns into a bind probe of the port; a real second listener is still refused.
# v1 (no-match status 1 becomes 0, for the pre-#14812 null.length crash) is redundant since #14812 and does not help with clients.
#
# Posture. The workstation runs with REQUIRE_API_KEY=false and requireLogin=false by the user's decision, which is
# safe on loopback only. Any multi-user or non-loopback host sets REQUIRE_API_KEY=true and keeps the dashboard login.
Expand All @@ -67,7 +69,7 @@ After=network-online.target
[Service]
Type=simple
EnvironmentFile=%h/.local/share/omniroute/server.env
# shim/ first, so serve's port preflight finds the lsof no-match adaptation (see "The lsof shim" above).
# shim/ first, so serve's port preflight is guarded by the bind probe and not by lsof (see "The lsof shim" above).
Environment=PATH=@OMNIROUTE_PREFIX@/shim:@NODE_PREFIX@/bin:/usr/local/bin:/usr/bin:/bin
# serve binds 0.0.0.0 when this is unset (bin/cli/utils/serverHost.mjs L16-26); the keyless posture needs loopback.
Environment=OMNIROUTE_SERVER_HOST=127.0.0.1
Expand Down
37 changes: 34 additions & 3 deletions docs/decisions/2026-09-30-omniroute-rebuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ Every claim carries the evidence class used in the receipt (`receipt.json`, `evi
| --- | --- | --- | --- |
| #13788 (two commits) | both builds | `/v1/alpha/search` for Codex `web.run` | a release carries it (open upstream PR at the time of writing) |
| affinity patch `045aa81f3` | 20128 | keeps a reused session pin ahead of OAuth occupancy | upstream ships an equivalent |
| upstream PR 15167 (`f5d8e150b`, one commit) | 20128 | `gpt-6.1-sol` in the Codex registry and both alias sets, so `max` and the `-max` suffix reach the wire | a release carries it (open upstream PR at the time of writing) |
| `lsof` shim v2 (`b6ae900224df3dc7`) | 20128's new prefix | keeps a client's dead connection from blocking a restart (upstream's bind-probe fallback becomes the preflight guard) | upstream's preflight counts only listeners |
| `lsof` shim on `PATH` | both units | port preflight on a free port | redundant now: upstream #14812 (`8183e9b79`, `resolveServeBusyPids`) is in 2f42a9ac1; drop at the next rebuild after a free-port start passes without it |
| settings above (512, `compressToolResults` false, headroom off in the engines map) | 20129 | defect mitigations | upstream fixes the defects |

Expand Down Expand Up @@ -228,13 +230,42 @@ Classes are kept apart.
- **Headerless `[ccr]` only** (the first plan, from our fixtures). Superseded by the user's direction to follow upstream.
- **Compression on 20128.** Not applied; see below.

## Update 2026-09-30, 06:32Z: 20128 carries upstream PR 15167 (gpt-6.1-sol at max)

**Why.** The rebuild's residual said `max` clamps to `xhigh` for `gpt-6.1-sol`. The live cost was measured before the restart: 1154 of 1495 `gpt-6.1-sol`
rows since 00:00Z had `max` requested and `xhigh` sent ([`checks/calllog-effort-counts-before-switch.json`](../../evidence/artifacts/omniroute-sol-max-20260930/checks/calllog-effort-counts-before-switch.json)),
native Codex callers included, and the `-max` suffix of the new base was an unknown model id (HTTP 400 with the prefix, 401 without it). The user asked (relayed by the pi-practice session, not seen
first-hand here) for the highest quality on 6.1.

**Source.** Upstream PR [#15167](https://github.com/diegosouzapw/OmniRoute/pull/15167), head `f5d8e150b79e0901fa18241c7f29bff889b87c14`, one commit, 5 files +23/-0 on release/v3.8.52 (same practice as
the #13788 carry: a cited upstream change, no self-written patch). It applies cleanly, its stable patch-id equals the cherry-pick's, and its registry entries use the capabilities
block whose context (872000) equals the live catalog's. Codex 0.159.2's bundled catalog lists `max` for `gpt-6.1-sol`.

**Decision.** Carry it on 20128 only. The clamp and the suffix parser are in the Codex executor, which runs only on 20128; 20129's sharedgw node forwards to it. One restart, no
hindsight-live restart, 20129 unchanged (the Gate A owner's conditions). Alternatives: both builds (a second restart for no effect); wait for a release (upstream's release/v3.8.52 and
main lack it); use the body effort only (`max` in the body is the clamped path, the defect itself; the suffix ids `-max` and `-xhigh` were rejected with HTTP 400 before the carry).

**A hazard found on the way, and its fix in the new prefix only.** `omniroute serve` refuses to start while any client holds a dead connection to its port: its preflight runs
`lsof -ti :PORT`, which lists client sockets, and hindsight-api held such a CLOSE-WAIT socket to 20128 (this is why the 00:02Z switch restarted hindsight-live). Upstream main and
release/v3.8.52 still do it. Shim v2 (`b6ae900224df3dc73fff2a50b3d7206d78895c6147e93e80b62e66d423e69854`; v1 was `b12c64614c54bc86...`) answers that one query with exit status 2, which upstream's own fallback for an unusable discovery tool
(`resolveServeBusyPids`, #14518) turns into a bind probe. Tests with kept outputs: control with shim v1, real `omniroute serve` of the candidate prefix: restart refused; shim v2: same restart
reaches health in 5 s; a second real instance is still refused. The previous prefix and 20129's prefix keep v1 (residual).

**Applied.** 2026-09-30T06:32:50Z, `switch_gateways.py --only 20128`: three unit lines changed (Description, the PATH shim segment, ExecStart), MainPID 950031 to 3262255, 20129 and hindsight-live
untouched, no settings write, rollback copy in the switch directory. Probe gate before and after: `gpt-6.1-sol` with body `max` went from `xhigh` to `max` upstream, the suffix ids and the
bare id answer 200 with the right effort, astra stays `max`, a 0.157.1 client request answers 200. The gateway's context-window reconciler removed one automatic override row on restart
(same 872000 now in the registry). Everything is in [`evidence/artifacts/omniroute-sol-max-20260930/`](../../evidence/artifacts/omniroute-sol-max-20260930/receipt.json).

**Also recorded.** The sharedgw connection expiry of 05:50Z to 05:55Z (claim C9): my baseline probe sent `sharedgw/gpt-6.1-sol-max` before the carry; 20128 answered 401 and 20129 parked the node's
only connection as expired for all callers until the dashboard's Test connection restored it. Upstream has no fix; the probe script now sends a lane request only after the bare id answered 200.

## Comparison that would overturn it

- The tip's `check:pack-boot` or a later unit run shows a defect the carries cause; then rebuild without the carry.
- Upstream merges #13788 into a release or `main`: drop the carry. Upstream ships an equivalent of the affinity patch:
drop it. Upstream fixes the session-dedup key collision, the integer re-encoding or the Responses tool-loop truncation:
restore the upstream default of the matching setting (80, headroom on, `compressToolResults` true).
- Upstream lists `gpt-6.1-sol` in `CODEX_MAX_ALIAS_MODELS`: `max` stops clamping to `xhigh` for it.
- Upstream merges PR 15167 into a release: drop that carry (20128 carries it since 2026-09-30T06:32:50Z).
- A measured drop of the cache-read share on 20128 traffic that arrives through the `sharedgw` hop (baseline 93.8% over
573 rows, reported by the pi-practice session, not reproduced here) after headerless dedup, beyond what the user accepts.
- A first-time `apply_patch` failure, or another exact-match failure, traced to lite's whitespace folding on traffic through either
Expand Down Expand Up @@ -263,8 +294,8 @@ Classes are kept apart.
outputs of older models and very long sessions with large tool outputs. The Gate A owner's stated preference is off through the
windows, and any change must land at least 6 h before the seal announcement with a new owner record. (b) `blockedProviders` and `noAuthFallbackDisabledProviders`,
which the apply contract cannot read back.
- `max` effort on `gpt-6.1-sol` clamps to `xhigh` (static alias sets in `reasoningSuffix.ts`; a two-line local patch
would lift it and is not applied).
- `max` effort on `gpt-6.1-sol` clamped to `xhigh` on the rebuild (static alias sets in `reasoningSuffix.ts`); 20128 carries upstream PR 15167
since 2026-09-30T06:32:50Z and sends `max` (update below); 20129 forwards and never had the clamp.
- The live canary of the token-save settings (12 requests) waits for Codex capacity (2026-10-04T00:35Z); the output style
it would have measured is now off. The cache-share effect of headerless dedup is unmeasured until the pi runs report.
- The Opus review of the first plan returned twelve defects (three medium); the workflow was stopped in its fix stage,
Expand Down
8 changes: 4 additions & 4 deletions docs/foundation-stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,12 @@ For owned lifecycle, preserve the same DATA_DIR/secrets through restart. Upstrea
Since 2026-09-27 the workstation's gateway pools its Codex accounts for GPT-6 lanes. The [decision record](decisions/2026-09-27-omniroute-account-pool.md) holds the reasons, the keyless loopback posture and its risk, and the overturn conditions. Its [evidence](../evidence/artifacts/omniroute-gateway-20260927/README.md) holds the 2026-09-27 build's provenance, its installed unit and the probes. Both gateways were rebuilt on 2026-09-30 ([decision](decisions/2026-09-30-omniroute-rebuild.md), [evidence](../evidence/artifacts/omniroute-rebuild-20260930/README.md)).

**What runs.** Two source builds of upstream's default branch `release/v3.8.51` at [`2f42a9ac1`](https://github.com/diegosouzapw/OmniRoute/commit/2f42a9ac19d1a247ec9ce5473b790843724b3061) (upstream tagged `v3.8.51` later, on the same tree; see the decision record):
- **20128**, `omniroute.service`, the shared gateway: build `ae5539a56`. It carries the open upstream PR [#13788](https://github.com/diegosouzapw/OmniRoute/pull/13788) (`/v1/alpha/search`, which Codex's standalone `web.run` calls) and the local affinity patch, which keeps a reused session pin ahead of OmniRoute's OAuth occupancy re-pick.
- **20128**, `omniroute.service`, the shared gateway: build `cf6748d04` (since 2026-09-30T06:32Z; `ae5539a56` before). It carries the open upstream PR [#13788](https://github.com/diegosouzapw/OmniRoute/pull/13788) (`/v1/alpha/search`, which Codex's standalone `web.run` calls), the local affinity patch, which keeps a reused session pin ahead of OmniRoute's OAuth occupancy re-pick, and the open upstream PR [#15167](https://github.com/diegosouzapw/OmniRoute/pull/15167) (`gpt-6.1-sol` in the Codex registry and alias sets, so `max` and the `-max` suffix reach the wire).
- **20129**, `omniroute-fw.service`, the framework instance: build `87c4c488d`, which is `2f42a9ac1` + #13788. It has its own data directory, and a provider node inside it forwards to 20128.

Upstream's merged [#14886](https://github.com/diegosouzapw/OmniRoute/pull/14886) (`7f5de7ba6`, in the base since `81c9b6da`) replaces the 2026-09-27 build's cherry-pick of [#14904](https://github.com/diegosouzapw/OmniRoute/pull/14904). Without such a fix, every `/v1` inference route answered HTTP 500 behind Next 16.3.5's request Proxy on this host's Node 24, as the coordinator reported. A synthetic fixture shows the same `Request` construction failure on Node 26, upstream's Docker base, where the gateway was not run.

The non-upstream deltas are #13788 (both gateways) and the affinity patch (20128 only); the `lsof` shim is still on both units' `PATH` but redundant, because upstream #14812 is in the base. The [decision's deltas table](decisions/2026-09-30-omniroute-rebuild.md#non-upstream-deltas) gives each one's purpose, evidence and the upstream change that retires it. While the affinity patch runs, create no OAuth (Codex) routing combo on 20128 (its standing constraint F1; the [decision record](decisions/2026-09-30-omniroute-rebuild.md#non-upstream-deltas) gives its basis and limits).
The non-upstream deltas are #13788 (both gateways), the affinity patch and #15167 (20128 only); the `lsof` shim is on both units' `PATH`: v1 (redundant since upstream #14812) for 20129 and the previous 20128 prefix, v2 in 20128's new prefix, which makes upstream's bind probe the preflight guard so that a client's dead pooled connection cannot block a restart. The [decision's deltas table](decisions/2026-09-30-omniroute-rebuild.md#non-upstream-deltas) gives each one's purpose, evidence and the upstream change that retires it. While the affinity patch runs, create no OAuth (Codex) routing combo on 20128 (its standing constraint F1; the [decision record](decisions/2026-09-30-omniroute-rebuild.md#non-upstream-deltas) gives its basis and limits).

npm published 3.8.51 on 2026-09-30 (the tag's tree equals `2f42a9ac1`'s), so the pin's own condition is met, and the published package passed its own install, boot smoke and provenance check (`evidence/receipts/omniroute-3851-npm-qualification-20260930.json`); the component pin in `manifests/stack.json` is still 3.8.50, and moving it is a separate change to that shared file. Upstream already carries the fix, #14886.

Expand All @@ -242,8 +242,8 @@ npm published 3.8.51 on 2026-09-30 (the tag's tree equals `2f42a9ac1`'s), so the
Serve's port preflight counts any process with a socket on the port, a client in CLOSE_WAIT included, as the port's owner (`lsof -ti :PORT`, `bin/cli/utils/pid.mjs` L86). So before restarting 20128, restart the clients that hold connections to it, such as `hindsight-live.service`.
- **Effort.** `a58000c7` caps `gpt-6-astra` at `ultra` ([`reasoningSuffix.ts` L11-31](https://github.com/diegosouzapw/OmniRoute/blob/a58000c7685f4091c7a6fd8ddf3ebce7d2ec67c3/open-sse/executors/codex/reasoningSuffix.ts#L11-L31)), and sends `max` on the wire for `ultra` ([`codex.ts` L1463](https://github.com/diegosouzapw/OmniRoute/blob/a58000c7685f4091c7a6fd8ddf3ebce7d2ec67c3/open-sse/executors/codex.ts#L1463)).
- The gateway's `call_logs` recorded `max` requested and `max` upstream on `bf0255649`, the 2026-09-27 build before #13788 was added.
- `reasoningSuffix.ts` and both `codexClient.ts` files are byte-identical at `2f42a9ac1` (`codex.ts` changed only in upstream's #15119, which moves `getResponsesSubpath` into its own file and makes it refuse path traversal). No live effort observation has been recorded on the rebuilt gateways.
- `gpt-6.1-sol` is in neither alias set, so `max` clamps to `xhigh` for it until upstream lists it.
- `reasoningSuffix.ts` and both `codexClient.ts` files are byte-identical at `2f42a9ac1` (`codex.ts` changed only in upstream's #15119, which moves `getResponsesSubpath` into its own file and makes it refuse path traversal). The effort actually sent upstream is recorded in `call_logs` for rows with encrypted reasoning (`reasoning_effort_upstream`; NULL means absent, not none sent); the 2026-09-30 update of the decision record has the before and after.
- `gpt-6.1-sol` was in neither alias set on the rebuild, so `max` clamped to `xhigh` for it; 20128 carries upstream PR 15167 since 2026-09-30T06:32Z and sends `max`.

Keep Thinking Budget `passthrough`.
- **Compression.** `a58000c7` compresses native Codex passthrough when compression is on; `chatCore.ts` changes at `2f42a9ac1`, and the comment that advises excluding `codex/*` is now at L1437.
Expand Down
20 changes: 20 additions & 0 deletions evidence/artifacts/omniroute-sol-max-20260930/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 20128 at max effort for gpt-6.1-sol: upstream PR 15167 on the running build, 2026-09-30

Record of the restart of the 20128 gateway (`omniroute.service`) at 2026-09-30T06:32:50Z onto build `cf6748d04` (the running build `ae5539a56` plus the one commit of
upstream PR 15167, head `f5d8e150b79e0901fa18241c7f29bff889b87c14`), of its qualification and of the read-backs; claims, evidence classes and residuals are in `receipt.json`. The decision is the
2026-09-30 update in [`docs/decisions/2026-09-30-omniroute-rebuild.md`](../../../docs/decisions/2026-09-30-omniroute-rebuild.md).

| Files | What they are | Class |
| --- | --- | --- |
| `checks/upstream-pr-15167-identity.txt`, `checks/codex-bundled-catalog-0159.2.txt` | the PR's identity and patch-ids from git alone; the effort levels Codex 0.159.2 lists for the GPT-6 models | source review |
| `checks/calllog-effort-counts-before-switch.json`, `checks/calllog-effort-counts-after-switch.json` | counts of requested and upstream effort per model from 20128's call_logs (metadata columns, read-only) | our check |
| `checks/effort-wire-*.json` | what the Codex executor would put on the wire for 13 requests, on the running build's source and on the candidate's | our check |
| `checks/qualification-*.txt` | install, boot smoke (shim v1 as installed), upstream check:pack-boot, targeted tests on the candidate and on the running build's source | upstream check and our check |
| `checks/preflight-*.txt`, `checks/preflight-*.json` | the restart-blocking preflight trap (control with shim v1), the fix with shim v2, a second real instance still refused, and the scratch-port tables | our check |
| `checks/switch-output.txt`, `checks/readback-after-switch.txt`, `checks/unit-before-after.diff`, `checks/omniroute.service.after-switch.txt` | the switch script's output, the units' states and hashes, the three changed unit lines, the installed unit | our check |
| `checks/owner-record-*.json`, `checks/owner-record-diff.txt` | `gateway_record.py` (schema 2, both ports) before and after, and the path-by-path difference | our check |
| `checks/probe-gate-before-switch.json`, `checks/probe-gate-after-switch.json` | the same probe script before and after: statuses and the effort columns of each request | live model calls |
| `checks/sharedgw-connection-expiry-20260930.txt` | the 05:50Z to 05:55Z incident on 20129's sharedgw node and its repair (a transcription of printed outputs) | our check |
| `scripts/` | the harness as it ran, `lsof-shim-v2.sh.txt` (sha256 `b6ae900224df3dc73fff2a50b3d7206d78895c6147e93e80b62e66d423e69854`), and the diff of `switch_gateways.py` | our tools, not upstream |

Host paths are masks (`<NS>`, `<B3>`, `<B2>`, `<TOOLS>`, `<HOME>`, `<STATE>`); colour codes are removed; nothing else in an output is edited.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"observed_utc": "2026-09-30T06:34:09Z",
"store": "omniroute",
"since": "2026-09-30T06:30:03Z",
"filter": "gpt-6",
"groups": [
{
"model": "gpt-6.1-sol-max",
"requested": "-",
"upstream": "max",
"reasoning_source": "encrypted",
"n": 3
},
{
"model": "gpt-6-astra-max",
"requested": "-",
"upstream": "max",
"reasoning_source": "encrypted",
"n": 1
},
{
"model": "gpt-6-sol",
"requested": "low",
"upstream": "low",
"reasoning_source": "encrypted",
"n": 1
},
{
"model": "gpt-6.1-sol",
"requested": "max",
"upstream": "max",
"reasoning_source": "encrypted",
"n": 1
},
{
"model": "gpt-6.1-sol-xhigh",
"requested": "-",
"upstream": "xhigh",
"reasoning_source": "encrypted",
"n": 1
}
]
}
Loading
Loading