Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .claude/hooks/markdown-audit-reminder.mts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ interface HookPayload {
const REMINDER =
'This edit changed a Markdown file. Follow `.claude/rules/docs-authoring.md` ' +
'(canonical spec: `.github/prompts/audit-docs.prompt.md`): document only what the ' +
'code provably does (no speculation), no subjective adjectives, reference files as ' +
'code provably does (no speculation), no subjective adjectives but not robotic prose ' +
'(lead with the point; show facts rather than assert them), reference files as ' +
'clickable markdown links to files (never bare names or directories), keep snippets ' +
'to 3-10 lines, and give every Mermaid diagram `accTitle` + `accDescr`. ' +
'To audit docs against the code, run the `/audit-docs` skill.';
Expand Down
5 changes: 3 additions & 2 deletions .claude/rules/docs-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ When creating or editing any markdown file, follow the discipline below. These a

- **No em-dashes or en-dashes.** Never write `—` (em-dash) or `–` (en-dash); replace each with a comma, parenthesis, colon, separate sentence, or a spaced hyphen `-`. The hyphen `-` is fine wherever it is grammatically correct, including the ` - ` separator between a label and a brief description in lists. When you edit a markdown file, replace its existing em-dashes and en-dashes too.
- **Canadian English (strong preference)** for prose you write or change: colour, behaviour, favour, centre, defence, and `-ize`/`-ization` (standardize, organization). See the [Canadian spelling guide](https://our-languages.canada.ca/en/blogue-blog/canadian-spelling-eng). Don't retroactively convert existing prose, and never change code identifiers, config/JSON keys, quoted code, file/package names, or CSS properties (`background_color`, `themeColor`).
- **No subjective adjectives** in new prose (important, critical, robust, seamless, powerful, efficient, etc.). State facts.
- High-density, low-volume: explain *why* and *how the system uses it*, not line-by-line narration. Bullets for lists/steps, paragraphs only for intros/complex architecture.
- **No subjective adjectives** in new prose (important, critical, robust, seamless, powerful, efficient, etc.). State facts. Objective is not robotic, though: replace the adjective with the concrete cited fact that earns it (show, don't tell).
- Use prose for reasoning (the *why* and *how the system uses it*), not line-by-line narration; reserve bullets and numbered lists for genuine enumerations (steps, options, fields). Don't force explanation into parallel bullet fragments, and don't de-list a real list. Lead each paragraph with its point.
- **Voice (new or changed prose only).** Read as a careful human wrote it: lead with the point, vary sentence length where natural, and cut AI tells (signposting previews, puffery copulas like "serves as" / "is a testament to", rule-of-three by default, filler transitions, formulaic conclusions). Stay formal and neutral (no contractions). Full list and scope: the **Voice** section of the [canonical prompt](../../.github/prompts/audit-docs.prompt.md).
- Document a tunable value by the **name a consumer changes it by** (env var, config key, CLI flag, or a named member of a centralized constants/config module that other code reads), judging by role, not location. Don't document an ephemeral local variable as the config surface.
- **Acronyms** in prose you write or edit use capitals (ID, URL) and are expanded on first use per doc ("Deoxyribonucleic acid (DNA)"). Keep exact casing for brand/tool/package names (npm, iOS), domain terms (snRNA), and direct code references (an `id` field).
- No placeholders, TODOs, or empty "add details here" sections.
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/audit-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Full detail in [`.claude/rules/docs-authoring.md`](../../rules/docs-authoring.md

- **Documentation only.** Change docs/comments/docstrings, never executable code or behaviour (note code problems for a human instead), unless the task explicitly asks for code changes.
- **Zero hallucination / prove it.** Document only what the code provably does: read it, don't infer from names, types, comments, or structure. If you can't point to the proof, don't write it. No "appears to" / "should" / planned behaviour.
- **Objective tone.** No subjective adjectives (important, critical, robust, …). Fix existing claims that contradict the code.
- **Objective tone, not robotic.** No subjective adjectives (important, critical, robust, …); replace each with the concrete cited fact (show, don't tell). Write as a careful human would: formal and neutral, leading with the point and cutting AI tells, per the **Voice** section of the [canonical prompt](../../../.github/prompts/audit-docs.prompt.md). Fix existing claims that contradict the code.
- **Links.** Every file reference is a clickable relative markdown link to a *file* (never a bare name, never a directory; link its `index.md`/`README.md`). Verify the path resolves.
- **Snippets.** Link to files instead of pasting definitions; inline only 3-10 lines for a usage example or critical config line.
- **Mermaid.** Every diagram includes `accTitle` and `accDescr`; valid syntax; reflects real code; choose the fitting diagram type.
Expand Down
42 changes: 26 additions & 16 deletions .github/prompts/audit-docs.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ labels:

## Role & Purpose

Act as a **Strictly Factual Technical Writer and Auditor**. Make the `docs/` directory an objective, verifiable reflection of the current #codebase. Write and correct documentation so `docs/` matches the #codebase, #activePullRequest, or #changes.
Act as a **Strictly Factual Technical Writer and Auditor**. Make the `docs/` directory an objective, verifiable reflection of the current #codebase. Write and correct documentation so `docs/` matches the #codebase, #activePullRequest, or #changes. Being strictly factual does not mean sounding machine-generated: write the way a careful human technical writer would, applying the **Voice** guidance in section 3.

**Scope: documentation only.** Unless the invoking task explicitly asks for code or behaviour changes, this run edits documentation (markdown, text files, and in-code comments, docstrings, JSDoc, module headers) and never changes executable code or behaviour. See Rule 1.

**Core philosophy:**

- **Reporter, not editor.** Convert code facts into documentation. Do not editorialize.
- **Reporter, not editor.** Convert code facts into documentation. Do not editorialize, which means do not make value judgments you cannot cite. Objective means no unverified claims.
- **Document value, not narration.** Code is self-documenting for _what_ it does; docs must add what code cannot show: _why_ something exists (decisions, constraints, trade-offs), _how_ parts interact (boundaries, data flows, integration points), and _when_ to use it (context, prerequisites). If a sentence only restates the code, cut it. _Exception:_ consumer-facing API/tool docs must state _what_ the code does, since external readers cannot see the source.
- **Link, don't duplicate.** Point to source files; never copy code into markdown.
- **Link, do not duplicate.** Point to source files; never copy code into markdown.

**Dual audience:** every document serves internal developers (maintaining the architecture) and/or external developers (consuming the APIs/tools). Prefer content useful to both.
**Dual audience:** every document serves internal developers (maintaining the architecture) and/or external developers (consuming the APIs/tools). Prefer content useful to both. Serve human skimmers and LLM/coding-assistant readers with the same prose: use one canonical term per concept (no synonym-swapping for the same thing), and replace an ambiguous `it`/`this`/`these` with the actual noun when the referent could drift.

**Tone:** approachable for concepts, precise for details, objective always (Rule 3).
**Tone:** approachable for concepts, precise for details, objective always (Rule 3). The register stays formal and neutral, never stiff or machine-like; see **Voice** in section 3. Do not add contractions or a conversational register.

---

Expand Down Expand Up @@ -82,6 +82,7 @@ Every statement must be grounded in code you have **opened and read in full duri

- **Correct falsehoods.** If existing docs say "returns JSON" but the code returns XML, fix the documentation.
- **New content:** no subjective adjectives (important, critical, robust, seamless, powerful, elegant, efficient, optimal, and the like). State facts.
- **Objective is not flat.** Banning subjective adjectives does not mandate robotic prose. Replace the adjective with the concrete cited fact that earns it: not "the retry logic is robust" but "the retry runs three times with a two-second backoff ([retry.ts](../src/retry.ts) lines 12-19)." (show, do not tell)
- **Existing content:** preserve existing subjective terms unless they are factually wrong.
- _Bad (AI):_ "The `auth.ts` middleware is a critical component." _Good (AI):_ "The `auth.ts` middleware blocks unauthorized requests."

Expand All @@ -102,10 +103,22 @@ No exceptions. Do not output any diagram missing either field.

## 3. Writing Guidelines

### Voice

Write as a careful human technical writer: formal and neutral, never robotic. The robotic feel comes from the tells below, not from a formal register, so cut the tells and keep the register.

- **Lead with the point.** Put the conclusion, answer, or action in the first sentence; detail follows.
- **Show, do not tell.** Demonstrate with a command, number, cited line, or named edge case instead of asserting significance.
- **Vary sentence length where natural.** Do not force a cadence target; reference and spec material may run uniform.
- **Avoid these AI tells** (representative, not exhaustive): signposting previews ("This section covers", "In this section we will"); puffery copulas ("serves as", "stands as", "is a testament to", "plays a vital/pivotal role"); the rule-of-three triad as a default; filler transitions ("Additionally", "Furthermore", "Moreover" at high frequency); formulaic conclusions ("In conclusion", "Despite its ... it faces challenges"); and padded words such as delve, leverage, underscore, showcase, intricate, vibrant, foster, tapestry, seamless. Keep a word when it is factually correct in context (a test `harness`, an OAuth `realm`).
- **A why-claim is still a claim (Rule 2).** Cite the comment, ADR, commit, test, or config that proves a rationale or trade-off, or state the _what_ and stop.
- **Scope.** Apply this guidance only to prose you add or change; do not rewrite accurate existing prose for rhythm or voice (Phase 2, Rule 1). It applies to `docs/` prose, not in-code documentation (Phase 3 keeps docstrings and comments terse).
- **Stay formal.** No contractions, no casual asides, no emoji, and no "add imperfections" or detector-evasion tricks. Naturalness comes from cutting tells, not from informality.

### Brevity & style

- Paragraphs only for introductions and complex architecture. Bullets for lists and steps. No walls of text.
- **High density, low volume:** no line-by-line narration. Explain _why_ architecturally and _how_ the system uses it.
- Use prose to carry reasoning and explanation (the _why_ and _how_); reserve bullets and numbered lists for genuine enumerations (steps, options, fields, parameters). Do not force explanation into parallel bullet fragments, and do not de-list a real list: genuine enumerations stay lists (scannable for people, and easy for an LLM to retrieve). No walls of text.
- **Concise, not choppy:** no line-by-line narration, but keep the connective prose that carries logic; cutting every transition reads as robotic. Lead each paragraph and section with its point (inverted pyramid), then give the detail.

### Language

Expand All @@ -116,10 +129,7 @@ No exceptions. Do not output any diagram missing either field.
### Configuration references

- Document a tunable value by the **name a consumer changes it by**, judging by role, not location. That surface includes external interfaces (env vars, config-file keys, CLI flags) **and** named members of a centralized or exported constants/configuration module that other code reads as tunable values: if a named, stable value is read elsewhere and changing it changes behaviour, document it by that name even when it is an internal `const`.
- Do not document a transient local or private variable as if it were the configuration surface.
- Format: "Set or change `<NAME>` in `<LOCATION>` to control `<behaviour>`."
- ✅ "Set `DATABASE_URL` in your `.env` file." / "`LIMITS.MAX_RETRIES` in the constants module caps retry attempts."
- ❌ "The `dbUrl` local variable stores the connection." (ephemeral internal variable)
- Format: "Set or change `<NAME>` in `<LOCATION>` to control `<behaviour>`." Name the consumer-facing value, for example `LIMITS.MAX_RETRIES` in the constants module, not a transient internal such as a `dbUrl` local.

### File citations & references (strictly enforced)

Expand Down Expand Up @@ -170,18 +180,18 @@ Exclude logging, metrics, telemetry, trivial validation, internal utilities, and

Before finalizing, review your own work and fix everything below. No exceptions.

**Re-verify citations (highest priority).** For every claim, re-open the file and lines you cited and confirm they actually state it. This is a verification pass, not a re-read of the rules: if a citation does not resolve or does not say what you wrote, the statement is wrong. Delete any statement you cannot tie to lines you read this run.
**Re-verify citations (highest priority).** For every claim, re-open the file and lines you cited and confirm they actually state it. If a citation does not resolve or does not say what you wrote, the statement is wrong: delete it. A why-claim (rationale, trade-off) needs a citable source too, or state the _what_ and stop.

Then confirm:

- Only documentation changed: no executable code, config values, tests, or dependencies were modified (unless the invoking task explicitly asked for code changes).
- No hedging words ("appears to", "seems to", "likely", "probably", "should", "will").
- Pre-existing content changed only to fix factual errors; accurate phrasing preserved.
- Pre-existing content changed only to fix factual errors; accurate phrasing and voice preserved (voice guidance applies to prose you added or changed only).
- Every file reference is a clickable link that resolves to a file, not a directory.
- Configuration references name the value a consumer changes it by (env/config/CLI flag or a constants-module member), not an ephemeral internal variable.
- Acronyms in prose you wrote are capitalized and expanded on first use (exceptions: brand/tool/package names, domain terms, code references).
- No new subjective adjectives; no code dumps (link instead).
- Architecture flows include only significant steps (§4).
- Every Mermaid diagram has `accTitle` and `accDescr`.
- No new subjective adjectives and no code dumps (link instead); reasoning sits in prose, genuine enumerations stay lists.
- New or changed prose reads as a careful human wrote it: leads with the point, no signposting previews or banned AI tells, one canonical term per concept, no ambiguous `it`/`this`/`these`.
- Architecture flows include only significant steps (§4); every Mermaid diagram has `accTitle` and `accDescr`.
- No em-dashes (`—`) or en-dashes (`–`) anywhere you wrote (a grammatically correct hyphen `-` is fine); new or changed prose uses Canadian English.
- Phase 3 ran and its result is reported.
3 changes: 1 addition & 2 deletions docs/architecture/components/avatar.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ After each sneeze, the component logs a `trigger_sneeze` analytics event via Fir

### Easter Egg: AAAAHHHH Transformation

After the 6th sneeze, instead of animating, the avatar calls the [`aaaahhhh()`](../../../src/helpers/aaaahhhh.ts) helper function which:
After the 6th sneeze, instead of animating, the avatar logs a `trigger_aaaahhhh` analytics event and then calls the [`aaaahhhh()`](../../../src/helpers/aaaahhhh.ts) helper function, which:

- Transforms all text on the page to "AAAAHHHH" format (first half → 'A', second half → 'H')
- Replaces all images with `/images/aaaahhhh/aaaahhhh.webp`
- Changes background images including the stars
- Sets page title to "Alexander Sullivan's AAAAHHHHH"
- Logs a `trigger_aaaahhhh` analytics event

This creates a playful full-page transformation. See [AAAAHHHH Helper](../helpers.md#aaaahhhh-easter-egg-helper) for implementation details.

Expand Down
6 changes: 3 additions & 3 deletions docs/architecture/components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This document describes the internal architecture, relationships, and usage of m
- [Banner & Avatar](./avatar.md): Header section with animated profile picture
- [ProjectsGrid](./projects.md): Displays project cards in a grid
- [Publications](./publications.md): Lists publications with metadata
- [Footer](./socials.md): Social media links and copyright
- [Footer](./socials.md): Social media links, contact buttons, and attribution
- [StarsBackground](./stars.md): Animated starfield background
- [CookieSnackbar](./cookie-snackbar.md): Cookie consent notification
- [ServiceWorkerRegister](../service-worker.md): PWA service worker registration
Expand Down Expand Up @@ -98,7 +98,7 @@ Lists publications with authors, abstracts, and metadata.
**Features:**

- Publication cards with metadata
- DOI and journal links
- Card links to the publication's DOI page
- Analytics tracking

**See:** [Publications Documentation](./publications.md)
Expand All @@ -107,7 +107,7 @@ Lists publications with authors, abstracts, and metadata.

**Location:** [`src/components/footer/Footer.tsx`](../../../src/components/footer/Footer.tsx)

Social media links and copyright information.
Social media links, contact buttons (email and resume), and an open-source attribution.

**Features:**

Expand Down
4 changes: 2 additions & 2 deletions docs/architecture/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ The portfolio stores all content as TypeScript files in [src/data/](../../src/da
sequenceDiagram
accTitle: Build-Time Data Integration Sequence
accDescr: Shows how the build imports and type-checks data files at compile time, after which components import the data directly via @data aliases and render it to HTML, avoiding any runtime data fetching
participant Build[Build Process]
participant Data[Data Files]
participant Build as "Build Process"
participant Data as "Data Files"
participant Component
participant Browser

Expand Down
2 changes: 1 addition & 1 deletion docs/usage/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ Here is an example of a Cypress test located in [cypress/e2e/landing.cy.ts](../.
```ts
// This test suite is for the landing page
describe('Landing Page', () => {
// Run an accessibility check after each test
afterEach(() => {
// Accessibility check
cy.a11yCheck();
});

Expand Down
Loading
Loading