Skip to content

Pricing says what it sells, and what free actually gives, in the first screen - #336

Merged
Apolloccrypt merged 1 commit into
mainfrom
feat/fe-prijs
Sep 2, 2026
Merged

Pricing says what it sells, and what free actually gives, in the first screen#336
Apolloccrypt merged 1 commit into
mainfrom
feat/fe-prijs

Conversation

@Apolloccrypt

@Apolloccrypt Apolloccrypt commented Sep 2, 2026

Copy link
Copy Markdown
Owner

What this is

A phone opening /pricing saw the word "Pricing", a decorative "00", and a
paragraph about a post-quantum core. No amount, no product, and nothing about
who holds the files. Every review of this branch came back on the same page and
the same screen, so this rewrites the first screen and pins it by measurement.

Rebased onto main, twice. #328 rewrote this file while the branch was open:
the tier cards are named Community, the Free/Community bridge sentence is gone,
/docs#parasign-api is fixed and the founder paragraph is on the page. Daarna
kwamen #334 (head-elementen op 50 pagina's) en #354 (Community-limieten op
index en docs). Niets daarvan is teruggedraaid.

De verdeling bij deze laatste rebase: in de <head> van pricing.html en
signup.html wint main. Titel, description, og:, twitter: en de JSON-LD komen
onveranderd van #334; bron-seo/apply_seo_head.py --check meldt "would change:
0 pages". De body is van deze PR. Het enige wat in pricing's head van deze
branch komt is de CSS-fix voor de tier-kaarten, en dat is geen head-element.

tests/site-claims.test.mjs test 11 sloot pricing.html bij naam uit van de
scan op "uploads per hour", omdat die zin daar nog stond. Die uitsluiting is
weg: de kaart noemt nu de limieten die de relay afdwingt, dus de scan mag
pricing meenemen. parasign en parasend blijven uitgesloten tot #339 landt.
frontend/apply-nav.py gedraaid na de rebase: nul wijzigingen.

Every review point, and what happened to it

Afkeurpunt Fix
Eerste schermvulling op 390px bevat geen bedrag "Community is €0 a month, forever" staat op y=278, "€15 a month" op y=440
Zegt niet wat je koopt "Sign documents and send files that vanish after one read." is de eerste regel, y=210
Decoratieve "00" boven de H1 Weg. Kostte de eerste 60px van de vouw en betekende niets
"a dedicated relay" "a server of their own"
"a connection to their own software" "signing built into their own software"
Kernbelofte noemt het getal niet "€0 a month, forever: 2 signatures per month and 10 uploads per hour, no card"
"from €15 a month" gold voor beide producten Gesplitst: "from €15 a month for sending, from €49 a month for signing". €15 is ParaSend Pro, €49 is ParaSign Pro
"10 uploads per hour per IP" als accountlimiet Vervangen door wat de relay afdwingt: 10 transfers per month, 5 MB per file. ParaSend Pro: 500 transfers per month in plaats van "no IP rate limit"
"ML-DSA-65 signed receipts" voor ParaShare Weg. Het register geeft ParaShare Default SIG "n/a" op een pre-v1 hybrid, migrerend naar v1; de zin zegt dat nu zo
Wie erachter zit pas op 1128px Mick Beer met de titel van /about plus KvK 42115132, y=682, binnen de vouw
Twee termen voor de gratis grens Overal "2 signatures per month", op /pricing en op /signup
FAQ zei "advanced (AES), not qualified (QES)" "A ParaSign signature is a Simple Electronic Signature (SES) under eIDAS, not an advanced (AES) or a qualified (QES) signature." Gelijk aan /about
"All tiers meet NIS2 and GDPR by design" "The architecture is built to support your NIS2 and GDPR work. Paramant itself holds no third-party certification for those frameworks."
Fold-test meet alleen aanwezigheid Meet nu de onderrand van elke regel tegen 390x844
Jargon-check dekt geen spans Leest tekstnodes, dus de kicker-span onder de H1 telt mee

Ook meegenomen uit de eerdere versie van deze branch: elke tierkaart zegt in
één regel voor wie hij is, ParaSign staat boven ParaSend, de Community-kaarten
sturen naar /signup in plaats van naar /dashboard, en de kaarten passen weer in
hun grid (grid items zijn min-width:auto en .btn is nowrap, dus de langste CTA
zette de min-content breedte van de hele track; op 390px was elke kaart 471px
in een container van 342px).

Gemeten op 390x844

onderrand
H1 "Pricing" 129
wat het product doet 216
eerste bedrag (€0, forever) 253
€15 voor versturen 415
€49 voor tekenen 442
de echte limieten (10 per maand, 5 MB) 471
doelgroep 550
CTA "Create a free account" 612
founderregel, hele claim incl. KvK 745

99px over. De founderregel wordt als hele regel gemeten, niet als de
met alleen de naam: die eindigt op 705, de titel en het KvK-nummer lopen daarna
door. Een assertie op de naam alleen noemt de regel zichtbaar terwijl de
registratie onder de schermrand valt.

De ruimte kwam uit de opmaak, niet uit geschrapte woorden. .sec-head draagt
sitebreed margin-bottom:var(--space-8); onder een sectiekop klopt dat, hier
kostte het 48px van het enige scherm dat het bedrag, de doelgroep, de founder
en de knop moet dragen. Alleen op deze hero overschreven, de gedeelde regel in
design-system.css is niet aangeraakt.

Bronnen

  • Founder en titel: frontend/about.html ("Mick Beer, privacy and security researcher"). Geen woord toegevoegd dat /about niet gebruikt; ui-truthfulness pint dat in beide richtingen.
  • KvK 42115132: staat al in de footer van dezelfde pagina en op /about.
  • SES-formulering: frontend/about.html op main.
  • "Paramant itself holds no third-party certification": stond al in de FAQ van deze pagina op main.
  • 2 handtekeningen per maand: relay/lib/entitlements.js; 10 uploads per uur: de Community-kaart van ParaSend.
  • Community-limieten: relay/lib/tiers.js (transfers_month: 10, file_mb: 5), afgedwongen op relay/relay.js:4598 (402 monthly_transfer_quota_reached) en relay/relay.js:4551 (413 Max 5MB tegen MAX_BLOB). ParaSend Pro transfers_month: 500 uit dezelfde tabel.
  • Dat "10 uploads per hour per IP" niet over een account gaat: relay/relay.js:4306-4312, /v2/anon-inbound, DEPRECATED 2026-05-28, Sunset: Wed, 31 Dec 2026, ANON_RATE_PER_HOUR default 10.
  • ParaShare-cryptografie: frontend/crypto-agility.html, rij "ParaShare (webapp)" met Default KEM "ML-KEM-768 + ECDH P-256", Default SIG "n/a", wire format "pre-v1 hybrid", status "migrating to v1".
  • Alle bedragen: verplaatst, niet gewijzigd. relay/test/pricing-page.test.js herrekent ze uit relay/lib/billing-catalog.js, 35 checks.

Tests

Groen: links, seo-contract (14), ui-truthfulness, site-claims (11), pricing-page
(35 checks), pricing-fold (4), frontend-loading-contract (7), navigation-shell,
product-heartbeat (9), check-csp-inline, check-cache-bust, eslint@9.
tests/static-sanity.sh: PASS, alle tien.

Sabotage, elk apart in de worktree en teruggedraaid, eindstand schoon:

sabotage suite
productregel uit de body ui-truthfulness ROOD
productregel uit de body pricing-fold ROOD
het getal uit de kernbelofte ui-truthfulness ROOD
"a dedicated relay" terug in de lead ui-truthfulness ROOD
"a connection to their own software" terug ui-truthfulness ROOD
FAQ terug naar advanced (AES) ui-truthfulness ROOD
compliance terug naar de garantie ui-truthfulness ROOD
founderregel uit de hero ui-truthfulness ROOD
/signup terug naar "2 documents a month" ui-truthfulness ROOD
Community-kaart terug naar /dashboard ui-truthfulness ROOD
founder 400px onder de vouw geduwd pricing-fold ROOD
jargon in de kicker-span pricing-fold ROOD
beide CSS-regels teruggedraaid pricing-fold ROOD
één bedrag voor beide producten ui-truthfulness ROOD
tekenbedrag naar het verkeerde product ui-truthfulness ROOD
ParaSign Pro-kaart naar €59, lead volgt niet ui-truthfulness ROOD
verzendbedrag uit de lead ui-truthfulness ROOD
founder: titel en KvK weg, naam blijft pricing-fold ROOD
founderregel 120px onder de vouw pricing-fold ROOD
tekenbedrag onder de vouw geduwd pricing-fold ROOD
tiers.js community transfers_month 10 → 25 pricing-page ROOD
tiers.js community file_mb 5 → 20 pricing-page ROOD
tiers.js pro transfers_month 500 → 900 pricing-page ROOD
"10 transfers per month" van de kaart pricing-page ROOD
"5 MB per file" van de kaart pricing-page ROOD
lead en kaart lopen uiteen pricing-page ROOD
"uploads per hour" terug op de kaart pricing-page ROOD
"uploads per hour" terug in de lead ui-truthfulness ROOD
"ML-DSA-65 signed receipts" terug pricing-page ROOD
register: ParaShare SIG n/a → ML-DSA-65 pricing-page ROOD
limietregel onder de vouw geduwd pricing-fold ROOD
"10 uploads per hour per IP" terug op de kaart site-claims ROOD
"uploads an hour" terug in de lead site-claims ROOD

De limietpins werken in beide richtingen: tiers.js alleen veranderen maakt de
test rood, en de pagina alleen veranderen ook. Er is geen kant waarop de twee
stil uit elkaar kunnen lopen.

Eén test is verwijderd in plaats van toegevoegd.
relay/test/pricing-page.test.js had een regel "de verouderde 5 MB-claim is
weg" die assert dat "5 MB" nergens op de pagina staat. Die reden was
verlopen: relay/relay.js weigert een groter bestand met 413 Max 5MB tegen
MAX_BLOB (default 5242880) en relay/lib/tiers.js geeft elke tier
file_mb: 5. De limiet is echt, dus de test hield een ware zin van de pagina.
Vervangen door een pin die het getal uit tiers.js leest.

Twee eerlijke uitkomsten horen erbij. min-width:0 en white-space:normal
los teruggedraaid houden de fold-test groen, samen teruggedraaid maakt hem
rood: elk van de twee is op zichzelf genoeg om de kaart binnen de grid te
houden, dus de test pint het paar en niet één regel. En de sabotages draaien nu
met een guard die afbreekt als de mutatie niets raakt. Zonder die guard gaf een
ronde vals groen, niet omdat de test zwak was maar omdat de zoekstring over een
regeleinde liep en er dus niets veranderde. Een sabotage die niets wijzigt
bewijst niets.

Ter controle van de founder-assertie: bij een duw van 100px eindigt de hele
regel op y=866 en wordt de test rood, terwijl de met alleen de naam op
826 zou zijn geëindigd en binnen de vouw was gebleven.

Scope

Zeven bestanden: frontend/pricing.html, frontend/signup.html,
frontend/billing/checkout.html, tests/pricing-fold.test.mjs (nieuw),
tests/ui-truthfulness.test.mjs, relay/test/pricing-page.test.js en
tests/site-claims.test.mjs (uitsluiting opgeheven). frontend/index.html, frontend/apply-nav.py
en frontend/js/nav-auth.js zijn niet aangeraakt. Geen prijs en geen checkout-link gewijzigd. Wel
limieten: die stonden fout op de pagina en staan nu zoals de relay ze afdwingt.

Open punten, niet in deze PR

  • frontend/index.html draagt dezelfde fout. Regel 360: "1 hour link
    expiry, burn on first read, 10 uploads per hour". Dat is hetzelfde
    ANON_RATE_PER_HOUR van het afgekondigde /v2/anon-inbound, gepresenteerd
    als wat een Community-account krijgt. Hier niet meegenomen: index.html valt
    buiten de prijsgroep en is in deze PR expliciet onaangeraakt. Volgt in een
    aparte PR, met dezelfde binding aan tiers.js.
  • Twee schrijfwijzen voor dezelfde limiet. Community limits on index and docs come from tiers.js #354 zet op index en /docs
    "10 transfers a month"; deze pagina zegt "10 transfers per month". Hetzelfde
    getal uit dezelfde tabel, twee formuleringen. Niet hier rechtgetrokken omdat
    het buiten de afgesproken scope van deze ronde viel; het is dezelfde soort
    drift als "2 signatures per month" tegenover "2 documents a month" die eerder
    in deze PR wel is opgelost. Voor de backlog, samen met index.html hierboven.
  • Taal. De pagina is Engels terwijl btw en KvK Nederlands zijn. Sitebrede
    keuze, niet iets voor deze PR.

@Apolloccrypt Apolloccrypt changed the title Pricing says who it is free for before it says what it costs Pricing says what it sells and who it is free for before it says what it costs Sep 2, 2026
@Apolloccrypt Apolloccrypt changed the title Pricing says what it sells and who it is free for before it says what it costs Pricing says what it sells, and what free actually gives, in the first screen Sep 2, 2026
…t screen

A phone showed "Pricing", a decorative "00" and a paragraph about a
post-quantum core. No amount, no product, and nothing about who holds the
files. Rebased onto main, so #328's rename (Community, not Free), its
founder paragraph and its /docs#parasign-api fix all stand; this builds the
first screen on top of them.

/pricing
- The lead says what you buy before what it costs: sign documents, send files
  that vanish after one read.
- The promise carries its own number. "Free forever" alone reads as generous
  until the table says two signatures a month; it now says "Community is
  €0 a month, forever: 2 signatures per month and 10 uploads per hour, no
  card" in the same breath.
- The lead prices the two products separately: from €15 a month for sending
  (ParaSend Pro), from €49 for signing (ParaSign Pro). One figure for both
  anchored an office that came to sign on the cheaper product's price. Both
  amounts are read off their own Pro card by the test, and those cards are
  already bound to the catalog.
- The Community limits are the ones the relay enforces. The page sold "10
  uploads per hour per IP", which is ANON_RATE_PER_HOUR on /v2/anon-inbound,
  deprecated 2026-05-28 with Sunset 2026-12-31. What actually stops an account
  is transfers_month 10 and file_mb 5 from relay/lib/tiers.js, refused with 402
  and 413. The lead and the ParaSend cards now say "10 transfers per month, 5 MB
  per file", and ParaSend Pro says 500 transfers per month instead of "no IP
  rate limit", which was the same misdescription from the other side.
- ParaSign's ParaShare claim matched no register entry. frontend/crypto-agility
  lists ParaShare with Default SIG "n/a" on a pre-v1 hybrid wire format, so
  "ML-DSA-65 signed receipts" is dropped for what the register says.
- Jargon out of the lead. "A dedicated relay" and "a connection to their own
  software" became "a server of their own" and "signing built into their own
  software". The cryptography sentence keeps doing its work under the tables.
- Who is behind it moved from 1128px into the first screen: Mick Beer, with
  the exact title /about gives him, and KvK 42115132 beside it.
- The decorative "00" over the h1 is gone. It meant nothing and cost the
  first 60px of the fold.
- Every tier card says who it is for, in one line. ParaSign moved above
  ParaSend; it is the flagship and it was second.
- The Community cards send a visitor to /signup instead of /dashboard, which
  is a page they cannot open yet.
- The FAQ said "Signatures are advanced (AES), not qualified (QES)" while
  /about says Simple Electronic Signature. /about is right: a ParaSign
  signature is an SES under eIDAS, not AES and not QES.
- "All tiers meet NIS2 and GDPR requirements by design" was a guarantee the
  same page withdraws four paragraphs later. It now says the architecture is
  built to support that work and that Paramant holds no third-party
  certification.
- Layout: grid items default to min-width:auto and .btn is nowrap, so the
  longest CTA set the min-content width of the track. At 390px every card was
  471px inside a 342px container.

/signup names the free limit in the same words /pricing uses. billing/checkout
says where checkout actually happens and that nothing is charged there.

Tests. tests/pricing-fold.test.mjs measures the laid-out page: the bottom edge
of the amount, the audience line, the founder line and the first action must
fall inside 390x844, in that order. It reads text nodes rather than a list of
block tags, so the kicker span under the h1 is covered too. Prices, limits and
checkout links are untouched; relay/test/pricing-page.test.js still recomputes
all 34 of them from the catalog.
@Apolloccrypt
Apolloccrypt merged commit b38196b into main Sep 2, 2026
11 checks passed
Apolloccrypt added a commit that referenced this pull request Sep 2, 2026
The three pages a buyer reaches after the homepage were written for someone
who already believes the product. /about opened on the mission and put the
founder in section 03, below the cryptography. /security opened on defence in
depth and kept the one row a buyer came for, the jurisdiction table, seven
screens down. /trust never said who it was for.

They now run the order docs/brand/messaging.md fixes: what this is, who it is
for, who is behind it, a next step, then the proof including the honest
limits. Copy, hierarchy and order only. No restyle. index.html, apply-nav.py
and js/nav-auth.js are untouched.

