Skip to content

Observability renderer: host loopback port overrides that survive a re-render - #290

Merged
seathatflowsinourveins merged 3 commits into
mainfrom
claude/backends-host-port-overrides
Sep 25, 2026
Merged

seathatflowsinourveins merged 3 commits into
mainfrom
claude/backends-host-port-overrides

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Collaborator

Scope

Behaviour

  • --port-overrides FILE takes a JSON object {"template port": host port}. It rewrites every 127.0.0.1:<template port> address in the rendered configs and the five unit texts in one regex pass, with no chaining, so a swap works.
  • The map is kept as <config-root>/port-overrides.json, and later renders reuse it without the flag. Deleting that file returns to the template ports.
  • Fails closed: the map is validated against the full render before any file is written. It exits 2 and writes nothing when:
    • an override matches no rendered address (a stale entry);
    • the port also appears outside a 127.0.0.1:<port> address, such as Grafana's http_port or Loki's listen ports, which the override does not rewrite;
    • the host port is already a rendered address that is not itself overridden;
    • the input is invalid: not an object, a non-digit key, a non-int or bool value, out of range, the same port, or two template ports mapped to one host port.
  • Without overrides the output is unchanged: same files and same content. Only the write order moved after rendering.

Evidence

  • Tests (local, WSL2): the new test_observability_backends_configure.py covers no overrides, overrides with persistence and a byte-identical re-render, the swap, and 9 refusal cases. Together with the other backend tests and the docs-consistency, contract and release-pin tests: 85 passed, 1 skipped. scripts/validate.py passed.
  • Native check on the workstation, read-only: main plus this change was rendered with the workstation's map into a scratch root, and the paths were substituted. The result was compared with the live files, using only an allowlist of the template outputs plus the five units; the Grafana credential file was never read.
    • 14 of 15 files were byte-identical, including the rules file with 14333→24333 and all five units.
    • ecosystem-prometheus.yml was equal as parsed YAML; the live file was re-serialized with different formatting.
    • The scratch render was deleted afterwards.
  • After merge: write the workstation's map to its <config-root>/port-overrides.json (host-local), so the next re-render keeps the ports.
  • Review: an independent read-only reviewer (Sonnet) is reviewing this commit. Its findings will be addressed or answered here before merge.

🤖 Generated with Claude Code

…e-render

All WSL 2 distributions share one network namespace, so the workstation
moved five scraped services off their template ports (collector 18889 and
18888, Qdrant 16333, vLLM 8231, the 14333 HTTP check). configure.py had no
input for that, so the host's live config was hand-adapted and any re-render
would reset those ports; the #284 rollout (#287) had to be applied
surgically for that reason.

configure.py --port-overrides FILE takes a JSON object of template port to
host port and rewrites every 127.0.0.1:<port> address in the configs and
units in one pass. It keeps the map as <config-root>/port-overrides.json,
which later renders reuse. It refuses the whole render (exit 2, nothing
written) for a stale override, for a port that also appears outside a
127.0.0.1:<port> address (Grafana's http_port, Loki's listen ports), for a
host port that collides with another rendered address, and for invalid
input. The map is validated against the full render before any file is
written.

Rendering main with the workstation's map into a scratch root reproduces
the live files: 14 of 15 byte-identical, and ecosystem-prometheus.yml equal
as parsed YAML.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@seathatflowsinourveins seathatflowsinourveins added the lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers label Sep 25, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

- Medium: the bare-port check scanned the caller's root paths, so a data
  root such as .../18888-data refused an 18888 override with a misleading
  cause. The checks now ignore the four root paths, and the refusal names
  the file that has the bare port.
- Low: a non-ASCII digit key (such as U+00B2) passed str.isdigit() and
  crashed int() with exit 1. Keys must now be ASCII digits (exit 2).
- Low: the README lists malformed input among the refusals.
- Tests: each template output without overrides equals the template with
  only its path tokens replaced; a root path containing the port digits
  renders; a mixed valid and stale map is refused; a non-ASCII digit key
  is refused.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@seathatflowsinourveins

Copy link
Copy Markdown
Collaborator Author

Independent review of 25d4580d by a separate read-only reviewer (Sonnet evidence-reviewer). No high-severity findings. It verified the no-chaining single pass, the swap and collision logic, the ordering (nothing is written on refusal) and the unchanged no-override path. Fixed in 30a173bf:

  • Medium, reproduced: --data-root .../18888-data with an 18888 override was refused as a bare-port collision, because the check scanned the substituted root paths. The checks now ignore the four root paths, and the refusal names the offending file.
  • Low, reproduced: a key such as \"\\u00b2\" passed isdigit() and crashed int() with exit 1. Keys must now be ASCII digits (exit 2).
  • Low: the README lists malformed input among the refusals.
  • Tests added: a full no-override template check, the root-path digits case, a mixed valid and stale map, and a non-ASCII key.

After the fix: 86 passed, 1 skipped, 37 subtests; validate.py passed. The native comparison re-ran against the live workstation files with the same result, 14 of 15 byte-identical and ecosystem-prometheus.yml equal as parsed YAML.

@seathatflowsinourveins
seathatflowsinourveins enabled auto-merge (squash) September 25, 2026 21:23
…port-overrides

# Conflicts:
#	manifests/evidence.json
@seathatflowsinourveins
seathatflowsinourveins merged commit c0e9023 into main Sep 25, 2026
23 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/backends-host-port-overrides branch September 25, 2026 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant