Surface display names instead of UUID fragments #107
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: MEDIUM
The problem
Attribution data exists but is not surfaced, so collaboration is effectively invisible:
c.created_by.slice(0, 8)→"3f2a9c1e…" (
ReviewWorkspacePage.tsx:313)HistoryTab:348-363)Album: {uuid8}… · SHA: {uuid8}…(:469-472)There is also no API to resolve a user id to a name — only
/auth/meexists.docs/circa-spec.md§7.4 requires "who changed this" to be answerable in the workspace, and §11.2requires recent editor identity.
Why this is separable from #22
#22 carries the full role model, user management, and permission matrix, and sits in v0.4.0. The
display name slice is small, independently valuable, and needed as soon as a second person
touches the collection. It also removes the UUID disclosure that the security milestone requires
anyway (#57) — the two fixes are the same change viewed from different angles.
Scope
Done when
References
frontend/src/pages/ReviewWorkspacePage.tsx:313,348-363,469-472docs/circa-spec.md§7.4, §11.2Related: #22 (full role model), #57 (UUID disclosure).
Picking this up. Probed first, and most of this issue is already done — by #57/#64, which landed the serializer half while this was open.
What is already true
created_by_display_nameandis_own, resolved in one batched query per response (app/api/attribution.py). That covers comments, decisions, evidence, note revisions and jobs — the whole list in "Scope", bullet one.ReviewWorkspacePage.tsxrendersc.created_by_display_name; thec.created_by.slice(0, 8)this issue quotes is gone.Album: {uuid8}… · SHA: {uuid8}…is gone, removed under #104 as developer debris./auth/me" is no longer a gap: names arrive inline on the rows that have authors, which is better than a resolve endpoint since it costs no extra round trip and exposes no id.So one of the four "Done when" boxes was already ticked and a second was mostly ticked.
What was actually left
docs/circa-spec.md§7.4 names explicitly. Fixed.System, whichSOURCE_LABELSalready says better in the first column. Printing "System" on every EXIF and OCR row is noise repeating what the row says. A manual row is the one where a person is the origin, and there the name is part of the provenance — "Mom wrote 1972 on the back" means something different depending on who wrote that down.Duplicate of #3f2a91c0…, which this issue was asked to absorb. Now the other scan's filename, as a link. The other photograph is fetched rather than joined intoPhotoOut: a filename on the serializer would have to be resolved for every row of every listing — a join on the hot path to serve one line on one screen — whereas this is one request, on the only screen that shows it, usually already cached because the queue has been through it. Being a duplicate is still stated when that fetch fails, because "this is a duplicate" is established and "of that one" is a second fact a 404 or a permission boundary may not supply; collapsing them would let a failed request quietly unsay something true (#78).photo: 164b0909-c06b…— a raw UUID fragment in reviewer-facing UI, which "Done when" forbids and nothing had noticed. A queue of work was a column of hex a reviewer could neither tell apart nor navigate to, and the commonest reason to open that page is to find out what happened to a rerun queued a minute ago.JobOutgainsentity_label, resolved in batch and scoped to the collection (#70), and the page links to the photograph by name.entity_idstays on the wire because the UI needs it to build the link — #57's rule is about user ids, which are what a forged session cookie is built from; a photo id is not a credential.Not done, and why
No attribution on
PhotoOutfor who excluded a scan (#106)._photo_outhas no batched name resolution and is called per row in every listing, so adding one there is a join on the hot path — the same objection as the duplicate filename. The audit ledger records the actor, which is what §6.4 asks for. Worth its own issue if the excluded queue turns out to need it.Done in
8c4298a, CI green (run 65).All four boxes, with the probe corrections noted in my previous comment:
Mutation-tested: dropping the author from the history fails one test, showing it on machine evidence rows fails one, rendering nothing when the duplicate cannot be read fails one, and printing the raw id on the jobs page fails one.
One thing worth recording, because it is the change proving itself. The exclusion end-to-end test started failing on
getByText("1979")resolving to two elements. Every ingest in that suite uploads the same fixture bytes, so every photograph after the first is an exact duplicate ofredbk42_010_1979.jpg— and the Current State card now names that scan instead of printing eight hex characters, which put a second "1979" on the card. The assertion was tightened to say which one it means. Before this change the same card saidDuplicate of #a1b2c3d4…, which is precisely the uselessness the issue is about: it could not have collided with anything, because it told the reviewer nothing.Frontend tests 202 → 212 (a new
JobsPage.test.tsx, which had none).