Skip to content

feat(harness): record why a rebuild drops a scenario for a removed capability and restore it under its key when the capability returns (TH-8754) - #325

Draft
KarthikAvinashFI wants to merge 7 commits into
feat/TH-8918-scenario-lifecyclefrom
feat/TH-8754-restore-dropped-scenarios
Draft

KarthikAvinashFI wants to merge 7 commits into
feat/TH-8918-scenario-lifecyclefrom
feat/TH-8754-restore-dropped-scenarios

Conversation

@KarthikAvinashFI

Copy link
Copy Markdown
Member

Why

TH-8754: when an agent version loses a tool, the scenario rebuild drops the cases that need it, and until now nothing remembered why. When the tool came back, the cases were gone for good: a rebuild wrote new ones under new keys, so their run history no longer lined up.

Now a rebuild records each case it drops for a removed capability (which tools and sub-goals it needed, which were missing, the agent version, a readable reason and the case's last content). When a later rebuild has every capability back, the case comes back under its own key from its last content, is proved like any other case, and is listed as restored.

What changed

File Change
src/fi/alk/harness/dropped.py (new) dropped.json beside the scenarios: record_drops (from the turn-start snapshot, only drops whose needed tools or sub-goals are missing), restore (every record whose capabilities are all back goes into the kept list under its key), finish_restore (a restored case that fails its proof or is dropped again stays recorded with restore_failed and the why), submit_refusal (a rebuild may bring a dropped key back only by restore), restore_note. save({}) removes the file.
src/fi/alk/harness/nudge.py The suite rebuild records drops in report_update, restores at the start of the turn, and reports restored and restore_failed.
src/fi/alk/harness/hosted_chat_entrypoint.py The rebuild's message names the restored cases and any step whose arguments the tool no longer takes.
src/fi/alk/harness/skills/builder/topics/agent-update.md The builder is told not to rewrite a dropped case under a new key, and that a tool the agent's source defines again is added back with declare_tool.
src/fi/alk/harness/amend.py fix_tool and adopt_tool on a tool the contract lacks said "is not a tool this agent has"; they now say it is not in the contract and point at declare_tool. Found live: the builder took the old message at its word and never added the tool back, so nothing could be restored.

Behavior callouts

  • Drop and restore run only in the scenario rebuild that follows an agent change (the suite stage of a rebuild nudge). A person's edit in the builder chat that removes a case records nothing.
  • The platform raises rebuild nudges only with HARNESS_VERSIONING_NUDGES_ENABLED on. Production values do not set it today, so this feature does nothing in production until that flag is on.
  • An ordinary drop (not for a missing capability) is not recorded.

Tests

tests/harness/test_dropped_scenarios.py, 13 tests: a v5 drop records capabilities, agent and reason; an ordinary drop is not recorded; no restore while the capability is still missing; restore under the same keys and last content when it returns; restored cases are proved; restore only once every capability is back; a repeated report_update keeps the restore listed; the message names the restored cases and a changed argument; a restore that cannot be proved stays dropped with why; a restored case dropped again is a failed restore; a rebuild cannot write a new case under a dropped key; editing a restored case is allowed; with no drops left dropped.json is removed and the scenario digest never reads it (so the platform hashes such a suite exactly as before).

Also tests/test_harness.py::test_fixing_a_tool_the_contract_lacks_points_at_declare_tool.

Run on this branch (the targeted harness modules, one process): 2654 pass; three failures, the same on dev (0203bdf5). Mutations: keeping an empty dropped.json fails the last test; the old refusal text fails the declare_tool test.

Break-it attempts (throwaway tests), all hold: a corrupt dropped.json reads as no drops and restores nothing; a record whose content no longer reads as a scenario is refused with why while the others restore; a restore whose name a kept case now holds is refused; restoring twice restores nothing the second time; submit_refusal with empty, null or padded keys.

Live proof

See future-agi feat/TH-8754-restore-dropped-scenarios for the screenshots; the run is summarised here.

Local stack with production sandbox specs, a chat demo environment (deals desk) on its environment v12, the last version before tools were added through chat. Rebuild nudges turned on locally (see the callout). Agent v3 is v1's source with the apply_discount tool removed.

Step Result Proof
Agent v3 becomes the default The card offers a rebuild: "Agent v3 changed ... Rebuild the environment?" Image 1
Rebuild (environment, then scenarios) apply_discount leaves the contract; the suite rebuild drops live-manager-discount-negotiation and manager-initiated-post-discussion-workflow; suite v10 keeps each drop with "agent v3 no longer has apply_discount; the environment retired applied_discount_to_deal", the missing tools and sub-goals, and the agent version; the version diff carries the same reason Image 2, API below
A person adds a new case under a dropped key 422 scenario_key_retired: "live-manager-discount-negotiation was removed earlier and can't be reused; give the scenario a new name" API
Agent v1 (the tool is back) becomes the default; rebuild The environment stage adds apply_discount back with declare_tool (environment v18); the suite rebuild restores both cases under the same keys from their last content, proved by the gates; the card reads "2 scenarios restored" and lists them under Restored Image 3
The restored case Same number (#4) and key; its revisions run from suite v1 to v9 and on to v11, so its history stays linked Image 4

Suite v10's diff (GET versions/suite/{id}/diff/), removed entries:

{"key": "live-manager-discount-negotiation",
 "reason": "agent v3 no longer has `apply_discount`; the environment retired `applied_discount_to_deal`",
 "capabilities": {"tools": ["apply_discount"], "sub_goals": ["applied_discount_to_deal"]},
 "agent_version": "v3"}

1: rebuild offered

2: drop recorded

3: restored

4: restored case keeps its key and history

Found while running it, fixed here and in the harness PR: the rebuild card's change list showed the generic "removed when the environment was updated" instead of the stored reason (ad6acfdcf); and on the first attempt the environment rebuild did not put apply_discount back (the harness told the builder it was "not a tool this agent has" when it was only missing from the contract), so nothing was restored. With the harness fix the second attempt restored both cases.

The restored cases read Draft "No negative control" on the Scenarios tab: they were written before negative controls existed, which the lifecycle reports for any such case.

Stacked on / merge order

  1. agent-learning-kit feat/TH-8918-scenario-lifecycle (feat(harness): negative controls, leaked-answer check, grounding and suite proving (TH-8918) #321), this PR's base
  2. This PR, with future-agi feat/TH-8754-restore-dropped-scenarios

Linear: TH-8754

@KarthikAvinashFI KarthikAvinashFI self-assigned this Nov 15, 2026

This branch has not been deployed

No deployments
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