Pricing says what it sells, and what free actually gives, in the first screen - #336
Merged
Conversation
Apolloccrypt
force-pushed
the
feat/fe-prijs
branch
from
September 2, 2026 14:44
7518186 to
fa06d6c
Compare
Apolloccrypt
force-pushed
the
feat/fe-prijs
branch
from
September 2, 2026 17:43
fa06d6c to
5c4ef54
Compare
This was referenced Sep 2, 2026
Apolloccrypt
force-pushed
the
feat/fe-prijs
branch
from
September 2, 2026 18:01
5c4ef54 to
21ef1b3
Compare
Apolloccrypt
force-pushed
the
feat/fe-prijs
branch
from
September 2, 2026 18:09
21ef1b3 to
07ab0c6
Compare
…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
force-pushed
the
feat/fe-prijs
branch
from
September 2, 2026 18:21
07ab0c6 to
0d37ec5
Compare
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.
This was referenced Sep 2, 2026
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.
This was referenced Sep 2, 2026
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.
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.
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 ensignup.html wint main. Titel, description, og:, twitter: en de JSON-LD komen
onveranderd van #334;
bron-seo/apply_seo_head.py --checkmeldt "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.mjstest 11 sloot pricing.html bij naam uit van descan 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.pygedraaid na de rebase: nul wijzigingen.Every review point, and what happened to it
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
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-headdraagtsitebreed
margin-bottom:var(--space-8); onder een sectiekop klopt dat, hierkostte 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
frontend/about.html("Mick Beer, privacy and security researcher"). Geen woord toegevoegd dat /about niet gebruikt;ui-truthfulnesspint dat in beide richtingen.frontend/about.htmlop main.relay/lib/entitlements.js; 10 uploads per uur: de Community-kaart van ParaSend.relay/lib/tiers.js(transfers_month: 10,file_mb: 5), afgedwongen oprelay/relay.js:4598(402monthly_transfer_quota_reached) enrelay/relay.js:4551(413Max 5MBtegenMAX_BLOB). ParaSend Protransfers_month: 500uit dezelfde tabel.relay/relay.js:4306-4312,/v2/anon-inbound, DEPRECATED 2026-05-28,Sunset: Wed, 31 Dec 2026,ANON_RATE_PER_HOURdefault 10.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".relay/test/pricing-page.test.jsherrekent ze uitrelay/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:
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.jshad een regel "de verouderde 5 MB-claim isweg" die assert dat "5 MB" nergens op de pagina staat. Die reden was
verlopen:
relay/relay.jsweigert een groter bestand met 413Max 5MBtegenMAX_BLOB(default 5242880) enrelay/lib/tiers.jsgeeft elke tierfile_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:0enwhite-space:normallos 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.jsentests/site-claims.test.mjs(uitsluiting opgeheven).frontend/index.html,frontend/apply-nav.pyen
frontend/js/nav-auth.jszijn niet aangeraakt. Geen prijs en geen checkout-link gewijzigd. Wellimieten: die stonden fout op de pagina en staan nu zoals de relay ze afdwingt.
Open punten, niet in deze PR
frontend/index.htmldraagt dezelfde fout. Regel 360: "1 hour linkexpiry, burn on first read, 10 uploads per hour". Dat is hetzelfde
ANON_RATE_PER_HOURvan het afgekondigde/v2/anon-inbound, gepresenteerdals 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.
"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.
keuze, niet iets voor deze PR.