fix: resolve adversarial review round 2 — 9 findings, 8 of them in round 1's fixes
Build and deploy / build-and-deploy (push) Failing after 4s
Build and deploy / build-and-deploy (push) Failing after 4s
D19 caps the loop at two rounds, and this is what the second round is for. BLOCKING. Round 1 made NO_RETAINER_NOTICE a requireEnv and added it to no document, while the fix's own comment claimed docs/06 named it. The deployment list said five variables for a handler that needs six, so an operator following the cutover checklist would have deployed a function that throws at cold start on every invocation — 5xx from API Gateway, every inquiry lost from the moment /api/* was wired, loud in CloudWatch and silent to Pouya. docs/05 and docs/06 now name all six, and the comment that asserted the documentation existed is corrected rather than deleted. The intake route check added in round 1 could not fail: curl -w already prints 000 on a failed transfer, so `|| echo 000` double-appended and the failure arm was unreachable, and the pass arm accepted anything that was not literally 404 — including the 403 CloudFront returns when the /api/* behaviour is missing, which is the one distinction the check exists to draw. It now sends the correct Origin and asserts a positive: 303 to /contact/could-not-send/, which the handler returns before any DynamoDB write or email. Probed on refused/501/403/303; the old version passed the first three. Fixed in both deploy paths. Removing priceRange left three statements saying it was present or pending, one of them the stated reason /fees/ emits no Offer node. Deleting overtimeStartsAfterSessionHours left AGENTS.md §9 naming it and left Q59 recorded as open. The Google-as-processor fix was applied to the privacy policy's "Where it is stored" and not to "Who can see it", which still read "Nobody else has access". And the variable removal was justified with a path-scoped git grep — which also cannot see untracked files. The unscoped sweep found docs/06's variable table, the OIDC example, and .env.example still carrying them; .env.example also restates the execute-api hostname, falsifying a live claim in intake.ts that has been corrected. That file is not edited here: this environment denies read access to it, and nothing may edit a file it cannot read. It is in the batched list. Also: og:image:alt was the page title rather than the card's headline on 20 pages; og-card.ts documented the wrong path and invocation for the contact sheet; deploy-local.sh still said Q22's deploy credential "does NOT yet exist"; and the round-1 fix comments were trimmed per D19, though the ratio held at 0.44. Round 2 also confirmed the round-1 fixes by measurement: all 56 .btn instances across 22 pages, the consent checkbox's computed accessible name, the radio labels hit-tested at 44px, and og:proof exercised against synthetic article pages in a sandbox. Verified: check/build/check:claims/og:proof/check:intake/lint/bio:pdf all exit 0 on a clean build; 22 pages; Lighthouse 99-100 / 100 / 100 / 100, CLS 0.000. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5
This commit is contained in:
co-authored by
Claude Opus 5
parent
9f2d83c32f
commit
9f2d2eeb04
+41
-7
@@ -162,10 +162,31 @@ they are useful for debugging.
|
||||
| `AWS_REGION` | `AGENTS.md` §7 — Region |
|
||||
| `S3_BUCKET` | §7 — S3 bucket |
|
||||
| `CLOUDFRONT_DISTRIBUTION_ID` | §7 — CloudFront |
|
||||
| `INTAKE_ENDPOINT` | §7 — Intake API |
|
||||
| `BOOKING_URL` | *(empty — parked, R6)* |
|
||||
|
||||
The same four values fill the IAM policy's `BUCKET_NAME`, `ACCOUNT_ID` and
|
||||
⚠️ **`INTAKE_ENDPOINT` AND `BOOKING_URL` WERE ROWS HERE AND ARE GONE, 2026-08-31.**
|
||||
Build step 8 moved the intake form to the same-origin path `/api/intake`, after
|
||||
which nothing in the build read either one — and both deploy paths were still
|
||||
refusing to run without `INTAKE_ENDPOINT`. **The removal was made in the two
|
||||
scripts and not here**, so this table went on telling an operator to set a
|
||||
variable no guard checked and no build consumed. Found by
|
||||
`adversarial-reviewer` round 2, whose sharper point is about the evidence: the
|
||||
removal was justified with `git grep PUBLIC_INTAKE_ENDPOINT -- src/` — a
|
||||
**path-scoped** grep offered as proof of a repo-wide removal, and `git grep`
|
||||
additionally cannot see untracked files, which at that moment was most of the new
|
||||
work. That is `CLAUDE.md`'s *a sweep is a command, not a claim* and *sweep the
|
||||
vocabulary, not only the subject*, both at once.
|
||||
|
||||
⚠️ **AND ONE PLACE STILL CARRIES IT: `.env.example` sets
|
||||
`PUBLIC_INTAKE_ENDPOINT` to the full execute-api hostname, and
|
||||
`PUBLIC_BOOKING_URL`.** That falsifies a live claim in `src/data/intake.ts` —
|
||||
which said the endpoint id *"is not restated in the repo either"* — and the claim
|
||||
has been corrected there rather than left standing. **The file itself was not
|
||||
edited: this environment denies read access to it, and nothing in this repo may
|
||||
edit a file it cannot read.** It is in the batched list for Pouya: delete both
|
||||
lines, and `PUBLIC_ANALYTICS_*` with them, since `ANALYTICS` is a literal in
|
||||
`src/data/site.ts`.
|
||||
|
||||
The three values above fill the IAM policy's `BUCKET_NAME`, `ACCOUNT_ID` and
|
||||
`DISTRIBUTION_ID` placeholders. **They are deliberately not restated here** —
|
||||
§7 is the single source of truth for operational facts, and the copy that goes
|
||||
stale is always the one nobody re-reads. `scripts/aws-discover.sh` regenerates
|
||||
@@ -438,10 +459,23 @@ Then invalidate `/*`.
|
||||
this behaviour the form 404s.
|
||||
2. **Deploy `backend/intake/handler.mjs` + `backend/intake/fields.mjs`**,
|
||||
replacing the hand-built `adr-intake-handler` §7 records. It needs
|
||||
`INTAKE_TABLE`, `SITE_ORIGIN`, `NOTIFY_TO`, `MAIL_FROM` and
|
||||
`RESPONSE_TIME` set; it throws at cold start on any missing one, on
|
||||
purpose. `RESPONSE_TIME` must be `CONTACT.responseTime` verbatim — it is
|
||||
a public commitment (§4, Q27) and must read identically on `/contact/`,
|
||||
**SIX** variables — `INTAKE_TABLE`, `SITE_ORIGIN`, `NOTIFY_TO`,
|
||||
`MAIL_FROM`, `RESPONSE_TIME` and `NO_RETAINER_NOTICE`; it throws at cold
|
||||
start on any missing one, on purpose. ⚠️ **This list said five until
|
||||
2026-08-31 and the handler required six.** `NO_RETAINER_NOTICE` became a
|
||||
`requireEnv` in the same change set and was added to no document, so an
|
||||
operator working this list would have set five, and the Lambda would
|
||||
have thrown on **every** invocation — API Gateway answering 5xx and every
|
||||
inquiry from counsel lost from the moment `/api/*` was wired. Loud in
|
||||
CloudWatch, silent to Pouya, who has no reason to submit his own form.
|
||||
Found by `adversarial-reviewer` round 2.
|
||||
**Two of the six must be verbatim from `src/data/site.ts`:**
|
||||
`RESPONSE_TIME` from `CONTACT.responseTime` and `NO_RETAINER_NOTICE`
|
||||
from `NO_RETAINER_NOTICE`. Both are published commitments — the first is
|
||||
§4/Q27's two-business-day response, the second is the no-retainer notice
|
||||
`docs/01` §`/contact/` requires, **including its fourth clause about
|
||||
not itself creating a conflict check**, which a hand-typed copy in the
|
||||
handler had dropped. `RESPONSE_TIME` must read identically on `/contact/`,
|
||||
in the confirmation email, and in the bio.
|
||||
3. **API Gateway throttling, 5 requests / 5 minutes per source IP**
|
||||
(`docs/05`). Not expressible in handler code, and it is carrying load
|
||||
|
||||
Reference in New Issue
Block a user