feat: production run — Q61 ramp, /404/, CloudFront router, cutover runbook
Build and deploy / build-and-deploy (push) Failing after 4s
Build and deploy / build-and-deploy (push) Failing after 4s
Five items of Pouya's production run, 2026-09-01.
Q61 — scroll-padding-top becomes a max() ramp on `10lh - 83px`, with the
plain calc() first as the fallback for engines without `lh`. Hidden focus
stops under minimumFontSize=32: 290 of 1,455 -> 0, control build still
290. Default settings byte-identical (0 differences over 352 page-widths x
17 fields). The 12 residual cells at minimumFontSize=16/20 are pre-existing
and unchanged-or-better; reported, not widened, per instruction.
Intake backend + CloudFront — docs/09-cutover-runbook.md is the
copy-paste sequence for admin execution: every command followed by its
verification and expected output, rollback per part, and Part 10 is Q60's
TTL test. infra/cloudfront/router.js is the trailing-slash function
(30-case suite; 8 fail against the pre-review version, incl. a
protocol-relative open redirect). infra/cloudfront/configure.mjs is
dry-run-by-default and idempotent. scripts/intake-env.mjs emits the six
Lambda env vars from src/data/site.ts.
Four launch blockers found by reading the running system:
- handler.mjs wrote pk/sk; the live table's key is submissionId with no
sort key, so every submission would have failed validation silently
- the Lambda invoke permission is scoped to the old route path
- 22 of 23 pages 403 without the router function
- there was no 404 page; src/pages/404.astro adds it
Claims audit (D20 cutover pass) — five gloss over-reaches corrected on
/practice/energy/, /practice/insurance/ (x2), /practice/technology/ and
/med-arb/. Three findings left open for Pouya: Q62, the /med-arb/ gloss,
and Q60.
Q62 — one frozen-tripwire pattern added under the freeze's own breach
exception, with a probe and four negative fixtures. check:claims exits 1
until the false /legal/privacy/ sentence is corrected, so both deploy
paths are blocked by a mechanism rather than by memory.
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
ca1c2524e1
commit
bd282aa47d
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Prints the intake Lambda's six environment variables as the JSON that
|
||||
* `aws lambda update-function-configuration --environment` takes.
|
||||
*
|
||||
* ⚠️ THIS EXISTS SO THAT TWO PUBLISHED COMMITMENTS ARE NEVER RETYPED INTO A
|
||||
* SHELL COMMAND. `RESPONSE_TIME` and `NO_RETAINER_NOTICE` are read from
|
||||
* `src/data/site.ts` — the same constants `/contact/` renders — because a
|
||||
* hand-typed copy of the notice inside the handler had already dropped a clause
|
||||
* once (`docs/05`, and the handler's own comment on the constant). A deploy
|
||||
* procedure that asks an operator to paste a sentence is the same defect one
|
||||
* step further out, and the notice contains an EN DASH in "mediator–party",
|
||||
* which is exactly the character a retype loses.
|
||||
*
|
||||
* Resource names come from `AGENTS.md` §7 and are passed in, not defaulted from
|
||||
* a second copy here — except the two that are pure site facts.
|
||||
*
|
||||
* usage: node scripts/intake-env.mjs --table <name> --notify <addr> --from <addr>
|
||||
* node scripts/intake-env.mjs ... --shell # export lines instead
|
||||
*/
|
||||
import { CONTACT, NO_RETAINER_NOTICE, SITE } from '../src/data/site.ts';
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const flag = (name) => {
|
||||
const i = args.indexOf(`--${name}`);
|
||||
return i === -1 ? undefined : args[i + 1];
|
||||
};
|
||||
|
||||
const table = flag('table');
|
||||
const notify = flag('notify');
|
||||
const from = flag('from');
|
||||
const missing = [
|
||||
['--table', table],
|
||||
['--notify', notify],
|
||||
['--from', from],
|
||||
]
|
||||
.filter(([, v]) => !v)
|
||||
.map(([k]) => k);
|
||||
|
||||
if (missing.length > 0) {
|
||||
console.error(`missing: ${missing.join(' ')}`);
|
||||
console.error(
|
||||
'usage: node scripts/intake-env.mjs --table <dynamodb-table> ' +
|
||||
'--notify <address> --from <ses-verified-address> [--shell]',
|
||||
);
|
||||
console.error('Resource names are in AGENTS.md §7.');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
/* The site origin is not a deploy-time choice: the handler compares the request
|
||||
Origin against it and redirects to pages ON it, so it must be the canonical
|
||||
origin `astro.config.mjs` builds against. */
|
||||
const origin = SITE.url.replace(/\/$/, '');
|
||||
|
||||
const vars = {
|
||||
INTAKE_TABLE: table,
|
||||
SITE_ORIGIN: origin,
|
||||
NOTIFY_TO: notify,
|
||||
MAIL_FROM: from,
|
||||
RESPONSE_TIME: CONTACT.responseTime,
|
||||
NO_RETAINER_NOTICE,
|
||||
};
|
||||
|
||||
/* Guards, not decoration. Each one is a failure this project has already had or
|
||||
has written down as the next one. */
|
||||
for (const [k, v] of Object.entries(vars)) {
|
||||
if (typeof v !== 'string' || v.trim() === '') {
|
||||
throw new Error(
|
||||
`${k} resolved empty — the handler throws at cold start on that`,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!/^https:\/\//.test(origin)) {
|
||||
throw new Error(`SITE_ORIGIN must be an https origin, got ${origin}`);
|
||||
}
|
||||
/* The clause a hand-copy dropped. `docs/01` §/contact/ requires it, so its
|
||||
absence is a published-disclosure defect rather than a typo. */
|
||||
if (!NO_RETAINER_NOTICE.includes('create a conflict check')) {
|
||||
throw new Error(
|
||||
'NO_RETAINER_NOTICE is missing its fourth clause about not itself creating ' +
|
||||
'a conflict check — docs/01 §/contact/ requires it. Do not deploy this.',
|
||||
);
|
||||
}
|
||||
if (!/–/.test(NO_RETAINER_NOTICE)) {
|
||||
throw new Error(
|
||||
'NO_RETAINER_NOTICE no longer contains the en dash in "mediator–party". ' +
|
||||
'Either the constant changed deliberately, or something re-typed it.',
|
||||
);
|
||||
}
|
||||
if (!/\btwo business days\b/.test(CONTACT.responseTime)) {
|
||||
throw new Error(
|
||||
`RESPONSE_TIME is "${CONTACT.responseTime}" — AGENTS.md §4/Q27 is a ` +
|
||||
'two-business-day commitment. If the commitment changed, /contact/, the ' +
|
||||
'bio and this all move together.',
|
||||
);
|
||||
}
|
||||
|
||||
if (args.includes('--shell')) {
|
||||
for (const [k, v] of Object.entries(vars)) {
|
||||
console.log(`export ${k}=${JSON.stringify(v)}`);
|
||||
}
|
||||
} else {
|
||||
console.log(JSON.stringify({ Variables: vars }));
|
||||
}
|
||||
Reference in New Issue
Block a user