Skip to content

fix: HITL verifier no longer rejects VALID approvals just because an earlier approval in the array failed - #415

Merged
imran-siddique merged 3 commits into
agentrust-io:mainfrom
rajnisht7:fix-hitl-require-at-least-one-valid-approval
Sep 11, 2026
Merged

fix: HITL verifier no longer rejects VALID approvals just because an earlier approval in the array failed #415
imran-siddique merged 3 commits into
agentrust-io:mainfrom
rajnisht7:fix-hitl-require-at-least-one-valid-approval

Conversation

@rajnisht7

Copy link
Copy Markdown
Contributor

What

verify_manifest() now marks hitl_record as APPROVED if any approval in hitl_record.approvals is valid, unexpired, and sufficient instead of rejecting the whole record the moment it hits the first bad approval.

Why

Spec 5.3 says a VALID result only needs at least one good approval. The verifier's loop breaked on the first expired/invalid/unverifiable/insufficient approval and never looked at the rest of the array. So [expired_approval, valid_approval] was wrongly rejected as EXPIRED, even though the second approval was perfectly valid. Same for an invalid or unverifiable approval placed before a good one. (HITL-004)

Spec impact

None

Test plan

  • pytest -v passes
  • mypy src/agent_manifest passes
  • ruff check src/ tests/ passes
  • New or updated tests cover the change
  • If spec change: CHANGELOG.md updated

DCO

All commits in this PR are signed off (git commit -s). By submitting this PR I certify the Developer Certificate of Origin.

Signed-off-by: rajnisht7 <rajnishtiwari9787@gmail.com>
@rajnisht7
rajnisht7 requested review from a team, carloshvp and zohebk8s as code owners September 11, 2026 07:02
Signed-off-by: rajnisht7 <rajnishtiwari9787@gmail.com>
Signed-off-by: rajnisht7 <rajnishtiwari9787@gmail.com>

@imran-siddique imran-siddique left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approving. Measured against the spec text rather than the PR body, because this widens what the verifier accepts and that direction earns the check.

The rule this is held to, spec/agent-manifest-spec-v0.2.md section 5.3, in the list of conditions a VALID result requires:

If enforce_hitl is true, at least one HITL approval is present, valid, not expired, and meets the approval_method requirement for the declared risk_tier

"At least one" is unambiguous, so breaking out of the loop on the first bad entry was a defect, and [expired_approval, valid_approval] returning EXPIRED was wrong under the spec we publish.

What I checked beyond the headline, since a loosened check is only safe if the failure path survives it:

  • Each mode is still recorded separately, any_expired, approval_insufficient, approval_unverifiable, approval_invalid, so a record where every approval is bad still reports which way it failed rather than collapsing to one reason. That distinction is the reason this is a fix and not a weakening.
  • The defensive fallback for a non-empty approvals where every entry fell through is still there.
  • Unparseable approved_at still fails safe as expired (HITL-001). That is the line a later tidy-up would most easily drop, and it is doing real work.
  • Level 2 still refuses software-key, and still refuses anything other than hardware-key for high and critical risk tiers, per entry rather than per record.

Merge state. #407 landed in _verify.py a few minutes before this, and the trial merge onto current main is clean with no conflicts in either that file or CHANGELOG.md. The merged tree runs 1572 passed, 10 skipped.

@imran-siddique
imran-siddique merged commit 3525644 into agentrust-io:main Sep 11, 2026
14 of 15 checks passed
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.

2 participants