The heads say which client burns the file, and a paid read count names the API - #391
Merged
Conversation
…s the API Batch 4, the half of the burn-on-read sweep #388 left in the heads because #380 held them open. #380 landed, so this closes the claim. THE HEADS. /audit-log-export and /parasend stated burn-on-read flat in four places each: meta description, og:description, twitter:description and the JSON-LD WebPage description. A meta description is the sentence that travels. A search result and a chat preview show it with none of the page around it to qualify it, and /audit-log-export names the ParaSend web app only in step 01 of a workflow further down. Both now name the client. /get, /ontvang and /parashare keep "burns after one download", and the reason is better than the one this branch has been using. It is not the web app: it is that GET /v2/dl/:token/get deletes the blob outright and never looks at views_remaining, so a download-token link is single-use on every plan. Only GET /v2/outbound/:hash spends a read. Their exemption from the head sweep is pinned to those two lines in relay.js rather than to their slugs, so it goes red the day the route stops burning. /vs keeps burn-on-read as the name of a comparison dimension. THE CARDS. "Up to 10 reads per link" on a price card is an offer, and a Pro buyer who sends through the web app or an extension never sees a second read: those clients do not ask for one. The Pro and Enterprise cards on /pricing and /parasend now say "through the API", and so do the same figures on /index, /about, /privacy and /terms. The rule went from client pages only to every page, because the misleading half was never the page, it was the offer. Block 12 captures the card phrase with the qualifier included, so /about has to repeat that too. THE VOCABULARY. Sabotage S11 got past the block: putting the /parasend head back to "gone once it has been downloaded" stayed green, because the moment vocabulary knew "once it has been read" and not the three other verbs for the same event. Widened to read, downloaded, opened, delivered, with the miss written into the comment. S11 is red now. Sabotage, four ways, all red: either head back to its flat claim, a card dropping "through the API", and /v2/dl no longer burning outright. Row 37 of docs/site-claims.md is closed and says why the three download-link pages keep their wording.
Apolloccrypt
added a commit
that referenced
this pull request
Sep 3, 2026
…e bar is measured on three pages Review of #392 found the hole in the first round. developer.html keeps its own navigation (KEEP_OWN_NAV in frontend/apply-nav.py), is stamped by hand, and carries a hamburger. The round moved Sign in and Help out of the bar below 700px and into a strip under the drawer, and that page never got a strip. So on a 390px screen both links measured 0x0 there, where main still had them in the bar. A page the generator does not own is a page a generated fix does not reach. Three things, because one of them alone would leave the same gap open. The markup. developer.html carries the strip now, like every stamped page. The script. nav.js builds the strip when a page has a menu button and no strip. A page can forget the markup; this cannot forget to build it. That is a floor under the live site, not a substitute for the markup, which is why it comes with the check below rather than instead of it. The check. tests/navigation-shell reads every .html in frontend/, not only the 51 the generator writes, and fails on any page that has id="nav-hamburger" without id="nav-mobile-tail". 52 pages carry the button. Taking the strip back out of developer.html turns it red and names the file. And the measurement moved. The three phone-bar checks ran on the homepage alone, which is exactly why they were green while /developer was broken. They run on /, /pricing and /developer now, each with a fourth check that the strip really holds /auth/login and /help at 44px or more. /developer measures logo x16-95, Create account x181-318, menu x330-374, gaps 86 and 12, all heights 44. 39 checks, all green. Rebased on main with #379, #390 and #391.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Batch 4: the half of the burn-on-read sweep #388 left in the heads because #380 held them open. #380 has landed, so this closes the claim.
1. The heads
A meta description is the sentence that travels. A search result and a chat preview show it with none of the page around it to qualify it.
audit-log-exportparasendBoth stay inside the 50-165 char window
seo-contractenforces, andapply_seo_head.py --checkstill reports 0 pages.Checked and left alone, per instruction:
/get,/ontvang,/parasharekeep "burns after one download". The reason turned out to be better than the one this branch had been using: it is not the web app, it is thatGET /v2/dl/:token/getdeletes the blob outright and never looks atviews_remaining(relay.js,td.used = true; blobStore.delete(blobHash);). A download-token link is single-use on every plan. OnlyGET /v2/outbound/:hashspends a read, and it is the only place that decrements the counter. Their exemption from the head sweep is pinned to those two lines, not to their slugs, so it goes red the day the route stops burning./vskeeps "burn-on-read" as the name of a comparison dimension in a list next to "EU jurisdiction" and "self-hosting". The compound noun is a feature name and the patterns deliberately do not match it.seo-contractPINNED table needed no change:/parasendand/audit-log-exportare not in it, and the pinned/pricingdescription never carried a read count.2. A paid read count names the API
"Up to 10 reads per link" on a price card is an offer, and a Pro buyer who sends through the web app or an extension never sees a second read: those clients do not ask for one.
pricing:436,:464<li>Up to N reads per link **through the API**</li>parasend:326,:341index:526about:213privacy:208terms:246Enterprise went with Pro, and the four prose spots went with the cards, because leaving them inconsistent is a review finding waiting to happen. The rule in block 37 moved from client pages only to every page: the misleading half was never the page, it was the offer.
The cards stay pinned to
tiers.js.pricing-page.test.jsuses a substring match (statesLine), so itsUp to 10 reads per linkpin still holds unchanged. Block 12 now captures the card phrase with the qualifier, so/abouthas to repeat that too.pricing-foldunaffected.3. The vocabulary, and a miss I have to report
Sabotage S11 got past the block. Putting the
/parasendhead back to "gone once it has been downloaded" stayed green: the moment vocabulary knewonce it has been readand not the three other verbs for the same event. Widened toread|downloaded|opened|delivered, with the miss written into the comment above it so the next person sees how the list is meant to grow.4. Row 37
Closed. It now records why the three download-link pages keep their wording, and ends "Nothing on this claim is open".
Sabotage, four ways, all red
/parasendhead back to "gone once it has been downloaded" (S11)parasend: the head says "gone once it has been downloaded" with no page around it to qualify it/audit-log-exporthead back to the flat claimaudit-log-export: the head says "destroyed after the first read" with no page around it to qualify itpricing: offers "Up to 10 reads per link" without naming the API; through the web app or an extension a paid plan never gets a second read/v2/dlstops burning outrightthe /v2/dl download-token route no longer deletes the blob outright; /get, /ontvang and /parashare call a Paramant link single-use because it doesGates
Green locally: site-claims (37), all 41 browser suites (first-screen, pricing-fold, ui-truthfulness, navigation-shell, user-dashboard-documents, seo-contract, links, frontend-loading-contract), cache-bust, csp-inline, static-sanity, check-test-declarations (124 suites), eslint,
relay/test/pricing-page.test.js,apply_seo_head.py --check(0 pages),apply-nav.pyidempotent. Root integration suites 173 pass, 1 pre-existing environment failure (heartbeat-libneeds@noble/post-quantum, installed bynpm ciin CI).9 files, +87 / -36.