The terminal dialog that refuses a class removal states how many annotations block it and across
how many assets, and then leaves the person holding a number with no way to reach the thing it
counts. The class-removal flow work (#588) asks for that link explicitly — the dialog should state
the fact, state the way out, and link to the annotations filtered to that class — and it is the one
requirement of that issue which cannot be built in the browser today, because nothing on the wire
can express the filter.
All citations are at 2e4346d.
What the dialog does now
OrphanBlockersDialog in frontend/ui-core/src/screens/SchemaEditor.tsx renders one line per
blocking class from the preview's typed report — the class name, its annotation count, its asset
count — and a single Close button. That is correct as far as it goes: the refusal has no override,
so a second button would be a lie. The counts come from POST .../schema/preview, so they agree
with what the publish would refuse over.
The remedy sentence is "Keep the class or remove the annotations first." Removing them means
finding them, and the product currently offers no way to do that for one class.
Why this is not a frontend task
No endpoint accepts a label-class filter. The three asset-listing routes are the whole surface, and
each takes pagination and nothing else:
GET /batches/{batch_id}/assets ['limit', 'offset']
GET /datasets/{dataset_id}/assets ['limit', 'offset']
GET /projects/{project_id}/assets ['limit', 'offset']
A scan of openapi.json for any query parameter naming a class or a label returns nothing at all.
So a client cannot ask "which assets carry an annotation of class lane" without reading every
asset and filtering in the browser, which is the hand-mirroring the ui-capabilities contract
exists to forbid: the frontend never decides what is legal or derives a projection the wire declines
to make, and where a capability is missing the fix belongs in the wire rather than in a client-side
workaround.
There is a second, independent question underneath the first. Even given a filter, there is no
screen for the result. The gallery is scoped to a batch and the dataset view to a dataset, while the
count in this dialog is project-wide — it comes from a walk over every asset in the project. Sending
somebody to a batch gallery would show them a subset of what the dialog just counted, which is worse
than sending them nowhere, because the two numbers would disagree with no explanation for why.
What settling this looks like
- A wire filter. One of the asset-listing routes learns to narrow by label class, or a new
route answers the question directly. Whichever shape is chosen, the scope it walks has to be the
same scope SchemaService counts over, so the dialog's number and the list's length agree. Two
independently written walks that agree by coincidence is the defect the typed preview report was
introduced to end.
- A destination. The sitemap in the
information-architecture skill gains an entry for
wherever the filtered result lives, and the entry is added in the same change that creates it.
A project-wide scope is what the count implies; if the answer is that no project-wide asset view
should exist, then the dialog's remedy sentence has to change instead, and that is a legitimate
outcome of this issue rather than a failure of it.
- The link.
OrphanBlockersDialog gains one link per blocking class. ui-core is router-free,
so it arrives as a callback prop from the app package the way other cross-screen navigation does,
not as an imported router.
Acceptance criteria
- Either the wire declares a label-class filter over a project-wide asset scope and the sitemap
names where its result is shown, or a written decision records that it will not and the dialog's
remedy copy is rewritten to match what the product can actually offer.
- If the filter ships: the count in
OrphanBlockersDialog and the number of results behind the link
are the same number, and a test ties them together rather than asserting each separately.
- No client-side reconstruction of the filter. A browser-side walk over every asset does not satisfy
this issue.
- The dialog gains no second button. The refusal still has no override, and this issue does not
change that.
Notes
The counted report the dialog renders arrived with the typed narrowing refusals, and the dialog
itself was rebuilt in the pull request that gave the narrowing confirmation its blast radius
(#698). Neither touched the link, and both left the remedy sentence as it stands.
The terminal dialog that refuses a class removal states how many annotations block it and across
how many assets, and then leaves the person holding a number with no way to reach the thing it
counts. The class-removal flow work (#588) asks for that link explicitly — the dialog should state
the fact, state the way out, and link to the annotations filtered to that class — and it is the one
requirement of that issue which cannot be built in the browser today, because nothing on the wire
can express the filter.
All citations are at
2e4346d.What the dialog does now
OrphanBlockersDialoginfrontend/ui-core/src/screens/SchemaEditor.tsxrenders one line perblocking class from the preview's typed report — the class name, its annotation count, its asset
count — and a single
Closebutton. That is correct as far as it goes: the refusal has no override,so a second button would be a lie. The counts come from
POST .../schema/preview, so they agreewith what the publish would refuse over.
The remedy sentence is "Keep the class or remove the annotations first." Removing them means
finding them, and the product currently offers no way to do that for one class.
Why this is not a frontend task
No endpoint accepts a label-class filter. The three asset-listing routes are the whole surface, and
each takes pagination and nothing else:
A scan of
openapi.jsonfor any query parameter naming a class or a label returns nothing at all.So a client cannot ask "which assets carry an annotation of class
lane" without reading everyasset and filtering in the browser, which is the hand-mirroring the
ui-capabilitiescontractexists to forbid: the frontend never decides what is legal or derives a projection the wire declines
to make, and where a capability is missing the fix belongs in the wire rather than in a client-side
workaround.
There is a second, independent question underneath the first. Even given a filter, there is no
screen for the result. The gallery is scoped to a batch and the dataset view to a dataset, while the
count in this dialog is project-wide — it comes from a walk over every asset in the project. Sending
somebody to a batch gallery would show them a subset of what the dialog just counted, which is worse
than sending them nowhere, because the two numbers would disagree with no explanation for why.
What settling this looks like
route answers the question directly. Whichever shape is chosen, the scope it walks has to be the
same scope
SchemaServicecounts over, so the dialog's number and the list's length agree. Twoindependently written walks that agree by coincidence is the defect the typed preview report was
introduced to end.
information-architectureskill gains an entry forwherever the filtered result lives, and the entry is added in the same change that creates it.
A project-wide scope is what the count implies; if the answer is that no project-wide asset view
should exist, then the dialog's remedy sentence has to change instead, and that is a legitimate
outcome of this issue rather than a failure of it.
OrphanBlockersDialoggains one link per blocking class.ui-coreis router-free,so it arrives as a callback prop from the app package the way other cross-screen navigation does,
not as an imported router.
Acceptance criteria
names where its result is shown, or a written decision records that it will not and the dialog's
remedy copy is rewritten to match what the product can actually offer.
OrphanBlockersDialogand the number of results behind the linkare the same number, and a test ties them together rather than asserting each separately.
this issue.
change that.
Notes
The counted report the dialog renders arrived with the typed narrowing refusals, and the dialog
itself was rebuilt in the pull request that gave the narrowing confirmation its blast radius
(#698). Neither touched the link, and both left the remedy sentence as it stands.