Dev.to WebDev 🛠 Dev 👁 0 📖 6 min read

Our homepage promises a CSV export, and the feature page for it says nothing has to be exported

PubTrivia has a feature called session history. A quiz night finishes, the night is kept, and a week later you can open it and see who answered what. It is a good feature and it is the one I would point at first if someb

PubTrivia has a feature called session history. A quiz night finishes, the night is kept, and a week later you can open it and see who answered what. It is a good feature and it is the one I would point at first if somebody asked what the product does that paper does not.

It is also named six different ways across the site, and one of those names makes a promise that no code in the repository can keep.

The two sentences

On the homepage, in the features grid, there is a card:

Session history & export
Review past nights and export results as CSV.

On the page for that exact feature, the second paragraph says:

Nothing has to be exported or filed at the end of the night. You end the session and walk away, and it is there on Thursday when somebody asks about it.

Both are live right now. You can read the first by opening pub-trivia.app and scrolling to the feature cards, and the second by clicking through to the feature page. They are describing the same thing, two clicks apart, and they disagree about whether exporting is something the product does or something it saves you from.

The second one is correct.

The grep that settles it

$ grep -rni csv app components lib utils __tests__ ws-server/src
app/features/session-history/page.tsx:9: * Session history. This page used to claim a CSV export; the codebase has no
components/FeaturesGrid.tsx:9: { ... desc: "Review past nights and export results as CSV." },

Two hits in the whole repository. One of them is the homepage card. The other is a comment at the top of the feature page that exists specifically to explain why the page no longer says it:

/**
 * Session history. This page used to claim a CSV export; the codebase has no
 * such feature, so it does not. What it describes is what getSessionDetail and
 * getSessionHistory in app/dashboard/history/actions.ts actually return.
 */

So this was found once already, and fixed in one place. The page was rewritten to describe what the two server actions return. The URL was renamed at the same time, which you can still see from the outside:

$ curl -s -o /dev/null -w '%{http_code}\n' https://pub-trivia.app/features/results-and-export
404
$ curl -s -o /dev/null -w '%{http_code}\n' https://pub-trivia.app/features/session-history
200

The old path named the thing that did not exist. It is gone from the sitemap, gone from the content registry and answers 404. Everything that was in my head as "the export claim" got dealt with, and the card on the homepage was not in my head.

Six names for one feature

Counting the places that name this feature in customer-facing copy:

where what it is called
homepage feature card Session history & export
homepage plan cards, both plans Session history & export
/pricing plan cards, both plans Session history & export
dashboard plan cards Session history & export
dashboard billing page Session history & analytics
/features hub card Session history
the feature page and its registry node Session history

Three distinct labels. The middle one is interesting in its own right: Session history & analytics on the billing page, which is a third noun, and the closest thing to analytics in the codebase is a server action called getDashboardAnalytics that returns counts for one dashboard widget. That is not a lie in the way the CSV line is a lie, but it is a word doing more work in a feature list than it does in the product.

You can count the live version of this yourself without a session:

$ curl -s https://pub-trivia.app/ | grep -o 'Session history & export' | wc -l
3
$ curl -s https://pub-trivia.app/ | grep -o 'export results as CSV' | wc -l
2
$ curl -s https://pub-trivia.app/pricing | grep -o 'Session history & export' | wc -l
2

Three on the homepage because the feature card and both plan cards carry the label, and the CSV line counts twice because it appears in the HTML and again in the React flight payload underneath it.

Why the one place got fixed and the five did not

Because the five are arrays and the one was prose.

The feature page is 59 lines, almost all of it written sections, and rewriting it meant reading it. The other five are entries in a list of label strings, and a label string gets read when you are looking at the thing it labels, which in the case of the dashboard plan cards means being a signed-in host looking at an upgrade screen.

const features = [
  { label: 'Up to 5 quizzes per day', included: true },
  { label: 'Up to 50 tables per venue', included: true },
  ...
  { label: 'Session history & export', included: true },
]

Twelve labels per plan, two plans, in a file that also holds the prices. Nothing in it is wrong except seven characters in one entry, which is exactly the sort of thing that survives a review of the file it lives in.

There is also a real reason the word kept feeling true: the product does download files. Table QR codes come out of the dashboard as a PDF, and two of the free tools, the scoresheet generator and the QR code generator, build PDFs in the browser with no server involved at all. Something in the product does export. Just not results.

What a test would have caught, and why we do not have one

There is already a test in the repository that holds pricing copy to a rule. It reads eleven customer-facing files as text and fails if any of them describes our prices as approximate or converted. It would be easy to write the equivalent for this: a list of words that may not appear in a feature label unless something in the codebase implements them.

I do not think that test is a good idea in general, because the honest version of it is a list of every noun the product does not have, and nobody maintains that list. The version I would write is narrower and dumber: a test that fails when the string CSV appears anywhere outside a file that imports a CSV writer. We have no CSV writer, so today that test is expect(hits).toHaveLength(0) and it would have failed on the homepage card.

The more general fix is the one I am actually doing: the label and the feature page should not be two independent strings. The content registry already holds the canonical short label for this feature, Session history, because the page title, the breadcrumb and the nav link all need it and all need it to agree. The feature lists on the pricing surfaces do not read from the registry. They are their own arrays, and that is the gap the CSV line fell through.

The fix

Session history on all five, dropping both the & export and the & analytics, and the card description becomes "Review past nights question by question", which is what the feature page says and what the actions return.

That is a six word change and it makes the homepage slightly less impressive, which is the whole reason a sentence like that gets written in the first place. A format name in a feature list reads as proof: it is specific, it sounds like something that was built. Writing "CSV" was a tiny act of optimism about a thing that would obviously be easy to add, and then the quarter went elsewhere and the optimism stayed on the page.

If you want to check whether the fix has shipped, the homepage is the test: open pub-trivia.app, find the card with the clock icon, and see whether it still says CSV. The feature page it links to has been telling the truth for weeks.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.