fix(cli): retire the remaining "free API key" and "Authorization" payment copy - #414
Open
KishiTheMechanic wants to merge 2 commits into
Open
KishiTheMechanic wants to merge 2 commits into
KishiTheMechanic wants to merge 2 commits into
Conversation
…ment copy #413 left four link-less "Get a free API key" prose sites behind, pending a copy ruling. That ruling is now recorded (elsoul/vs2-app#13261): the EUR 5 charge is a one-time payment that is captured in full, not a credit hold, and nothing the customer receives for it may be described as free. Two words are wrong against that ruling wherever they reach a customer: - "authorization" names one regulated step of a card transaction, not the purchase. Using it as the name of the whole purchase reads as a hold that will be released, which is false here. - "free" attached to something the EUR 5 buys is the UCPD Annex I point 20 shape (per se, no materiality test). Changes, scoped to customer-visible strings: - check: both "Get a free API key" sites now point at the ERPC dashboard, matching the phrasing already shipped in onboard (5 locales). - signup: "complete the EUR 5 payment authorization" -> "complete the one-time EUR 5 payment". - ai/console: "Complete Authorization (EUR 5) to receive 100,000 free AI tokens" -> "Complete the one-time EUR 5 payment to receive 100,000 AI tokens". The 100,000 grant is real and is what the EUR 5 buys, so the tokens are not free. - ai/product: the same sentence in the hardcoded product description, and the money-button label "Authorization" -> "Payment" (the sibling branch already labels its equivalent "Purchase"). - slv-benchmark SKILL.md + its dist mirror: same substitution in prose. Not touched: "free" attached to the erpc.global subdomain and to egress, which are included features and a pricing term rather than a price claim about the API key; and every internal identifier and HTTP Authorization header, none of which is customer-visible. No release is cut here and sh/install VERSION is untouched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ed skill docs The first review round on this PR (rocky, EN payment-register) returned FAIL: the CLI-side copy was repaired in 242c8ec, but 15 sites in the skill documentation still told readers the ERPC API key was free. Those docs ship to clawhub, so the false claim would have gone out with the release. Against the recorded ruling (elsoul/vs2-app#13261) the claim is simply untrue: an API key is issued only after a EUR 5 registration payment that is captured in full and is not refundable. There is no free tier, so "free" attached to the key is the UCPD Annex I point 20 shape — blacklisted per se, with no materiality test available. The repair drops the price adjective rather than qualifying it, and points at the issuance endpoint instead of the marketing site: - "ERPC API keys are free to obtain at https://erpc.global" -> "Get an ERPC API key at https://dashboard.erpc.global" (3 AGENT.md + 3 dist) - "ERPC API keys are free at https://erpc.global" -> "Get an ERPC API key at https://dashboard.erpc.global" (3 SKILL.md + 3 dist) - "Get a free one and add it to ~/.slv/api.yml" -> "Get one at https://dashboard.erpc.global and add it" (benchmark AGENT.md + dist) - "instruct the user to get a free key" -> "instruct the user to get their API key at https://dashboard.erpc.global" (slv-rpc SKILL.md; mirrors the phrasing already landed at slv-benchmark SKILL.md:65 in 242c8ec) These lines carried two defects each: a price claim, and a destination that cannot issue a key. Both are fixed. dist/oss-skills/** is a checked-in build mirror. build-skill-oss.sh copies SKILL.md/AGENT.md verbatim from oss-skills/**, but the committed mirror has drifted from its source, so regenerating would produce unrelated churn. Both trees are therefore edited by hand in this commit, as 242c8ec did. Measured, predicate `API key[s]? (are|is) free|free (one|key)|get a free|free to obtain` over *.md *.ts *.js *.json *.yml *.j2: BEFORE 15 rows -> AFTER 0 rows. Predicate liveness: the same predicate still returns 17 rows against parent c76986f, so the 0 is a real clearance and not a broken pattern. A widened gratis sweep (free / gratis / complimentary / no cost / no charge / zero cost / $0 / EUR 0) over the customer-visible doc trees returns 4 rows, none of them a claim about the API key: two `free -m` / "free port" command references, and the WireGuard app being free software (a third-party fact). deno check cli/src/index.ts: 12 pre-existing errors before and after, identical error set. No code paths touched. No release is cut here and sh/install VERSION is untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Follow-up to #413, which deliberately left four link-less "Get a free API key"
prose sites behind pending a copy ruling. The ruling is now recorded in
elsoul/vs2-app#13261: the EUR 5 charge is a one-time payment, captured in
full — not a credit hold — and nothing the customer receives for it may be
called free.
Two words break that ruling wherever they reach a customer:
authorizationnames one regulated step of a card transaction, not thepurchase. Used as the name of the whole purchase it reads as a hold that will
be released, which is false here.
freeattached to something the EUR 5 buys is the UCPD Annex I point 20shape — per se, no materiality test.
Sites changed
CLI strings (commit
242c8ecc)cli/src/check/index.ts:59Get a free API key and configure it first.Get your API key at ${ERPC_DASHBOARD_URL} and configure it first.cli/src/check/index.ts:344Get a free API key and configure ~/.slv/api.yml, …Get your API key at ${ERPC_DASHBOARD_URL} and configure ~/.slv/api.yml, …cli/src/signup/index.ts:15complete the €5 payment authorizationcomplete the one-time €5 paymentcli/src/ai/console/providers/slv.ts:139Complete Authorization (€5) to receive 100,000 free AI tokensComplete the one-time €5 payment to receive 100,000 AI tokenscli/src/ai/product/productAction.ts:80Complete Authorization to receive 100,000 free AI tokens and …Complete the one-time payment to receive 100,000 AI tokens and …cli/src/ai/product/productAction.ts:197formatLink('Authorization', …)formatLink('Payment', …)oss-skills/slv-benchmark/SKILL.md:65+dist/mirrorget a free API key and configure it first.get their API key at https://dashboard.erpc.global and configure it first.The
checkphrasing is not new:Get your API key: https://dashboard.erpc.globalalready ships in
cli/src/ai/onboard/onboardAction.tsacross 5 locales. Thisconverges four stray sites onto the string already in the binary.
The 100,000 AI tokens are real and are what the EUR 5 buys — the checkout path
applyAuthRegistrationCheckoutSession.tscallsgrantSlvAiFreeAuth, grantingSLV_AI_TOKENS.freeAuth = 100_000. So the grant stays in the copy; only theword
freegoes, because the tokens are paid for.The money-button label matters on its own: the sibling branch one block up
already labels its equivalent
Purchase, soAuthorizationwas the odd one outin the same list.
Shipped skill documentation (commit
e1cc94bb)The first review round on this PR returned FAIL (see Review record below):
the CLI copy above was repaired, but 15 further sites in the skill
documentation still told readers the API key was free. These docs ship to
clawhub, so the claim would have gone out with the release.
Each of these lines carried two defects — a price claim, and a destination
that cannot issue a key (
erpc.globalis the marketing site; keys are issued atdashboard.erpc.global). Both are fixed.ERPC API keys are free to obtain at https://erpc.global — **recommended for full monitoring**.Get an ERPC API key at https://dashboard.erpc.global — **recommended for full monitoring**.slv-validator,slv-rpc,slv-grpc-geyserAGENT.md×2 trees = 6ERPC API keys are free at https://erpc.global — enables full slot sync monitoring …Get an ERPC API key at https://dashboard.erpc.global — enables full slot sync monitoring …slv-validator,slv-rpc,slv-grpc-geyserSKILL.md×2 trees = 6You'll need an ERPC API key first. Get a free one and add it to ~/.slv/api.yml:You'll need an ERPC API key first. Get one at https://dashboard.erpc.global and add it to ~/.slv/api.yml:slv-benchmark/AGENT.md×2 trees = 2instruct the user to get a free key and configure it first.instruct the user to get their API key at https://dashboard.erpc.global and configure it first.oss-skills/slv-rpc/SKILL.md= 1The last row deliberately mirrors the phrasing already landed at
slv-benchmark/SKILL.md:65in242c8ecc, so the two sibling agentinstructions stay worded the same.
On the
dist/mirror:dist/oss-skills/**is a checked-in build artifact.build-skill-oss.shcopiesSKILL.md/AGENT.mdverbatim fromoss-skills/**,but the committed mirror has already drifted from its source (e.g.
slv-rpc/SKILL.mddiffers by 191 lines), so regenerating would produce largeunrelated churn. Both trees are therefore edited by hand in the same commit,
exactly as
242c8eccdid.Not touched (deliberate)
freeattached to the erpc.global subdomain and to egress(
onboardAction.ts,storage/product/productAction.ts+ i18n mirrors) —an included feature and a pricing term, not a price claim about the API key.
authorizationLink,AuthState,isSecureAuthorizationProduct) and every HTTPAuthorizationheader — nevercustomer-visible, and correct as a header name.
Secure Authorizationas the Stripe product name stays; only theimperative "Complete Authorization" as a call to action is replaced.
Receipts
All figures below were re-measured on the current head
e1cc94bb.BEFORE is measured at
c76986f5(the merge base withmain).Doc price claim — predicate
API key[s]? (are|is) free|free (one|key)|get a free|free to obtainover
*.md *.ts *.js *.json *.yml *.j2, excluding.git:242c8ecc)e1cc94bb)c76986f5The control matters: it proves the 0 is a real clearance rather than a predicate
that stopped matching. It returns 17 because it still sees the two
slv-benchmark/SKILL.mdrows that242c8ecchad already cleared.Widened gratis sweep (per reviewer request, so the measured population
matches the scope of the claim) —
free/gratis/complimentary/no cost/no charge/zero cost/$0/EUR 0over the customer-visible doc trees(
oss-skills,dist/oss-skills,docs,README.md): 4 rows, none a claimabout the API key —
free -mand "free port" (shell command references), andthe WireGuard app being free software (a true third-party fact).
CLI strings — repo-wide, excluding
.git:free api key(-i)payment authorization(-i)Complete Authorizationfree AI tokensPositive control on the same predicate shape (proves it can return non-zero):
one-time= 10,Get your API key= 9,dashboard.erpc.global= 34.Build / test:
deno check cli/src/index.ts: 12 errors before, 12 after, identical errorset (
diffof the sorted error sets returns rc=0). The 12 are pre-existingon
mainand unrelated to this PR; thee1cc94bbcommit touches.mdfilesonly, so no code path changed.
cd cli && deno test -A --config=deno.json test: 124 passed, 0 failed(rc=0) — the same command CI runs.
deno.lockis not in this PR: theERPC_DASHBOARD_URLimport intocheck/index.tsadds no dependency.Review record
An earlier revision of this description claimed this PR had passed the EN
payment-register review. That was wrong, and it is corrected here. The actual
sequence:
Round 1 —
rocky(stablecoin/payments register owner): FAIL. Three findings:API key was free. Fixed in
e1cc94bb— this is the substance of thesecond commit.
cli/src/ai/product/productAction.tsshows the "Complete the one-timepayment" description whenever the authorization state is not
authorized,including the
unknownstate. Out of scope for this PR — see below.Secure Authorizationstill reaches thecustomer's
Plan:line. Out of scope for this PR — brand/product naming,owned elsewhere.
Round 2 —
rocky: PASS. Verdict, verbatim on the substantive question:On whether these docs must also state the EUR 5 price, rather than only routing
to the issuance point:
The reviewer recorded one condition that is not a finding against this PR
and does not block it: this review certifies the doc strings only, not the
checkout surface at
dashboard.erpc.global, which is where the actualpre-contractual disclosure obligation sits (CRD Art 6(1)(e) / Art 8(2)). Whether
the EUR 5, its one-time nature and its refund treatment are disclosed clearly
and prominently there is owned by that surface, and is worth a separate look.
Findings deferred out of this PR
N1 —
productAction.tsauthorization-state asymmetry. Reproduced, and itpre-dates this PR: both lines are byte-identical at the merge base
c76986f5, so this PR neither introduced nor worsened it.The mechanism is not quite as first reported. The description string at line 80
has no state check at all — it is selected purely by product name. The
asymmetry is between two other lines:
productAction.ts:143—if (authorizationStatus.state !== 'authorized') return truekeeps the Secure Authorization product visible for all three states.
productAction.ts:194—authorizationStatus.state === 'unauthorized'renders the Payment link for one state only.
'unknown'is reachable:cli/src/ai/authorization.tsreturns it on a null ormalformed payload (:121), a non-OK HTTP response (:149), and a thrown fetch
(:160). So when the authorization endpoint is merely unreachable, the user is
shown an instruction to "Complete the one-time payment" with no payment link
to act on — and a customer who is in fact already authorized is told to pay
again. Worth a follow-up; not a copy defect, and not this PR's to fix.
N2 — Stripe product name.
Secure Authorizationstill reaches the customeras the
Plan:value. That is a product/brand naming decision, not a registerquestion, and is owned outside this repository.
Not in this PR
No release is cut here and
sh/installVERSION is untouched.Note for whoever ships this:
ValidatorsDAO/slvcannot currently produce arelease. Both the
testjob (for non-PR events) and theremote-buildjobtarget the self-hosted
slv-bm-runnersscale set, which has picked up no jobsince 2026-07-03; the #413 merge run
34401455125has been queued since2026-09-09. A tag push today would queue and never build. That is tracked
separately, and is why no tag accompanies this PR.
Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com
Co-Authored-By: Claude Opus 5 noreply@anthropic.com