feat: price med-arb by phase, attest the conflicts undertaking, and answer the first real spam
Build and deploy / build-and-deploy (push) Failing after 4s
Build and deploy / build-and-deploy (push) Failing after 4s
Pouya's rulings of 2026-09-03 (the last two D20 findings) and 2026-09-04 (the spam observation and four mitigations), in one change set. D20 finding 10 — med-arb is billed BY PHASE, each phase at the rates already published, so /fees/'s "Every figure is on this page" is true as written rather than narrowed. FEES.medArb is the single source; docs/07 §Med-arb carries the rule INTERIM against R5, and R5 now carries it back, because a derived price moves silently when a rate moves. D20 finding 13 — conduct undertaking (g), attested 2026-09-03, published as his wording verbatim on /legal/privacy/ and /contact/. The clause that raised the finding promised to DISCLOSE a conflicts check's outcome, which the attestation does not cover; it is struck. D20 now partitions 17 fixed / 2 refuted / 1 owed. Spam, 2026-09-04 — recorded in docs/05 §Observed abuse with the date and signature. A second honeypot (a decoy checkbox, own class, `hidden`, a label that tells a human not to tick it) and scoring that LABELS and never rejects: nothing is dropped, nothing new is stored, and only the operator notification changes. Q65 opens the WAF cost call. The timing floor could not be built: there is no timing check and never has been. docs/05 carries it struck, and every mechanism that would give a real per-visitor clock breaks zero-JS, handler-and-form-only, or D1. Q66. configure.mjs gains section 5 — a custom origin request policy forwarding CloudFront-Viewer-Address on /api/*. Written, dry-run against the live distribution, NOT applied. It reads the handler's own header reads and refuses to run if the whitelist omits one. And reading the live account to do it found four AGENTS.md §7 rows saying the intake backend was undeployed, two days after it went live — corrected against get-function-configuration, get-routes, get-stage, get-policy and the deployed zip, which was downloaded and read. Review: adversarial-reviewer only (claims-auditor is D20's cutover pass and has run). Round 1 five lenses, 56 findings, 7 blocking, 4 refuted by an independent refuter; round 2 four lenses, 36 findings, 33 of them defects in round 1's own repairs. Stopped at two per D19. Gates, exit status read for each: check 0 · build 0 (23 pages) · check:claims 0 · check:intake 0 · og:proof 0 · lint 0 · spam-score.test 39/39 with 6/6 mutations killed · router.test 30/30 · minifier grep 1 (clean) · lighthouse 0, no category below 95 · configure.mjs dry run 0, nothing written. Nothing deployed and nothing applied. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5
This commit is contained in:
co-authored by
Claude Opus 5
parent
02739adac9
commit
3c3ba5dc6e
@@ -31,7 +31,7 @@ The second is what the neutral will actually do. That is a different question, a
|
||||
## What I undertake
|
||||
|
||||
{/* ⚠️ RENDERED FROM `CONDUCT_UNDERTAKINGS`, NEVER TYPED — §4's third class says
|
||||
so in terms: "The six strings live in `CONDUCT_UNDERTAKINGS` in
|
||||
so in terms: "The strings live in `CONDUCT_UNDERTAKINGS` in
|
||||
`src/data/site.ts` and the pages render them, so the diff that would soften
|
||||
one is visible on one constant rather than distributed through three
|
||||
templates." They were hand-typed here in the first draft, which put a fourth
|
||||
|
||||
+65
-8
@@ -10,8 +10,15 @@
|
||||
*
|
||||
* What stops the two drifting is a check rather than a shared import:
|
||||
* **`npm run check:intake`** asserts that the two tables agree on every field
|
||||
* name, on which are required, and on every length cap — and fails the build
|
||||
* script if they do not. Independent validation, mechanically cross-checked. If
|
||||
* name, on which are required, on every length cap, and — since 2026-09-04 — on
|
||||
* both honeypot names.
|
||||
*
|
||||
* ⚠️ **IT IS A KEYBOARD GATE, NOT A DEPLOY GATE, AND THIS COMMENT SAID IT "fails
|
||||
* the build script".** It does not: `npm run build` is `astro build`, and
|
||||
* `scripts/deploy-local.sh` runs `check`, `build` and `check:claims` and not this
|
||||
* one. Run it yourself. A control described as running where it does not is
|
||||
* `AGENTS.md` Q22, and this change set makes this check the only thing keeping
|
||||
* the second honeypot's two names in step. Independent validation, mechanically cross-checked. If
|
||||
* you add a field here, add it there, and the check will tell you if you didn't.
|
||||
*
|
||||
* WHAT THIS DATA IS, because it changes how the form is built (`docs/05`): in a
|
||||
@@ -200,6 +207,50 @@ export const CONSENT_TEXT =
|
||||
*/
|
||||
export const HONEYPOT_FIELD = 'company_website';
|
||||
|
||||
/**
|
||||
* THE SECOND HONEYPOT, AND IT IS A DIFFERENT TRAP RATHER THAN A SECOND COPY OF
|
||||
* THE FIRST. Pouya's ruling, 2026-09-04, after two automated submissions walked
|
||||
* through `HONEYPOT_FIELD` (`docs/05` §Observed abuse).
|
||||
*
|
||||
* ⚠️ **THE MECHANISM IS INVERTED, WHICH IS THE POINT.** `HONEYPOT_FIELD` is a
|
||||
* text input that must arrive EMPTY — it catches a bot that fills every input it
|
||||
* finds. The pair of 2026-09-04 did not fill it, so a second field of the same
|
||||
* kind would catch them exactly as well as the first did: not at all.
|
||||
*
|
||||
* This is a CHECKBOX, and what it catches is a bot that sets every control it
|
||||
* enumerates rather than one that fills every text field.
|
||||
*
|
||||
* ⚠️ **WHAT IT IS AIMED AT, AND WHAT THE EVIDENCE ACTUALLY SUPPORTS — READ THIS
|
||||
* BEFORE RELYING ON IT.** An earlier version of this comment said the decoy
|
||||
* targets *"a behaviour anything reaching validation must have"*, because the
|
||||
* consent box is required and unchecked by default, so a submission that
|
||||
* validated must have sent `consent=on`. **That argument does not survive its own
|
||||
* premise.** The 2026-09-04 pair did NOT fill the text honeypot, so they are
|
||||
* selective about hidden fields — and a bot selective enough to skip a hidden
|
||||
* text input is selective enough to skip a hidden checkbox. Sending `consent=on`
|
||||
* shows only that it knows one field name, not that it ticks everything it finds.
|
||||
*
|
||||
* **So this trap is very likely INERT against the traffic it was built from**,
|
||||
* and it is defence in depth against a different and common class: the bot that
|
||||
* enumerates controls and sets all of them. That is worth having and it is not
|
||||
* what the observation proved. `docs/05` §Observed abuse states the same limit;
|
||||
* the two must not drift, because the tempting sentence is the confident one.
|
||||
*
|
||||
* ⚠️ **ABSENCE IS THE PASS, AND SO IS AN EMPTY VALUE.** A browser sends nothing
|
||||
* at all for an unchecked box, so every way this field can fail to arrive — a
|
||||
* stripping extension, a proxy, a future template that drops it — reads as a
|
||||
* HUMAN; and a serialiser that emits `updates_optin=` without reading the
|
||||
* checked state reads as one too, because the handler tests for a NON-EMPTY
|
||||
* value rather than for presence. The failure mode of a trap is a lost legal
|
||||
* inquiry that looks like a successful one, and this trap fires only on
|
||||
* something that deliberately ticked a box no person can see.
|
||||
*
|
||||
* The name is a plausible marketing opt-in, which is what a bot expects to find
|
||||
* and a real form here does not have. Hidden the same way as the first — the
|
||||
* hiding is standard, the mechanism is not.
|
||||
*/
|
||||
export const DECOY_CHECKBOX_FIELD = 'updates_optin';
|
||||
|
||||
/**
|
||||
* WHERE THE FORM POSTS — AND IT IS A SAME-ORIGIN PATH, NOT THE API GATEWAY
|
||||
* HOSTNAME. This is a design decision with four consequences, taken at step 8
|
||||
@@ -209,6 +260,13 @@ export const HONEYPOT_FIELD = 'company_website';
|
||||
* Posting to `/api/intake` instead, with a CloudFront behaviour routing `/api/*`
|
||||
* to that origin:
|
||||
*
|
||||
* ⚠️ **AND IT IS ALL LIVE SINCE 2026-09-02** — see the closing paragraph of this
|
||||
* block. The same stale sentence was corrected in `handler.mjs`, `docs/01` and
|
||||
* `docs/05` before it was corrected here; this note was added, in the same pass,
|
||||
* ABOVE a paragraph that still said the opposite twenty lines below it. **A note
|
||||
* asserting a correction is not the correction**, and the two sat contradicting
|
||||
* each other until `adversarial-reviewer` round 2.
|
||||
*
|
||||
* 1. **`Content-Security-Policy: form-action 'self'`** — `docs/05` specifies
|
||||
* `form-action 'self' <api-endpoint>`; with a same-origin post the second
|
||||
* term is unnecessary, so the policy is strictly tighter.
|
||||
@@ -229,11 +287,10 @@ export const HONEYPOT_FIELD = 'company_website';
|
||||
* a POST 404s. Under the alternative, clicking Submit on a laptop would
|
||||
* write a real DynamoDB record and send two real emails.
|
||||
*
|
||||
* ⚠️ **THE COST, STATED RATHER THAN LEFT TO BE DISCOVERED: THE FORM DOES NOT
|
||||
* WORK UNTIL THAT CLOUDFRONT BEHAVIOUR EXISTS AND THE HANDLER IS DEPLOYED.**
|
||||
* Neither has been done — nothing on this project deploys before cutover (D11),
|
||||
* and both are checklist items in `docs/06`. Until then the page is complete and
|
||||
* the pipe behind it is not, which is why `/contact/` also publishes the email
|
||||
* address rather than treating the form as the only way in.
|
||||
* ⚠️ **THE COST, WHICH WAS REAL AND IS NOW PAID: THE FORM DID NOT WORK UNTIL
|
||||
* THAT CLOUDFRONT BEHAVIOUR EXISTED AND THE HANDLER WAS DEPLOYED.** Both ran at
|
||||
* cutover on 2026-09-02 — `AGENTS.md` §7 holds the state and this comment does
|
||||
* not restate it. `/contact/` still publishes the email address beside the form,
|
||||
* which is now a courtesy rather than a fallback.
|
||||
*/
|
||||
export const INTAKE_ACTION = '/api/intake';
|
||||
|
||||
+60
-2
@@ -303,7 +303,12 @@ export const NEUTRAL_ROLE_LINE =
|
||||
'party should have their own legal advice.';
|
||||
|
||||
/**
|
||||
* THE SIX CONDUCT UNDERTAKINGS — Q54, ANSWERED BY POUYA 2026-08-29.
|
||||
* THE CONDUCT UNDERTAKINGS — Q54, ANSWERED BY POUYA 2026-08-29, plus (g).
|
||||
*
|
||||
* ⚠️ **(a)–(f) ARE Q54's SIX. (g) IS NOT** — it was attested 2026-09-03 to
|
||||
* close D20 finding 13 and carries its own stamp on the object below. The
|
||||
* heading no longer states a count: this comment said "THE SIX" while the
|
||||
* object held seven for exactly as long as it took to notice.
|
||||
*
|
||||
* A THIRD CLASS OF CLAIM, and the class is his: not a credential (a fact about
|
||||
* him, §4 Verified) and not an offering (a process the practice conducts, §4
|
||||
@@ -365,7 +370,26 @@ export const CONDUCT_UNDERTAKINGS = {
|
||||
arbitrationAwardDate:
|
||||
'The date the award is due is fixed in the first procedural order rather ' +
|
||||
'than left open.',
|
||||
} as const; // [verified 2026-08-29 — Pouya, Q54]
|
||||
/**
|
||||
* (g) `/legal/privacy/` — the conflicts check. **ATTESTED 2026-09-03 by
|
||||
* Pouya, closing D20 finding 13.** It is NOT one of the Q54 six: its own
|
||||
* date, its own ruling, and it is stamped separately below.
|
||||
*
|
||||
* The page was already stating a conflicts undertaking in prose, and §4's
|
||||
* gate for this class is one line — he must have made it IN TERMS. He now
|
||||
* has, so the sentence is rendered from here rather than typed there.
|
||||
*
|
||||
* ⚠️ **IT IS HIS WORDING, NOT A RENDERING OF IT, AND THAT IS THE WHOLE GATE.**
|
||||
* The attestation is *"runs a conflicts check on every inquiry before
|
||||
* engaging"*. This string shipped for one round as *"before I accept an
|
||||
* appointment"* — the site's own vocabulary, defensible, and **a paraphrase of
|
||||
* a commitment the page publishes as his**. §4's gate for this class is that
|
||||
* he made it IN TERMS, and a substitution recorded in a code comment is not
|
||||
* that. Do not smooth it back. If "engaging" turns out to be the wrong verb,
|
||||
* the fix is a second attestation, never an edit here.
|
||||
*/
|
||||
conflictsCheck: 'I run a conflicts check on every inquiry before engaging.',
|
||||
} as const; // (a)–(f) [verified 2026-08-29 — Pouya, Q54]; (g) [attested 2026-09-03 — Pouya]
|
||||
|
||||
/**
|
||||
* THE HELD-DESIGNATIONS SENTENCE, RENDERED AND NEVER RETYPED.
|
||||
@@ -552,6 +576,40 @@ export const FEES = {
|
||||
* it, and do not price it.
|
||||
*/
|
||||
hourly: 500, // [verified 2026-08-26]
|
||||
/**
|
||||
* MED-ARB IS BILLED BY PHASE, AND THAT IS WHY THERE IS NO NUMBER IN HERE.
|
||||
*
|
||||
* Pouya's ruling, 2026-09-03, closing D20 finding 10. `/fees/` opens *"Every
|
||||
* figure is on this page"* while §4 Offerings carries a **Med-Arb** row that
|
||||
* `docs/07-fees.md` priced nowhere — so the promise was wider than the card.
|
||||
* The ruling closes it by pricing the offering out of the two rate sets that
|
||||
* are already published rather than by narrowing the promise: each phase is
|
||||
* charged at the rates for that process, so no third set of figures exists
|
||||
* and the sentence becomes true as written.
|
||||
*
|
||||
* ⚠️ **THERE IS NO `amount` HERE ON PURPOSE. Do not add one.** A med-arb
|
||||
* figure would be a fourth price for a process priced twice already, and the
|
||||
* first thing it would do is disagree with one of them.
|
||||
*
|
||||
* ⚠️ **`termsApply` SAYS "as they apply to that process on its own", NOT
|
||||
* "to both phases".** The additional-party fee is a MEDIATION row; the
|
||||
* arbitration card has no equivalent. Saying the terms apply to each phase as
|
||||
* they apply to that process invents nothing; saying they apply throughout
|
||||
* would invent an additional-party charge in the arbitral phase.
|
||||
*
|
||||
* INTERIM, set 2026-09-03, reviewed at the §12 R5 twelve-month fee review.
|
||||
* `docs/07` §Med-arb — billed by phase carries the rule and the same stamp.
|
||||
*/
|
||||
medArb: {
|
||||
rule:
|
||||
'Med-arb is billed by phase. The mediation phase is charged at the ' +
|
||||
'mediation rates above. If the matter proceeds to arbitration, that ' +
|
||||
'phase is charged at the arbitration rates above.',
|
||||
noSeparateFee: 'There is no separate med-arb fee.',
|
||||
termsApply:
|
||||
'The additional-party and cancellation terms apply to each phase as ' +
|
||||
'they apply to that process on its own.',
|
||||
}, // [verified 2026-09-03 — Pouya, interim; R5]
|
||||
cancellation: [
|
||||
{ window: 'More than 30 days before', fee: 'No fee. Disbursements only.' },
|
||||
{ window: '15 to 30 days before', fee: '50% of the booked fee.' },
|
||||
|
||||
+64
-7
@@ -38,15 +38,21 @@
|
||||
*/
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Button from '../components/Button.astro';
|
||||
import Undertaking from '../components/Undertaking.astro';
|
||||
import ContactBand from '../components/ContactBand.astro';
|
||||
import Eyebrow from '../components/Eyebrow.astro';
|
||||
import SectionHeading from '../components/SectionHeading.astro';
|
||||
import { getImage } from 'astro:assets';
|
||||
import ogDefault from '../assets/og-portrait.jpg';
|
||||
import { pageGraph } from '../data/schema';
|
||||
import { CONTACT, NO_RETAINER_NOTICE } from '../data/site';
|
||||
import {
|
||||
CONDUCT_UNDERTAKINGS,
|
||||
CONTACT,
|
||||
NO_RETAINER_NOTICE,
|
||||
} from '../data/site';
|
||||
import {
|
||||
CONSENT_TEXT,
|
||||
DECOY_CHECKBOX_FIELD,
|
||||
HONEYPOT_FIELD,
|
||||
INTAKE_ACTION,
|
||||
INTAKE_FIELDS,
|
||||
@@ -117,11 +123,20 @@ const hintId = (name: string) => `${name}-hint`;
|
||||
</div>
|
||||
<div class="prose">
|
||||
<p class="statement">{NO_RETAINER_NOTICE}</p>
|
||||
<p>I ask for the other parties and their counsel for one reason.</p>
|
||||
{
|
||||
/* RENDERED FROM `CONDUCT_UNDERTAKINGS`, NEVER TYPED — undertaking (g).
|
||||
⚠️ THIS PAGE HAND-TYPED THE SAME PROPOSITION AS *"I cannot accept an
|
||||
appointment before conflicts are checked"* UNTIL 2026-09-04, and it
|
||||
survived the change set that struck the identical sentence from
|
||||
`/legal/privacy/` — one file swept, its sibling missed, which is the
|
||||
shape R8 exists for. §4 row (g) lists BOTH surfaces. */
|
||||
}
|
||||
<Undertaking>{CONDUCT_UNDERTAKINGS.conflictsCheck}</Undertaking>
|
||||
<p>
|
||||
I ask for the other parties and their counsel because I cannot accept
|
||||
an appointment before conflicts are checked, and that check needs
|
||||
names. Please keep the summary short and leave privileged or
|
||||
confidential detail out of it — the call is for that.
|
||||
That check needs names, and the call above is where it happens. Please
|
||||
keep the summary short and leave privileged or confidential detail out
|
||||
of it — the call is for that.
|
||||
</p>
|
||||
<p>
|
||||
What is collected, where it is stored, how long it is kept, and how to
|
||||
@@ -248,7 +263,13 @@ const hintId = (name: string) => `${name}-hint`;
|
||||
the form: a browser that helpfully fills a plausible-looking field
|
||||
would make a human look like a bot. */
|
||||
}
|
||||
<div class="honeypot" aria-hidden="true">
|
||||
{
|
||||
/* `hidden` ADDED 2026-09-04, for the reason spelled out on the decoy
|
||||
below: a class-only rule leaves this field on screen wherever author
|
||||
styles do not apply, and a visitor who fills it loses their inquiry
|
||||
behind a success page. */
|
||||
}
|
||||
<div class="honeypot" hidden aria-hidden="true">
|
||||
<label for={HONEYPOT_FIELD}>Company website</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -287,6 +308,41 @@ const hintId = (name: string) => `${name}-hint`;
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{
|
||||
/* THE SECOND HONEYPOT — a decoy CHECKBOX. The mechanism, and the
|
||||
limits of what the observed spam supports, are in `src/data/intake.ts`
|
||||
and are not restated here. Four properties of the MARKUP, each of
|
||||
which is what stops this field costing a real inquiry:
|
||||
|
||||
· its own CLASS NAME, not `.honeypot` — one selector must not
|
||||
match both traps. They share a declaration block below, which is
|
||||
presentation; what matters is that `.honeypot` does not select
|
||||
this one;
|
||||
· placed after the consent block, not beside the other honeypot;
|
||||
· `hidden` as well as the CSS rule, so it stays hidden where
|
||||
author styles do not apply;
|
||||
· a label that tells a human not to tick it. With `hidden` in
|
||||
place a human essentially cannot see it, so this is the last
|
||||
line rather than the first — and it costs almost nothing,
|
||||
because the PLAUSIBLE NAME is what a bot matches on and the name
|
||||
is unchanged.
|
||||
|
||||
⚠️ NO `required`, AND NO `checked`. An unchecked box sends nothing,
|
||||
so absence is the pass — and the handler tests for a NON-EMPTY value,
|
||||
so an empty one passes too. */
|
||||
}
|
||||
<div class="optin-decoy" hidden aria-hidden="true">
|
||||
<label for={DECOY_CHECKBOX_FIELD}>Leave this box unticked.</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={DECOY_CHECKBOX_FIELD}
|
||||
name={DECOY_CHECKBOX_FIELD}
|
||||
value="on"
|
||||
tabindex="-1"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
/* ⚠️ `<Button type="submit">`, NOT a hand-written `<button class="btn">`.
|
||||
`.btn` and `.btn-primary` are SCOPED TO `Button.astro`, so a raw
|
||||
@@ -505,7 +561,8 @@ const hintId = (name: string) => `${name}-hint`;
|
||||
the input are belt and braces for the case where a future stylesheet
|
||||
un-hides it. Do not swap this for `visibility` or an off-screen position:
|
||||
an off-screen input is still focusable and still announced. */
|
||||
.honeypot {
|
||||
.honeypot,
|
||||
.optin-decoy {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
+42
-4
@@ -36,6 +36,17 @@
|
||||
* sentence ships **adjacent to the overtime row**, not in a footnote. Same
|
||||
* structural rule as `PROCESS_FRAMING` beside the five timings under Q43.
|
||||
*
|
||||
* ✅ **MED-ARB IS PRICED HERE AS OF 2026-09-03, AND IT CARRIES NO FIGURE.**
|
||||
* Pouya's ruling closing D20 finding 10: it is billed **by phase**, each phase
|
||||
* at the rates already on this page. The finding was that the hero promises
|
||||
* *"Every figure is on this page"* while §4 Offerings carries a Med-Arb row
|
||||
* that `docs/07` priced nowhere — a promise wider than the card. It is closed by
|
||||
* pricing the offering, not by narrowing the promise, so the hero sentence is
|
||||
* unchanged and is now true as written. **Do not give the section a rate row:**
|
||||
* a med-arb figure would be a fourth price for a process priced twice, and the
|
||||
* first thing it would do is disagree with one of them. `FEES.medArb` holds the
|
||||
* three sentences; `docs/07` §Med-arb holds the rule. INTERIM, reviewed at R5.
|
||||
*
|
||||
* ⚠️ **NO TRIBUNAL-SECRETARY RATE AND NO SETTLEMENT COUNSEL.** Both are struck
|
||||
* rows in §4 Offerings — the first removed by Pouya from D14, the second by him
|
||||
* as his own error in `docs/01`. **A rate on a fee page is an offer**, which is
|
||||
@@ -240,8 +251,35 @@ const ARBITRATION_ROWS = [
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ---- 4. Other services ---------------------------------------------- */}
|
||||
{/* ---- 4. Med-arb ------------------------------------------------------ */}
|
||||
<section class="section section-alt reveal">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<SectionHeading
|
||||
eyebrow="Med-arb"
|
||||
level={2}
|
||||
lede="One appointment, two processes. Each phase is charged at the rates for that process."
|
||||
>
|
||||
<span slot="heading">Billed by phase.</span>
|
||||
</SectionHeading>
|
||||
</div>
|
||||
{
|
||||
/* NO `<dl class="rates">` HERE, AND THE ABSENCE IS THE POINT — see the
|
||||
header. Every other section on this page pairs an item with a figure;
|
||||
this one has no figure of its own, and giving it a row would mean
|
||||
inventing one. The three sentences come from `FEES.medArb` so the rule
|
||||
lives beside the numbers it points at rather than in this template. */
|
||||
}
|
||||
<ul class="notes" role="list">
|
||||
<li>{FEES.medArb.rule}</li>
|
||||
<li>{FEES.medArb.noSeparateFee}</li>
|
||||
<li>{FEES.medArb.termsApply}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ---- 5. Other services ---------------------------------------------- */}
|
||||
<section class="section reveal">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<SectionHeading
|
||||
@@ -304,8 +342,8 @@ const ARBITRATION_ROWS = [
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ---- 5. Cancellation ------------------------------------------------ */}
|
||||
<section class="section reveal">
|
||||
{/* ---- 6. Cancellation ------------------------------------------------ */}
|
||||
<section class="section section-alt reveal">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<SectionHeading
|
||||
@@ -334,7 +372,7 @@ const ARBITRATION_ROWS = [
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ---- 6. Terms -------------------------------------------------------- */}
|
||||
{/* ---- 7. Terms -------------------------------------------------------- */}
|
||||
<section class="section section-inverse reveal">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
|
||||
@@ -59,10 +59,16 @@
|
||||
*/
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Eyebrow from '../../components/Eyebrow.astro';
|
||||
import Undertaking from '../../components/Undertaking.astro';
|
||||
import { getImage } from 'astro:assets';
|
||||
import ogDefault from '../../assets/og-portrait.jpg';
|
||||
import { pageGraph } from '../../data/schema';
|
||||
import { ANALYTICS, CONTACT, SITE } from '../../data/site';
|
||||
import {
|
||||
ANALYTICS,
|
||||
CONDUCT_UNDERTAKINGS,
|
||||
CONTACT,
|
||||
SITE,
|
||||
} from '../../data/site';
|
||||
import { INTAKE_FIELDS } from '../../data/intake';
|
||||
|
||||
const ldImage = await getImage({
|
||||
@@ -85,7 +91,7 @@ const RETENTION_MONTHS = 24;
|
||||
|
||||
/** Bump this on ANY substantive edit. A privacy policy with a stale date is a
|
||||
* policy a reader cannot tell they are reading an old version of. */
|
||||
const LAST_UPDATED = '3 September 2026';
|
||||
const LAST_UPDATED = '4 September 2026';
|
||||
|
||||
/* Rendered from the form's own field list, so the two cannot drift. `consent`
|
||||
and the honeypot are absent from `INTAKE_FIELDS` deliberately and are
|
||||
@@ -160,15 +166,34 @@ const COLLECTED = INTAKE_FIELDS.map((field) => field.label);
|
||||
<p>
|
||||
The form asks for the other parties to the dispute and their counsel.
|
||||
That is information about people who have not filled in the form and
|
||||
may not know it was sent. It is asked for one reason: I cannot accept
|
||||
an appointment before conflicts are checked, and the check needs
|
||||
names.
|
||||
may not know it was sent. It is asked for one reason, and the reason
|
||||
is a commitment rather than an observation.
|
||||
</p>
|
||||
{
|
||||
/* `<Undertaking>` AND `CONDUCT_UNDERTAKINGS`, NEVER TYPED PROSE —
|
||||
§4's third class, whose characteristic failure mode is that a
|
||||
promise gets quietly smaller and nothing fails. Undertaking (g),
|
||||
attested 2026-09-03.
|
||||
|
||||
⚠️ IT IS THE COMPONENT FOR THE REASON THE COMPONENT EXISTS: one
|
||||
treatment on every page, so a reader can tell a promise from a
|
||||
description. This shipped for one pass as an ordinary paragraph in
|
||||
`“`/`”` — the only such entities in `src/`, and a
|
||||
commitment set as body prose reads as another sentence about
|
||||
process.
|
||||
|
||||
It REPLACED the hand-typed "I cannot accept an appointment before
|
||||
conflicts are checked", which stated the same proposition as a
|
||||
constraint; keeping both would have set the undertaking beside its
|
||||
own paraphrase — the (e)/(f) treatment. */
|
||||
}
|
||||
<Undertaking>{CONDUCT_UNDERTAKINGS.conflictsCheck}</Undertaking>
|
||||
<p>
|
||||
Please give names and nothing more about them. The form asks you not
|
||||
to include privileged or confidential detail anywhere in it, and the
|
||||
summary field says so directly. There is deliberately no field for
|
||||
amounts in dispute and no way to attach a document.
|
||||
The check needs names. Please give names and nothing more about them.
|
||||
The form asks you not to include privileged or confidential detail
|
||||
anywhere in it, and the summary field says so directly. There is
|
||||
deliberately no field for amounts in dispute and no way to attach a
|
||||
document.
|
||||
</p>
|
||||
|
||||
<h2>Why it is collected, and on what basis</h2>
|
||||
@@ -340,11 +365,21 @@ const COLLECTED = INTAKE_FIELDS.map((field) => field.label);
|
||||
delete it before the {RETENTION_MONTHS} months are up.
|
||||
{' '}{CONTACT.responseTime}
|
||||
</p>
|
||||
{
|
||||
/* ⚠️ THE CLAUSE THAT WAS HERE PROMISED TO DISCLOSE THE OUTCOME OF A
|
||||
CONFLICTS CHECK — *"I will tell you what its outcome was rather than
|
||||
pretending the inquiry did not happen"* — and that is an UNDERTAKING,
|
||||
which §4 may publish only where Pouya has made it in terms. He had
|
||||
not. D20 finding 13, and it is closed by his attestation of
|
||||
2026-09-03, which covers RUNNING the check and says nothing about
|
||||
reporting it. The sentence now states what deletion does not undo and
|
||||
stops there. Do not restore the promise without a second attestation:
|
||||
it is a different commitment from the one he made. */
|
||||
}
|
||||
<p>
|
||||
Deletion removes the record. It does not retract the emails already
|
||||
sent, and if a conflicts check has already been run I will tell you
|
||||
what its outcome was rather than pretending the inquiry did not
|
||||
happen.
|
||||
sent, and it does not undo a conflicts check that has already been
|
||||
run.
|
||||
</p>
|
||||
|
||||
<h2>What an inquiry is not</h2>
|
||||
|
||||
Reference in New Issue
Block a user