Skip to content

auditMetaItem's unqualified catch reports ANY failed audit read as {events: []} — the compliance trail says "no entries" when the read broke #9638

Description

@os-zhuang

Found while implementing #9426 (PR #9637), by the Zone-2 check that card asked for: confirm the missing-capability path and the unprovisioned-table path are genuinely separate. They are — and measuring that is what exposed this, one layer down. Filed rather than ridden on that PR: #9426's declared file surface is packages/rest/src/rest-server.ts, and this lands in a different package.

The measurement

packages/metadata-protocol/src/protocol.ts, closing the read inside ObjectStackProtocolImplementation.auditMetaItem (locate by text, not line number — this file moves):

} catch (err: any) {
    // Table not provisioned (legacy env) or driver doesn't
    // expose `find` — return empty rather than 500ing the tab.
    console.warn(
        `[Protocol] auditMetaItem read failed for ${request.type}/${request.name}: ${err?.message ?? err}`,
    );
    return { events: [] };
}

The comment names two benign causes. The catch is unqualified and takes every other one with them: a driver connection failure, a permission error, a malformed row, a query bug, a timeout. All of them are reported to the caller as the well-formed statement "this item has no audit entries".

ADR-0110 D3 — a miss and a fault are different facts. This is the same collapse #9426 fixed at the route, but at the layer below it, and the harm shape is worse in one respect: at the route the condition was a static capability gap, whereas here it is a transient read failure, so the same item can report a full trail one minute and a clean one the next, with nothing on the wire distinguishing them.

⚠️ Consequence, same as #9426's: this is the compliance surface. auditMetaItem is the read behind GET /api/v1/meta/:type/:name/audit, which exists so Studio's 审计日志 / Audit log tab can show "who tried what and whether a lock blocked it". An empty answer reads as nobody touched this item. A console.warn on the server is not an answer to the reader.

Control — this is a discriminating finding, not a blanket claim about catch

The same defect class has been filed and closed repeatedly in this package, which is what makes an unswept survivor worth naming rather than assuming:

So the sweep that produced this had a real chance of finding nothing here. It did not.

Scope note — what #9637 does and does not change

PR #9637 refuses at the route when the protocol has no auditMetaItem method at all. It does not touch this path and deliberately leaves the unprovisioned-table answer intact, because the two are separate frames in separate packages and only the first was #9426's card. This one is still open after that PR merges.

What would close it

Not obvious enough to assert here, and there is a real design question — which is why this is filed rather than fixed:

  1. Narrow the catch to the two conditions the comment already names (missing table / driver without find) and let everything else propagate, so the route's existing handleRouteError turns it into an honest 5xx. Keeps the documented empty-array promise exactly as documented.
  2. Distinguish on the wire — a third state beside "read, no entries" and "read failed". That is a response-shape decision and would be fenced to packages/spec, the same fence [finding] The REST references route answers a MISSING findReferencesToMeta capability with {references: []} — "nothing depends on this item", one layer above the defect #9190 just closed #9326 and The REST audit route answers a MISSING auditMetaItem capability with {events: []} — a compliance surface reporting "this item has no audit trail" #9426 both carried.

Option 1 looks like the one that needs no contract decision, but the choice belongs to triage, and #8901 (the read-seam failure-propagation vocabulary) may govern how the propagating half is expected to be spelled.

Dedup

Searched open issues for auditMetaItem, for the empty-collection-on-read-failure shape in metadata-protocol, and for the audit route generally. Nearest cards are #8747 (auditMetaItem's org scope — closed, different defect on the same method), #9426 (the route's missing-capability limb — this card's sibling, open) and the four closed same-class cards listed above. None covers this catch. No duplicate.

Related

#9426 / PR #9637 (the route limb, same class, one layer up) · #9326 / PR #9425 · #8896 (the empty-accumulator harm shape) · #8901 (read-seam failure-propagation vocabulary) · ADR-0110 D3

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions