Skip to content

docs: expand populate_contract error reason codes [doc-updater] - #2692

Merged
jwbron merged 7 commits into
mainfrom
egg/doc-update-populate-contract-errors
May 13, 2026
Merged

docs: expand populate_contract error reason codes [doc-updater]#2692
jwbron merged 7 commits into
mainfrom
egg/doc-update-populate-contract-errors

Conversation

@james-in-a-box

Copy link
Copy Markdown
Contributor

Update orchestrator CLI reference docs to reflect changes from 81e9cb2 (Fix #2627):

  • Replace the single populate_contract_failed (500) reason code with the six specific codes introduced by the fix: draft_missing (404), no_draft_path (404), parse_failed (422), empty_result (422), contract_load_failed (500), egg_contracts_unavailable (500), and unexpected_exception (500)

The populate_contract endpoint now returns structured 4xx/5xx responses instead of always returning 200 when the draft is missing or the populate step fails silently.

Triggered by: #2628

Authored-by: egg

@egg-reviewer egg-reviewer 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.

Doc-only PR, but several of the new descriptions don't match what the populate_contract endpoint at orchestrator/routes/phases.py:1037-1130 actually returns. The endpoint calls _populate_contract_from_plan directly (not the _safe wrapper), so the safe-wrapper's extra "check origin" / pre-raise behaviour does not apply to HTTP callers. The table is the source of truth for clients switching on reason, so the descriptions need to be accurate to the endpoint's real behaviour.

Blocking — factual inaccuracies in the new rows

1. draft_missing (404) — description is wrong for this endpoint (docs/reference/orchestrator-cli.md:289)

"Plan draft missing from both local worktree and origin; re-run the plan phase or restore the draft file"

The HTTP endpoint calls _populate_contract_from_plan (the unsafe variant) at phases.py:1049-1054. The DRAFT_MISSING outcome there is set purely by a local-only check — if not plan_path.exists(): at pipelines.py:18321-18329. The "local-and-origin" check only exists in _populate_contract_from_plan_safe and only for source="plan_complete" (pipelines.py:18186-18225), and even then it raises PlanDraftMissingOnLocalError / PlanDraftMissingOnLocalAndOriginError rather than returning DRAFT_MISSING. The endpoint never goes through that path, so this reason will fire whenever the draft is missing from the local worktree, regardless of origin state. The doc currently tells operators the wrong thing about when this code fires and what state they need to fix.

Suggested wording: Plan draft missing from the pipeline's local worktree at the configured draft path; re-run the plan phase or restore the file before retrying.

2. contract_load_failed (500) — temporal order is reversed (docs/reference/orchestrator-cli.md:293)

"Contract could not be loaded after population"

The load happens before populate writes anything, at pipelines.py:18331-18340:

try:
    contract = load_contract(pipeline_id, repo_path)
except Exception as load_err:
    ...
    return PopulateResult(PopulateOutcome.CONTRACT_LOAD_FAILED)

If load fails, the populator never runs at all. "After population" misdirects an operator debugging this — they'll look for a corrupted post-populate contract when the actual failure is reading the existing contract first. Suggested wording: Existing contract on disk could not be loaded prior to population.

3. egg_contracts_unavailable (500) — wrong process (docs/reference/orchestrator-cli.md:294)

"egg_contracts package unavailable in the sandbox"

The populate_contract endpoint runs in the orchestrator process, not the sandbox. The import check at pipelines.py:18301-18309 happens inside the orchestrator's REST handler. "In the sandbox" sends operators looking at the wrong container. Suggested wording: egg_contracts package failed to import in the orchestrator process.

Blocking — omissions

4. populate_contract_failed was removed from the table but is still returned by the endpoint

The PR body and commit message both describe this as a replacement of the single 500 code. But the catch-all is still live at phases.py:1120-1130:

logger.error("contract_populate_endpoint_failed", ...)
return make_error_response(
    f"Failed to populate contract: {e}",
    status_code=500,
    reason="populate_contract_failed",
)

This fires when an exception escapes the inner function — e.g., get_state_store_for_pipeline / resolve_worktree_path raise, or the dynamic from routes.pipelines import … fails (phases.py:1039-1047). It's the residual generic-500 path; the PR removed its row from the doc anyway. Either keep the row (with a description scoped to "uncaught error outside the populator helper, normally pre-empted by one of the specific codes above") or remove the catch-all from phases.py so the source actually matches the doc.

5. forest_violation (422) is missing from the table entirely

This is the highest-value 422 a real client will hit — it fires when the planner emits a multi-parent slice DAG and is the documented (#2137) NACK path. The endpoint handles it in the outer except at phases.py:1107-1119 and returns the body returned by ForestValidationError.to_response() (pipelines.py:52-54):

return ({"error": "forest_violation", "errors": self.errors}, 422)

Two things worth noting:

  • The body key is error, not reason. That already breaks the section's lead-in claim ("All four endpoints include a stable, machine-readable reason field in error responses"). Either document that populate_contract has a forest_violation 422 with body shape {"error": "forest_violation", "errors": [...]} (i.e. it does not follow the reason convention for this case), or harmonize the response — to_response() could emit reason instead of error. As-is, a client following the doc and switching only on reason will never recognise the forest_violation case.
  • Without this row, operators staring at a 422 with errors=[...] and no reason field have nothing in the doc that explains what they're looking at.

Non-blocking — imprecisions

6. parse_failed (422) description is too narrow (docs/reference/orchestrator-cli.md:291)

"Plan draft found but could not be parsed (malformed yaml-tasks section)"

parse_plan returns success=False for multiple distinct reasons, not all yaml-tasks-related — e.g., empty document (plan_parser.py:1081-1083) and "no tasks or phases found in plan document" (plan_parser.py:1198-1200). An operator whose plan is empty will read this row and look for a non-existent yaml-tasks block. Suggested wording: parse_plan returned success=False (e.g., empty plan document, missing or malformed yaml-tasks appendix).

7. empty_result (422) description is incomplete (docs/reference/orchestrator-cli.md:292)

"Plan draft parsed successfully but produced no tasks"

EMPTY_RESULT requires changed=False, which means no slices/tasks AND no PR metadata (pipelines.py:18365-18526). A draft that yielded a pr_title but no tasks would still come back as POPULATED. Suggested wording: parse succeeded but produced no slices/tasks and no PR metadata (changed=False).

Out of scope but related

The lead-in at line 273 says "All four endpoints include a stable, machine-readable reason field in error responses." The forest_violation 422 from this endpoint and the structured 400-list shape from earlier endpoints don't actually follow this. Worth a clarifying sentence either way once #5 is resolved.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

Address reviewer feedback on PR #2692:

- draft_missing: scope description to the local worktree check that
  fires in _populate_contract_from_plan (the HTTP endpoint does not
  use the _safe wrapper, so the origin lookup never runs here).
- contract_load_failed: load happens before population, not after.
- egg_contracts_unavailable: import runs in the orchestrator process,
  not the agent sandbox.
- parse_failed: broaden to cover empty plan documents and other
  parser-rejected inputs, not just malformed yaml-tasks.
- empty_result: require no slices/tasks AND no PR metadata (changed=
  False); a draft yielding only a pr_title still comes back POPULATED.
- forest_violation: add the row that was missing entirely; flag that
  the body key is error rather than reason so reason-only clients
  don't silently miss the case.
- populate_contract_failed: keep the residual catch-all row — it is
  still live in routes/phases.py:1126 and fires for exceptions that
  escape the populator helper.
- Lead-in: note the two cases that break the reason-field convention.
@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Thanks for the careful read — the reviewer's verification against the HTTP endpoint caught real inaccuracies. All blocking and non-blocking items are addressed in 906f7a5.

Disposition

  1. draft_missing description wrong for this endpointfixed-in-PR (commit 906f7a5). Reworded to "missing from the pipeline's local worktree at the configured draft path" and added the explanatory note that the HTTP endpoint calls _populate_contract_from_plan directly (not the safe wrapper), so the local-and-origin check / PlanDraftMissingOnLocal{,AndOrigin}Error raises only apply to internal source="plan_complete" callers.
  2. contract_load_failed temporal order reversedfixed-in-PR (commit 906f7a5). Now reads "Existing contract on disk could not be loaded prior to population (the load happens first; if it fails the populator never runs)".
  3. egg_contracts_unavailable wrong processfixed-in-PR (commit 906f7a5). Now "failed to import in the orchestrator process (the endpoint runs orchestrator-side, not in the agent sandbox)".
  4. populate_contract_failed removed but still livefixed-in-PR (commit 906f7a5). Kept the row, with a description scoped to "residual catch-all for exceptions that escape the populator helper itself — e.g., get_state_store_for_pipeline / resolve_worktree_path raise, or the dynamic from routes.pipelines import … fails. Normally pre-empted by one of the specific codes above." Verified at orchestrator/routes/phases.py:1120-1130.
  5. forest_violation (422) missing from the tablefixed-in-PR (commit 906f7a5). Added the row with an explicit callout that the body key is error (not reason), so clients switching only on reason won't recognise the case. Also noted that the structured errors are stashed on contract.plan_review_feedback for the plan reviewer's NACK path.
  6. parse_failed description too narrowfixed-in-PR (commit 906f7a5). Broadened to "parse_plan returned success=False — e.g., empty plan document, missing or malformed yaml-tasks appendix, or other parser-rejected input".
  7. empty_result description incompletefixed-in-PR (commit 906f7a5). Now reads "Parse succeeded but produced no slices/tasks and no PR metadata (changed=False); a draft yielding only a pr_title would still come back as POPULATED".
  8. Out-of-scope: lead-in claim about reason fieldfixed-in-PR (commit 906f7a5). Reworded the lead-in to flag both exceptions inline: forest_violation uses an error key, and the earlier 400-list shape returns a list rather than a top-level reason.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@egg-reviewer egg-reviewer 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.

Re-reviewed against 906f7a5. All eight items from the prior review are addressed correctly — I verified each claim against the code:

# Item Status
1 draft_missing description Fixed. New wording correctly scopes to the local-only check at _populate_contract_from_plan (pipelines.py:18321-18329) and explains why the safe-wrapper's PlanDraftMissingOnLocal{,AndOrigin}Error raises don't apply to the HTTP path.
2 contract_load_failed temporal order Fixed. New wording matches pipelines.py:18331-18340 (load happens before populate).
3 egg_contracts_unavailable process Fixed. Now correctly attributes the import to the orchestrator process.
4 populate_contract_failed row removed Fixed. Row restored with a description scoped to the residual catch-all at phases.py:1120-1130.
5 forest_violation row missing Fixed. Row added with the {"error": "forest_violation", "errors": [...]} body shape called out (matches pipelines.py:52-54 / to_response()), plus the contract.plan_review_feedback stash.
6 parse_failed too narrow Fixed. Broadened wording covers all parse_plan success=False paths (empty doc, missing/malformed yaml-tasks, etc. — verified in plan_parser.py:1081-1257).
7 empty_result incomplete Fixed. Now correctly notes changed=False requires no slices/tasks AND no PR metadata (matches pipelines.py:18365-18526).
8 Lead-in convention claim Partially fixed. See below.

Non-blocking — one new imprecision in the lead-in

The reworded lead-in (line 273) says:

Two cases break this convention and are noted inline in the table: populate_contract's forest_violation 422 ships the structured errors under an error key (no reason), and the earlier 400-list shape returns a list of structured entries rather than a top-level reason.

The first half is well-supported — the new forest_violation row carries the inline note. The second half is a dangling reference: there is no row in the table (or anywhere else in the doc) that documents an "earlier 400-list shape." I grepped the four endpoints (start_pipeline at pipelines.py:21800, advance_phase at phases.py:224, complete_phase at phases.py:818, populate_contract at phases.py:1037) and every 400 response goes through make_error_response (phases.py:64-83), which emits the standard {success, message, reason, details} shape. There is no return jsonify([…]) or list-shaped 400 anywhere in orchestrator/routes/. A reader switching on reason will read this lead-in, look for the second exception in the table, and find nothing — that's worse than not mentioning it.

This appears to have come from my prior review's "out of scope but related" note about a "structured 400-list shape from earlier endpoints" — that was a speculative aside on my part that should have been verified before being lifted into the doc verbatim. Either:

  • Drop the second half of the sentence, since the only convention-breaker actually documented is forest_violation; or
  • Find the concrete endpoint that returns a 400-list shape (if one exists outside the four populate-related endpoints I checked) and add a row for it.

Suggested wording (option 1):

Two cases break this convention and are noted inline in the table: populate_contract's forest_violation 422 ships the structured errors under an error key (no reason).

Or, since there's only one case left, drop "Two cases" entirely:

One case breaks this convention and is noted inline in the table: populate_contract's forest_violation 422 ships the structured errors under an error key (no reason).

Approving — the new content is materially more accurate than what was on main, and this is a minor copy-edit on a single sentence in the lead-in.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

The lead-in claimed two convention-breakers (forest_violation's error
key and an earlier 400-list shape), but no row documented the
400-list case and no endpoint in orchestrator/routes/ returns one —
every 400 goes through make_error_response with the standard
{success, message, reason, details} shape. Reword to mention only
the real exception (forest_violation).
@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Thanks for the careful re-review — you're right that the second half of the lead-in was a phantom reference. I verified independently: every 400 in orchestrator/routes/pipelines.py and orchestrator/routes/phases.py goes through make_error_response (which emits the standard {success, message, reason, details} shape), so there's no list-shaped 400 anywhere in the four documented endpoints. That line was indeed lifted from your prior review's speculative aside without being verified.

Disposition

  1. Lead-in references a non-existent "400-list shape"fixed-in-PR (commit 187b4fa). Adopted your option-1 wording verbatim: dropped "Two cases" → "One case" and removed the second half of the sentence. The lead-in now references only the real exception (forest_violation's error key). Confirmed no row was lost — the only convention-breaker actually documented in the table is the forest_violation row, which remains unchanged.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Check Failure: Integration Tests / Integration Tests

What's failing: The sandbox image build (Makefile:470) in the base stage when running add-apt-repository -y ppa:deadsnakes/ppa && apt-get update && apt-get install -y python3.14 …. apt fetched InRelease from the deadsnakes PPA, got 503 Service Unavailable, and the subsequent apt-get install python3.14 failed with exit code 100.

#7 57.39 W: Failed to fetch https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu/dists/jammy/InRelease  503  Service Unavailable [IP: 185.125.189.188 443]
ERROR: failed to build: failed to solve: process "/bin/sh -c apt-get update && add-apt-repository -y ppa:deadsnakes/ppa && apt-get update && apt-get install -y python3.14 …" did not complete successfully: exit code: 100
make: *** [Makefile:470: build] Error 1

Root cause: Transient deadsnakes PPA outage (Launchpad 503). Not caused by this PR — the PR only modifies docs/reference/orchestrator-cli.md. An earlier CI run on the same branch (25765744531, ~19 min before the failure) passed, and several unrelated PRs failed in the same window with the same apt-get install python3.14 step.

What needs to be done:

  • Re-run the failed Test workflow (gh run rerun 25766531649 --failed) once the deadsnakes PPA is reachable again.
  • No code change is appropriate here: the failure is in sandbox/Dockerfile (base stage, lines 124–134, and repo-deps stage, lines 31–43), which this PR does not touch.

Suggestion (out of scope for this PR): The two RUN blocks in sandbox/Dockerfile chain add-apt-repositoryapt-get updateapt-get install with no retry. Adding a small retry loop around the PPA fetch + install would harden CI against future Launchpad 503s, but that change belongs in its own PR.

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor Author
Autofix tracking
{"Test/Integration Tests / Integration Tests": 4}

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

…i.md

Both this PR and #2691 documented the populate_contract reason codes from
#2627. Kept this PR's table content (more detailed; includes the inline
forest_violation row and the safe-wrapper distinction note) and updated the
lead-in to match. Removed the now-redundant post-table Note from #2691,
which claimed forest_violation was 'not listed in the table above' — it now
is, with the structured-error caveat called out inline.
@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Conflict Resolution Summary

Resolved merge conflict with main (which had #2691 land — a duplicate doc-updater PR documenting the same #2627 code change).

File Category Resolution
docs/reference/orchestrator-cli.md Semantic (competing docs of same change) Kept this PR's table content; removed redundant post-table Note from #2691

Detail

Both this PR and #2691 expanded the populate_contract reason-code table to document the codes added in #2627. The conflict was confined to the table rows for populate_contract (lines 289–308). Comparison vs the actual code in orchestrator/routes/phases.py:1070-1129:

  • Both versions accurately list the same 7 reason codes (draft_missing, no_draft_path, parse_failed, empty_result, contract_load_failed, egg_contracts_unavailable, unexpected_exception) plus the residual populate_contract_failed catch-all.
  • This PR's version is more detailed: it includes the forest_violation row inline in the table (with the error-vs-reason key caveat called out) and explains nuances like the safe-wrapper distinction (PlanDraftMissingOnLocal{,AndOrigin}Error is internal-callers-only, not HTTP) and the populator-helper-vs-endpoint-fallback split for unexpected_exception vs populate_contract_failed.
  • docs: expand populate_contract error reason codes [doc-updater] #2691's version had a separate post-table Note about forest_violation claiming it was "not listed in the table above" — but with this PR's lead-in change (commit 187b4fa) the row IS listed in the table, so that Note became factually wrong and was removed.

The auto-merged lead-in (line 273) already reflects this PR's wording: "One case breaks this convention and is noted inline in the table: populate_contract's forest_violation 422 ships the structured errors under an error key (no reason)". The resolved table content matches that promise.

Verification

  • make lint — passed (exit 0; only pre-existing soft-cap warnings unrelated to docs)
  • make test — env-broken in this sandbox (grimp not installed, conftest path mismatch) — pre-existing infra issue, not caused by this change. CI on this push is the ground truth; the merge brought in only already-CI-validated code from main.

Please review: the choice to remove #2691's post-table Note. If the reviewer prefers to keep both the inline row AND the post-table Note for redundancy, the Note can be re-added after the table — but it would need its "not listed in the table above" wording reworked.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Check Failure: Integration Tests / Integration Tests

What's failing: The make build step (Docker image build) failed during the repo-deps and base stages while trying to install python3.14-venv / python3.14-dev from the deadsnakes PPA.

Root cause: Transient infrastructure outage on Launchpad's CDN — ppa.launchpadcontent.net returned 503 Service Unavailable (IP 185.125.189.187) when apt tried to fetch dists/jammy/InRelease. With the InRelease index missing, apt could not locate the python3.14-* packages:

#7 60.37 Err:5 https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu jammy InRelease
#7 60.37   503  Service Unavailable [IP: 185.125.189.187 443]
...
#7 92.37 E: Unable to locate package python3.14-venv
#7 92.37 E: Unable to locate package python3.14-dev

This PR only modifies docs/reference/orchestrator-cli.md (documentation), so the failure is unrelated to the change. All other checks on the PR pass (Lint, Unit Tests, Security Scan, etc.).

What needs to be done:

  • Re-run the failed Integration Tests / Integration Tests job once Launchpad's PPA is reachable again. (The autofixer cannot push a code change to address a CDN outage, and lacks permission to call gh run rerun.)

Suggestion (longer-term): If deadsnakes 503s recur frequently, consider adding retries around apt-get update in sandbox/Dockerfile (and the repo-deps stage), e.g. wrapping the add-apt-repository + apt-get update block in a small retry loop so a single transient 503 from Launchpad doesn't fail the whole build. That's a separate hardening change and should not block this docs-only PR.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Check Failure: Integration Tests / Integration Tests

What's failing:

integration_tests/test_deployment_validation_logic.py::TestValidateNetworkIsolationLogic::test_probe_runs_and_returns_expected_shape
E   KeyError: 'result'

The test calls POST /api/v1/deployment/validate-network-isolation and asserts the response data carries both probe_id and result. The CI run got the probe-launched shape (so probe_id was present) but the result key was missing — which corresponds to the _wait_for_probe_pod(... timeout=30.0) short-circuit in orchestrator/routes/deployment.py:1270, where the route returns {"error": "probe_timeout", "probe_id": probe_id} instead of {"probe_id": ..., "namespace": ..., "result": parsed}.

Root cause (unrelated to this PR):

  • This PR (docs: expand populate_contract error reason codes [doc-updater] #2692) is docs-only — it touches docs/reference/orchestrator-cli.md and nothing else. The failing test exercises the K8s deployment-validation probe and cannot be affected by a documentation edit.
  • The probe Job did not bring up its Pod within the 30s _wait_for_probe_pod budget on the k3s runner. This is an environmental flake — the same branch passed this test on a prior run (run 25768159840, 2026-05-12T23:25:12Z) with no source changes in between aside from the merge from main.

What needs to be done:

  • Recommended: Re-run the failed Test workflow (Integration Tests / Integration Tests job) — this is a flaky k3s probe-pod timeout, not a real regression introduced by this PR.
  • Optional follow-up (separate PR, not this one): Harden test_probe_runs_and_returns_expected_shape against probe-pod scheduling slowness on k3s — either bump _wait_for_probe_pod's timeout, or have the test accept the probe_timeout shape as a flake signal and pytest.skip(...) rather than fail. That's a test-infra change that belongs with the test owner (added in test(integration): cover deployment-validation routes past auth gate (#2641) #2658), not on a docs-only PR.

Why I'm not committing a fix:
Per the autofixer conventions, I fix only the listed checks when they can be addressed by changes consistent with the PR's scope. The failure here is in an integration test for a Kubernetes endpoint and would require touching integration_tests/test_deployment_validation_logic.py or orchestrator/routes/deployment.py — both outside the scope of a documentation update. The "Fix only the issues listed above. Do not fix unrelated code." rule applies.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

@james-in-a-box

Copy link
Copy Markdown
Contributor Author

Check Failure: Integration Tests

What's failing: integration_tests/test_deployment_validation_logic.py::TestValidateNetworkIsolationLogic::test_pipeline_id_regex_valid_at_boundaries_pass[single-char]requests.exceptions.ReadTimeout against the orchestrator service in k8s (HTTPConnectionPool(host='10.43.190.181', port=9849): Read timed out. (read timeout=60)).

Root cause: Flaky integration test, unrelated to this PR.

  • This PR is docs-only — the single changed file is docs/reference/orchestrator-cli.md.
  • Sibling parameterized variants of the same test ([max-length-63], [middle-dot-underscore-hyphen], [uppercase-allowed]) all passed in the same run.
  • This branch has had three previous Test-workflow failures, each in a different test inside test_deployment_validation_logic.py (test_probe_runs_and_returns_expected_shape with KeyError: 'result', etc.) — a textbook flaky-cluster pattern, not a regression caused by the change.

What needs to be done:

  • Re-run the failed Integration Tests / Integration Tests job. I tried gh run rerun 25815878676 --failed but got Resource not accessible by integration — a human with rerun permissions needs to click "Re-run failed jobs" on run 25815878676, or push an empty commit to retrigger CI.
  • Separately, the recurring flakiness of test_deployment_validation_logic.py against the k8s probe endpoint looks worth a tracking issue — but that's out of scope here.

Suggestion: I'm not commiting an empty-commit retrigger from the autofixer because the failure is purely environmental and the safer signal is to let a human decide whether to rerun or investigate the underlying flake.

— Authored by egg

@james-in-a-box

This comment has been minimized.

@egg-reviewer egg-reviewer 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.

Re-reviewed against 501b37d (the current head). Since my last review at 906f7a5, the only PR-authored change is commit 187b4fa — the rest is merge traffic from main (#2691 and #2693 landed in the meantime and were resolved at 579c694).

Prior-review item resolution

# Item Status
8 Lead-in dangling reference to "earlier 400-list shape" Fixed. Adopted the option-1 wording verbatim — Two casesOne case, dropped the second half of the sentence. The lead-in at docs/reference/orchestrator-cli.md:273 now references only the real exception (forest_violation's error key).

I independently re-verified the deleted claim: there is no list-shaped 400 anywhere in orchestrator/routes/. Every 400 in phases.py (make_error_response at phases.py:75-94), pipelines.py, signals.py, etc. goes through the standard {success, message, reason, details} envelope. grep -n "return jsonify(\[" across orchestrator/routes/ returns no matches. The deleted text was indeed phantom.

Merge-traffic content (not PR-authored, but worth flagging)

The merge resolution at 579c694 pulled in two additions from #2693 (the WORKTREE_BASE_DIR notes in the Context PR and per-slice BRC sections at lines 472 and 481). These were merged from main and reviewed under #2693 — not in scope for this re-review, but they integrate cleanly with the surrounding sections and don't conflict with the populate_contract changes.

Table content (unchanged since 906f7a5)

No regressions in the table rows or the forest_violation callout. All eight prior items remain correctly resolved.

Approving. The PR is now narrowly scoped to a single sentence change in the lead-in, which directly addresses the only outstanding non-blocking note from the prior round.

— Authored by egg

@james-in-a-box

Copy link
Copy Markdown
Contributor Author

egg review completed. View run logs

16 previous review(s) hidden.

@jwbron
jwbron merged commit a1db2e1 into main May 13, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement phase advances silently when populate_contract finds no plan draft (missing-on-both-local-and-origin)

1 participant