Skip to content

Show the plan-map synth what the integration actually landed - #2063

Open
ppXD wants to merge 1 commit into
mainfrom
fix/show-the-synth-what-landed
Open

ppXD wants to merge 1 commit into
mainfrom
fix/show-the-synth-what-landed

Conversation

@ppXD

@ppXD ppXD commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • The defect. The plan-map synth narrated a partial integration as a whole deliverable. The integrate step's outputs reached only the done terminal (appliedCount, conflicts and reason were bound nowhere), and a unit withheld for a Failed/Waived acceptance is dropped before integration (RunIntegrationContributions), so it appears in no output. git.integrate_run now emits, on every pass (clean, conflicted, empty, skipped, resumed), summary (one account of what landed, at most 2,000 chars) and withheld ([{label, reason}]). The resumed pass's reviewApproved / reviewComment / reviewedBy are now declared in its OutputSchema too, because DefinitionValidator rejects a reference to an undeclared output.
  • The prompt. A repo-bound graph's synth user prompt gains \n\nIntegration outcome:\n{{nodes.integrate.outputs.summary}}, and its system prompt gains an instruction to state what landed and to name anything conflicted or withheld as NOT delivered. A repo-less graph keeps both halves byte-for-byte; the existing pins (PlanMapSynthDefinitionBuilderTests user-prompt and system-prompt pins) are untouched and green. On a clean run the summary is one factual sentence, not the failure furniture the "no failure furniture" pin forbids (that pin is on a repo-less graph). It sits outside the 120k promptBudgetChars; the 2,000-char bound is under 2% of that budget, so it stays negligible.
  • Exact texts (the first three are what the real-loop E2E handed the synth; <...> is a per-run id):
    • Clean: Integration: 2 contribution(s) landed on codespace/integration/<runId>.
    • Conflicted: Integration conflicted: no integrated branch was published, so none of this run's work landed on one (1 of 2 contribution(s) applied cleanly, but integration is all-or-nothing). Conflicted and withheld from the integrated branch: agent#map#0 → codespace/agent/<id>.
    • Skipped: Integration skipped: the run produced no integrable work for this repository. (or ... the produced work recorded no base revision to integrate from.)
    • Any of them gets Withheld before integration: agent#map#1 — acceptance Failed. appended when a unit was withheld.
  • Where the code and the brief disagreed, the code won:
    • Conflicted: the brief's template read "N landed on {integratedBranch}", but IntegrationResult nulls IntegratedBranch on every non-Clean status and the integrator resets its clone on abort (IntegrationResult.cs:16-29, :104). Nothing landed and AppliedCount is a trial count, so the summary says that.
    • The instruction is a sibling constant, SynthIntegrationInstruction, appended only when the graph has an integrate node. Adding it to SynthSystemPrompt would have changed every repo-less prompt.
    • withheld names a unit only when none of its attempts landed, once per unit at its latest verdict. The withhold filter runs before the per-unit retry reduction, so a flunked first attempt of a unit whose retry passed would otherwise be reported as withheld.
    • The withheld clause is label — acceptance Failed, not the brief's (acceptance Failed): label — reason, which would repeat the state.
    • The conflicted E2E derives the conflicted unit and its branch from the ledger: the two parallel items are applied in a non-fixed order (a run here conflicted on agent#map#0, not map#1).
    • The shared "real failure before bystander" ordering is now one method, GitIntegrateNode.NotApplied, read by both conflicts[] and the summary; behavior is unchanged and GitIntegrateNodeTests still pins it. The authored git.integrate node is otherwise untouched, and so is DoneInputs.
  • Side effect. The synth prompt of repo-bound Standard-lane runs changes, so the TaskLaunchStandard qualification arm now measures the new prompt. No digest covers the synth prompt (the runtime manifest digests only the planner and supervisor). The stale E2E comment about "no outcome filter" is corrected.

Test plan

Red first, each for the stated reason (a stub renderer and the unchanged node/builder), then green. Counts are before → after:

Class Tier Count
PlanMapSynthDefinitionBuilderTests Unit 33 → 35
PlanMapDynamicDefinitionBuilderTests Unit 11 → 12
RunIntegrationContributionsTests Unit 21 → 31
RunIntegrationSummaryTests (new) Unit 16
GitIntegrateRunNodeManifestTests (new) Unit 10
GitIntegrateNodeTests Unit 8 → 8 (pins the shared ordering)
GitIntegrateRunNodeFlowTests Integration 9 → 18
PlanMapIntegrateWholeLoopE2ETests E2E 3 → 3, with the Clean, flunked and conflicted assertions on what the synth was shown
  • Mutations, each applied to a copy-backed file, rebuilt, run, then restored byte-identically:
Mutation Turned red
M1 drop the Integration outcome: prompt append builder A_repo_bound_reduce_is_shown_what_actually_landed_and_told_to_name_what_did_not, dynamic ..._like_its_sibling; E2E all three
M2 drop withheld population 7 unit Withheld cases, 3 node cases; E2E A_flunked_item_still_leaves_its_siblings_work_on_one_reviewable_candidate only
M3 drop the system-prompt instruction the two builder tests
M4 leak the integration text onto repo-less graphs 7 unit, including the untouched user-prompt and system-prompt pins
M5 drop the "did the unit land" subtraction A_unit_whose_retry_landed_is_not_reported_withheld_for_its_abandoned_attempt
M6 key "landed" on the label only A_supervisor_turns_withheld_agent_is_named_even_though_a_peer_sharing_its_cell_landed
M7 drop the 2,000 bound 3 unit, node A_wide_conflict_cannot_bloat_the_summary_past_its_bound
M8 undeclare the five new output keys 5 manifest cases (only the new keys), 4 builder/validator tests, 8 node emitted-keys-declared checks
M9 use the brief's Conflicted template 3 unit, 2 node
M10 drop the real-failure-first ordering GitIntegrateNodeTests.Conflicts_sorts_the_real_failure_before_a_skipped_survivor..., A_conflict_is_named_before_a_bystander_the_set_merely_never_attempted
M11 skip arms ignore the withheld set node When_every_unit_was_withheld_the_skip_names_them_and_git_is_never_touched
M12 drop the surrogate-pair guard A_cut_never_splits_a_surrogate_pair
M13 drop the per-unit grouping Every_attempt_of_a_withheld_unit_is_reported_once_under_its_latest_verdict
M14 drop the withheld clause from the prose 4 unit, 3 node
M15 take the first row's verdict instead of the latest Every_attempt_of_a_withheld_unit_is_reported_once_under_its_latest_verdict
  • Regression sweep: the whole CodeSpace.UnitTests project on the pushed tip is 11,660 tests, 11,658 passed, 1 skipped (pre-existing). The 1 failure is ModelCredentialBrokerTests.A_rebind_with_a_socket_reopens_it_at_the_recorded_path_after_the_worker_that_minted_it_is_gone(staleFileLeftBehind: True), a Unix-socket test this diff does not touch; its class passed 108/108 in isolation three times in a row.
  • Integration classes that build or run git.integrate_run or a plan-map graph, all green: GitIntegrateRunNodeRealGitFlowTests, CompletionTerminalAuthorityFlowTests, SupervisorDependencyStagingFlowTests, TaskLaunchBenchmarkCellRunnerFlowTests, TaskLaunchFlowTests, TaskLaunchContractFlowTests, MapPromptBudgetFlowTests, EffortRouterFlowTests, CompletionComposerFlowTests, CompletionEnforcedCohortFlowTests, BoundsHardClampFlowTests, PlannerCassetteDriftTests, and the learning and premature-stop flow classes.
  • E2E classes, all green: PlanMapSynthFanoutFlowTests, PlanMapDynamicFanoutFlowTests, StandardPlanConfirmFanoutFlowTests, ReviseLoopFanoutE2ETests, RubricReviseFanoutE2ETests, RunPhaseProjectorFlowTests (RealModelPlannerWholeLoopE2ETests skips without its model env). Run before the final rebase onto 1a9055a91, which touches none of these paths; the eight target classes above were re-run after it.
  • CI

The plan-map synth reduces the per-subtask results into the run's combined
answer, but it never saw the integration outcome. The integrate step's
outputs reached only the done terminal, appliedCount, conflicts and reason
were bound nowhere, and a unit withheld for a Failed or Waived acceptance
is dropped before integration, so it appears in no output at all. A
conflicted or partial candidate was narrated as a whole deliverable.

git.integrate_run now owns the narrative. Every pass (clean, conflicted,
empty, skipped, resumed) emits summary, one account of what actually
landed that is bounded at 2,000 characters, and withheld, the units the
head gate kept off the candidate. A conflicted set says nothing landed:
the integrator publishes no branch on any non-Clean status, so its
applied count is a trial count. The resumed pass's review keys are now
declared in the OutputSchema, which the validator requires in order to
bind them.

A repo-bound graph's synth prompt carries the account under "Integration
outcome:" and its system prompt says to state what landed and to name
anything conflicted or withheld as not delivered. A repo-less graph keeps
both prompt halves byte-for-byte.
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.

1 participant