Skip to content

feat!: rename validation window to verification phase#213

Open
hashedone wants to merge 5 commits into
mainfrom
refactor/rename-validation-window-to-verification-phase
Open

feat!: rename validation window to verification phase#213
hashedone wants to merge 5 commits into
mainfrom
refactor/rename-validation-window-to-verification-phase

Conversation

@hashedone
Copy link
Copy Markdown
Contributor

Breaking change. Renames the "validation window" feature to "verification phase" across the entire stack — DB, API, CLI, web, MCP, docs.

Why

Demo feedback: the presenter struggled to explain "validation window" because people heard "window" as a passive time range and missed the actual feature — an active gate that locks the agent into review-only mode before a push. Cleaner naming closes the comprehension gap.

The new term also splits the two concepts the old name conflated: "verification" (what the agent is doing inside) and "phase" (a discrete bounded period the agent must explicitly enter).

Renames

Wire format

Before After
PolicyScope value validation_window verification_phase
Repo setting validation_window_mode verification_phase_mode
StreamEventType validation_window_start verification_phase_start
CLI tracevault validation-start tracevault verify-start

Database (migration 026_rename_validation_window_to_verification_phase.sql)

ALTER TABLE sessions
    RENAME COLUMN validation_window_started_at TO verification_phase_started_at;

UPDATE policies SET scope = 'verification_phase' WHERE scope = 'validation_window';
-- + reattach CHECK constraint with new value

ALTER TABLE repos
    RENAME COLUMN validation_window_mode TO verification_phase_mode;
-- + reattach CHECK constraint with new column name

UX (web Settings page)

The Settings page copy was rewritten to lead with the value proposition rather than the mechanism:

Verification phase — Lock the agent into a "review only" mode before each push. When an agent runs tracevault verify-start, it declares that it is done changing code. From that point until the push, only tools you whitelist below are allowed to run.

Catches agents that pretend to self-review while still making code changes — any tool call inside the phase that is not on the allow-list will either warn or block the push, depending on the mode you pick.

Dropdown labels now say outcomes explicitly: "Disabled (no enforcement)", "Warn (record but allow push)", "Block the push".

Agent instructions

The Markdown rendered by tracevault agent-policies (the doc agents read at session start) was also rewritten. New phrasing leads with the intent ("catch agents that pretend to review while still editing") before listing required/allowed tools.

Compatibility

No back-compat aliases. Hard rename, per the design decision made during review of this change:

  • Existing scripts calling tracevault validation-start need to update to tracevault verify-start.
  • Anything reading the policies API for scope values must expect verification_phase instead of validation_window.
  • Anything reading the repo settings API for validation_window_mode must read verification_phase_mode.
  • The validation_window_start event type wire value is gone — clients sending it will get a deserialization error.

Migration 026 handles all DB-side renames automatically on next deploy. No data migration needed beyond the column + value renames.

Verification

Layer Status
cargo fmt --check
cargo clippy --workspace --tests --all-targets -- -D warnings
cargo test --workspace ✅ all green (24 CLI lib tests, 89 core lib tests, 128 server lib tests, repo_policies_test/sliding_session and all others)
pnpm check ✅ 0 errors, 0 warnings

Files

30 files changed, ~660 insertions / ~200 deletions. Mostly mechanical renames; the substantive changes are:

  • crates/tracevault-server/migrations/026_*.sql — the rename migration.
  • crates/tracevault-core/src/agent_policies.rs — agent-facing instruction text rewritten.
  • web/src/routes/orgs/[slug]/repos/[id]/settings/+page.svelte — Settings page copy rewritten.
  • crates/tracevault-core/src/policy.rs — enum names + doc comments.
  • All other changes are find-and-replace driven by the renames above.

hashedone added 3 commits May 28, 2026 12:37
Demo feedback: 'validation window' was misleading — people heard
'window' as a passive time range and missed that the feature is an
active gate locking the agent into review-only mode before push.
Rename across the domain layer to match the user mental model.

This is a breaking change for any external caller of the policy or
streaming API.

Renames (core crate + migration):

* PolicyScope::ValidationWindow → PolicyScope::VerificationPhase
* ValidationWindowMode → VerificationPhaseMode
* StreamEventType::ValidationWindowStart → ::VerificationPhaseStart
* sessions.validation_window_started_at →
  sessions.verification_phase_started_at
* repos.validation_window_mode → repos.verification_phase_mode
* policies.scope value 'validation_window' → 'verification_phase'
* Agent-policies renderer text rewritten to lead with the gate story
  (what is forbidden) instead of the time-range story (when measured).

Migration 026_rename_validation_window_to_verification_phase.sql
performs the column renames, drops + re-adds the relevant CHECK
constraints with the new column names, and rewrites
policies.scope='validation_window' rows in place.

Closes the demo-presenter UX complaint.
Follow-up to the core rename. Wires the new domain types through:

* Server API: PUT/GET repo settings JSON now uses
  verification_phase_mode; check endpoint matches policy scope on
  'verification_phase'; SQL files renamed in lockstep with column
  renames from migration 026.
* CLI: `tracevault validation-start` → `tracevault verify-start`.
  No alias for the old name; existing scripts will need to update.
  Command module renamed validation_window.rs → verification_phase.rs.
* Web Settings: 'Validation Window' section heading and copy rewritten
  to lead with what the feature DOES (lock the agent into review-only
  mode before push) rather than what it MEASURES (a time range). New
  dropdown labels: 'Disabled (no enforcement)', 'Warn (record but
  allow push)', 'Block the push' — each option now says outcome
  explicitly.
* Web Policies editor: scope dropdown renamed 'Validation' →
  'Verification'.
* MCP integration: tool description updated to match.
* tracevault-server tests updated for new names; same coverage.

Breaking changes for external integrators:

* CLI scripts calling `tracevault validation-start` must change.
* Anything reading the policies/check API for scope values must
  expect 'verification_phase' instead of 'validation_window'.
* Anything reading the repo settings API for validation_window_mode
  must read verification_phase_mode instead.
* StreamEventType wire value 'validation_window_start' is now
  'verification_phase_start'.
Updates the project's own CLAUDE.md instructions (tracevault uses its
own validation feature against this repo) and the public README to
use 'verification phase' / 'tracevault verify-start' consistently.

Cargo.lock churn from the v0.16.0 dep updates that landed via
release-plz on main — picks up the same lockfile state as PRs #211
and #212.
Comment on lines 155 to 165
out.push_str(
"A validation window restricts which tools can be called before push, \
gating the push on a clean validation run. Before pushing, open a \
validation window:\n\n tracevault validation-start\n\n\
The window stays open until you push, or until you open a new window. \
Opening a new window invalidates the prior one.\n",
"When you are done changing code and ready to push, you must enter a \
**verification phase** by running:\n\n tracevault verify-start\n\n\
From that point until the push, you are only allowed to call the tools \
listed below. Any other tool call will fail the push.\n\n\
The intent: catch agents that pretend to review while still editing. \
If you need to make a code change after entering the phase, that is fine — \
make the change, then run `tracevault verify-start` again to restart the \
phase and rerun the required tools. The most recent `verify-start` is the \
only one that counts.\n",
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The verification-phase text says unknown tool calls "will fail the push," but this section also renders in Warn mode where pushes are allowed. This contradiction gives incorrect behavior guidance.

Show fix
Suggested change
out.push_str(
"A validation window restricts which tools can be called before push, \
gating the push on a clean validation run. Before pushing, open a \
validation window:\n\n tracevault validation-start\n\n\
The window stays open until you push, or until you open a new window. \
Opening a new window invalidates the prior one.\n",
"When you are done changing code and ready to push, you must enter a \
**verification phase** by running:\n\n tracevault verify-start\n\n\
From that point until the push, you are only allowed to call the tools \
listed below. Any other tool call will fail the push.\n\n\
The intent: catch agents that pretend to review while still editing. \
If you need to make a code change after entering the phase, that is fine — \
make the change, then run `tracevault verify-start` again to restart the \
phase and rerun the required tools. The most recent `verify-start` is the \
only one that counts.\n",
);
let consequence = match verification_phase_mode {
VerificationPhaseMode::Block => "Any other tool call will fail the push.",
VerificationPhaseMode::Warn => "Any other tool call will generate a warning.",
VerificationPhaseMode::Disabled => unreachable!(),
};
out.push_str(&format!(
"When you are done changing code and ready to push, you must enter a \
**verification phase** by running:\n\n tracevault verify-start\n\n\
From that point until the push, you are only allowed to call the tools \
listed below. {consequence}\n\n\
The intent: catch agents that pretend to review while still editing. \
If you need to make a code change after entering the phase, that is fine — \
make the change, then run `tracevault verify-start` again to restart the \
phase and rerun the required tools. The most recent `verify-start` is the \
only one that counts.\n",
));
Details

✨ AI Reasoning
​The updated instruction text is trying to explain behavior inside the new phase. However, it now asserts that any non-allowlisted tool call "will fail the push" regardless of mode. In the same logic, this section is rendered for both blocking and warning configurations, so in warning mode that statement is false. This creates contradictory runtime guidance that can cause agents to act on incorrect assumptions.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

hashedone added 2 commits May 28, 2026 12:50
The function rename to `get_verification_phase_tool_call_stats`
pushed two call sites past the 100-column limit. `cargo fmt --all`
rewraps them onto a continuation line. CI's `cargo fmt -- --check`
caught this on PR #213.
The rewritten verification-phase intro unconditionally said 'Any other
tool call will fail the push.' That sentence is true in Block mode
but wrong in Warn mode — the same section renders in both, so warn-mode
agents were getting incorrect guidance.

Switch on `verification_phase_mode` to emit:
  * Block: 'Any other tool call will fail the push.'
  * Warn:  'Any other tool call will be recorded as a warning on the push.'
  * Disabled: unreachable (gated upstream by has_verification).

Two tests lock the per-mode wording in place so this can't drift again.

Addresses Aikido review comment on PR #213.
Comment on lines +156 to +165
// never get here because has_verification short-circuits above), so
// it is safe to switch on those two arms and `unreachable!` Disabled.
let consequence = match verification_phase_mode {
VerificationPhaseMode::Block => "Any other tool call will fail the push.",
VerificationPhaseMode::Warn => {
"Any other tool call will be recorded as a warning on the push."
}
VerificationPhaseMode::Disabled => unreachable!(
"verification phase section is only rendered when mode is Warn or Block"
),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The VerificationPhaseMode::Disabled arm containing unreachable! is unreachable due to the has_verification guard. Remove the unreachable arm or simplify the match to only the reachable modes.

Show fix
Suggested change
// never get here because has_verification short-circuits above), so
// it is safe to switch on those two arms and `unreachable!` Disabled.
let consequence = match verification_phase_mode {
VerificationPhaseMode::Block => "Any other tool call will fail the push.",
VerificationPhaseMode::Warn => {
"Any other tool call will be recorded as a warning on the push."
}
VerificationPhaseMode::Disabled => unreachable!(
"verification phase section is only rendered when mode is Warn or Block"
),
// never get here because has_verification short-circuits above).
let consequence = match verification_phase_mode {
VerificationPhaseMode::Block => "Any other tool call will fail the push.",
VerificationPhaseMode::Warn => {
"Any other tool call will be recorded as a warning on the push."
}
Details

✨ AI Reasoning
​A match on verification_phase_mode was added that includes a VerificationPhaseMode::Disabled arm which calls unreachable!. Earlier in the function, has_verification is computed to be false when verification_phase_mode is Disabled, and the entire block guarded by if has_verification only runs when mode is Warn or Block. Thus the Disabled arm cannot be reached at runtime given the surrounding logic, making the unreachable! invocation dead code.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

match on an enum must be exhaustive — VerificationPhaseMode has three variants, so removing the Disabled arm breaks compilation. The unreachable!() documents the invariant from has_verification and survives future refactors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant