Skip to content

feat(registry): one-shot re-probe of unknown agents with extended timeout#3558

Merged
EmmaLouise2018 merged 3 commits into
mainfrom
EmmaLouise2018/registry-reprobe-unknown
May 1, 2026
Merged

feat(registry): one-shot re-probe of unknown agents with extended timeout#3558
EmmaLouise2018 merged 3 commits into
mainfrom
EmmaLouise2018/registry-reprobe-unknown

Conversation

@EmmaLouise2018

Copy link
Copy Markdown
Contributor

Closes #3551.

77% of agents in the public registry currently render type: 'unknown'. Before designing the full retry/backoff system (Problem 2 in #3538), ship a one-shot script that re-probes every currently-unknown agent with an extended timeout. The output tells us whether unknown is mostly transient (timeouts/network) or mostly dead — informs the full Problem 2 PR's scope.

Script

server/scripts/reprobe-unknown-agents.ts:

  • Selects every agent where agent_capabilities_snapshot.inferred_type IS NULL or the snapshot row is missing.
  • Re-probes with 30s timeout (vs current 10s in crawler.ts:548).
  • Reuses the crawler's probe + write helpers (CapabilityDiscovery.discoverCapabilities, inferTypeFromProfile, AgentSnapshotDatabase.upsertCapabilities) — no parallel probe path.
  • Reports {still_unknown, newly_classified: {sales, creative, signals, buying}, probe_failed, dns_failed}.
  • Idempotent: real runs skip rows that became classified between selection and probe. --dry-run mode probes everything but writes nothing.

Stack ordering / known gap

PR #3541 will export resolveAgentTypes() from server/src/routes/member-profiles.ts so this script can also refresh member_profiles.agents[] after each re-probe. As of this branch, resolveAgentTypes is not yet exported on main. The script tries a dynamic import, logs [warn] resolveAgentTypes not exported … skipping member_profiles.agents[] refresh. Land #3541 to enable it., and continues. Once #3541 lands, the import resolves automatically — no code change here. Land #3541 first; merge order: 3540 → 3542 → 3543 → 3541 → this PR.

Test

server/tests/unit/reprobe-unknown-agents.test.ts pins the report-shape contract across success / probe-failed / DNS-failed cases. 5/5 pass, mirrors the crawler-type-update-policy.test.ts style.

Operator runbook

Same protocol as #3541's backfill:

# 1. Dry-run on staging
DATABASE_URL=<staging> npx tsx server/scripts/reprobe-unknown-agents.ts --dry-run | tee 2026-04-29-staging-reprobe-dryrun.log

# 2. Eyeball the report. Expect: most-of-77% either transient or dead.

# 3. Real run on staging
DATABASE_URL=<staging> npx tsx server/scripts/reprobe-unknown-agents.ts | tee 2026-04-29-staging-reprobe.log

# 4. Repeat 1-3 against prod.

# 5. Paste final reports back into this PR's comments so the full Problem 2 PR can scope from real data.

Test plan

  • npx vitest run server/tests/unit/reprobe-unknown-agents.test.ts — 5/5 pass.
  • npm run typecheck — clean.
  • Pre-commit hooks green (test:unit 834/834, test:test-dynamic-imports 7/7, typecheck clean).
  • Operator: --dry-run on staging.

Out of scope

Comment thread server/scripts/reprobe-unknown-agents.ts Fixed
…eout

Closes #3551 (Problem 2 quick-win for #3538).

77% of agents in the public registry currently render type='unknown'. Before
designing the full retry-with-backoff system, ship a one-shot script that
re-probes every currently-unknown agent with an extended 30s timeout. The
output tells us whether unknown is mostly transient or mostly dead — informs
the full Problem 2 PR's scope.

## Script

server/scripts/reprobe-unknown-agents.ts:
- Selects every agent with snapshot.inferred_type='unknown' or missing snapshot
- Re-probes with 30s timeout (vs current 10s in crawler.ts:548)
- Reuses the crawler's probe + write helpers — no bypass
- Calls resolveAgentTypes from member-profiles.ts (#3541) so member_profiles.agents[] picks up new types
- Reports {still_unknown, newly_classified by type, probe_failed, dns_failed}
- Idempotent. --dry-run mode for staging validation before real runs.

## Test

server/tests/unit/reprobe-unknown-agents.test.ts pins the report-shape contract
across success/failure/dns-fail cases.

## Operator note

Same protocol as the #3541 backfill: dry-run on staging, capture stdout,
eyeball the diff, then real run. Repeat on prod. Operator paste-back of the
final report into a PR comment so the full Problem 2 PR can scope from real
data.

## Out of scope

- Full retry-with-backoff loop with last_probe_attempt_at tracking
- Mark-as-dead semantics for permanently unreachable agents
Both depend on this script's output to scope correctly.
…r-agent timing

#3541 has merged, so resolveAgentTypes is statically imported from
member-profiles.ts (the dynamic-import workaround is gone). Adds a
load-bearing silent-corruption guard: a transient probe failure on an
agent that already had a snapshot row never overwrites that row back to
NULL — decideWrite() routes probe_failed/dns_failed to "preserve". Adds
per-agent elapsed_ms + slowest-N report so operators see the slow tail.
Fails loud on missing DATABASE_URL. Test coverage: success / probe-failed
(timeout) / DNS-failed / discovery_error routing / silent-corruption
guard / dry-run / per-agent timing — 18/18 pass.
Previous shim was a no-op due to ESM import hoisting — imports run before
module-body statements, so member-profiles.ts (transitively imported via
the script's static import of resolveAgentTypes) constructed WorkOS before
WORKOS_API_KEY got set. Passed locally where the env was already set;
failed in CI where it wasn't.

Mock member-profiles directly so WorkOS init never triggers. The script's
behavior around resolveAgentTypes is exercised through the mock — unit
tests pin the behavior, not the implementation.

18/18 reprobe tests pass.
@EmmaLouise2018 EmmaLouise2018 force-pushed the EmmaLouise2018/registry-reprobe-unknown branch from 9ce641d to a65e235 Compare May 1, 2026 16:29
@EmmaLouise2018 EmmaLouise2018 merged commit 6f52a0a into main May 1, 2026
13 checks passed
@EmmaLouise2018 EmmaLouise2018 deleted the EmmaLouise2018/registry-reprobe-unknown branch May 1, 2026 17:02
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.

feat(registry): one-shot re-probe of all type='unknown' agents with extended timeout (Problem 2 quick-win)

1 participant