The agent first traces which uncovered paths connect to user entry points. From there, it weighs the codebase's thousands of lines, hundreds of functions, and dozens of UI flows to decide what deserves a test. Testing every line would be impractical and unhelpful. The real task is identifying the gaps with the greatest consequence, using codebase signals instead of generic heuristics.
Building TestSprighte's gap detection logic involved plenty of false starts. The simple strategy, "find untested paths and write tests for them," creates technically complete tests that miss the real concern. Coverage does not equal risk. A 200-line date-formatting utility with 0% coverage may pose little danger, while a 20-line payment confirmation handler with 60% branch coverage may expose users to significant risk. The useful signals show which coverage gaps map to user-visible consequences.
Signal 1: Reachable Code Paths from User Entry Points
The agent begins with uncovered paths reachable from user entry points. API handlers, form submission functions, page routes, and click handlers are the points where user actions become code execution. A path reached only through internal calls already covered elsewhere carries a different risk from one triggered directly by a user.
To do this, it builds a call graph inward from each entry point and finds branches lacking test assertions. That produces reachable, uncovered paths tied to real user actions. In Playwright, they become direct test steps: open this URL, use this element, and check this result. The agent traces each code gap back to the action that would reveal it.
Signal 2: Change Frequency of Untested Code
Frequently changed code with no tests creates compounding risk. Every edit can introduce a regression that remains hidden until a user reports it. The agent reads git history to find files and functions changed more than 2 times in the trailing 30 days without matching test assertions. Untested, high-churn code becomes the top target.
The reverse pattern also matters. Code unchanged for 18 months with no tests has another risk profile. It remains untested, but it has stayed intact, suggesting stable behavior. It still enters the queue, though below code modified actively in recent work.
Version control change frequency is among the strongest signals for ordering coverage gaps. It tracks developer attention and, in turn, the chance that a later edit causes a regression. Auditing coverage without examining churn means optimizing the wrong factor.
Signal 3: Test Patterns Around Related Code
Before writing a test, the agent studies tests for similar or nearby code to learn the team's conventions. It checks which selectors similar elements use, which assertion style is standard, and how fixtures are organized. Matching those conventions has practical value: deviations add maintenance work when other engineers meet the new tests.
The agent also learns data-testid naming conventions. If form elements use data-testid="submit-btn", it selects those attributes instead of CSS classes. If the team uses page object models, the new tests use them too. The aim is generated code that feels written by the development team, both syntactically valid and stylistically consistent.
Signal 4: Type Signatures and Error Branches
TypeScript signatures describe the inputs a function accepts and the value it returns. The agent uses them to find boundary cases: a nullable field set to null, a union taking its less common variant, or an empty array. Most codebases under-test these cases because they require considering inputs outside the happy path.
Error branches deserve special attention. A try/catch block without a test for its catch branch contains unexercised error handling. If that handler sends a tracking event, displays a user-facing message, or starts a fallback flow, none of it has been validated. The agent targets catch blocks, conditional renders controlled by error flags, and early returns.
What the Agent Does Not Decide Alone
Some test choices need developer judgment, so the agent flags them instead of resolving them on its own. Choosing integration over unit testing involves a tradeoff between maintenance cost and isolation. Deciding whether to mock a third-party integration or use its sandbox depends on the team's isolation policy. Determining whether a new flow is a critical path for the required check suite or a secondary path for the broader suite is a product decision.
The agent writes tests for gaps it can infer from code signals and presents the remaining choices for review. A developer examines the proposed-test diff, approves or edits it, and then the tests join the suite. The agent's job is to bring the effort needed to start test writing close to zero. The team still confirms that the priority matches actual product risk.
We do not claim perfect prioritization. We claim that covering the top 80% of high-risk gaps through an agent-driven process is far better than a manual process reaching 20% because no one has time for retrospective test writing. The aim is to raise the codebase-wide floor for coverage quality, not to replace developer judgment about which tests matter.
A Concrete Example
On one early-access team, onboarding included an optional "invite team members" step. It was added during a sprint that ran long, and its engineer wrote "tests needed" in the PR, but the sprint ended first. The flow worked and did not break, so it remained untested for 3 months. TestSprighte flagged it within 2 days of setup because it was reachable from onboarding, had changed 2 times in the trailing 30 days, and lacked coverage in the existing suite. It generated a Playwright test for the happy path, the skip case, and invalid email validation. That test exposed a bug in invalid email handling. The value is not merely finding gaps, but finding gaps where something is actually wrong.