/about is the founder page.

  The lede is plain language: sign and send documents so only you and the
  recipient can read them, so anyone can check later that the document is
  genuine, on servers in Germany under EU law. Under it, in the first phone
  screen, who it is for, then Mick Beer with the title the guide fixes, then
  two buttons. Measured at 390x844: the founder sits at y=463 and the second
  button at y=608. The section number "00" is hidden in the mobile override
  instead of landing under the H1 as a stray number.

  Two sentences are gone. "The cryptography is post-quantum, which is the
  proof that it still holds up in ten years" was not a proof and not
  checkable, on the page whose argument is that everything on it is
  checkable. The founder paragraph explained the free plan with a
  jurisdiction claim ("should not depend on a US subscription"), which the
  guide forbids beside his name. In its place stands the paragraph #332
  landed on main while this branch was in review: the Community plan is his
  way of giving something back to society, the business plans pay for it,
  that is the whole arrangement, and it is why the Community plan is not a
  trial and has no end date. Taken from main verbatim, moved with the section
  into the top half, and pinned so the two copies cannot drift.

  The tier block names the free plan Community, which is what /pricing prints
  on the card since #328.

/security answers "why would I trust you" before it answers "how it works".

  The promise carries its own scope. It read "even if our own server is
  broken into, nobody can read your documents" flat out, while ten screens
  lower the page says the Chromium and Outlook extensions take a server-side
  encryption path. For an extension user the flat version is untrue today, so
  the exception now travels with the promise, in the hero.

  It also says what that exception costs the reader, in words rather than in
  ours: the extensions encrypt on our server, which means we can read what
  you upload through them until that is changed. "Treat those uploads as
  relay-side" was the internal phrasing, and relay is exactly the word this
  branch removed from the /trust hero. Neither hero uses it now, and a test
  says so.

  The first screen also carries who is behind the page (Paramantis Solutions
  B.V., Harderwijk, KvK 42115132, and the founder line) and the next step.
  The buttons used to sit at roughly y=11400 on a phone; "See pricing" is now
  at y=656 and "Verify a document" at y=716.

  The free plan is Community here too. A first version of this branch left
  "ParaSign Free and ParaSend Free cost EUR 0" standing at r.448, because the
  only check that forbade the old name was scoped to /about. That check now
  covers all three pages, and the sitewide sweep in ui-truthfulness gained the
  shape it was missing, so any page using it fails. The page description no
  longer sells "relay architecture" either.

  The audit block says what /docs#audits actually adds up to: three external
  audits in April 2026, two by R. Zwarts and one by Ryan Williams of Smart
  Cyber Solutions, forty findings, four of them critical, with the resolving
  commits in the table. The previous round claimed "the audit reports
  themselves are not published" and pinned it. That was false:
  docs/security-audit-2026-04.md is the full Smart Cyber Solutions writeup
  and it ships in the site tree. Only the raw pentest output is missing,
  which is what that document itself calls the raw report. Both pages now say
  that, and link the report.

  The CLOUD Act row and the EU-law card move to the data-path wording, as
  section 9.2 of the guide requires: no US provider in the data path, with
  Resend named as the one exception in the same breath. The old row read "not
  applicable: no US infrastructure, no US company", which is broader than
  /privacy allows.

/trust names its reader, then gives that reader somewhere to go.

  The hero addresses organisations running their own relay and anyone
  checking a supplier, and now offers them two buttons instead of one text
  link mid-paragraph (y=416 and y=476). The first sentence under the hero no
  longer says "the operator who runs the relay": relay is not a word a
  supplier reviewer knows.

  The page called itself Trust & Verification in its title and H1 while the
  social card and the structured data still said Trust & Transparency. #334
  then rewrote every head on the site, so the literal strings belong there and
  tests/seo-contract.test.mjs pins them. What this branch pins is the
  relation: the title, og:title, twitter:title and the JSON-LD name must name
  the page the same, and that name must contain the words the H1 uses.
  Punctuation and case are not the point; Transparency versus Verification
  was. Its plan sentence named two of the three paid
  ParaSign tiers; it names all three, and both free tiers as Community.

Tests

  tests/ui-truthfulness.test.mjs pins each of the above, and each one was
  sabotaged in place to confirm it goes red: the ten-year promise, the
  give-back sentence, the US-subscription framing, the Community rename, the
  CLOUD Act row, the Resend exception dropped from the card, the finding
  counts, the "reports not published" sentence, the auditor names on
  /security as well as /trust, the two hero buttons on each page, the
  who-is-behind line, the bounded promise, the /trust og:title and JSON-LD
  name, the jargon in the first screen, and the paid tiers. Twenty-six
  sabotages, twenty-six red, no gaps.

  tests/site-claims.test.mjs block 11 reads the numbers out of the /pricing
  tier card that owns them and requires /about to repeat them; it follows the
  Community rename and now also forbids "ParaSign Free" on /about.

  node --test over the CI glob: 162 pass, 0 fail. check-csp-inline,
  check-cache-bust and eslint exit 0. At 390px all three pages have
  scrollWidth === clientWidth === 390.

Two things this branch had to touch on main's side

  tests/ui-truthfulness.test.mjs did not parse on main: #336 and #339 each
  landed a const named pricingVisible in the same module, for two different
  values. The one #339 added is renamed to pricingText, with a comment saying
  why. Without it nothing in this file runs, this branch included.

  tests/site-claims.test.mjs block 12 read the /pricing tier cards by their
  section heading. #336 renamed both headings and put ParaSign first, so the
  split now finds them by product prefix and orders them by position.

  Not touched, and still broken on main: relay/test/pricing-page.test.js r.498
  declares tiers twice, so eslint cannot parse it. It is outside these three
  pages and outside this PR.

Still open, deliberately

  The eIDAS level (SES on /about, advanced (AES) in the /pricing FAQ) is a
  real contradiction and needs a decision, not a copy edit. This branch stops
  it spreading and pins that it stays on the one page that has always carried
  it.
