Skip to content

orb(observability): GET /v1/internal/decision has 404'd for every PR since the 2026-06-22 cutover #9576

Description

@JSONbored

Found while verifying #9136. Not named anywhere in that issue.

handleInternalDecision (src/review/ops.ts), routed at /v1/internal/decision and bearer-protected, looked its target up with:

const id = rowId(config.slug, kind, repo, number);
const target = await storage(env).prepare(`SELECT * FROM review_targets WHERE id = ?`).bind(id).first();
if (!target) return Response.json({ error: "no such target", id }, { status: 404 });

review_targets has had no writer since the 2026-06-22 convergence cutover. So this endpoint has returned 404 for every pull request opened since then — silently, while remaining routed, authenticated, and documented as the "explain any verdict on demand" surface.

A second, independent break in the same handler

The audit-trail query bound rowId(...)project:kind:owner/repo#n — against review_audit.target_id, which is owner/repo#n. Different namespaces, so the trail came back empty even where rows existed. This one would have survived any repopulation of review_targets.

Fields with no live equivalent

decided_sha and approved_sha (the per-head-SHA approve-once cache) were dropped as a concept at the cutover, so the endpoint cannot be restored to its exact former shape. The nearest honest answer is decision_records.head_sha — the sha the standing decision was actually made on, which is what decided_sha was a cache of.

Likewise review_targets' processing-status enum (queued/reviewing/error/error_retryable) has no live source; the realized disposition (merged/closed/open) does, and is the half every consumer reads.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.orbGittensory Orb related - maintainer self-hosting analytics.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions