Skip to content

Commit 8644f9c

Browse files
committed
docs+feat: address review nits N1–N4 on the ECS substrate
Review follow-ups for #596 (fix itself unchanged; B1 dead-export fixed in the base PR #503): - N1: correct the stale "64 GB / 16 vCPU" comment in agent.ts — the task is larger (64 GB was itself OOM-killed per the construct's sizing history). Defer the exact figure to EcsAgentCluster rather than duplicate/drift it. - N2: reword the memory-grant + oauth-grant comments — an AccessDenied on those paths is LOGGED (memory.py treats it as an infra failure; config.py's token resolver logs it), not "silently" no-op'd. Describe the user-visible effect (no persisted learning / no 👀→✅ reaction) rather than pin a log level that drifts. - N3: the ec2:DescribeAvailabilityZones comment already frames it correctly as a FALSE build-gate failure (not a WARN no-op) — no change needed; noted here for completeness. - N4: run_task_from_payload now emits a WARN when it drops a KNOWN orchestrator key (build_command / merge_branches / base_branch / github_token_secret_arn) that run_task doesn't accept — expected today (consumed elsewhere / not yet wired), but makes a future "wired one side, forgot the other" no-op visible instead of silent (the ABCA-487 class). Foreign keys still drop quietly. + 2 tests (warns on a known dropped key; stays quiet on a foreign key). Full cdk build green (2286) + full agent suite green (1194); eslint/ruff clean.
1 parent a5550eb commit 8644f9c

4 files changed

Lines changed: 54 additions & 8 deletions

File tree

agent/src/pipeline.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,21 @@ def _on_trace_truncated(max_bytes: int, first_dropped: int) -> None:
12751275
#: shadow it). Any payload key not in this set is ignored, never passed through.
12761276
_RUN_TASK_PARAMS = frozenset(inspect.signature(run_task).parameters)
12771277

1278+
#: Orchestrator payload keys we KNOW about that ``run_task`` does not (yet)
1279+
#: accept as a parameter. Dropping one of these is expected today (e.g.
1280+
#: ``base_branch`` is consumed via ``hydrated_context``, not a run_task kwarg;
1281+
#: ``github_token_secret_arn`` is resolved before this call), but a key that
1282+
#: shows up here AND is silently dropped is exactly the "wired one side of an
1283+
#: orchestrator→agent field, forgot the other" no-op that ABCA-487 was — so we
1284+
#: WARN when we drop one, making a future contract gap visible instead of silent.
1285+
#: Keys not in this set (genuinely foreign) are dropped quietly as before.
1286+
_KNOWN_ORCHESTRATOR_KEYS = frozenset({
1287+
"build_command",
1288+
"merge_branches",
1289+
"base_branch",
1290+
"github_token_secret_arn",
1291+
})
1292+
12781293

12791294
def run_task_from_payload(payload: dict) -> dict:
12801295
"""Invoke :func:`run_task` from a full orchestrator payload dict.
@@ -1301,7 +1316,15 @@ def run_task_from_payload(payload: dict) -> dict:
13011316
for key, value in (payload or {}).items():
13021317
target = _PAYLOAD_KEY_ALIASES.get(key, key)
13031318
if target not in _RUN_TASK_PARAMS:
1304-
continue # not a run_task parameter — ignore (e.g. github_token_secret_arn)
1319+
# Not a run_task parameter — ignore. A KNOWN orchestrator key being
1320+
# dropped is expected today but worth a breadcrumb: if run_task ever
1321+
# grows a matching param, this WARN is where a "forgot to wire it
1322+
# through" no-op surfaces (N4 / ABCA-487 class). Foreign keys are
1323+
# dropped quietly.
1324+
if key in _KNOWN_ORCHESTRATOR_KEYS and value is not None:
1325+
log("WARN", f"run_task_from_payload: dropping known orchestrator key '{key}' "
1326+
f"(not a run_task parameter) — consumed elsewhere or not yet wired")
1327+
continue
13051328
if value is None:
13061329
continue # let run_task's default apply
13071330
if target in _PAYLOAD_STR_KEYS:

agent/tests/test_run_task_from_payload.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,22 @@ def test_every_forwarded_key_is_a_real_run_task_param(self):
142142
}
143143
)
144144
assert set(seen).issubset(accepted)
145+
146+
def test_warns_when_dropping_a_known_orchestrator_key(self):
147+
# N4: a KNOWN orchestrator key that run_task doesn't accept is dropped
148+
# (expected today) but logged, so a future "wired one side, forgot the
149+
# other" contract gap (the ABCA-487 class) is visible, not silent.
150+
logs: list[tuple[str, str]] = []
151+
with patch("pipeline.log", side_effect=lambda level, msg, **kw: logs.append((level, msg))):
152+
_capture({"build_command": "mise run build", "repo_url": "r"})
153+
assert [m for level, m in logs if level == "WARN" and "build_command" in m], (
154+
"expected a WARN when dropping the known orchestrator key build_command"
155+
)
156+
157+
def test_does_NOT_warn_when_dropping_a_foreign_key(self):
158+
# A genuinely-foreign key (not a known orchestrator field) is dropped
159+
# quietly — no log noise for keys we never expected to forward.
160+
logs: list[tuple[str, str]] = []
161+
with patch("pipeline.log", side_effect=lambda level, msg, **kw: logs.append((level, msg))):
162+
_capture({"some_future_unrelated_key": "v", "repo_url": "r"})
163+
assert not [m for level, m in logs if "some_future_unrelated_key" in m]

cdk/src/constructs/ecs-agent-cluster.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ export interface EcsAgentClusterProps {
8383
* ``bedrock-agentcore:CreateEvent``) succeed on the ECS substrate. The
8484
* AgentCore runtime role already gets this via ``agentMemory.grantReadWrite``
8585
* in agent.ts; without the same grant here, memory writes hit AccessDenied and
86-
* silently no-op on ECS (WARN), so learning never persists on an ECS-only
87-
* deployment. Omitted in isolated construct tests / memory-less deployments.
86+
* no-op on ECS (logged, non-fatal — memory.py treats an AccessDenied as an
87+
* infra failure), so learning never persists on an ECS-only deployment.
88+
* Omitted in isolated construct tests / memory-less deployments.
8889
*/
8990
readonly agentMemory?: AgentMemory;
9091
}
@@ -240,8 +241,8 @@ export class EcsAgentCluster extends Construct {
240241
// (write_task_episode / write_repo_learnings → bedrock-agentcore:CreateEvent)
241242
// succeed on ECS. The AgentCore runtime role gets this via
242243
// agentMemory.grantReadWrite(runtime) in agent.ts; without the same grant
243-
// here the writes hit AccessDenied and silently no-op (WARN) on the ECS
244-
// substrate, so learning never persists on an ECS-only deployment.
244+
// here the writes hit AccessDenied and no-op on the ECS substrate (logged,
245+
// non-fatal), so learning never persists on an ECS-only deployment.
245246
if (props.agentMemory) {
246247
props.agentMemory.grantReadWrite(taskRole);
247248
}
@@ -253,7 +254,9 @@ export class EcsAgentCluster extends Construct {
253254
// 👀→✅ reaction and drive the channel MCP. The AgentCore runtime role +
254255
// orchestrator/fanout/screenshot roles all have this prefix grant; the ECS
255256
// task role did NOT, so on ECS the token fetch hit AccessDenied and
256-
// reactions/MCP silently no-op'd (ECS-parity gap, live-caught on ABCA-488).
257+
// reactions/MCP no-op'd — logged by config.py's token resolver, not silent,
258+
// but the channel effect (no 👀→✅, no MCP) is invisible to the user
259+
// (ECS-parity gap, live-caught on ABCA-488).
257260
// GetSecretValue only — the container reads the token; the orchestrator owns
258261
// refresh/PutSecretValue.
259262
taskRole.addToPrincipalPolicy(new iam.PolicyStatement({

cdk/src/stacks/agent.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,8 +579,9 @@ export class AgentStack extends Stack {
579579
// --- ECS Fargate compute backend (CONTEXT-GATED) ---
580580
// K12 (2026-06-29): AgentCore's fixed microVM envelope OOM-kills heavy
581581
// CI-parity builds (ABCA's own ~2800-test `mise run build`). ECS Fargate
582-
// gives a tunable 64 GB / 16 vCPU task (see EcsAgentCluster) for repos that
583-
// set ``compute_type: 'ecs'``. GATED on the ``compute_type`` deploy context
582+
// gives a bigger, tunable task (see EcsAgentCluster for the exact vCPU/memory
583+
// sizing + its OOM history — 64 GB was itself OOM-killed, so it runs larger)
584+
// for repos that set ``compute_type: 'ecs'``. GATED on the ``compute_type`` deploy context
584585
// (default 'agentcore') — ECS resources only synthesize when you deploy with
585586
// ``--context compute_type=ecs``, so the default synth (and the
586587
// bootstrap-coverage test that synths with default context) stays

0 commit comments

Comments
 (0)