Apolloccrypt added a commit that referenced this pull request Sep 2, 2026
The three pages a buyer reaches after the homepage were written for someone
who already believes the product. /about opened on the mission and put the
founder in section 03, below the cryptography. /security opened on defence in
depth and kept the one row a buyer came for, the jurisdiction table, seven
screens down. /trust never said who it was for.

They now run the order docs/brand/messaging.md fixes: what this is, who it is
for, who is behind it, a next step, then the proof including the honest
limits. Copy, hierarchy and order only. No restyle. index.html, apply-nav.py
and js/nav-auth.js are untouched.

/about is the founder page.

  The lede is plain language: sign and send documents so only you and the
  recipient can read them, so anyone can check later that the document is
  genuine, on servers in Germany under EU law. Under it, in the first phone
  screen, who it is for, then Mick Beer with the title the guide fixes, then
  two buttons. Measured at 390x844: the founder sits at y=463 and the second
  button at y=608. The section number "00" is hidden in the mobile override
  instead of landing under the H1 as a stray number.

  Two sentences are gone. "The cryptography is post-quantum, which is the
  proof that it still holds up in ten years" was not a proof and not
  checkable, on the page whose argument is that everything on it is
  checkable. The founder paragraph explained the free plan with a
  jurisdiction claim ("should not depend on a US subscription"), which the
  guide forbids beside his name. In its place stands the paragraph #332
  landed on main while this branch was in review: the Community plan is his
  way of giving something back to society, the business plans pay for it,
  that is the whole arrangement, and it is why the Community plan is not a
  trial and has no end date. Taken from main verbatim, moved with the section
  into the top half, and pinned so the two copies cannot drift.

  The tier block names the free plan Community, which is what /pricing prints
  on the card since #328.

/security answers "why would I trust you" before it answers "how it works".

  The promise carries its own scope. It read "even if our own server is
  broken into, nobody can read your documents" flat out, while ten screens
  lower the page says the Chromium and Outlook extensions take a server-side
  encryption path. For an extension user the flat version is untrue today, so
  the exception now travels with the promise, in the hero.

  It also says what that exception costs the reader, in words rather than in
  ours: the extensions encrypt on our server, which means we can read what
  you upload through them until that is changed. "Treat those uploads as
  relay-side" was the internal phrasing, and relay is exactly the word this
  branch removed from the /trust hero. Neither hero uses it now, and a test
  says so.

  The first screen also carries who is behind the page (Paramantis Solutions
  B.V., Harderwijk, KvK 42115132, and the founder line) and the next step.
  The buttons used to sit at roughly y=11400 on a phone; "See pricing" is now
  at y=656 and "Verify a document" at y=716.

  The free plan is Community here too. A first version of this branch left
  "ParaSign Free and ParaSend Free cost EUR 0" standing at r.448, because the
  only check that forbade the old name was scoped to /about. That check now
  covers all three pages, and the sitewide sweep in ui-truthfulness gained the
  shape it was missing, so any page using it fails. The page description no
  longer sells "relay architecture" either.

  The audit block says what /docs#audits actually adds up to: three external
  audits in April 2026, two by R. Zwarts and one by Ryan Williams of Smart
  Cyber Solutions, forty findings, four of them critical, with the resolving
  commits in the table. The previous round claimed "the audit reports
  themselves are not published" and pinned it. That was false:
  docs/security-audit-2026-04.md is the full Smart Cyber Solutions writeup
  and it ships in the site tree. Only the raw pentest output is missing,
  which is what that document itself calls the raw report. Both pages now say
  that, and link the report.

  The CLOUD Act row and the EU-law card move to the data-path wording, as
  section 9.2 of the guide requires: no US provider in the data path, with
  Resend named as the one exception in the same breath. The old row read "not
  applicable: no US infrastructure, no US company", which is broader than
  /privacy allows.

/trust names its reader, then gives that reader somewhere to go.

  The hero addresses organisations running their own relay and anyone
  checking a supplier, and now offers them two buttons instead of one text
  link mid-paragraph (y=416 and y=476). The first sentence under the hero no
  longer says "the operator who runs the relay": relay is not a word a
  supplier reviewer knows.

  The page called itself Trust & Verification in its title and H1 while the
  social card and the structured data still said Trust & Transparency. #334
  then rewrote every head on the site, so the literal strings belong there and
  tests/seo-contract.test.mjs pins them. What this branch pins is the
  relation: the title, og:title, twitter:title and the JSON-LD name must name
  the page the same, and that name must contain the words the H1 uses.
  Punctuation and case are not the point; Transparency versus Verification
  was. Its plan sentence named two of the three paid
  ParaSign tiers; it names all three, and both free tiers as Community.

Tests

  tests/ui-truthfulness.test.mjs pins each of the above, and each one was
  sabotaged in place to confirm it goes red: the ten-year promise, the
  give-back sentence, the US-subscription framing, the Community rename, the
  CLOUD Act row, the Resend exception dropped from the card, the finding
  counts, the "reports not published" sentence, the auditor names on
  /security as well as /trust, the two hero buttons on each page, the
  who-is-behind line, the bounded promise, the /trust og:title and JSON-LD
  name, the jargon in the first screen, and the paid tiers. Twenty-six
  sabotages, twenty-six red, no gaps.

  tests/site-claims.test.mjs block 11 reads the numbers out of the /pricing
  tier card that owns them and requires /about to repeat them; it follows the
  Community rename and now also forbids "ParaSign Free" on /about.

  node --test over the CI glob: 162 pass, 0 fail. check-csp-inline,
  check-cache-bust and eslint exit 0. At 390px all three pages have
  scrollWidth === clientWidth === 390.

