Why my land was blocked by a semantic check
TVO-SEM-004, and what to do about it.
Written By Dustin
Last updated 27 minutes ago
TVO-SEM-004 means the target lane declares semantic-check = required and your change introduces a breaking interface change, an interface-level semantic conflict, or both.
An interface-level semantic conflict is the subtler half: two sides of a merge each edited the same exported symbol in ways that disagree, or one side removed a symbol the other side started referencing. The text merge is clean. The interfaces are not.
See what it found
tovio semantic difftovio explain semantic --into <lane>explain semantic is the one to reach for here: it names the symbols, the reason each changed, and states whether the gate on that lane would pass or fail — so you can check your fix before re-running the land.
The options, in order of preference
- Do not break it. Add an overload, keep the old signature as a deprecated wrapper, or widen rather than change. Usually the right answer.
- Update the callers in the same change, so nothing is left broken.
- Land it as a deliberate breaking change, following whatever your project requires — a version bump, a changelog entry, an announcement.
Find the callers
tovio semantic find-refs <moniker>tovio semantic impactWith no argument, impact seeds itself from what your most recent commit removed or altered. That is usually the right starting point, but it is not the same set the gate compared: the gate looks at everything your lane changed since it diverged from the target. If your lane has several commits, fix what impact names, then re-run tovio explain semantic --into <lane> to confirm the gate agrees before landing again.
The sibling code: TVO-SEM-005
If the lane requires the check but your tovio binary was built without the semantic layer, the land is refused with TVO-SEM-005 instead. A required check is never silently passed because it could not be run. Use a default build, or target a lane that does not require the check.
Who to ask
The requirement is set on the lane, not by you. If the check is wrong about your change, that is worth reporting — a false positive on a land gate is a real bug.
On a Forge
The same refusal appears at the Forge advance gate over HTTP 422, re-applying the same check against the pinned reviewed commit — so a change cannot pass review and then land something different. The message names the lane only; it never carries your code.
What it will not tell you
Every semantic finding is plaintext-free by design: monikers, change reasons, and counts, never a line of source. That is deliberate, and it holds on the Forge too. To see the actual code, run the diff locally.