Skip to content

feat(OMN-19507): the dev-200 deploy agent defers a deploy while .200's model servers need the host; .101 is out of the deploy pool - #4128

Merged
jonahgabriel merged 10 commits into
devfrom
jonah/omn-19507-dev-200-load-gate
Sep 25, 2026
Merged

jonahgabriel merged 10 commits into
devfrom
jonah/omn-19507-dev-200-load-gate

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

What

Ticket OMN-19507, epic OMN-19500. Authority: omni_home ledger RULING 2026-09-25T12:40:36Z (ledger:3893), items (b) "a deploy lane on .200 with a load gate" and (c) "leave .101 out of the deploy pool and leave its dogfood copy as is".

This branch carries #4117 (deploy-agent instances as data, dev-200 declared and routed nothing) merged with current dev. #4117 is DIRTY against dev since #4105 landed. This PR resolves that conflict, so landing it lands #4117's two commits (f7e80c80b, 63376a979) too, and #4117 can then be closed as superseded. #4118 (compose-dev-200 receipt lane reader) stays stacked on top and carries the same EnumLabLane.COMPOSE_DEV_200 hunk, so it merges cleanly after this.

Summary (first draft by lab delegation run c1dd9e9d-6315-4622-9c3c-3a9bd578e92e from a fact list, then corrected against the diff):

  • Load gate. The new module scripts/deploy-agent/deploy_agent/load_gate.py gives an instance a gate. When the instance declares load_gate: in config/deploy_lane_routing.yaml, its agent does not accept a rebuild command, and does not start an idle converge, while the gate is shut. A deferral commits no offset and publishes nothing, so the command waits on the topic. The gate has two rules:

    • load1 per cpu above max_load1_per_cpu defers;
    • headroom = free - build_reserve - max(0, model_reserve - gpu_in_use) below min_headroom_gib defers.

    An input the agent cannot read defers the job, and the deferral names that input. Only dev-200 declares a gate.

  • .101 out of the pool. excluded_hosts: in the routing table names .101 (first hostname label stickybeatz; the .200 host is stickybeatz-studio), with the ruling cited in the value. The parser refuses an instance that names it. An agent on that host refuses to start, even with DEPLOY_AGENT_INSTANCE set. The .101 dogfood copy is not touched.

  • dev-200 verify targets. Since feat(OMN-19507): the per-merge verify jobs read the lane the deploy agent routed the merge to #4105, every instance needs a verify: block. dev-200 now has one on its 42xxx ports: receipt lane compose-dev-200, runner labels self-hosted, omnibase-verify, host-200. EnumLabLane.COMPOSE_DEV_200 is added outside ANY_OF_DEFAULT_LANES.

  • No route names dev-200. No runner carries host-200. The org runners API, read at 2026-09-25T14:58Z, lists 71 runners and none on .200. A test pins this, and it is the one test that changes when a verify runner is registered there and a route is added.

  • A fix found by the first real dev-200 job (2026-09-25T13:32Z, job 9abe33a6). The LLM endpoint env contract check always read ~/.omnibase/.env. On .200 that is the operator's workstation file (embedding port 8100), which the lane never reads. It now checks the store the agent was launched against (DEPLOY_AGENT_ENV_FILE). On .201 that declared store is ~/.omnibase/.env itself, so nothing changes there.

  • The agent logs its routing instance and load gate after logging is configured. Before this change, the dev-200 bring-up found no instance line in the log (ledger 2026-09-25T11:23:31Z, finding 2).

Measured baselines for the .200 thresholds

The .200 host is Stickybeatz-Studio: 24 cpu (sysctl hw.ncpu) and 192 GiB unified memory. It also runs the orchestration sessions and the gpt-oss-120b llama-server on :8130, with every layer on the GPU. On this machine GPU memory is system memory.