Three things this branch had to touch on main's side

  tests/ui-truthfulness.test.mjs did not parse on main: #336 and #339 each
  landed a const named pricingVisible in the same module, for two different
  values. The one #339 added is renamed to pricingText, with a comment saying
  why. Without it nothing in this file runs, this branch included.

  tests/site-claims.test.mjs block 12 read the /pricing tier cards by their
  section heading. #336 renamed both headings and put ParaSign first, so the
  split now finds them by product prefix and orders them by position.

  relay/test/pricing-page.test.js r.498 required ../lib/tiers a second time,
  under a name the file already binds at r.18. That is a SyntaxError, and it
  took down two CI checks on every PR: "static, every name must exist" (eslint
  cannot parse the file) and "relay - unit suite". The duplicate line is
  removed; the binding at the top of the file is the same module. This was
  outside the three pages, but no PR can go green while it stands.

Still open, deliberately

  The eIDAS level (SES on /about, advanced (AES) in the /pricing FAQ) is a
  real contradiction and needs a decision, not a copy edit. This branch stops
  it spreading and pins that it stays on the one page that has always carried
  it.
Apolloccrypt added a commit that referenced this pull request Sep 2, 2026
…ly form

/parasend had no inbound link anywhere on the site and /parasign had one, from
/sign. Both product cards on the homepage now lead with the page that explains
the product and keep the app as the second action. tests/links.test.mjs gains a
reachability check (a page nothing links to is indexed and unreachable at the
same time) and tests/navigation-shell.test.mjs pins the order per card.

outbound_per_hour has been enforced since the rate-limit finding (relay.js,
outboundRateOk on GET /v2/outbound/:hash) and appeared on no page: a Community
account scripting its own downloads hit a 429 it was never told about. It is now
on /parasend per tier and on the /parasign Pro card, pinned to tiers.js like the
other limits. It is stated as retrievals, not sends: it counts the account's own
fetches with its own key, and the browser recipient path (GET /v2/dl/:token/get)
has no rate limit at all, so a recipient never spends the sender's hour.

"Unlimited receiving" pointed at no field in tiers.js or entitlements.js. It is
true: nothing meters receiving, and being invited, opening an invitation and
fetching the document back are not counted on any plan. The line now reads "No
limit on receiving", /parasign says what it rests on and that signing what you
receive still counts, and pricing-page.test.js pins it negatively: the day a
receiving dimension appears in tiers.js or in the entitlement quotas, the test
goes red and the pages have to name the real ceiling.

The same Community limit shipped as "10 transfers a month" on / and /docs and
"10 transfers per month" on /pricing, /parasend and /parasign. The site's form
is "a month" everywhere now. The number checks accept both spellings on purpose,
so a tiers.js change fails on the number; the wording is pinned once, so a page
that drifts back fails on wording.

Two test files could not parse on main. #336 and #339 each added a
"const tiers = require('../lib/tiers')" to relay/test/pricing-page.test.js and a
"const pricingVisible" to tests/ui-truthfulness.test.mjs; both merged, both files
threw SyntaxError, and neither suite ran. Deduplicated as a one-line change per
file, so a hotfix that does the same rebases cleanly on top.

So that this cannot recur through this branch: every block added here sits in a
function scope and reaches the top level with nothing. The two helpers that are
used from two distant places are function declarations, which tolerate being
declared twice where a const throws.

Also in ui-truthfulness: the ParaShare register assertions sat inside
"if (shareSig === 'n/a')", so moving the webapp to ML-DSA-65 in the register
switched the check off instead of failing it. They now run on whatever the SIG
column holds, in both directions, and an unmapped value fails loudly.
Apolloccrypt added a commit that referenced this pull request Sep 2, 2026
The three pages a buyer reaches after the homepage were written for someone
who already believes the product. /about opened on the mission and put the
founder in section 03, below the cryptography. /security opened on defence in
depth and kept the one row a buyer came for, the jurisdiction table, seven
screens down. /trust never said who it was for.

They now run the order docs/brand/messaging.md fixes: what this is, who it is
for, who is behind it, a next step, then the proof including the honest
limits. Copy, hierarchy and order only. No restyle. index.html, apply-nav.py
and js/nav-auth.js are untouched.

/about is the founder page.

  The lede is plain language: sign and send documents so only you and the
  recipient can read them, so anyone can check later that the document is
  genuine, on servers in Germany under EU law. Under it, in the first phone
  screen, who it is for, then Mick Beer with the title the guide fixes, then
  two buttons. Measured at 390x844: the founder sits at y=463 and the second
  button at y=608. The section number "00" is hidden in the mobile override
  instead of landing under the H1 as a stray number.

  Two sentences are gone. "The cryptography is post-quantum, which is the
  proof that it still holds up in ten years" was not a proof and not
  checkable, on the page whose argument is that everything on it is
  checkable. The founder paragraph explained the free plan with a
  jurisdiction claim ("should not depend on a US subscription"), which the
  guide forbids beside his name. In its place stands the paragraph #332
  landed on main while this branch was in review: the Community plan is his
  way of giving something back to society, the business plans pay for it,
  that is the whole arrangement, and it is why the Community plan is not a
  trial and has no end date. Taken from main verbatim, moved with the section
  into the top half, and pinned so the two copies cannot drift.

  The tier block names the free plan Community, which is what /pricing prints
  on the card since #328.

/security answers "why would I trust you" before it answers "how it works".

  The promise carries its own scope. It read "even if our own server is
  broken into, nobody can read your documents" flat out, while ten screens
  lower the page says the Chromium and Outlook extensions take a server-side
  encryption path. For an extension user the flat version is untrue today, so
  the exception now travels with the promise, in the hero.

  It also says what that exception costs the reader, in words rather than in
  ours: the extensions encrypt on our server, which means we can read what
  you upload through them until that is changed. "Treat those uploads as
  relay-side" was the internal phrasing, and relay is exactly the word this
  branch removed from the /trust hero. Neither hero uses it now, and a test
  says so.

  The first screen also carries who is behind the page (Paramantis Solutions
  B.V., Harderwijk, KvK 42115132, and the founder line) and the next step.
  The buttons used to sit at roughly y=11400 on a phone; "See pricing" is now
  at y=656 and "Verify a document" at y=716.

  The free plan is Community here too. A first version of this branch left
  "ParaSign Free and ParaSend Free cost EUR 0" standing at r.448, because the
  only check that forbade the old name was scoped to /about. That check now
  covers all three pages, and the sitewide sweep in ui-truthfulness gained the
  shape it was missing, so any page using it fails. The page description no
  longer sells "relay architecture" either.

  The audit block says what /docs#audits actually adds up to: three external
  audits in April 2026, two by R. Zwarts and one by Ryan Williams of Smart
  Cyber Solutions, forty findings, four of them critical, with the resolving
  commits in the table. The previous round claimed "the audit reports
  themselves are not published" and pinned it. That was false:
  docs/security-audit-2026-04.md is the full Smart Cyber Solutions writeup
  and it ships in the site tree. Only the raw pentest output is missing,
  which is what that document itself calls the raw report. Both pages now say
  that, and link the report.

  The CLOUD Act row and the EU-law card move to the data-path wording, as
  section 9.2 of the guide requires: no US provider in the data path, with
  Resend named as the one exception in the same breath. The old row read "not
  applicable: no US infrastructure, no US company", which is broader than
  /privacy allows.

/trust names its reader, then gives that reader somewhere to go.

  The hero addresses organisations running their own relay and anyone
  checking a supplier, and now offers them two buttons instead of one text
  link mid-paragraph (y=416 and y=476). The first sentence under the hero no
  longer says "the operator who runs the relay": relay is not a word a
  supplier reviewer knows.

  The page called itself Trust & Verification in its title and H1 while the
  social card and the structured data still said Trust & Transparency. #334
  then rewrote every head on the site, so the literal strings belong there and
  tests/seo-contract.test.mjs pins them. What this branch pins is the
  relation: the title, og:title, twitter:title and the JSON-LD name must name
  the page the same, and that name must contain the words the H1 uses.
  Punctuation and case are not the point; Transparency versus Verification
  was. Its plan sentence named two of the three paid
  ParaSign tiers; it names all three, and both free tiers as Community.

Tests

  tests/ui-truthfulness.test.mjs pins each of the above, and each one was
  sabotaged in place to confirm it goes red: the ten-year promise, the
  give-back sentence, the US-subscription framing, the Community rename, the
  CLOUD Act row, the Resend exception dropped from the card, the finding
  counts, the "reports not published" sentence, the auditor names on
  /security as well as /trust, the two hero buttons on each page, the
  who-is-behind line, the bounded promise, the /trust og:title and JSON-LD
  name, the jargon in the first screen, and the paid tiers. Twenty-seven
  sabotages, twenty-seven red, no gaps.

  tests/site-claims.test.mjs block 11 reads the numbers out of the /pricing
  tier card that owns them and requires /about to repeat them; it follows the
  Community rename and now also forbids "ParaSign Free" on /about.

  node --test over the CI glob: 173 pass, 0 fail. check-csp-inline,
  check-cache-bust and eslint exit 0, bron-seo/apply_seo_head.py --check
  reports 0 pages, and tests/static-sanity.sh is PASS on all eleven checks,
  including #362's new test-scope guard. At 390px all three pages have
  scrollWidth === clientWidth === 390.

Following main through four parallel merges

  #359 landed the deduplication this branch was carrying (the second const
  tiers in relay/test/pricing-page.test.js, and pricingVisible renamed to
  pricingText), so both local fixes are dropped in favour of main's.

  This branch's own block in tests/ui-truthfulness.test.mjs now sits inside a
  bare block scope and declares nothing at module level. Four PRs merged into
  that file in parallel on 2 September and two of them collided on a top-level
  const, which is a SyntaxError: not one assertion in the file runs, on any
  branch. A block that declares nothing at module level cannot do that to the
  next branch.

  tests/site-claims.test.mjs block 12 stopped spelling the units itself. #336
  renamed both /pricing section headings and put ParaSign first, and #359
  reworded "2 signatures per month" to "2 signatures a month". The block now
  finds the headings by product prefix, orders them by position, and lifts each
  fact out of the card as a whole phrase, so /about repeats what /pricing says
  rather than what this file guesses /pricing says. /about follows the new
  wording: "2 signatures a month", "24 hour link expiry", "up to 10 reads per
  link".

Still open, deliberately

  The eIDAS level (SES on /about, advanced (AES) in the /pricing FAQ) is a
  real contradiction and needs a decision, not a copy edit. This branch stops
  it spreading and pins that it stays on the one page that has always carried
  it.
Apolloccrypt added a commit that referenced this pull request Sep 2, 2026
The three pages a buyer reaches after the homepage were written for someone
who already believes the product. /about opened on the mission and put the
founder in section 03, below the cryptography. /security opened on defence in
depth and kept the one row a buyer came for, the jurisdiction table, seven
screens down. /trust never said who it was for.

They now run the order docs/brand/messaging.md fixes: what this is, who it is
for, who is behind it, a next step, then the proof including the honest
limits. Copy, hierarchy and order only. No restyle. index.html, apply-nav.py
and js/nav-auth.js are untouched.

/about is the founder page.

  The lede is plain language: sign and send documents so only you and the
  recipient can read them, so anyone can check later that the document is
  genuine, on servers in Germany under EU law. Under it, in the first phone
  screen, who it is for, then Mick Beer with the title the guide fixes, then
  two buttons. Measured at 390x844: the founder sits at y=463 and the second
  button at y=608. The section number "00" is hidden in the mobile override
  instead of landing under the H1 as a stray number.

  Two sentences are gone. "The cryptography is post-quantum, which is the
  proof that it still holds up in ten years" was not a proof and not
  checkable, on the page whose argument is that everything on it is
  checkable. The founder paragraph explained the free plan with a
  jurisdiction claim ("should not depend on a US subscription"), which the
  guide forbids beside his name. In its place stands the paragraph #332
  landed on main while this branch was in review: the Community plan is his
  way of giving something back to society, the business plans pay for it,
  that is the whole arrangement, and it is why the Community plan is not a
  trial and has no end date. Taken from main verbatim, moved with the section
  into the top half, and pinned so the two copies cannot drift.

  The tier block names the free plan Community, which is what /pricing prints
  on the card since #328.

/security answers "why would I trust you" before it answers "how it works".

  The promise carries its own scope. It read "even if our own server is
  broken into, nobody can read your documents" flat out, while ten screens
  lower the page says the Chromium and Outlook extensions take a server-side
  encryption path. For an extension user the flat version is untrue today, so
  the exception now travels with the promise, in the hero.

  It also says what that exception costs the reader, in words rather than in
  ours: the extensions encrypt on our server, which means we can read what
  you upload through them until that is changed. "Treat those uploads as
  relay-side" was the internal phrasing, and relay is exactly the word this
  branch removed from the /trust hero. Neither hero uses it now, and a test
  says so.

  The first screen also carries who is behind the page (Paramantis Solutions
  B.V., Harderwijk, KvK 42115132, and the founder line) and the next step.
  The buttons used to sit at roughly y=11400 on a phone; "See pricing" is now
  at y=656 and "Verify a document" at y=716.

  The free plan is Community here too. A first version of this branch left
  "ParaSign Free and ParaSend Free cost EUR 0" standing at r.448, because the
  only check that forbade the old name was scoped to /about. That check now
  covers all three pages, and the sitewide sweep in ui-truthfulness gained the
  shape it was missing, so any page using it fails. The page description no
  longer sells "relay architecture" either.

  The audit block says what /docs#audits actually adds up to: three external
  audits in April 2026, two by R. Zwarts and one by Ryan Williams of Smart
  Cyber Solutions, forty findings, four of them critical, with the resolving
  commits in the table. The previous round claimed "the audit reports
  themselves are not published" and pinned it. That was false:
  docs/security-audit-2026-04.md is the full Smart Cyber Solutions writeup
  and it ships in the site tree. Only the raw pentest output is missing,
  which is what that document itself calls the raw report. Both pages now say
  that, and link the report.

  The CLOUD Act row and the EU-law card move to the data-path wording, as
  section 9.2 of the guide requires: no US provider in the data path, with
  Resend named as the one exception in the same breath. The old row read "not
  applicable: no US infrastructure, no US company", which is broader than
  /privacy allows.

/trust names its reader, then gives that reader somewhere to go.

  The hero addresses organisations running their own relay and anyone
  checking a supplier, and now offers them two buttons instead of one text
  link mid-paragraph (y=416 and y=476). The first sentence under the hero no
  longer says "the operator who runs the relay": relay is not a word a
  supplier reviewer knows.

  The page called itself Trust & Verification in its title and H1 while the
  social card and the structured data still said Trust & Transparency. #334
  then rewrote every head on the site, so the literal strings belong there and
  tests/seo-contract.test.mjs pins them. What this branch pins is the
  relation: the title, og:title, twitter:title and the JSON-LD name must name
  the page the same, and that name must contain the words the H1 uses.
  Punctuation and case are not the point; Transparency versus Verification
  was. Its plan sentence named two of the three paid
  ParaSign tiers; it names all three, and both free tiers as Community.

Tests

  tests/ui-truthfulness.test.mjs pins each of the above, and each one was
  sabotaged in place to confirm it goes red: the ten-year promise, the
  give-back sentence, the US-subscription framing, the Community rename, the
  CLOUD Act row, the Resend exception dropped from the card, the finding
  counts, the "reports not published" sentence, the auditor names on
  /security as well as /trust, the two hero buttons on each page, the
  who-is-behind line, the bounded promise, the /trust og:title and JSON-LD
  name, the jargon in the first screen, and the paid tiers. Twenty-seven
  sabotages, twenty-seven red, no gaps.

  tests/site-claims.test.mjs block 11 reads the numbers out of the /pricing
  tier card that owns them and requires /about to repeat them; it follows the
  Community rename and now also forbids "ParaSign Free" on /about.

  node --test over the CI glob: 173 pass, 0 fail. check-csp-inline,
  check-cache-bust and eslint exit 0, bron-seo/apply_seo_head.py --check
  reports 0 pages, and tests/static-sanity.sh is PASS on all eleven checks,
  including #362's new test-scope guard. At 390px all three pages have
  scrollWidth === clientWidth === 390.

Following main through four parallel merges

  #359 landed the deduplication this branch was carrying (the second const
  tiers in relay/test/pricing-page.test.js, and pricingVisible renamed to
  pricingText), so both local fixes are dropped in favour of main's.

  This branch's own block in tests/ui-truthfulness.test.mjs now sits inside a
  bare block scope and declares nothing at module level. Four PRs merged into
  that file in parallel on 2 September and two of them collided on a top-level
  const, which is a SyntaxError: not one assertion in the file runs, on any
  branch. A block that declares nothing at module level cannot do that to the
  next branch.

  tests/site-claims.test.mjs block 12 stopped spelling the units itself. #336
  renamed both /pricing section headings and put ParaSign first, and #359
  reworded "2 signatures per month" to "2 signatures a month". The block now
  finds the headings by product prefix, orders them by position, and lifts each
  fact out of the card as a whole phrase, so /about repeats what /pricing says
  rather than what this file guesses /pricing says. /about follows the new
  wording: "2 signatures a month", "24 hour link expiry", "up to 10 reads per
  link".

Still open, deliberately

  The eIDAS level (SES on /about, advanced (AES) in the /pricing FAQ) is a
  real contradiction and needs a decision, not a copy edit. This branch stops
  it spreading and pins that it stays on the one page that has always carried
  it.
@Apolloccrypt
Apolloccrypt deleted the feat/fe-prijs branch September 5, 2026 18:56
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