Skip to content

Release: the catalogue stops throwing away the market price, and the receipt tab stops throwing - #776

Merged
sridharkalaibala merged 7 commits into
mainfrom
develop
Sep 15, 2026
Merged

sridharkalaibala merged 7 commits into
mainfrom
develop

Conversation

@sridharkalaibala

Copy link
Copy Markdown
Contributor

Promotes develop to main. Two merged pull requests since the last release.

Merge with a merge commit, never a squash. The repository ruleset enforces that, so the button should only offer it.

The one that matters to a bill

#775 fixes the second field the ordering catalogue was throwing away, found by asking the question the last release raised of every storefront field rather than the four it already knew about.

waitingForTodaysPrice() reads daily_price and price_set_on to decide whether a dish is waiting for the morning's market rate. Neither has ever reached it, so its first line has been dead since the daily-price release and the gate could only ever answer "has it got a price at all". A whole fish flagged as daily and last priced yesterday was offered on /order at yesterday's rate with an ordinary Add button, while /menu said "Market price".

Nothing is wrong on a live shop today, because nothing writes daily_price yet. What was broken is the surface that would have gone on being broken, silently, on the day the item form gains the flag.

Two features have now been eaten by that one object literal, so the test is the rule rather than a third field name: every storefront field the ordering bundle reads off a catalogue product must be kept by the catalogue. The whitelist also gets a name, catalogueItem(), so the test drives it over a real payload instead of running a regex over its source.

From another session

#773 - the Receipt Printer tab stops throwing on every click. Four functions in the desktop shell wrote to five elements that have never existed in that file, called from switchTab on every visit to the receipt tab.

Verified before opening

Root suite 2,555 of 2,558 on the develop tip; the three remaining are the release-artifact tests that need frontend/public built, which CI does.

After the merge

The previous release is already live and verified on production: /order/assets/spice.js serves at ?v=64f29278 and the served indexedDB.js carries the fixed catalogue. Both that release and this one stay invisible on every shop until somebody enters nutrition or ticks a dish for spice - production still carries 272 dishes and zero dish facts, which is exactly why neither bug was ever visible.

Owner: "receipt printer previously its multi selct. have you changed
anything?"

Nothing had. The multi-select was there and working - #rpPrinterList,
checkboxes, saved as `receipt_printers`. But beside it the same file carried a
SECOND printer picker that had never worked at all.

refreshPrinters, selectPrinter, printToSelected and printToDefault wrote to
#printerStatus, #printerList, #printBtn, #printContent and #copies. Not one of
those elements has ever existed here: `git log --follow -S 'id="printerList"'`
finds no commit that added or removed them, including before the move into
src/.

switchTab called it on every receipt-tab click, and refreshPrinters did
`statusDiv.classList.remove('hidden')` on null OUTSIDE its own try block - so it
threw, unhandled. The throw came BEFORE `printers` was assigned, so the
`printers.length === 0` guard never went false and it threw again on every
single click, for the life of the file. Two of the four functions were never
called by anything at all.

Also removes a listener relabelling #rpDefaultOption, the "default printer"
entry of the old dropdown. Guarded by `if (opt)`, so it never threw; it simply
stopped doing anything when the checkbox list replaced the dropdown, and nothing
said so. OS_DEFAULT_LABEL stays - the warning about sending a receipt to the
system default still uses it.

WHY NOTHING CAUGHT THIS

tests/tools/dead-selectors.js exists for exactly this and could not see it: it
matches jQuery `$('#id')` only, and only inside .js under frontend/.../modules/.
The shell uses getElementById inside HTML, which is neither - so src/ was never
scanned at all, and the tool reported "All good" for the life of the fault.

So tests/tools/dead-shell-ids.js, which can be exact where the frontend one
cannot. The shell's pages are self-contained, markup and script in one file, so
the question is not "does anything anywhere create this id" but "does THIS
file" - no cross-file guessing and no verify-before-deleting caveat. Run against
the pre-fix file it reports all six; against this one, nothing.

The test proves that rather than asserting it: it builds a page with the same
shape and requires the check to find it. A guard nobody has watched fail is a
guard nobody should trust.

Desktop 2506 pass.
order/indexedDB.js builds the whole /order catalogue in one object
literal out of what the storefront sent. It is a whitelist, and a field
it does not name is dropped in silence: no error, no log, no failing
test, because every test on those features reads the source of the
feature rather than the source of the catalogue.

That has now cost two features. The dish facts went first: nutrition,
tags, marks and claims sent for three releases and dropped on arrival.
The second is about money. waitingForTodaysPrice() reads daily_price and
price_set_on, and has never once received either, so on /order a whole
fish priced from the morning's market and last priced YESTERDAY was
offered at yesterday's rate with an ordinary Add button, while /menu said
"Market price".

Rather than add a third named field to a third test, this states the
rule: every storefront field the ordering bundle reads off a catalogue
product must be kept by the catalogue. Add a read tomorrow and the test
fails until the literal names it. Consumers are listed rather than swept
up, because the thank-you page walks the server's receipt and its lines
carry their own tax.
It was an anonymous object literal three levels inside a fetch, which is
why the only tests possible on it were regexes over its source - and a
regex passes on a line that names nutrition and stores the wrong thing.

catalogueItem(item, categoryName) is the same literal, lifted out and
called from the loop. The test now drives it over a real payload: a dish
with facts keeps them, a dish with nothing entered gets empties rather
than undefined, the market-price pair survives, and a flag arriving as
the string "false" is still off.

No behaviour change.
…page-reads

The ordering catalogue keeps what the page goes on to read
The Receipt Printer tab stops throwing on every click
Bootstrap does not show `title`. On init it moves the title into
data-original-title and empties the real attribute, and markup that sets
data-original-title itself wins outright. So data-t-title on one of those
elements changed an attribute nothing displays, and the tooltip went on
saying the English in every language.

It rendered perfectly, which is why it survived. Same shape as the
requests dock, where a local t() helper hid fourteen words from the
scanner: a translation that silently does nothing looks exactly like one
that works.

Two elements were in that state, and the collector could not see either.
It reads the English out of `title`, which these do not carry, so
lang_ai_describe_hint was counted as used and never given any English to
translate - the one key the tool has been reporting as unanswered.

apply() now also writes the attribute the tooltip reads, restore() puts
it back, the collector looks in data-original-title, and the missing
words are in all seventeen packs. English answers 3,370 of 3,370 keys for
the first time.

218 other data-t-title elements carry a plain title and were always fine.
A tooltip nobody could translate, in two places
@sridharkalaibala
sridharkalaibala merged commit 0f21509 into main Sep 15, 2026
15 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant