Generate a suite with one writer per use case, and persona values the platform understands - #63
Draft
KarthikAvinashFI wants to merge 2 commits into
Draft
Conversation
… by use case and branch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Scenario generation could not produce a suite of the size people ask for, and the reason was not speed.
not_ready()refused to save when two scenarios shared ause_case, because coverage is counted by use case and a duplicate overstates it. An agent contract names a limited number of use cases, so a request for forty produced a suite that could never be saved. Separately, generation ran in one session at roughly three turns per scenario against a single budget, so a large request ran out of turns partway and lost everything it had written.Both are addressed here.
Coverage is counted by use case and branch. A scenario carries a new
branchfield: the condition that makes it different from its siblings in the same use case. Several scenarios sharing a use case is now normal, which is what branches are for. Two scenarios agreeing on both is still refused.A suite is written by one session per use case, several at a time.
write_in_parallel()splits the requested count across the contract's use cases, gives each writer its own session and its own turn budget, and bounds how many run at once. Wall clock becomes the slowest use case rather than the sum of all of them. A newgenerate_suitetool exposes this to the open session, so asking for a suite in chat fans out instead of writing one scenario at a time.Writers run submit-only.
save_scenariosregenerates the index and deletes any folder it does not know about, so two writers saving at the same time would delete each other's work. They keep their scenarios in memory and the caller merges and writes once, dropping the collisions the writers could not see.Persona values come from the platform. A generated persona used to be free text, so nothing matched what the platform understands, no behaviour guidance attached, and the accent selected no voice. The fields are now constrained to the platform's own vocabularies and checked on submit, and the behaviour guidance is read from the platform's tables rather than restated here, so a caller behaves the same way in a harness run as in a platform simulation. Where those files are not mounted, personas still render without guidance rather than failing.
Progress is visible while it runs. The fan-out writes its state as it goes and
GET /api/generationserves it, so a page can show which use cases are being written and how many of their share have been proved. A scenario counts only once it has cleared all three gates.How a suite is decided, not just divided
The first version split the count evenly across use cases. That is a poor plan and it showed: a use case with one real branch padded to fill its share while one with six under-covered, and nothing ever read the finished suite to notice.
The plan is now consumed rather than discarded. The session talking to the person already writes one, because the skill asks for it. It now passes that plan in: each slice names its use case, the angle it should take, how many scenarios it is worth, and why. Even division remains the fallback for a caller that supplies nothing.
Each writer is briefed rather than templated. It is told its own slice, what its siblings hold so it stays out of their way, the caller spread it should start from, and what a scenario has to be before submitting: every value read from the world rather than invented, an instruction that is a circumstance rather than a script, a setup that makes true whatever the instruction presumes, a solution rehearsed with try_calls first, checks that assert the right call with the right arguments, and a scenario a competent agent could plausibly fail.
The finished suite is reviewed. Writers are blind to each other and the merge only removes collisions, so a use case that came back short, or a branch every writer assumed somebody else had, survived to the end unnoticed. One session now reads the whole suite and names what is missing, and only those gaps are re-delegated. Bounded to one round, because a reviewer asked twice will always find something smaller to say.
A large ask is served a batch at a time. Fifty scenarios in one pass is the ceiling and eight concurrent writers is the other, both overridable. Asking for a thousand is reasonable to want and unreasonable to do at once: the batch comes back, the rest is offered, and the session is told to show what it has and ask whether to carry on rather than silently looping.
Measured on a deliberately uneven plan (3 scenarios on the rule under pressure, 1 on the ordinary path, 2 on the branch that cannot be completed): 6 scenarios in 294 seconds, and the angles reached the output. The pressure slice produced three scenarios about a caller pushing to skip a step; the ordinary slice produced the clean path; the refusal slice produced the two payment failures.
The review pass was exercised separately against that finished suite: 8 gaps in 43 seconds, each naming real records and real tools, including one no individual writer could have seen, that both existing payment-link scenarios were failure variants and the success path was missing.
Measured
Against the Uber ride-voice contract, which has 14 use cases:
The 40-scenario suite came out as 14 distinct use cases and 40 distinct use case and branch pairs, with no duplicates. Every scenario cleared all three gates. Concurrency was confirmed by counting processes rather than inferred.
Persona spread was measured too, because the first attempt at it failed. Telling each writer to vary its callers changed nothing, since a writer producing one scenario has nothing to vary and writers cannot see each other. Dealing the spread out at plan time works:
Testing
TOOL_NAMES.tests/simulation_contract/test_contract_native.py::test_legacy_manifest_without_block_byte_identicalfails, and fails identically on the base branch without these changes.Notes for review
generate_suiteis offered only to a session that can save. A writer that is itself one slice cannot fan out again.feat/hosted-harness-e2e-runtimerather thandev, since it builds on the harness layout introduced there.