Burn-on-read: which plan it holds for, and which client can even ask for more - #388
Merged
Conversation
Apolloccrypt
force-pushed
the
site-claims-burn-tiers
branch
from
September 3, 2026 02:38
ca30612 to
650af37
Compare
Apolloccrypt
force-pushed
the
site-claims-burn-tiers
branch
from
September 3, 2026 02:39
650af37 to
7559278
Compare
…service relay/lib/tiers.js gives a link 1 read on Community, 10 on Pro, 25 on Business and 100 on Enterprise, and /pricing sells exactly that. Twelve other pages stated burn-on-read flat: "the file is gone the moment it has been read", "each blob is destroyed after the first successful download", "one retrieval only". True on the free plan, false for everybody who pays. Every one of those sentences now names the plan it holds for, and none of them lose the promise: a file still does not stay behind. Block 37 of tests/site-claims.test.mjs splits every public page into paragraphs and requires each burn-on-read sentence to carry one of three qualifications: Community, the paid read count read off tiers.js, or the web app. The web app is not a loophole. frontend/js/parashare.page.js never sends max_views and relay.js defaults a transfer without one to a single read on every plan, so a web app transfer really does burn on the first read whatever the sender pays; both halves are pinned, so the day either changes the pages that lean on it go red. Tier-card feature lists are cut out of the sweep, because a bullet is scoped by the card it sits in rather than by the sentence, and are pinned against tiers.js directly instead, which is the stronger check. /docs gained the piece that was missing all along: POST /v2/inbound takes max_views, and the reference never said so. Verified by sabotage in both directions. Universalising any rewritten sentence turns the block red and names the page and the sentence. Setting pro.max_views to 1 turns it red too, because the qualification is then false the other way round: the site would promise reads the relay does not grant. Dropping pro to 12 turns the copy numbers red, and making the web app send max_views closes the third qualification. The /pricing product line moved with it, so the two pins on it in ui-truthfulness.test.mjs moved as well.
… never send it
Second pass on the burn-on-read sweep, after the buyer review and the
truthfulness review.
THE BLOCKER. extensions/shared/paramant-core.js:191 builds its upload body
as { hash, payload, ttl_ms, meta } and there are zero hits for max_views
anywhere under extensions/. That file is the single upload path for both
the Chromium extension and the Outlook add-in, so both burn on the first
read on every plan, exactly like the web app. The first pass sold "up to
10 reads on Pro" on /parasend, in the pricing prose and on both extension
pages: a read count offered to clients that never ask for one. On the
extension page the sentence it replaced was true before this branch
touched it, which makes it the worst kind of regression.
One formulation now carries both halves, on /parasend, in the pricing
prose and on both extension pages:
The web app and the extensions delete the file after the first read on
every plan. Through the API a paid link can allow more reads: up to 10
reads on Pro, 25 on Business and 100 on Enterprise.
Block 37 enforces it. Pages about a client that cannot ask for a second
read may qualify a claim only by naming that client, and a paid read
count may appear there only with the API named in the same paragraph.
Pinned to parashare.page.js, to the paramant-core.js upload body, and to
a scan that fails if any file under extensions/ starts sending max_views.
FROM THE BUYER REVIEW.
The homepage hero and the /parasend H1 name no count at all now: "a file
that deletes itself when the reading is done", "Send a file that deletes
itself after reading". True on 1, 10, 25 and 100 reads and on expiry. The
three-line mono eyebrow under the H1 is back to one line.
Five wordings of the same idea became one, "wiped after the last read the
link allows", short-formed as "after its last read", explained once per
page. The wordings it replaced are now forbidden, because five ways of
saying a thing is how the site drifted into saying it wrong.
Four unconditional sentences that survived the first pass are in: "opens
it once and the file is wiped", "until the read burns it", "gone after it
is read", "Deleted on burn", "zeroed immediately on download". They were
missed because the pattern list was written FROM the sentences the grep
had surfaced, so it matched those wordings and nothing else. Every miss
was a different erase verb, a different name for the moment, or the two
halves in the other order. The list is now built from two vocabularies
crossed against each other. The sweep found five more the moment it ran.
More reads is sold as a feature instead of confessed as a weaker promise:
one link a whole team can open, or a counterparty reopening it after a
misclick, instead of sending the file a second time.
/pricing no longer opens with the free plan's ceiling. Its pinned SEO
description was checked and needed no change: it never carried a read
count.
The sweep now covers the signed-in screens as well. /dashboard and
/auth/setup were outside publicPages and both carried the flat claim.
Nine sabotages, all red: universalising the /index hero, the /parasend
H1 or the /security card; a paid read count back on /parasend; tiers.js
pro 10 to 1 and 10 to 12; the web app or the extension sending max_views;
and the replaced phrasing creeping back.
Apolloccrypt
force-pushed
the
site-claims-burn-tiers
branch
from
September 3, 2026 02:51
07e1763 to
a60765c
Compare
This was referenced Sep 3, 2026
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.
Site-claims batch 3, the sweep #372 wrote down as "out of scope, next batch". Rebased on
39179f50. Second pass after the buyer review and the truthfulness review.relay/lib/tiers.jsgives a ParaSend link 1 read on Community, 10 on Pro, 25 on Business, 100 on Enterprise. The site sold burn-on-read as a property of the service. That was the first half.The second half only surfaced in review, and it is the more interesting one: the read count is an API parameter, and the clients most of the site is about never send it.
frontend/js/parashare.page.jsdoes not, and neither doesextensions/shared/paramant-core.js:191, whose body is{ hash, payload, ttl_ms, meta }and which is the single upload path for both the Chromium extension and the Outlook add-in. Zero hits formax_viewsanywhere underextensions/. So through the web app or either extension the file goes on the first read on every plan.The first pass treated that as an escape hatch. It is the opposite: offering "up to 10 reads on Pro" on a page about a client that cannot ask for a second read sells something that client will never do. On
/help/gmail-extensionthe sentence the first pass introduced was less true than the one it replaced.One formulation, both halves
Carried whole on
/parasend, in the/pricingprose and FAQ, and on both extension pages. The numbers are written offtiers.js, so a policy change moves the copy with it.Everywhere else, one short form: "wiped after the last read the link allows", short-formed "after its last read". It names no count, which is why it is true on 1, 10, 25 and 100 reads and on expiry, and why it needs no qualification. The five competing wordings the first pass left behind are now forbidden.
What changed since the first pass
Why block 37 missed those five
The first pattern list was written from the sentences the grep had surfaced, so it matched those wordings and nothing else. Every miss was a different erase verb (
zeroed,deleted), a different name for the moment (on burn, noton read), or the two halves in the other order (opens it once ... and the file is wiped). The list is now built from two vocabularies crossed against each other (erase verb x a moment that names one read, in either order) plus six verb-free phrases. It found five more the moment it ran.The pin
Block 37 of
tests/site-claims.test.mjs, function scope. Splits every page, public and signed-in, into paragraphs.tiers.js.CLIENT_ONLYpage (parasend, get, ontvang, parashare, dashboard, auth/setup, both extension pages): only naming the client counts. A paid read count may appear there only with "through the API" in the same paragraph.parashare.page.js, theparamant-core.jsupload body,relay.js's single-read default, and a walk overextensions/that fails if any file starts sendingmax_views.tiers.jsdirectly./parasendand/pricingmust say why more reads is worth paying for.Sabotage, nine ways, all red
parasend: says "up to 10 reads on Pro", and the client this page is about never sends max_views. Name the API in the same paragraph or drop the number.tiers.jspro 10 to 1pro now allows 1 reads, the same as Community: burn-on-read is universal again ...tiers.jspro 10 to 12max_viewsthe extension upload body changed shape; both extension pages promise the file goes on the first read on every plan because this body carries no max_viewsmax_views... now asks the relay for a read count; the pages about that client may no longer say the file goes on the first read on every planabout: says "once the reads its link allows are spent"; the site says this one wayLeft alone on purpose
The Community tier cards on
/pricingand/parasend;/privacy,/termsand the/pressexpiry bullet (settled by #372); the compound noun used as a feature name ("a burn-on-read link" says nothing false, "burns it on read" does).Still open, and written into
docs/site-claims.mdrow 37 so the row does not read as closed: the flat claim survives in the meta description and JSON-LD of/audit-log-export(line 14) and/vs, and in the head of/parasend,/get,/ontvang,/parashare. This batch stayed in body text because #380 is still open in the heads and stylesheets. That head sweep is the next batch.The
/pricingpinned SEO description inseo-contract.test.mjswas checked for point 6 and needed no change: it never carried a read count.Gates
Green locally: first-screen (9), ui-truthfulness, site-claims (37), seo-contract (14), links, navigation-shell, frontend-loading-contract (7), pricing-fold (4), user-dashboard-documents, all 32 browser suites, cache-bust, csp-inline, static-sanity, check-test-declarations (121 suites), eslint,
relay/test/pricing-page.test.js,apply_seo_head.py --check(0 pages),apply-nav.pyidempotent. Root integration suites 172 pass, 1 pre-existing environment failure (heartbeat-libneeds@noble/post-quantum, installed bynpm ciin CI).Three test pins moved with the copy, each with the reason in the comment: two in
ui-truthfulness.test.mjsand one inpricing-fold.test.mjs(the /pricing product line), one inuser-dashboard-documents.test.mjs(the dashboard mission line).17 pages, 1 test block, 4 moved pins, row 37 in
docs/site-claims.md. 21 files, +213 / -117.