Repository navigation
Description
What is missing
#484 (draft, needs odal-node/dpp-core#486) makes the registry drain recover a submission whose correlation identifier was lost, by the unique product identifier the passport was submitted under. It settles the common case on its own. Three cases it deliberately does not settle still need a person:
Ambiguous: more than one registry submission reports the passport's identifier (a successor can be submitted under its predecessor's), so the lookup refuses to choose. Choosing would give a passport another passport's registration.- Never found: the identifier is not among the tasks read, or a task that might be the one is still being checked, so absence proves nothing. The row is retried and counted as an attempt until it stalls.
- Unsupported or unreadable: an adapter that cannot look a submission up, or a row whose frozen payload cannot say what was submitted.
For those, two things are missing, and #484's runbook text says so plainly.
1. The row does not say why it is waiting
mark_submitted clears the row's message on every pass. The candidate correlation identifiers of an Ambiguous lookup, and the reason a lookup found nothing, are only written to the log. GET /vault/api/v1/dpp/{dppId}/registry therefore shows a submitted row with no handle and no explanation, and an operator has to go to the logs of the node to learn that it needs a person and what the candidates are.
2. There is no way to settle it
No route or command records a correlation identifier for a row. An operator who has worked out which candidate is the passport's can do nothing with the answer. The row stays where it is and loses nothing, but it never registers.
Proposed shape
This is a design of its own, because it puts a write on a registry row behind the HTTP surface.
- A route, for example
POST /vault/api/v1/dpp/{dppId}/registry/handlewith{ "correlationId": "…" }, behind the admin scope, for a row that issubmittedand has no handle, and for nothing else. - It does not trust the operator's say-so. It reads the submission by that identifier (
check_submission) and refuses unless the registry reports this passport's unique product identifier under it: the check that stops a typo from giving a passport another passport's registration. A found submission then takes its ruling in the same step, as a recovered one does. - An entry in the passport's audit trail recording who recorded which identifier.
- The reason is kept on the row so
GET …/registryshows it, which needs a way to write a message without counting an attempt or clearing it. odalgets the matching command, and the OpenAPI description, the contract fixtures and thedocumented_error_codes_are_the_ones_handlers_returngate follow the route.
Open questions
- Is admin the right scope, or does recording a handle deserve a narrower one?
- Should the route also accept "this passport is not registered, give it up", for a row whose submission was never accepted? That is a different and more dangerous write.
- Does the idempotency policy table (
KEYED) need an entry?
Done when
A stalled submitted row says why on the per-passport registry route, and an operator can settle one that needs a person, with the registry confirming the identifier belongs to the passport, in one call and with an audit entry.
Activity