threshold value baseline
build_reserve_gib 24 The Docker VM is capped at 31 GiB (docker info MemTotal 33333612544). The running dev-200 lane holds about 7.3 GiB of it (docker stats, ledger 2026-09-25T11:23:31Z).
model_reserve_gib 70 IOAccelerator "In use system memory" peaked at 73418407936 bytes (68.4 GiB) while llama-server was serving (ioreg -c IOAccelerator 12:49:08Z).
min_headroom_gib 16 What a build may leave the host after both reserves.
max_load1_per_cpu 3.0 A backstop. Decode held at 66 tok/s single-stream at load1 47-49 (llama-server /metrics 12:57Z), against 68.6 tok/s at 12:42Z. The sessions-and-provers baseline peaked at load1 54.31, which is 2.26 per cpu (uptime 13:04Z).

Tests

  • scripts/deploy-agent/tests/unit/test_load_gate_omn19507.py: 23 tests. They cover the decision, the macOS readers (memory_pressure, ioreg), the probe never raising, recheck cadence, the table parsing, the committed table gating dev-200 only, the excluded-host refusals, the consumer deferring without commit or publish and resuming once a recheck opens, and idle converge waiting. test_llm_endpoint_env_contract_guard.py covers the env-store fix.
  • tests/ci/test_dev_200_verify_targets_omn19507.py (new, 4 tests): each lane: block agrees with its verify: block, dev-200's verify targets agree with docker-compose.dev-200.yml, no route names dev-200, and compose-dev-200 declares a settle budget inside its bounds (config/lab_pass_settle_budget.yaml, boots measured on the lab job below).
    • RED: against the pre-merge table (053d2305f), 2 fail: KeyError: 'verify', and 0 instances emit receipt lane 'compose-dev-200'. Against the pre-image settle file, the budget read raises SettleBudgetError ... declares no settle budget for lane 'compose-dev-200'.
    • GREEN: at the head, 4 pass.
  • Focused, local: 157 deploy-agent unit tests passed (load gate, instances as data, routing, env guard, dev-202 executor lane, host mutex, idle converge), plus 258 CI tests (verify route, dev-200, dev-105 and dev-202 lane boundaries, the lab-pass receipt gate, census host scope and manifest parity, incident replay, compose-dev-202 release-train and receipt tests). I did not run the whole suite on the launching host (omni_home rule 21).

Lab (rule 24)

Run on .200 under ledger HOLD 2026-09-25T15:25:07Z-lab-200-deploy-83 (surface 200-compose-dev; it extends 2026-09-25T13:05:42Z-lab-200-deploy-83). The agent clone ~/onex-lanes/dev-200/omnibase_infra runs this branch at b01886427. After the LaunchAgent kickstart, its log reads Deploy agent routing instance: dev-200, consumer group onex-deploy-agent-dev-200, 0 route(s), default dev-201, then Deploy agent load gate: {max_load1_per_cpu 3.0, build_reserve_gib 24, model_reserve_gib 70, min_headroom_gib 16, recheck_seconds 60} and loaded_code_sha b01886427 (15:34:03Z).

The gate deferred, then opened, on the real thresholds. The proof ran one real deploy of the omnibase_infra dev head f43e7d9b3a38 through the agent's own job code (DeployAgent._execute_command), with the gate checked first and the two bus publishes stubbed, so the shared dev bus carries no lab-proof terminal event.

  • Deferred 25 times, one reading a minute, from 15:35:18Z to 15:59:30Z. load1 was 89.60 to 131.08 on 24 cpu, which is 3.73 to 5.46 per cpu, above 3.00. Headroom stayed at 68.4-70.2 GiB, so the CPU rule shut the gate, not the memory rule.
  • Opened at 16:00:31Z, at load1 71.54 (2.98 per cpu), free 84%, GPU in use 2.6 GiB, headroom 69.9 GiB.
  • The job is fec4e429-f9fa-4818-a1b9-1919138255e9, accepted 16:00:31Z and finished success at 16:21:49Z. Its phases were preflight, git, compose_gen, runtime and verification, all success; seed and core were skipped. The agent's /job/<id> endpoint reads the same record.
    • The LLM env-contract preflight passed against the lane's own store. The first attempt at 13:32Z (job 9abe33a6) had failed there.
    • omninode-runtime answered /health after 358.7s.
    • runtime-effects needed the agent's one verify recreate and recovered after 241s.
    • Both containers carry org.opencontainers.image.revision=f43e7d9b3a38. omnimarket is vendored at 11ad3ddccad1, the omnimarket dev head.
  • The model server was not starved. llama-server (gpt-oss-120b, :8130) was never stopped or restarted. A read-only sampler polled it every 30s. Across the job's build and compose-up, from 16:08:01Z to 16:21:49Z, it took 28 samples: every /health answered 200 in at most 5.0 ms, host free memory held at 86-87%, and load1 ran from 45 to 76.

Receipts. The lane's verify job ran locally with lab_pass_receipt.py (converge, probe-lane, emit, verify), reading loopback URLs instead of host.docker.internal, which does not resolve on the host itself. Both receipts are FAIL, on one check each:

subject receipt lane result checks ok receipt sha256 (prefix)
omnibase_infra f43e7d9b3a38 compose-dev-200 FAIL 10 of 11 50b551c654fc54a2
omnimarket 11ad3ddccad1 compose-dev-200 FAIL 8 of 9 533a914339f2fb4d
  • The failing check in both is health_dimensions: discovery_errors, unhealthy across the full 900s budget. The runtime log names the cause: contract 'projection_lab_lane_health' is scoped to runtime lanes [compose-dev, onex-lab, onex-lab-k3s] and this runtime cannot name its lane (ONEX_RUNTIME_LANE='compose-dev-200' is not a registered lane).
    • This is the omnibase_core OMN-19408 registry gap. dev-202 on .202 reads the same DEGRADED dimension (its /health, read at 16:52:49Z), and the .201 dev lane reads HEALTHY.
    • The fix is omnibase_core#1771 (register compose-dev-105, -200 and -202), open. The dev-200 workspace build vendors the core dev head, so the next dev-200 deploy after chore(OMN-12245): backmerge main into dev for infra promotion #1771 lands picks it up.
  • Every other check passed: deployed and sibling revision, superseded-by-newer-rebuild, ready main and effects, projections, node inventory (312 wired contracts), the settle budget, the probe's generation binding, migrations (90 of 90 applied), and consumer-group lag (6 groups, max 0).
  • These receipts are local evidence only and were never uploaded as artifacts. The omnibase_infra one counts for nothing: omnibase_infra stays proven on .201 (ruling 2026-09-25T00:56:45Z, ledger:2772).

Runtime classification

This PR is runtime-affecting because it changes the deploy agent. On .201 nothing changes: dev-201 declares no gate and no lane block, and the table routes nothing to a new instance. On .202 nothing changes either: dev-202 declares no gate. SOLO, with the .201 agent idle.

Evidence-Ticket: OMN-19507
Evidence-Source: OCC#11294

onexbot-occ-writer Bot and others added 9 commits September 25, 2026 06:36
…e overlay on the 42xxx block

Onex-Lane: dev-200-lane
Onex-Session: 50705c397acd4413bdee8c1379652cf8
…, dev-200 declared routed-nothing, one launchd template for macOS lab hosts

Onex-Lane: dev-200-lane
Onex-Session: 50705c397acd4413bdee8c1379652cf8
…0-load-gate

# Conflicts:
#	deploy/lane-census/lane-manifest.yaml
#	scripts/generate_claude_lane_block.py
#	tests/unit/scripts/test_lane_census_manifest_parity.py
… servers need the host; .101 is an excluded host

