Conversation
A plan for a negative scenario names the guard it expects — a validation message beside the field. An app may block the same action by disabling the control instead, which meets the goal just as well. Pilot read the missing message as a failure and told Tester to record the run failed, so a test that found the app behaving correctly was reported as a failure. Navigator had no URL assertion available either. Its verification vocabulary is closed, and no command in it could express "the page is at this address", so every URL claim failed while the page was on exactly that URL and Tester lost the cheapest evidence a navigation worked. seeInCurrentUrl and dontSeeInCurrentUrl were already accepted by Action and the recorder; only the vocabulary omitted them. Pilot's completion review was unreachable: Tester called it under task.isComplete(), and reviewDecision returns early on task.hasFinished, which is itself status === DONE || isComplete(). The trigger was also the bail-out, so the call never did anything. Removed; the no-Pilot branch keeps its behavior. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DenysKuchma
requested changes
Sep 15, 2026
| const hasPassed = task.hasAchievedAny(); | ||
| task.finish(hasPassed ? TestResult.PASSED : TestResult.FAILED); | ||
| } | ||
| if (input.status !== null && task.isComplete() && !this.pilot) { |
Collaborator
There was a problem hiding this comment.
With Pilot enabled, recording the last expected outcome makes task.hasFinished true via isComplete(), but leaves task.result null. The loop then exits before finalReview() because of the if (task.hasFinished) break guard. Please keep reviewCompletion() here, or separate “all expectations settled” from the terminal state, otherwise these tests finish without a Pilot verdict
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.
Session
SweetRequiredViolet966(trace1a2ef014d2e2f5d74b731507132e8515) reported a failure for a test the app passed. Scenario: "Attempt to save a manual plan without entering a title and verify that creation is prevented by validation feedback." Creation was prevented — Save stays disabled while Title is empty, the form stayed open, no plan was created.Three things came out of reading it.
Pilot failed the test because the guard was the wrong shape
The plan predicted a validation message; the app blocks by disabling the control. Pilot's progress review acknowledged the block worked and then said:
Tester obeyed,
record(status:"fail")settled that expectation FAILED,hasAchievedAll()went false, andfinishTest(src/ai/tester.ts:709) wroteFAILED.Pilot's "Already-achieved detection" paragraph only describes goals met by something happening. A negative scenario's goal is met by something not happening, so Pilot fell back to the planned expectation's literal label. One line added to that paragraph:
Same principle as #213, one decision site over — that one grounds capability presence, this one grounds the verdict.
Navigator could not assert a URL
Both URL checks in the session failed while the page sat on exactly that URL:
verify("URL contains \"/plans/new/manual\"")→ failedverify("Current URL is /projects/…/plans/new/manual")→ failed, one call aftercontext()returned that same URLrules/navigator/verification-actions.mdis a closed vocabulary — it ends with[DO NEVER USE OTHER CODECEPTJS COMMANDS THAN PROPOSED HERE]— and listed no URL assertion, so Navigator reasoned "There's no I.seeInURL", "I think CodeceptJS has I.seeInCurrentUrl? Not standard", then emitted a weakerI.seeInSourcethat failed. It is standard:seeInCurrentUrl/dontSeeInCurrentUrlexist in the Playwright helper and are already accepted byASSERTION_STEP_NAMES(src/action.ts:557) andsrc/playwright-recorder.ts:328. Only the vocabulary omitted them, so they are added.This did not cause the failure — Tester routed around it ("we could skip verify… but we can't prove") — but every URL claim was unverifiable.
Pilot's completion review was unreachable
recordcallspilot.reviewCompletion()undertask.isComplete()(src/ai/tester.ts:1129), butreviewDecisionopens withif (task.hasFinished) return false(src/ai/pilot.ts:99) andhasFinishedisstatus === DONE || this.isComplete()(src/test-plan.ts:282). The trigger condition was also the bail-out condition, so the call returned immediately every time — the trace has no verdict observation and no Pilot call after the last guidance.Removed. Zero behavior change: Pilot still never reviews a records-completed test. Making it actually run means changing
hasFinished, which also feedsisSuccessful/hasFailed/plan.isComplete— worth doing, but not here. The no-Pilot branch is kept as-is because unit tests construct pilot-less Testers and it uses a looser pass criterion thanfinishTest.Testing
bun test tests/integration/ tests/unit/— 1564 pass, 0 fail. Format and lint clean.Replay expectation for the same scenario: no
failguidance from Pilot, 3/3 expectations settled passed,hasAchievedAll()true →PASSED.🤖 Generated with Claude Code