Skip to content

Config-First Verification

When a coding agent finishes a UI task and verifies it, Verfix runs the relevant flow. If a selector doesn’t resolve, the agent has a choice:

  • Fix it in Verfix configuration — the selectors alias map, a semantic selector, or let assisted mode heal it. ✅
  • Rewrite the project’s source — e.g. add a data-testid to a component just so the test passes. ⚠️

The second option is the easy failure mode for an agent under pressure: it rewrites production code to fit the test instead of fixing the actual gap. Verfix is built to prefer the first option — and to make the second one a typed, visible signal instead of a silent side effect.


Targeting elements without adding data-testid

Section titled “Targeting elements without adding data-testid”

The primary job when writing a flow is to read the source and reuse the selector that already exists — not invent one. In priority order:

1. Reuse the element’s existing selector (primary)

Section titled “1. Reuse the element’s existing selector (primary)”

Open the component and target what’s already in the code — an existing data-testid, id, name, role, or a stable semantic CSS selector. Put it directly in the flow step, or give it a logical name via the selectors alias map. This is deterministic and works in strict mode — what CI runs.

{
"selectors": {
"emailInput": "input[type=email]",
"submitBtn": "#login-form button[type=submit]"
},
"flows": [
{
"id": "login",
"steps": [
{ "action": "type", "selector": "emailInput", "value": "[email protected]" },
{ "action": "click", "selector": "submitBtn" }
]
}
]
}

The selectors alias map is for reuse and readability — the value must still be a real selector found in the source.

When there’s no stable structural selector, target by accessible role/name or visible text: role=button[name="Sign In"], text=Sign In. Works in every mode.

3. Assisted mode — a resilience fallback, not a targeting strategy

Section titled “3. Assisted mode — a resilience fallback, not a targeting strategy”

assisted mode adds self-healing: if a selector drifts and stops resolving, Verfix recovers it at run time via the accessibility tree (aria-label / role / text), then an AI suggestion. This is a safety net for flow stability over time — not a substitute for finding the real selector in step 1.

Healing derives an intent hint from the selector/alias token, so descriptive names heal better: a drifted sign-in testid or a signIn alias both map to the hint “sign in” and can re-resolve the “Sign In” button.

4. Last resort — add data-testid to source

Section titled “4. Last resort — add data-testid to source”

Only when an element genuinely can’t be targeted (e.g. an icon-only control with no accessible name — which is also a real accessibility gap worth fixing). Add an aria-label alongside it.


Instructions alone aren’t reliable, so Verfix makes source edits a typed signal in the run contract — consistent with its philosophy that reliability comes from structured contracts, not unconstrained intelligence.

verfix run snapshots a git baseline at the start of each verify cycle:

  • The first run of a cycle baselines the working tree — your feature work is not flagged.
  • Later runs report project files changed since the baseline — i.e. edits made inside the edit → verify → fix loop, where the anti-pattern lives.
  • A passing run ends the cycle and clears the baseline. A new git commit also starts a fresh cycle.
  • Outside a git repo, the guard disables itself and never blocks a run.

The JSON output gains a source_changes field:

{
"passed": true,
"source_changes": {
"status": "ok",
"baseline_captured": false,
"files": [{ "path": "src/LoginForm.tsx", "classification": "project" }],
"project_count": 1,
"config_count": 0
}
}

.verfix/**, verfix.config.*, and agent instruction files (AGENTS.md, CLAUDE.md, GEMINI.md, CODEX.md, .cursorrules, .cursor/**, .github/copilot-instructions.md, .github/instructions/**, .clinerules/**, .agents/**) are classified as config; everything else is project.

Set the policy in verfix.config.json, or override per run with --source-policy:

PolicyBehavior
warn (default)Run still passes, but reports changed project files and adds a source_edit_warning finding. Doesn’t block legitimate app-bug fixes.
blockIf project source changed during the loop, the run fails with a source_edit_blocked failure until reverted. Best for CI.
offNo source-change detection.
{ "sourceCodePolicy": "warn" }
Terminal window
verfix run --flow login --source-policy block --output json
verfix run --flow login --reset-baseline --output json # start a fresh cycle

When you see a source_edit_blocked / source_edit_warning finding: if the edit wasn’t a genuine bug fix, revert it and target the element via the selectors alias map or assisted mode instead.