chore: install toolchain, wire lint, add local deploy path
Answers four questions and starts build step 1. Q22 — the scoped deploy user does not exist: aws iam get-user returns NoSuchEntity. Recorded in §7 as NOT PROVISIONED and swept so that no file describes it as existing. §10 records that user/pouya, the broadly- permissioned personal user that has been authenticating to this account, must never be used in CI; scripts/deploy-local.sh refuses to run as it. Q23 — the Gitea instance reports 1.27.2, well above the vars-context floor, so the first-step guard is belt-and-braces rather than load-bearing. What remains is not a fact but a dependency: the instance is jointly administered, so enabling Actions and registering a runner both need a second admin. Hence npm run deploy (scripts/deploy-local.sh), which performs exactly what the workflow performs — same guard, same three passes, same headers, same invalidation. Documented as the current path, not as a workaround. §10 gains the risk that follows: the deploy secret will live on jointly administered infrastructure, where an instance admin can reach repo secrets. That does not change the plan, but it makes the scoped IAM policy the actual control between a shared Gitea instance and an AWS account holding another business's client-database backups. Never widen it. Q27 — response time is two business days, in site.ts with a derived short form so the confirmation email cannot drift from the page. Q28 — OBA sections confirmed, stamped "for now"; membership renews yearly, tracked as R10. Build step 1: dependencies installed and package-lock.json created, closing the npm ci blocker. ESLint flat config and Prettier config added; npm run lint, check and build all pass. Prettier deliberately excludes *.md and tokens.css — reasons recorded in .prettierignore. npm audit reports 7 high-severity advisories, all requiring an Astro major upgrade. Not applied; escalated in AGENTS.md entry (s) as a decision. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012XquaEq4BgWMCwUqLEyNkF
This commit is contained in:
co-authored by
Claude Opus 5
parent
2b6176e4d7
commit
0d8b63380a
@@ -155,11 +155,12 @@ since May.
|
||||
| Bilingual English and Farsi | `[verified 2026-08-25 — strategy brief §I]` |
|
||||
| Iranian-Canadian; cross-cultural fluency with diaspora business communities | `[verified 2026-08-25 — strategy brief §I]` |
|
||||
| Operator of SML Company Ltd. alongside the practice | `[verified 2026-08-25 — strategy brief §I]` |
|
||||
| Memberships: **ADRIC**, **ADRIO**, **OBA sections** | `[verified 2026-08-26 — Pouya]`. Which OBA sections is still `[assumed]` — the brief names Construction & Infrastructure, ADR, and Civil Litigation |
|
||||
| Memberships: **ADRIC**, **ADRIO**, and **OBA — Construction & Infrastructure, ADR, and Civil Litigation sections** | `[verified 2026-08-26 — Pouya]`, **for now**. Section membership renews yearly; this is a fact with a shelf life, tracked as R10 |
|
||||
| ~~OCNI~~ | **Not current. Do not publish** `[verified 2026-08-26 — Pouya]` |
|
||||
| ~~LSO~~ | **Do not publish.** Listing the Law Society among memberships implies licensure, which D13 bars. Excluded deliberately, not by oversight `[verified 2026-08-26]` |
|
||||
| Toronto, Ontario; by appointment | `[verified 2026-08-26]` |
|
||||
| Contact: `info@smlcompany.ca`; no public phone number; consultations by scheduled call | `[verified 2026-08-26 — Pouya]` |
|
||||
| **Response time: inquiries answered within two business days** | `[verified 2026-08-26 — Pouya]`. A public commitment — it must read identically on `/contact/`, in the inquirer confirmation email, and in any bio |
|
||||
| LinkedIn: `https://www.linkedin.com/in/pouyalajevardi/` | `[verified 2026-08-26 — Pouya]` |
|
||||
| ~~The boutique may be named on the site~~ | **STRUCK 2026-08-26 (Q25).** Superseded by **D16 — never named.** Pouya said it *could* be named, then reversed; the permission survived the reversal and sat in the Verified table authorising exactly what D16 bars. Refer to it only as *a Toronto litigation and ADR boutique* |
|
||||
|
||||
@@ -271,7 +272,10 @@ the audience it targets. Revisit at month 12–18. `[verified 2026-08-25 — dec
|
||||
| DNS | **Namecheap**, not Route 53 `[verified 2026-08-25 — AWS-Hosting-Guide.md]` |
|
||||
| Intake backend | API Gateway (HTTP API) → Lambda → DynamoDB, notifications via SES `[verified 2026-08-25 — AWS-Hosting-Guide.md]` |
|
||||
| Repository | **`adr-sml`**, self-hosted **Gitea**. Local clone at `/Users/pouya/Dev/Websites/adr-sml` `[verified 2026-08-26]` |
|
||||
| CI/CD | **Gitea Actions**, `.gitea/workflows/deploy.yml`. The GitHub OIDC workflow is kept as `docs/reference/github-actions-oidc.yml.example` — moved out of `.github/workflows/` on 2026-08-26 so Gitea cannot fall back to it. Credentials: scoped IAM user in Gitea secrets — **no OIDC available**. Whether that IAM user has actually been created is **Q22** `[verified 2026-08-26 — D3 as amended]` |
|
||||
| CI/CD | **Gitea Actions**, `.gitea/workflows/deploy.yml`. Instance **git.larsnolden.com, version 1.27.2** `[verified 2026-08-26 — /api/v1/version]` — well above the ~1.21 floor for the `vars` context. The GitHub OIDC workflow is kept as `docs/reference/github-actions-oidc.yml.example`, outside `.github/workflows/` so Gitea cannot fall back to it. **No OIDC available** — Gitea is not an AWS OIDC provider |
|
||||
| **Deploy credential — NOT PROVISIONED** | `aws iam get-user --user-name adr-sml-deploy` returns **NoSuchEntity** `[verified 2026-08-26 — Q22]`. The scoped IAM user does not exist, no access key has been issued, and the Gitea secrets are unset. **No file may describe this credential as existing.** Creation commands are with Pouya; this is a to-do, not an open question |
|
||||
| **How deploys actually happen today** | **Locally, via `npm run deploy`** (`scripts/deploy-local.sh`) — same guard, same three sync passes, same cache headers, same invalidation as the workflow. Gitea Actions needs `[actions] ENABLED` in `app.ini` and a registered `act_runner`, both of which need the instance's second administrator (Q23). At this scale the pipeline changes only **how a deploy is triggered**, not what it does `[verified 2026-08-26]` |
|
||||
| **Interim auth — do not repeat in CI** | Pouya has been authenticating as **`user/pouya`**, the broadly-permissioned personal user the Q10 inventory captured. Acceptable for interactive work at a keyboard; **never** as a CI credential — see §10 `[verified 2026-08-26]` |
|
||||
| Analytics | **Plausible or Fathom** — cookieless, no personal data, no consent banner, EU-hosted `[verified 2026-08-26 — D15]` |
|
||||
|
||||
## 8. Design system
|
||||
@@ -304,7 +308,7 @@ Nothing below can be invented. Each needs an answer from Pouya.
|
||||
| ~~Q25~~ | **ANSWERED 2026-08-26. Struck.** The §4 row permitting the boutique to be named is removed; D16 governs alone | — |
|
||||
| ~~Q26~~ | **ANSWERED 2026-08-26.** §4 now carries an explicit **Licence status — NOT ESTABLISHED** row, and its opening no longer asserts that LSO rules apply. The register's rationale stands on the fabricated-credentials history alone | — |
|
||||
| ~~Q24~~ | **ANSWERED 2026-08-26.** `AWS-Hosting-Guide.md` copied into `docs/reference/` — it is the only record of how the hand-built infrastructure was created. Scanned for credentials before copying: no access keys, no secrets, no account ID | — |
|
||||
| **Q22** | **Has the deploy credential actually been provisioned?** `docs/06-deployment.md` instructs creating IAM user `adr-sml-deploy`, issuing an access key, and setting `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` in the repository's Gitea Actions secrets. It is written imperatively — a procedure to perform, not a record of one performed — and nothing in this file records any of it as done; the inventory behind Q10 captured no such principal. Check with `aws iam get-user --user-name adr-sml-deploy`. Until it is confirmed, no file may describe the credential as existing, only as designed. **The §10 rotation obligation has no subject until this is answered** | CI/CD, the first deploy, and the accuracy of every credential claim in the docs |
|
||||
| ~~Q22~~ | **ANSWERED 2026-08-26 — it does not exist.** `aws iam get-user --user-name adr-sml-deploy` returns `NoSuchEntity`. Recorded in §7 as **NOT PROVISIONED**; creation commands are with Pouya, so it is now a **to-do**, not a question. Consequence while it is outstanding: deploys run locally (`npm run deploy`), and the quarterly rotation obligation in D3 still has no subject | — |
|
||||
| Q5 | Booking tool — **parked 2026-08-26 at Pouya's request.** Build `/contact/` with the form only and a clean slot for the embed. Now tracked as standing reminder R6 | `/contact/` — non-blocking |
|
||||
| ~~Q6~~ | **ANSWERED 2026-08-26.** Supplied and committed: `src/assets/pouya-lajevardi.jpg` (1600×1600 master) and `src/assets/og-portrait.jpg` (1200×630 link-preview crop) | — |
|
||||
| ~~Q7~~ | **ANSWERED 2026-08-26.** Pouya reverted to generic. The boutique is **never named**; refer to it as *a Toronto litigation and ADR boutique* throughout | — |
|
||||
@@ -317,10 +321,10 @@ Nothing below can be invented. Each needs an answer from Pouya.
|
||||
| ~~Q21~~ | **ANSWERED 2026-08-26.** `ca-central-1` is healthy (`SUCCESS`) on the resolving token set. The broken records belong to a stray `us-east-1` identity this project does not use. **Nothing to fix.** The three dead CNAMEs are inert; leaving them is the low-risk choice | — |
|
||||
| ~~Q11~~ | **ANSWERED 2026-08-26.** Privacy-first, cookieless — Plausible or Fathom. No GA4, no consent banner | — |
|
||||
| ~~Q12~~ | **ANSWERED 2026-08-26.** `https://www.linkedin.com/in/pouyalajevardi/` | — |
|
||||
| **Q27** | **Is a one-business-day response time a commitment you want published?** `src/data/site.ts` carried `responseTime: 'Inquiries are answered within one business day.'` — a service level a reader can hold you to, and not in the §4 register. Set to `null` with a `TODO(pouya)` until confirmed. Raised by `claims-auditor`, 2026-08-26 | The `/contact/` page copy |
|
||||
| **Q28** | **Which OBA sections?** §4 verifies OBA membership but marks the *section list* `[assumed]` — the brief names Construction & Infrastructure, ADR, and Civil Litigation. `src/data/site.ts` was publishing all three under a blanket `[verified]` stamp; now marked and flagged. Raised by `claims-auditor`, 2026-08-26 | The `/about/` credentials list |
|
||||
| ~~Q27~~ | **ANSWERED 2026-08-26 — two business days.** A public commitment, so it must read identically everywhere it appears: `src/data/site.ts`, `/contact/`, the inquirer confirmation email, and any bio | — |
|
||||
| ~~Q28~~ | **ANSWERED 2026-08-26 — OBA Construction & Infrastructure, ADR, and Civil Litigation** `[verified 2026-08-26 — Pouya]`, **for now**: section membership renews yearly, so this is a fact with a shelf life. Tracked as R10 | — |
|
||||
| ~~Q29~~ | **ANSWERED 2026-08-26 by implementation.** Guard widened on both counts: the two secrets are checked (emptiness only, never echoed), and `INTAKE_ENDPOINT` is promoted to job-level `env:` and guarded. Every `vars.*` and `secrets.*` the workflow consumes is now covered except `BOOKING_URL`, empty by decision (R6) | — |
|
||||
| **Q23** | **Is a Gitea `act_runner` registered to this repository or its organisation?** Without one the workflow queues silently and never runs — indistinguishable from a broken pipeline (`docs/06-deployment.md`). *The Gitea-version half of this question is closed:* rather than record a version fact that goes stale, `.gitea/workflows/deploy.yml` now runs a guard as its **first** step that fails the run if `AWS_REGION`, `S3_BUCKET`, or `CLOUDFRONT_DISTRIBUTION_ID` is empty — which is how a pre-1.21 instance manifests. Pouya's decision, 2026-08-26. Runner registration is not something a guard can cover | The first deploy |
|
||||
| **Q23** | **Is a Gitea `act_runner` registered, and are Actions enabled in `app.ini`?** *The version half is closed:* the instance reports **1.27.2** `[verified 2026-08-26 — /api/v1/version]`, so the `vars` context is supported and the first-step guard is belt-and-braces rather than load-bearing. **What remains is not a fact to look up but a dependency on a person:** git.larsnolden.com is **jointly administered**, and both enabling Actions and registering a runner need the second administrator. Until then `npm run deploy` is the path, and it is documented rather than treated as a workaround | How deploys are triggered — not what they do |
|
||||
|
||||
## 10. Risks
|
||||
|
||||
@@ -332,6 +336,8 @@ Nothing below can be invented. Each needs an answer from Pouya.
|
||||
| Personal data in the intake pipeline without a retention policy | Medium — PIPEDA | `docs/05-backend-spec.md` sets retention, and `/legal/privacy/` states it |
|
||||
| Cutover breaks the live site (D11 is a single-shot deploy) | Medium | Full pre-cutover checklist in `docs/06-deployment.md`; CloudFront can be rolled back to the prior origin path |
|
||||
| Twenty pages of thin copy rank worse than six good ones | Medium | Each page must justify itself with substantive content. Ship fewer pages rather than padded ones |
|
||||
| **`user/pouya` is a broadly-permissioned personal IAM user, and it is what has been authenticating to this account.** Q22 confirms the scoped deploy user does not exist yet | **High** | Fine at an interactive keyboard; **never** in CI, never in a Gitea secret, never in `scripts/deploy-local.sh`. That script refuses to run if `sts get-caller-identity` returns `user/pouya`. Create `adr-sml-deploy` before the first automated deploy `[verified 2026-08-26]` |
|
||||
| **The deploy secret will live on jointly-administered infrastructure.** git.larsnolden.com has a second administrator. An instance admin can generally reach repository secrets, or register a runner that receives them — that is inherent to how Actions runners are fed credentials, not a flaw in this setup | **High** | This does not change the plan; it changes **what the scoped IAM policy is for.** The policy is no longer hygiene — it is the actual control standing between a shared Gitea instance and an AWS account holding another business's client-database backups. Four actions, one bucket, one distribution. **Never widen it**, and treat any request to as a security decision, not a convenience one `[verified 2026-08-26]` |
|
||||
| **Deploy-credential blast radius.** AWS account `327082975128` is not a single-project account. It also holds `meshkinilaw.ca` and its preview site, `demesne.media`, `orynenergy.ca`, `lajirugs.ca`, and **`mlp-clientdb-prod-backups-327082975128`** (recorded in an earlier entry with the account suffix; the short form `mlp-clientdb-prod-backups` is used elsewhere in the docs) — which **by its name** holds production client-database backups. Only the name was ever observed; the contents were not inspected and the owner is not established | **High** | A static deploy key for a personal website must never be able to reach a client database. The scoped IAM policy in `docs/06-deployment.md` grants four actions on one bucket and one distribution and nothing else — that narrowness is now load-bearing, not hygiene. Never widen it. Never reuse the `user/pouya` credentials in CI `[verified 2026-08-26 — inventory]` |
|
||||
| ~~SES is in the sandbox~~ | ~~High~~ → **RESOLVED 2026-08-26** | Q19 closed: production access granted in `ca-central-1`, confirmed in writing. Residual, tracked in §7: the `ses-alerts` SNS email subscription is **pending confirmation**, so the bounce and complaint alarms currently notify nobody `[verified 2026-08-26]` |
|
||||
| ~~No SPF and no DMARC on `smlcompany.ca`~~ | ~~High~~ → **RESOLVED 2026-08-26** | Both records added by Pouya and independently verified (Q20). SPF authenticates Google Workspace mail; SES satisfies DMARC through DKIM alignment on the three resolving CNAMEs. DMARC sits at `p=none` — the residual task is to review reports and tighten to `quarantine`, which is monitoring, not a risk `[verified 2026-08-26 — DNS query]` |
|
||||
@@ -374,6 +380,7 @@ never being raised again.
|
||||
| R5 | **Fee review at 12 months.** Published rates are sticky; the right moment to move them is deliberate, not reactive | 2026-08-26 | D14 is priced for where the practice is going, not where it is |
|
||||
| R6 | **Booking tool.** Parked by Pouya on 2026-08-26; `/contact/` ships with the intake form and a reserved slot for an embed | 2026-08-26 | He asked to be reminded. D10 committed to booking because it removes the back-and-forth that loses appointments — the form alone is a partial answer |
|
||||
| R9 | **The SES alarms notify nobody until the `ses-alerts` email subscription is confirmed.** `SES-BounceRate-High` and `SES-ComplaintRate-High` are configured and live; the SNS email subscription to `info@smlcompany.ca` is **pending confirmation**, and an unconfirmed subscription drops every message | 2026-08-26 | A monitoring control that exists but does not deliver is worse than none, because it reads as covered. At this volume five bounces can cross the ~5% suspension threshold. Tracked in §7 and on the cutover checklist, but a one-click task nobody owns is exactly what §12 is for |
|
||||
| R10 | **OBA section membership renews yearly.** §4 verifies Construction & Infrastructure, ADR, and Civil Litigation as of 2026-08-26 — *for now* | 2026-08-26 | A credential that lapses quietly is the failure mode §4 exists to prevent, and OCNI already did exactly this (§4 records it as "not current, do not publish"). Re-confirm at renewal, and before any page listing memberships ships |
|
||||
| ~~R7~~ | **RATIFIED / SUPERSEDED 2026-08-26.** (a) Cache-policy table matching the pipeline — **accepted**; documenting what the pipeline does beats documenting an intention. (b) `s3:AbortMultipartUpload` omitted — **accepted, reasoning corrected**: the lifecycle rule does not exist and is therefore not the cover; the actual cover is that `aws s3 sync` only goes multipart above 8 MB and the largest asset is a 357 KB portrait. Recorded in `docs/06-deployment.md` with a revisit trigger. (c) The `aws s3 ls` pre-flight — **superseded** by the variable guard now running as the workflow's first step | 2026-08-26 | — |
|
||||
| ~~R8~~ | **PROMOTED TO A RULE 2026-08-26.** A reminder was too weak for a pattern that survived three entries. *A sweep is a command, not a claim* now sits in `CLAUDE.md` under Conventions, in `/build` Phase 6, and in `/wrap` step 3: any claim that a change was applied across files must cite the command and be written only after reading its output | 2026-08-26 | — |
|
||||
|
||||
@@ -381,6 +388,141 @@ never being raised again.
|
||||
|
||||
# Change Log
|
||||
|
||||
## 2026-08-26 (s) — Q22/Q23/Q27/Q28 answered; toolchain installed; build step 1 begun
|
||||
|
||||
**Who:** Pouya answered four questions mid-session and corrected one earlier
|
||||
instruction. Claude Code implemented and started build step 1.
|
||||
|
||||
### Q22 — ANSWERED, and the answer is that it does not exist
|
||||
|
||||
`aws iam get-user --user-name adr-sml-deploy` returns **`NoSuchEntity`**. §7 now
|
||||
carries **Deploy credential — NOT PROVISIONED**, and it is a **to-do** rather
|
||||
than a question: the creation commands are with Pouya. Swept by command; no file
|
||||
describes the credential as existing.
|
||||
|
||||
**Pouya has been authenticating as `user/pouya`** — the broadly-permissioned
|
||||
personal user the Q10 inventory captured. Recorded in §7 as interim, and in §10
|
||||
as a **High** risk: fine at an interactive keyboard, never as a CI credential.
|
||||
`scripts/deploy-local.sh` **refuses to run** if `sts get-caller-identity` returns
|
||||
that ARN, so the rule is enforced rather than merely written down.
|
||||
|
||||
### Q23 — correction: the version is verified, and the blocker is a person
|
||||
|
||||
**Old → new:** entry (r) recorded the Gitea version `[assumed]` on Pouya's
|
||||
instruction. It is now **1.27.2** at git.larsnolden.com
|
||||
`[verified 2026-08-26 — /api/v1/version]`, comfortably above the ~1.21 floor for
|
||||
the `vars` context. The first-step guard is therefore belt-and-braces rather than
|
||||
load-bearing — which is the right outcome: it was built so the answer would not
|
||||
matter, and now it does not.
|
||||
|
||||
**What remains is not a fact to look up.** The instance is **jointly
|
||||
administered**, so enabling Actions in `app.ini` and registering an `act_runner`
|
||||
both depend on a second administrator. Q23 is rewritten to say so.
|
||||
|
||||
**So the local path is documented, not treated as a workaround.**
|
||||
`npm run deploy` → `scripts/deploy-local.sh` (new) performs *exactly* what the
|
||||
workflow performs: same guard, same three sync passes in the same order with the
|
||||
same cache headers, same invalidation. At this scale the pipeline changes only
|
||||
**how a deploy is triggered**, not what it does. `docs/06` leads with it, and
|
||||
both files say the script and the workflow are one artefact in two places.
|
||||
|
||||
### §10 — a new risk that changes what the IAM policy is for
|
||||
|
||||
The deploy secret will live in a repository on **jointly-administered
|
||||
infrastructure**, where an instance admin can generally reach repo secrets or
|
||||
register a runner that receives them. That is inherent to how Actions runners are
|
||||
fed credentials, not a flaw in this setup, and it does not change the plan.
|
||||
|
||||
It changes the **reading** of the scoped policy. Four actions, one bucket, one
|
||||
distribution is no longer hygiene — it is the actual control standing between a
|
||||
shared Gitea instance and an AWS account holding another business's
|
||||
client-database backups. §10 now says so, and says that any request to widen it
|
||||
is a security decision rather than a convenience one.
|
||||
|
||||
### Q27 and Q28 — answered, and both are facts with obligations attached
|
||||
|
||||
**Q27 — two business days.** In `src/data/site.ts` as `responseTime`, with a
|
||||
derived `responseTimeShort` so the confirmation email cannot drift from the page.
|
||||
Added to §4 Verified as a **public commitment** that must read identically on
|
||||
`/contact/`, in the inquirer email, and in any bio. `docs/05` says to render it
|
||||
from `SITE`, never retype it. Swept for the superseded "one business day": no
|
||||
occurrences.
|
||||
|
||||
**Q28 — OBA Construction & Infrastructure, ADR, and Civil Litigation**
|
||||
`[verified 2026-08-26 — Pouya]`, **for now**. §4's row and `site.ts` both carry
|
||||
the "for now". Section membership renews yearly, so this is a fact with a shelf
|
||||
life — **R10** added, with OCNI as the precedent: §4 already records it as
|
||||
lapsed and not publishable, which is exactly this failure arriving a year late.
|
||||
|
||||
### Build step 1 — started
|
||||
|
||||
**Dependencies installed; `package-lock.json` exists.** That alone closes a
|
||||
blocker documented since entry (m): `npm ci` had no lockfile, so the CI pipeline
|
||||
could not get past its first step.
|
||||
|
||||
**`npm run check` and `npm run build` both pass** — 0 errors, 0 warnings. Worth
|
||||
recording because entry (m) F6 asserted both would *fail* on an empty
|
||||
`src/pages/`. `adversarial-reviewer` doubted that and was right: `astro build`
|
||||
emits zero pages and exits 0. **Correcting it here rather than editing (m).**
|
||||
|
||||
**ESLint and Prettier are now wired**, closing the "not yet wired" rows:
|
||||
|
||||
- `eslint.config.js` — flat config, `js.configs.recommended` +
|
||||
`typescript-eslint` + `eslint-plugin-astro`. **`typescript-eslint` added as a
|
||||
devDependency** because `.astro` frontmatter *is* TypeScript and the plugin
|
||||
cannot parse a component without it. Deliberately not type-aware: `astro check`
|
||||
already type-checks, and running both would be slower and would disagree at the
|
||||
edges.
|
||||
- `.prettierrc.json` — 80 columns, single quotes, `prettier-plugin-astro`.
|
||||
- **`.prettierignore` excludes `*.md` and `src/styles/tokens.css`, deliberately.**
|
||||
Prettier's reformat of `AGENTS.md` alone is an **892-line diff** with no reading
|
||||
benefit, and it collapses the aligned comment column in `tokens.css` that lets
|
||||
the measured contrast ratios be scanned down the page — the one thing that file
|
||||
exists for. Both exclusions carry their reason in the file.
|
||||
|
||||
`npm run lint` now passes clean. `npm run lighthouse` remains unwired, and now
|
||||
honestly so: there are no pages to measure.
|
||||
|
||||
**`npm audit` reports 16 vulnerabilities (7 high) — not fixed, flagged.** The
|
||||
high-severity set is Astro ≤ 7.0.9 (XSS via `define:vars`, spread attribute
|
||||
names, `transition:*` values, slot names; SSRF in a prerendered error page) plus
|
||||
transitive `esbuild`/`sharp`, and a `cookie` advisory reached only through
|
||||
`@lhci/cli`. `npm audit fix --force` wants **Astro 7.2.7, a major upgrade**, and
|
||||
`@lhci/cli@0.1.0`, a catastrophic downgrade. Most of the Astro advisories need
|
||||
authoring patterns this project does not use (no server islands, no
|
||||
`define:vars`, no view transitions, static output, no spread props yet). **This
|
||||
needs a deliberate decision, not an automated fix** — see the escalation below.
|
||||
|
||||
### Escalated
|
||||
|
||||
**Astro major upgrade.** The project pins `astro@^5.0.0`; the advisories are
|
||||
fixed in 7.x. Doing it now, before any pages exist, is far cheaper than doing it
|
||||
after — there is nothing to migrate. Doing it later means shipping on a
|
||||
known-vulnerable major. This is a D-series decision (D1 names Astro but not a
|
||||
version), so it is yours.
|
||||
|
||||
### Verification
|
||||
|
||||
`npm run check` — 0 errors, 0 warnings, 5 files. `npm run build` — completes,
|
||||
0 pages, as expected. `npm run lint` — ESLint clean, Prettier clean.
|
||||
`bash -n scripts/deploy-local.sh` — syntax OK. `node --check astro.config.mjs` —
|
||||
OK. `package.json` re-parsed as JSON after editing. Sweeps run as commands with
|
||||
output read: `adr-sml-deploy` (no file claims it exists), `one business day` (no
|
||||
occurrences), operational identifiers in `docs/*.md` (no matches).
|
||||
|
||||
**One error of mine, caught by my own sweep and recorded rather than quietly
|
||||
fixed:** the three new §7 rows initially landed in the **§3 decisions table**,
|
||||
overwriting D15's label, because the anchor I matched on (`| Analytics |`)
|
||||
appears in both sections. The `adr-sml-deploy` sweep surfaced it. §3 is restored
|
||||
— `git diff` over the decisions table is empty — and the rows are in §7. An
|
||||
anchor that is not unique is not an anchor.
|
||||
|
||||
**Closed:** Q22, Q27, Q28, and the version half of Q23. **Still open:** Q23
|
||||
(runner registration — needs the second administrator), R6 (parked). **Added:**
|
||||
R9 (SES subscription pending), R10 (OBA renewal).
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-26 (r) — Q19 closed; SES monitoring recorded; §7 made the single source of operational truth
|
||||
|
||||
**Who:** Pouya closed Q19, supplied the monitoring configuration, ruled on Q29,
|
||||
|
||||
Reference in New Issue
Block a user