Repository navigation
fix(cache): a hand-off no longer inflates the recorded end wait - #881
okwasniewski merged 10 commits into
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 3 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
d126bb0 to
4343971
Compare
|
Addressed in 4343971 ( |
|
Addressed in 4343971 ( |
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
|
[claude-opus-5-5] responding on behalf of okwasniewski Thanks, the bug is real and the fix direction is right: after a hand-off, 1. Don't drop the settle time when the executor acted after the hand-off. const actedAfter = this.handedOffMs !== undefined && (recorder.lastActionAtMs ?? 0) > this.handedOffMs;
const from =
this.handedOffMs === undefined || actedAfter
? (recorder.lastActionAtMs ?? this.startedMs)
: (this.executorCompletedMs ?? this.handedOffMs);Please add a test for "hand-off, then the executor acts" next to the existing one. 2. Simpler test clock. 3. Heads-up on overlap with #805. 4. PR body. |
|
Addressed the actionable items in |
|
Thanks for the review — items 2, 3 and 4 are in ( The test for it is the part I can't deliver, and I think the reason is in After an if (this.repairedAfterEndMismatch(recorder)) await this.evict();
else if (this.replayedWhole) { /* keep */ }
else if (!(await this.stage(recorder, verdictSummary)) && this.readEntryHit) await this.evict();
What I measured in the unit harness, recording a
Every shape that hands off lands on the evict branch, so there is no So one of these is true and I'd rather you tell me which:
I'd rather not ship a test I can't make fail before the fix. |
|
Correction to my previous reply and to the claim that every executor action after hand-off necessarily evicts: I found a non- |
05cdf69 to
c7f1bb9
Compare
|
Update: the executor-acted regression test and the preceding corrections are now rebased onto current |
|
CI update for head |
|
Both runs fail the same test with the same error:
The explorer runs against I have not re-run the job: rerunning it myself would only tell me whether the service was back, and either way this is a CI-infra failure to call, not mine to mask. Leaving it for you to decide — happy to re-run just |
c7f1bb9 to
14c10b1
Compare
|
Follow-up to my earlier CI note (#6002740835): that comment described head |
|
Thanks, this now does what we asked: settle time is kept when the executor acts, and its turn is left out when it doesn't. A few cleanups before merge:
|
4d5dab1 to
2a177be
Compare
|
Addressed all four cleanup requests in the current head
Verified after rebasing: focused |
|
Addressed all four cleanup requests in head
Locally verified on the new main base: |
2a177be to
8577015
Compare
| ): StepCacheHost { | ||
| let lastPath: string | undefined; | ||
| const nextScreen = async () => { | ||
| const path = paths.shift(); |
There was a problem hiding this comment.
Hi @santoislamsh-eng — I can't tell what issue you intended to flag from the comment (as). Could you clarify the behavior or expected change? The referenced line was in the shared test host; after the maintainer's request, both new hand-off tests now use dedicated hosts and the shared helper signature is restored. I have not treated this fragment as an actionable defect.
After a hand-off the executor settles without acting, the staged trace's `endWaitMs` counted from the last *replayed* action, so it included the replay's own end wait and the whole executor run. Each run re-recorded a longer budget, which the next replay then waited out, until it reached `MAX_TRACE_END_WAIT_MS` (120 s) and every hand-off of that step paid it. Measured with a probe that runs the healing path three times on the same entry: `200 -> 24519 -> 35021 -> 45522` on `main`, `200 -> 10503 -> 10502 -> 10501` with this change. The wait becomes the margin alone, which is what it was measuring on a step the cache replayed whole. Fixes tester-army#850
The healing path of the trace cache re-stages an entry after a hand-off the executor settled without acting. Measured from the last replayed action, the replay's own end wait and the executor's run both land in the next entry's `endWaitMs`, so the budget grows on every run until it reaches its ceiling. The clock is faked and the host holds its last path, so the loop measures the arithmetic and nothing else: on `main` the three runs read 42 000, 48 000, 54 000 (each the previous plus the replay wait and the executor's turn); the wait is bounded once the measure starts at the hand-off.
The growth check alone passes on a fix measured from the hand-off: the executor's turn is a constant per run, so the number stops climbing and the assertion never sees that every entry still carries it. Bound the recorded wait itself, which is what the change claims to fix. With this the test dies at both levels: on `main` with `expected 42000 to be less than or equal to 28000`, and with only the hand-off baseline with `expected 14000 to be less than 12000`.
Restore the shared makeHost and recordingSession helpers to their original signatures. The two tests that need a large replay budget and a held route now own small hosts instead of threading test-only switches through shared helpers. Keep the comments short; measured main-vs-branch values belong in the PR body.
Select the timestamp used for app settling in a private method, so the handoff/action/verdict cases have a name and JSDoc instead of a nested ternary in stage().
Clarify that the baseline is the agent's verdict for a silent handoff, or its last action when it acted.
8577015 to
40b29bb
Compare
okwasniewski
left a comment
There was a problem hiding this comment.
Thanks!
btw feel free to join our discord as a frequent contributor, we have a channel for e2e-contributors! https://tester.army/discord
Fixes #850
What happens
After a replay hands a step to the executor and the executor settles it without acting, the staged trace records
endWaitMsfrom the last replayed action. The interval before staging contains the failed replay's own wait and the executor's turn; both get counted again on the next recording. That causesendWaitMsto grow on repeated hand-offs until it reachesMAX_TRACE_END_WAIT_MS(120 s).The replay excludes the executor turn from the app-settling budget when the executor records no action. When it does act, settling is measured from that last action, so a slow app response after the action remains in the recording.
Measured
The fake-clock regression test replays and heals the same entry three times. I measured both versions with the current
mainruntime and this branch's runtime, using the same test harness:main(13da94b)With
main, each run adds the replay wait and executor turn. With the fix, the silent hand-off measures from the agent's verdict. A separateaction-failedregression verifies that when the executor acts, the app's post-action settling time is preserved.The assertions catch both unbounded growth and a stable-but-inflated wait; reverting the runtime change makes the regression fail with
expected 42000 to be less than or equal to 28000.Verified
Ran locally on top of current
main1b92a6d:pnpm check— passed end-to-end: lint, dead-code, typecheck, error-code docs, peer ranges, install scripts, build validation and broken links.pnpm --filter e2e exec vitest run tests/unit/step-cache.test.ts— 60 passed.pnpm test— passed: e2e 245 files / 3,064 passed / 2 skipped; web 56 / 507 passed / 1 skipped; mobile 12 / 232 passed; GitHub 4 / 32 passed; kernel 1 / 15 passed; EAS 1 / 35 passed; decision 5 / 88 passed; scripts 15 passed.The full suite includes local Chromium integration tests; the end-wait measurements remain deterministic fake-clock unit tests and use no live model or benchmark service. The rebase resolves main's
step-cache.tsoverlap while preservingkeyedBy, hand-off detail, and the correct completion-vs-last-action baseline.Versions
e2e0.17.0 @13da94b, Node 22.