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
11 changes: 7 additions & 4 deletions docs/architecture/context-discipline.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,15 @@ switches, each read in exactly one place:
| `EGG_CONTEXT_MEASUREMENT` | `egg_agent.measurement.measurement_enabled` | Opt-in for the emit-only per-event measurement surfaces (#3249). ON (and `EGG_PIPELINE_ID` set) → after each BRC event the agent emits the six context-discipline metrics through the progress + heartbeat surfaces; OFF (default) → the legacy path is byte-identical (no measurement emit). |
| `EGG_REAL_BACKEND_WINDOW` | `egg_agent.measurement._resolve_real_window` | Cross-boundary integer override of the model's real backend window, mirroring `EGG_RESEED_THRESHOLD`. Because `orchestrator` is off `PYTHONPATH` in-pod, this is the channel that populates the window-relative metrics (`real_backend_window` / `window_utilization`) in production; the orchestrator import is a dev/CI-only fallback, and both metrics degrade to `None` when neither yields a value. |

**Setting the flags in production.** `EGG_CONTEXT_DISCIPLINE` and
`EGG_SESSION_RESUME` are read in-pod but must be set on the **orchestrator
deployment** — `orchestrator/kubernetes_spawner.py` forwards them from the
**Setting the flags in production.** `EGG_CONTEXT_DISCIPLINE`,
`EGG_CONTEXT_MEASUREMENT`, and `EGG_SESSION_RESUME` are read in-pod but must be
set on the **orchestrator deployment** —
`orchestrator/kubernetes_spawner.py` forwards them from the
orchestrator's own environment into every spawned agent Job
(`_FORWARDED_DISCIPLINE_ENV_KEYS`, added in
[#3272](https://github.com/jwbron/egg/issues/3272)). Nothing else wires them
[#3272](https://github.com/jwbron/egg/issues/3272); `EGG_CONTEXT_MEASUREMENT`
added in [#3277](https://github.com/jwbron/egg/issues/3277) once #3271's in-pod
consumer landed). Nothing else wires them
into the Job env (`envFrom` is absent; `sandbox_env` is built from pipeline
fields), so a `kubectl set env` on the pods directly has no effect. The
forward runs before the per-spawn `extra_env` merge, so a targeted
Expand Down
13 changes: 6 additions & 7 deletions orchestrator/kubernetes_spawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,15 +221,14 @@ def _resolve_wait_producer_allowlist(phase: str | None, role: str, repo: str | N
# the per-spawn substrate (``EGG_SESSION_STATE_FILE`` / ``EGG_RESEED_THRESHOLD``)
# needs real per-pod wiring and is deliberately NOT a blind forward.
#
# NOTE: the #3249 emit-only measurement knob (``EGG_CONTEXT_MEASUREMENT``) is
# deliberately NOT forwarded yet — it has no in-pod consumer (no
# ``egg_agent.measurement`` module exists), and the flag-name auto-discovery
# convention (``sandbox/tests/test_context_discipline_flag.py``) means the
# eventual consumer's flag name isn't pinned. Forwarding a guessed name now would
# be a silent no-op. Add it here once #3249's emit consumer lands under a fixed
# name.
# ``EGG_CONTEXT_MEASUREMENT`` forwards the #3249 emit-only measurement knob: its
# in-pod consumer landed in #3271 as ``egg_agent.measurement`` under the fixed
# name ``MEASUREMENT_ENV = "EGG_CONTEXT_MEASUREMENT"``, which ``record_measurement``
# gates on. Without forwarding it the surfaces no-op in every pod (#3277), so the
# instrumented proving run captures zero metrics even with discipline active.
_FORWARDED_DISCIPLINE_ENV_KEYS: tuple[str, ...] = (
"EGG_CONTEXT_DISCIPLINE",
"EGG_CONTEXT_MEASUREMENT",
"EGG_SESSION_RESUME",
)

Expand Down
6 changes: 6 additions & 0 deletions orchestrator/tests/test_kubernetes_spawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,7 @@ def test_flags_forwarded_into_pod_env_when_set(
self, spawner, mock_k8s_client, mock_gateway, monkeypatch
):
monkeypatch.setenv("EGG_CONTEXT_DISCIPLINE", "true")
monkeypatch.setenv("EGG_CONTEXT_MEASUREMENT", "true")
monkeypatch.setenv("EGG_SESSION_RESUME", "1")
result = spawner.spawn_agent_job(
pipeline_id="pipe-cd",
Expand All @@ -985,10 +986,14 @@ def test_flags_forwarded_into_pod_env_when_set(
)
env = result.environment
assert env["EGG_CONTEXT_DISCIPLINE"] == "true"
# #3277: the measurement knob must ride along, else #3271's emit
# surfaces no-op in-pod and the proving run captures zero metrics.
assert env["EGG_CONTEXT_MEASUREMENT"] == "true"
assert env["EGG_SESSION_RESUME"] == "1"

def test_flags_absent_when_unset(self, spawner, mock_k8s_client, mock_gateway, monkeypatch):
monkeypatch.delenv("EGG_CONTEXT_DISCIPLINE", raising=False)
monkeypatch.delenv("EGG_CONTEXT_MEASUREMENT", raising=False)
monkeypatch.delenv("EGG_SESSION_RESUME", raising=False)
result = spawner.spawn_agent_job(
pipeline_id="pipe-cd2",
Expand All @@ -999,6 +1004,7 @@ def test_flags_absent_when_unset(self, spawner, mock_k8s_client, mock_gateway, m
)
env = result.environment
assert "EGG_CONTEXT_DISCIPLINE" not in env
assert "EGG_CONTEXT_MEASUREMENT" not in env
assert "EGG_SESSION_RESUME" not in env

def test_extra_env_overrides_forwarded_flag(
Expand Down
Loading