A load_gate: block on a routing-table instance makes its agent defer, not refuse,
a command for itself (and an idle converge) while load1 per cpu or the memory
headroom a rebuild would leave (free less the Docker VM's growth less the
model server's unmapped working set) is past the declared threshold. Nothing is
committed or published; the partition is paused and resumed once a re-check
opens the gate. An unreadable input defers by name. Only dev-200 declares a
gate, so the .201 and .202 agents are unchanged.

excluded_hosts: in the table names .101 (hostname stickybeatz) per operator
RULING omni_home ledger:3893 item (c); no instance may name it and no agent may
run as it, even with DEPLOY_AGENT_INSTANCE set.

Onex-Lane: lab-200-deploy-83
Onex-Session: c2d0be217b2d4bc7b90c63f1e06e5adc
… from the measured baseline

Onex-Lane: lab-200-deploy-83
Onex-Session: c2d0be217b2d4bc7b90c63f1e06e5adc
… gate after logging is configured

Onex-Lane: lab-200-deploy-83
Onex-Session: c2d0be217b2d4bc7b90c63f1e06e5adc
…ainst its own env store, not the host's workstation file

The first real dev-200 job (lab proof, .200, 2026-09-25T13:32Z) failed at
preflight: validate_llm_endpoint_env_contract always read ~/.omnibase/.env,
which on .200 is the operator's workstation file (LLM_EMBEDDING_URL on port
8100) that the lane never reads, while the lane's own store dev-200.env carried
the canonical 8002. The store the unit declares (DEPLOY_AGENT_ENV_FILE) is now
the file checked; .201 declares ~/.omnibase/.env itself, so it is unchanged.

Onex-Lane: lab-200-deploy-83
Onex-Session: c2d0be217b2d4bc7b90c63f1e06e5adc
Resolves the routing table against #4105 (verify: blocks) and #4116 (the
dev-200 lane declaration): dev-202 keeps its lane: and verify: blocks, and
dev-200 gets a verify: block on its 42xxx ports with receipt lane
compose-dev-200 (EnumLabLane.COMPOSE_DEV_200, the same hunk as #4118).
No route names dev-200: no runner carries host-200 yet.

Onex-Lane: lab-200-deploy-83
Onex-Session: c2d0be217b2d4bc7b90c63f1e06e5adc
…fy targets match its overlay

The routing table describes an instance twice: the lane: block the deploy
agent composes from (OMN-19543) and the verify: block the per-merge verify
job reads (#4105). Both name the receipt lane, compose project and
containers, so they are pinned together, and dev-200's verify targets are
pinned to docker-compose.dev-200.yml as dev-202's are to its overlay. No
route may name dev-200 while no runner carries host-200.

Onex-Lane: lab-200-deploy-83
Onex-Session: c2d0be217b2d4bc7b90c63f1e06e5adc
@jonahgabriel jonahgabriel added the hold:auto-merge Holds auto-merge (check_auto_merge_hold.py); remove to release label Sep 25, 2026
jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Sep 25, 2026
…ibase_infra#4128 (#11294)

* evidence(OMN-19507): author OCC companion for OmniNode-ai/omnibase_infra#4128

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head b01886427756621efc57043b4e4c6f1cf2023a47.

* evidence(OMN-19507): self-bind OCC#11294 + rebind contract_sha256

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ Hostile Reviewer — REVIEWED

Critical findings: 2
Major findings: 7
Total findings: 17
Models succeeded: qwen3-review,qwen3-review-b,glm-review

Action required: findings were posted as review threads. Address or reject each one, then resolve its thread — the Hostile Review Thread Gate fails while hostile-reviewer threads are unresolved (OMN-17492).


Semantics (OMN-17492 — the model finds, thread resolution gates)

Surface Meaning Blocks merge?
Review threads Per-finding, posted by the reviewer No (informational)
Hostile Review Thread Gate Deterministic: unresolved hostile-reviewer threads exist Fails until resolved (not yet a required context)
degraded verdict Fewer than 2 models succeeded (infra) Fails this job with a named reason

Powered by omniintelligence.review_pairing.cli_review — multi-model adversarial review: qwen3-review, qwen3-review-b, glm-review (OMN-8468/OMN-8524/OMN-17492)

… first real dev-200 deploy

The per-merge verify job derives its ceiling from the routed lane's
declaration, so a lane without one refuses at the budget read. dev-200's
boots are measured on the lab-proof job fec4e429 at omnibase_infra
f43e7d9: omninode-runtime /health after 358.7s, runtime-effects after
712s from compose-up with one verify recreate, both inside the same 900s
compose-dev and compose-dev-202 declare.

Onex-Lane: lab-200-deploy-83
Onex-Session: c2d0be217b2d4bc7b90c63f1e06e5adc

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hostile Reviewer — adversarial findings (OMN-17492)

Models succeeded: qwen3-review, qwen3-review-b, glm-review
Models failed: none
New finding threads: 2
Deduped (already posted on this PR): 0
Below quorum (one model only, reported not threaded): 14
Nit-level findings suppressed: 1

The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.

Below quorum: 14 finding(s) raised by one model only (OMN-18479)

These are reported and NOT dropped, but they get no thread and do not block: a single model's finding no other model reproduced is not evidence enough to stop a merge. Read them; act on them if they are right.

  • [MAJOR] scripts/deploy-agent/deploy_agent/consumer.py, _maybe_resume_after_load_gate and poll_and_accept (qwen3-review) — Load gate deferral leaves partition paused indefinitely if recheck clock is not advanced | In consumer.py, when a command is deferred by the load gate, the partition is paused and load_gate_paused
  • [MAJOR] scripts/deploy-agent/deploy_agent/load_gate.py, decide function (qwen3-review) — Load gate memory calculation does not account for memory already allocated to the Docker VM | The load gate's memory headroom calculation is: `headroom = free - build_reserve - max(0, model_reserve -
  • [MAJOR] scripts/deploy-agent/deploy_agent/consumer.py (qwen3-review-b) — Load gate deferral does not handle coalescing or multiple pending records | When the load gate defers a command, the consumer seeks back to the current record's offset and pauses the partition. Howeve
  • [MAJOR] scripts/deploy-agent/deploy_agent/routing.py (qwen3-review-b) — resolve_instance checks excluded_hosts before DEPLOY_AGENT_INSTANCE, breaking explicit instance selection on excluded hosts | The new code in resolve_instance checks if the host is in excluded_hosts B
  • [MINOR] scripts/deploy-agent/deploy_agent/consumer.py, load_gate_paused field and _maybe_resume_after_load_gate (qwen3-review) — Missing test for load gate deferral when multiple partitions are paused | The load gate pauses a single partition when a command is deferred. However, if multiple commands are in flight and multiple p
  • [MINOR] scripts/deploy-agent/deploy_agent/load_gate.py, probe_host_load and _run (qwen3-review) — Load gate probe runs subprocesses on every check, which can be expensive | The probe_host_load function runs sysctl, memory_pressure, and ioreg subprocesses on every check. The `recheck_second
  • [MINOR] scripts/deploy-agent/deploy_agent/routing.py, resolve_instance (qwen3-review) — Excluded host check uses first hostname label, which may not match the operator's intent | The excluded_hosts key is the lowercased first hostname label. The comment says .101 has hostname `Sticky
  • [MINOR] scripts/deploy-agent/tests/unit/test_load_gate_omn19507.py, test_load_gate_consumer_resumes_the_partition_once_a_recheck_opens (qwen3-review) — Test for load gate deferral does not verify that the partition is not resumed when the gate is still shut | The test test_load_gate_consumer_resumes_the_partition_once_a_recheck_opens verifies that
  • [MINOR] scripts/deploy-agent/deploy_agent/agent.py, _idle_converge_gate_open (qwen3-review) — The load gate is only checked for the consumer's own instance, but the idle converge does not check the gate for the routed instance | The load gate is checked in the consumer's _process_message for
  • [MINOR] config/deploy_lane_routing.yaml, routes (qwen3-review) — The dev-200 instance is declared but has no route, so it will never receive commands | The dev-200 instance is declared in the routing table, but no route names it. This means that no command will e
  • [MINOR] scripts/deploy-agent/deploy_agent/load_gate.py (qwen3-review-b) — Load gate check spawns subprocesses on every poll cycle when gate is open | The LoadGate.check() method is called on every poll cycle when the gate is not paused (via _maybe_resume_after_load_gate or
  • [MINOR] scripts/deploy-agent/tests/unit/test_load_gate_omn19507.py (qwen3-review-b) — Missing test for load gate interaction with host_slot busy state | The load gate check (step 5b) occurs after the host_slot busy check (step 5a). The tests cover the case where the gate defers and whe
  • [MINOR] scripts/deploy-agent/deploy_agent/executor.py (qwen3-review-b) — DEV_INSTANCE_LANE_CONFIGS is built at import time from the committed table, creating a hidden dependency on file system state | The module-level constant DEV_INSTANCE_LANE_CONFIGS is built by calling
  • [MINOR] scripts/deploy-agent/tests/unit/test_deploy_agent_instances_as_data_omn19543.py (qwen3-review-b) — Test for health bind host uses subprocess to import module, which is fragile and slow | The test test_the_health_bind_defaults_to_every_interface uses subprocess.run to import the agent module in a fr

Findings demoted from threads (anchor rejected)

  • [MAJOR] hostile-reviewer (qwen3-review)

    LaunchAgent plist exposes Kafka SASL credentials in plaintext environment variables | The deploy-agent-instance.plist.template sets KAFKA_SASL_MECHANISM=SCRAM-SHA-256 and KAFKA_SECURITY_PROTOCOL=SASL_PLAINTEXT as environment variables. While the actual SASL username and password are not in the plist (they come from the env file), the security protocol and mechanism are exposed. More critically, the DEPLOY_AGENT_ENV_PROTECTED list includes KAFKA_SASL_ENV_PREFIX but not the actual SASL credentials,

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MAJOR] hostile-reviewer (qwen3-review-b)

    LaunchAgent plist exposes internal network topology and credentials in plaintext | The rendered LaunchAgent plist contains hardcoded internal IP addresses (192.168.86.201:19092 for Kafka) and SASL mechanism details. While the plist is rendered to a user-local path (~/.omnibase/...), the template itself is committed to the repository. The KAFKA_BOOTSTRAP_SERVERS value is a static internal IP. If the repository is ever exposed or if the plist is accidentally committed with sensitive values, this leaks interna

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hostile Reviewer — adversarial findings (OMN-17492)

Models succeeded: qwen3-review, qwen3-review-b, glm-review
Models failed: none
New finding threads: 6
Deduped (already posted on this PR): 0
Below quorum (one model only, reported not threaded): 10
Nit-level findings suppressed: 1

The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.

Below quorum: 10 finding(s) raised by one model only (OMN-18479)

These are reported and NOT dropped, but they get no thread and do not block: a single model's finding no other model reproduced is not evidence enough to stop a merge. Read them; act on them if they are right.

  • [MAJOR] scripts/deploy-agent/deploy_agent/agent.py (qwen3-review) — Health endpoint binds to 0.0.0.0 by default | The HEALTH_BIND_HOST defaults to 0.0.0.0 if DEPLOY_AGENT_BIND_HOST is not set. While the launchd plist explicitly sets it to 127.0.0.1, the system
  • [MAJOR] scripts/deploy-agent/deploy_agent/consumer.py (qwen3-review) — Load gate deferral does not handle coalescing of newer commands | The load gate defers a command by seeking the partition back to the current offset and pausing it. If a newer command for the same cor
  • [MAJOR] scripts/deploy-agent/deploy/launchd/deploy-agent-instance.plist.template (qwen3-review-b) — Kafka SASL credentials exposed in LaunchAgent plist template | The new deploy-agent-instance.plist.template hardcodes KAFKA_BOOTSTRAP_SERVERS, KAFKA_SECURITY_PROTOCOL, KAFKA_SASL_MECHANISM, an
  • [MAJOR] scripts/deploy-agent/deploy_agent/load_gate.py (qwen3-review-b) — Load gate memory calculation uses free percent, not absolute free bytes, leading to inaccurate headroom | The decide function calculates `free_gib = reading.memory_total_gib * reading.memory_free_pe
  • [MAJOR] scripts/deploy-agent/deploy_agent/load_gate.py (qwen3-review-b) — Load gate probe spawns 4 subprocesses on every check, with no caching | Each call to LoadGate.check() invokes probe_host_load(), which spawns up to 4 subprocesses: os.getloadavg() (no subprocess
  • [MAJOR] scripts/deploy-agent/deploy_agent/routing.py (qwen3-review-b) — Excluded host check uses first hostname label, which may not match the operator's intent | The resolve_instance function extracts the first label of the hostname: `host = (hostname or socket.gethost
  • [MAJOR] scripts/deploy-agent/tests/unit/test_load_gate_omn19507.py (qwen3-review-b) — No test for load gate deferral timeout or escalation | The tests for the load gate cover the decision logic, the consumer's deferral behavior, and the idle converge's wait. However, there is no test f
  • [MINOR] scripts/deploy-agent/deploy_agent/load_gate.py (qwen3-review) — Load gate probe runs subprocesses on every check | The probe_host_load function runs sysctl, memory_pressure, and ioreg subprocesses on every call to LoadGate.check(). This is called on ever
  • [MINOR] scripts/deploy-agent/tests/unit/test_load_gate_omn19507.py (qwen3-review) — Missing test for load gate deferral with multiple messages in a batch | The tests for the load gate consumer deferral only test the case where a single message is deferred. There is no test for the ca
  • [MINOR] scripts/deploy-agent/deploy_agent/load_gate.py (qwen3-review-b) — Load gate recheck_due uses time.monotonic, which is not affected by system clock changes, but the recheck interval is not configurable per instance | The recheck_seconds is a field in `ModelLoad

Findings demoted from threads (anchor rejected)

  • [CRITICAL] hostile-reviewer (qwen3-review)

    Load gate deferral loses pending command on partition resume | When the load gate defers a command, the consumer seeks the partition back to the deferred record's offset and pauses it. However, when the gate later opens and the partition is resumed, the consumer does not re-process the deferred record. The record was never committed, so it remains at the paused offset. Upon resume, the consumer will fetch from that offset, but the code path in poll_and_accept that handles the deferred record is not re-ent

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [CRITICAL] hostile-reviewer (qwen3-review-b)

    Load gate deferral leaves partition paused indefinitely if gate never opens | When the load gate defers a command, the consumer seeks back to the current offset and pauses the partition. The partition is only resumed when _maybe_resume_after_load_gate detects the gate is open. However, if the host remains under load indefinitely (e.g., a model server is stuck in a high-memory state), the partition stays paused forever. The agent will never process any commands for that instance, and there is no timeout or

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MINOR] hostile-reviewer (qwen3-review)

    Instance lanes are loaded at module import time | The DEV_INSTANCE_LANE_CONFIGS is built at module import time by calling build_dev_instance_lane_configs(load_instance_lanes(AGENT_CLONE_ROOT)). This means the routing table is read from disk when the module is imported. If the routing table is updated while the agent is running, the agent will not see the new configuration until it is restarted. This is consistent with the existing behavior for the routing table, but it means that adding a new instance r

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MINOR] hostile-reviewer (qwen3-review)

    Test for health bind host uses subprocess | The test test_the_health_bind_defaults_to_every_interface uses a subprocess to import the agent module and check the HEALTH_BIND_HOST value. This is because the module reads the environment variable at import time. This is a valid approach, but it is slow and fragile. It relies on the Python interpreter being available and the module being importable in the subprocess. This could be flaky in CI environments where the Python path is not set up correctly. | Evid

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MINOR] hostile-reviewer (qwen3-review-b)

    Instance lane configs are built at module import time, preventing dynamic reconfiguration | The DEV_INSTANCE_LANE_CONFIGS dict is built at module import time by calling build_dev_instance_lane_configs(load_instance_lanes(AGENT_CLONE_ROOT)). This means the instance compositions are fixed at agent start. If the routing table is updated (e.g., a new instance is added), the agent must be restarted to pick up the change. This is consistent with the existing design (the router is also read at start), but it m

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

  • [MINOR] hostile-reviewer (qwen3-review-b)

    Test for dev-200 composition agreement with overlay does not verify port conflicts | The test test_dev_200_composition_agrees_with_its_overlay verifies that the health ports in the lane config match the ports published by the overlay. However, it does not verify that these ports do not conflict with other services on the host. The comment says 'its port block is 42xxx, below the macOS ephemeral range', but there is no test that verifies the ports are not already in use by other services. The `preflight_po

    Resolve this thread when addressed — the Hostile Review Thread Gate blocks while hostile-reviewer threads are unresolved (OMN-17492).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold:auto-merge Holds auto-merge (check_auto_merge_hold.py); remove to release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant