Skip to content

fix(registry): serve explicit heartbeat requeues first and reference the refresh fence tracking issue - #7648

Merged
bokelley merged 3 commits into
adcontextprotocol:mainfrom
idemidenko:fix/7632-heartbeat-requeue-priority
Sep 24, 2026
Merged

bokelley merged 3 commits into
adcontextprotocol:mainfrom
idemidenko:fix/7632-heartbeat-requeue-priority

Conversation

@idemidenko

Copy link
Copy Markdown

Summary

Fixes the requeue-ordering bug from #7632 and adds the missing tracking reference to the human-refresh fence.

  • Heartbeat ordering. requeueForHeartbeat only cleared next_compliance_check_at, while getAgentsDueForCheck orders by last_checked_at ASC NULLS FIRST, so an agent with a recent authoritative run sorted behind every agent checked earlier and "Requeue comply" never moved it forward. New agent_registry_metadata.requeued_at column (migration 605), set by requeueForHeartbeat, ordered first (requeued_at ASC NULLS LAST), and cleared in the schedule_next CTE when an authoritative run is published, so a requeue is served once and the agent then falls back to the regular cadence.
  • Fence response. HUMAN_REFRESH_AVAILABILITY now carries tracking_issue (fix(auth): preserve queued refresh credential provenance #7457). It is returned in the 503 body and in refresh_availability on /compliance, declared in the OpenAPI schema (static/openapi/registry.yaml regenerated), and linked from the dashboard fence notice. The alternative_description wording is updated to reflect that requeues are now prioritised.

Not included: the getAuthInfoByOrgAndUrl ORDER BY from the triage. agent_contexts has had UNIQUE (organization_id, agent_url) since migration 109 and migration 525 collapsed URL variants, so rows[0] cannot flip between duplicate rows; the credential change reported in #7632 needs a different explanation.

App-layer only, no changeset.

Validation

  • npx tsc --project server/tsconfig.json --noEmit
  • node tests/migration-validation.test.cjs
  • node scripts/check-changeset-protocol-scope.cjs origin/main
  • npx vitest run --config server/vitest.config.ts tests/unit/dashboard-agent-refresh.test.ts tests/unit/compliance-heartbeat.test.ts
  • DATABASE_URL=… npx vitest run --config server/vitest.config.ts tests/integration/compliance-run-publication.test.ts tests/integration/registry-api-agent-refresh.test.ts (new case: serves explicit requeues ahead of agents with an older authoritative check)
  • npx tsx scripts/generate-openapi.ts && git diff --exit-code static/openapi/registry.yaml

Closes #7632

https://claude.ai/code/session_01EhqPiLqfuPcPa15YGbUtpz

…the refresh fence tracking issue

Requeue comply only cleared next_compliance_check_at while the heartbeat
batch orders by last_checked_at ASC NULLS FIRST, so an agent with a recent
authoritative run never moved forward. Record requeued_at on requeue, order
by it first, and clear it when an authoritative run is published.

The human refresh 503 and refresh_availability now carry tracking_issue
(adcontextprotocol#7457) so owners can follow the fence.

Closes adcontextprotocol#7632

Claude-Session: https://claude.ai/code/session_01EhqPiLqfuPcPa15YGbUtpz
@aao-ipr-bot

aao-ipr-bot Bot commented Sep 22, 2026

Copy link
Copy Markdown

IPR Policy Agreement Required

@idemidenko — thanks for the contribution. Before this PR can be merged, the AgenticAdvertising.Org IPR Policy requires your agreement.

To agree, post a new comment on this PR with the exact phrase:

I have read the IPR Policy

Your signature is recorded once and covers all contributions to AAO repositories. See signatures/README.md for what gets recorded and why.

@idemidenko

Copy link
Copy Markdown
Author

I have read the IPR Policy

1 similar comment
@idemidenko

Copy link
Copy Markdown
Author

I have read the IPR Policy

Copy link
Copy Markdown
Contributor

I found that this PR’s migration number (605) now collides with migrations already on main (605–607). I pushed a focused correction to renumber it to 608 and updated the migration integration assertion. Local validation passed: migration-number validation, the dashboard/heartbeat unit suites (30 tests), and TypeScript. The database-backed integration suites could not connect to the workspace’s configured local Postgres, so CI remains authoritative for those.

@bokelley
bokelley marked this pull request as ready for review September 23, 2026 14:26

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ladon verdict: Approve

Approve — clean, well-scoped bugfix with no blocking findings.

What I checked:

  • Migration 608 (server/src/db/migrations/608_agent_registry_requeued_at.sql) adds a requeued_at column, idempotent/additive — judged as production-facing (runs on startup) and safe.
  • requeued_at lifecycle verified: set on requeue, cleared on authoritative publish, preserved across lock/deferral. Fixes #7632 (requeues sort ahead of regular cadence).
  • New required tracking_issue field on the human-refresh fence response is consistent across the constant, zod schema, OpenAPI (static/openapi/registry.yaml), and dashboard — all four availability emitters agree, no wire-shape drift.
  • Changeset scope: correct app-layer-only change, no protocol-surface (static/schemas/source/**) modifications, so no changeset required.
  • New integration + unit test coverage added for the new branches.

High-risk flag: true, but reasons are a new migration file (added) — normal scaffolding, not escalation-worthy — and a (modified) route file with no medium-or-higher finding, so presumed safe.

Gate checks: gated_paths false; no no-auto-approve team match; review_decision REVIEW_REQUIRED does not force any row (row 2 only fires when gated_paths is true). No critical/high/medium findings; only a Low doc nit ("migration 605" vs actual 608) which is omitted per severity model. Falls through to row 9 → approve.

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ladon verdict: Approve

Approve — clean pass, no blocking findings.

This PR adds a requeued_at column plus additive migration 608 and reorders the compliance heartbeat so explicit owner requeues are served ahead of the regular cadence (#7632), and surfaces a tracking_issue link on the paused human-refresh response (#7457).

Checks performed:

  • Migration 608 is additive and startup-safe (migrations run automatically on startup; judged as production-facing) — no destructive or backfill risk.
  • Requeue-clear lifecycle verified: authoritative publish clears requeued_at, deferral preserves it.
  • API/OpenAPI/zod consistency: required-field shape consistent across registry-api.ts, registry.yaml, and zod.
  • Queue-lane semantics preserved.
  • Changeset scope: operational/migration-only PR, none required (server-only, no static/schemas/source/** or normative-doc surface touched).
  • Dashboard XSS: escaping verified on the new tracking_issue link surface.

High-risk flag is true only for a new migration file (added) and a modification to registry-api.ts; the reviewer found no medium-or-higher concerns on the modified file, so the modification is presumed contract-preserving. No deletions in sensitive paths. gated_paths is false and review_decision is APPROVED.

Decision table: rows 1–8 do not fire (no critical/high/medium findings, no gated-path/deletion/team triggers, prior decision was approve). Falls through to row 9 → approve.

@EvgenyAndroid

Copy link
Copy Markdown
Contributor

RC6 gating dependency cleared & fleet telemetry context

Flagging that v3.2.0-rc.6 shipped this morning (2026-09-24T00:07Z), clearing the gating dependency previously noted on #7355 ("pending behind RC6"). Mechanically the PR looks ready: draft: false, mergeable_state: clean, reviewers assigned, IPR on file, and migration renumbered to 608.

Declaring an interest first: I reported the symptom this fixes, so I am not a neutral party here. The condition is registry-wide rather than specific to one operator, which is why the numbers seem worth having on the thread.

Registry staleness measured across all 34 agents with a compliance record, as of 2026-09-23T17:07Z:

  • 33 of 34 agents exceed the declared check_interval_hours: 12 (median staleness 8.4 days).
  • Bimodal distribution:
    • 27 agents between 2 and 14 days (12 in 2–7d, 15 in 7–14d; 29 including the 2 at ≤2d).
    • A 14–60 day void with zero agents.
    • 5 outliers at the head: 2 never checked, 3 last checked in early July (71–78 days ago).

How #7648 addresses this. Under last_checked_at ASC NULLS FIRST, an agent with a recent authoritative run sorts to the back of the queue. Because requeueForHeartbeat cleared only next_compliance_check_at, a manual requeue left the agent exactly where it was. Concretely: a refresh on one of our agents was triggered the evening of 2026-09-17 for an agent checked at 11:41 that same morning, so it was among the freshest in the registry and sorted to the tail. Six days later the same agent sits 23rd of 34, which is why a second requeue would not help either. The requeued_at column ordered first is the right shape for that.

One observation for maintainers. The 5 agents at the head — 2 never checked, 3 at 71–78 days — look like a separate failure mode from the general 2–14 day backlog, and the empty 14–60 day band is what suggests two mechanisms rather than one. #7648 will let requeued runs jump ahead and unblock active owners; those five may still warrant a look at the job records, in case they are in a state the scheduler skips rather than merely sorting late. Noting it as a separate question rather than scope for this PR.

@idemidenko

Copy link
Copy Markdown
Author

Thanks for the 605 → 608 renumber and the CI-after-review change. Both are on the branch and I have nothing further to push. The PR is approved and mergeable; could a maintainer merge it when convenient?

Once it lands, a requeue will actually reach agents with a recent last_checked_at. Ours (https://sales-agent.elementaltv.io/mcp) has had no authoritative run since 2026-09-17T08:09Z.

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

Labels

None yet

Projects

None yet

3 participants