Skip to content

Burn-on-read: which plan it holds for, and which client can even ask for more - #388

Merged
Apolloccrypt merged 3 commits into
mainfrom
site-claims-burn-tiers
Sep 3, 2026
Merged

Burn-on-read: which plan it holds for, and which client can even ask for more#388
Apolloccrypt merged 3 commits into
mainfrom
site-claims-burn-tiers

Conversation

@Apolloccrypt

@Apolloccrypt Apolloccrypt commented Sep 3, 2026

Copy link
Copy Markdown
Owner

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.js gives 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.js does not, and neither does extensions/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 for max_views anywhere under extensions/. 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-extension the sentence the first pass introduced was less true than the one it replaced.

One formulation, both halves

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.

Carried whole on /parasend, in the /pricing prose and FAQ, and on both extension pages. The numbers are written off tiers.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

# Point Where Old New
B extensions never send a read count help/gmail-extension:255, :329; help/outlook-extension:255; parasend:244; pricing:407 "A paid link survives until the reads it allows are spent"; "up to 10 reads on Pro" as a buying argument the unified sentence; "more reads through the API"
1 hero too weak, still false on Pro index:358 "a file that leaves nothing behind once it has been read" "A contract signed, or a file that deletes itself when the reading is done."
2 H1 contradicted its own eyebrow parasend:204-205 "Send a file that burns after one read." + a three-line mono eyebrow "Send a file that deletes itself after reading." + the eyebrow back to one line
3 five formulations parasend x4, pricing, security, about, architecture, audit-log-export, docs, press, rules "once the reads the link allows are spent", "gone when the last read is spent", ... one formulation, explained once per page, referred to in three words elsewhere
4 four unconditional sentences left standing parasend:275, :365; index:544, :471; security:285, :368 "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" all in the one formulation
5 more reads read as less safety parasend:225, pricing:407 "businesses pay for higher limits, not to unlock features" "More reads is not a weaker promise: it is one link a whole team can open, or a counterparty reopening it after a misclick, instead of you sending the file a second time."
6 price page opened with the free plan's ceiling pricing:269 "Sign documents and send files that vanish after one read on Community." "Sign documents and send files that delete themselves after reading."
+ signed-in screens were outside the sweep dashboard:419, auth/setup:266 "sends a file that burns on read"; "a link that burns after one read" "deletes itself after reading"; "a link that the web app burns on the first read, on every plan"
+ five more the widened sweep found parasend:213, :273; privacy:223; dashboard:436; parashare:531 "gone after one read"; "burns on first read"; "deleted on burn"; "gone the moment it has been read"; "After one download it is permanently destroyed" each names its client or its plan

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, not on 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.

  • general page: a burn-on-read claim must name Community, the client, or the paid read count off tiers.js.
  • CLIENT_ONLY page (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.
  • pinned to parashare.page.js, the paramant-core.js upload body, relay.js's single-read default, and a walk over extensions/ that fails if any file starts sending max_views.
  • tier-card feature lists are cut out of the sweep (scoped by their card) and pinned to tiers.js directly.
  • the replaced wordings are forbidden, so the site keeps one formulation.
  • /parasend and /pricing must say why more reads is worth paying for.

Sabotage, nine ways, all red

Sabotage Message
"up to 10 reads on Pro" back in the /parasend eyebrow 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.
/parasend H1 back to "burns after one read" red
/index hero back to "gone the moment it has been read" red
/security card back to "destroyed after the first successful download" red
tiers.js pro 10 to 1 pro now allows 1 reads, the same as Community: burn-on-read is universal again ...
tiers.js pro 10 to 12 copy numbers and tier cards stop matching
extension sends max_views the 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_views
web app sends max_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 plan
replaced phrasing creeps back about: says "once the reads its link allows are spent"; the site says this one way

Left alone on purpose

The Community tier cards on /pricing and /parasend; /privacy, /terms and the /press expiry 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.md row 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 /pricing pinned SEO description in seo-contract.test.mjs was 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.py idempotent. Root integration suites 172 pass, 1 pre-existing environment failure (heartbeat-lib needs @noble/post-quantum, installed by npm ci in CI).

Three test pins moved with the copy, each with the reason in the comment: two in ui-truthfulness.test.mjs and one in pricing-fold.test.mjs (the /pricing product line), one in user-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.

@Apolloccrypt
Apolloccrypt force-pushed the site-claims-burn-tiers branch from ca30612 to 650af37 Compare September 3, 2026 02:38
@Apolloccrypt Apolloccrypt changed the title Burn-on-read is the Community rule, and twelve pages said it was the service Burn-on-read: which plan it holds for, and which client can even ask for more Sep 3, 2026
@Apolloccrypt
Apolloccrypt force-pushed the site-claims-burn-tiers branch from 650af37 to 7559278 Compare September 3, 2026 02:39
…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
Apolloccrypt force-pushed the site-claims-burn-tiers branch from 07e1763 to a60765c Compare September 3, 2026 02:51
@Apolloccrypt
Apolloccrypt merged commit 3cc2df8 into main Sep 3, 2026
13 checks passed
@Apolloccrypt
Apolloccrypt deleted the site-claims-burn-tiers branch September 5, 2026 18:57
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.

2 participants