Flow
Each part and what it refuses
1Narrow read
Refuses any host, key or store from the browser, and items not on the list.
2Field states
Refuses values that are not missing, null or text.
3Live checks
Refuses a preview unless the fresh read shows the right label on an active item. Reads still work.
4No-op check
Refuses moves that change nothing, but keeps missing-to-blank.
5Locked records
Refuses edits and deletes on saved previews.
One of the fields on my shelf labels is named like a web link. It holds the price.
The label provider doesn't care what a field is called, and the pilot template puts the price text in a slot named for a URL. If I had built an editor first and checked fields by name, every real price would have failed. This change only builds the part that looks.
The ordering system's shelf-label tool can now read one item and save a proposed change to it. It can't send that change. There's no write key, no write permission, no write code and no apply button. The saved preview is just a record in my own database.
The old route had to go
An older route passed label data through a gateway. It let the caller pick the store, cached in memory, and showed the provider's raw error text on the page. Now it just answers "gone." The new screen also has its own permission, so general inventory access doesn't grant it.
Four parts worth copying
A narrow read. Keep the key on the server. Fix the host. Let the browser name an item and nothing else, and check that item against an exact list for one store before calling out. Cap the response size, set a timeout, and turn provider errors into a few clean codes. Don't retry for the user.
Honest field states. Report every field as missing, null, or a string. A blank is a string. A "not available" placeholder is a string. Anything else means the whole record is broken. Don't judge a field by its name.
A careful no-op check. A change has three moves per field: leave it, set it to some text, or clear it to blank. Before saving, drop any move that wouldn't change anything. No-op detection needs to be strict.
A move is a no-op only if the current value is an actual string equal to the wanted one.
If you treat missing, null and blank as the same, "clear this field" on a missing field gets thrown out, even though it does change the record.
Records that can't be edited. Hash the result together with who asked, the item's last-changed marker, the before-values and an expiry. Store it in tables that refuse updates and deletes. A follow-up commit kept these tables out of automatic copies between environments and flagged their values for review, with a test that checks the policy.
Before a preview is saved
The server reads the item again, live. It wants the provider to say the item matches a label, the match details to be complete and consistent, the label to be the one set up for the pilot, and the item to be active. If any check fails, no preview is made, but the plain read still works so you can see why. Empty requests fail before the provider is called at all.
Why stop at looking
My notes from earlier poking at the provider record a CSV upload that said it worked and then failed later, and a one-off manual write that only proved itself after waiting on a background job and reading the item back. The design doc lists open questions: do partial updates merge or replace, can a write be conditional, what does a retry do, and who owns a field when a CSV process also writes to it. A screen that only reads is a cheap place to answer those.
Previews aren't idempotent yet, so a retry after a lost response leaves two of them. After a page refresh, the only way to find a saved one is a database query. Expiry is a date in the row and nothing acts on it.