diff --git a/BUILD-NOTES.md b/BUILD-NOTES.md index 04f67cb..8cb3c8e 100644 --- a/BUILD-NOTES.md +++ b/BUILD-NOTES.md @@ -565,3 +565,91 @@ Do not hand-edit thumbnail PNGs or treat them as template source. The approved s keeps distinct document voices rather than applying one shared dashboard shell: decisions use a humanist decision spine, plans use phase/gate and readiness-ledger forms, status uses budget accounting, and research uses an editorial broadsheet. + +## Accepted operational templates — Batch03 integration (Astra) + +This is the separate three-template adoption after PR40, based on main +`661501182a82bcdd25e478bf965aa24452fb6c8f`. It does not replace or redesign the first +five approved templates. It does not complete the remaining gallery revamp. + +- **Metrics dashboard / Performance Sheet:** broad twelve-week trend with a compact + metric ledger, commentary, channel accounting and metered service levels. +- **Project status / Decision Dispatch:** changed verdict and two owned, dated asks + before milestones, scope and blockers. +- **Postmortem / Incident Atlas:** impact accounting alongside the failure trace, + then the complete chronology, causes, factors and owned action items. + +The accepted standalone sources remain immutable in the design evidence. Catalog +copy now describes these actual compositions. Each canonical thumbnail uses the +unchanged generator with an explicit 1280px viewport: the chart/ledger, two decisions, +and impact/trace remain visible in actual 1440px and 390px gallery cards. No global +capture changes or other template/thumbnail churn. All twenty options, nineteen HTML +plus Markdown, keep their existing slugs, categories, slots and API contracts. + +### Source provenance and the bounded semantic exception + +| Template | Accepted SHA-256 | Integrated SHA-256 | +| --- | --- | --- | +| metrics-dashboard | `696deb41eba35235f401244d909a1505f3b5424a35e578ade883a55c6fcc1730` | `7305ae47ce611cbf81cd39a230b10542a46d2d1eb97de399a78b43718ec59ea4` | +| project-status | `d8f0db0a085f20cf58bcdff20c04b1525e4e41f19fb17218cbfd7d41c16f484f` | same, byte-for-byte | +| postmortem | `791e91c086761ac21825ceca2ccb13d86699209e9533ec91e179b96dd38815a9` | `2b4660e588413516dd26f01e32123256911ac2cefd9bc3428809d533f78512b3` | + +Project Status is exact. The only accepted-source changes elsewhere are one +justified `noRedundantRoles`-only HTML file directive in Metrics and Postmortem, +and exactly four Postmortem action IDs changed from `td` to native `th scope="row"`, +retaining their class, explicit role and mobile-label attributes. No title changes, +CSS changes, text/data/link/code/SVG changes or other rule suppressions. + +The table-family roles are intentionally retained: responsive CSS uses block/grid +display and visually clips, rather than removes, column headings. [MDN's display +accessibility guidance](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/display) +warns that changing table display can alter accessibility representation in some +browsers. This is a compatibility exception, not a general permission to add redundant +roles. The scoped regression fixes its inventory: + +| Explicit role | Metrics | Postmortem | +| --- | ---: | ---: | +| table | 1 | 1 | +| rowgroup | 3 | 2 | +| row | 7 | 5 | +| columnheader | 5 | 5 | +| rowheader | 6 | 4 | +| cell | 24 | 16 | + +Each also retains one unchanged named SVG `img` role. Any expansion needs a new +justification. Native scoped row-header tests fail against the accepted pre-fix +Postmortem. Browser tests verify native scope, accessible names, row membership, +column order and matching mobile labels at all seven existing viewport projects. +Eight paired accepted/final captures (both tables at 1440/768/390/320) have identical +PNG bytes and Chromium accessibility snapshots. Native HTML header association plus +Chromium table/row hierarchy is verified; this is **not** a Safari/Firefox or screen +reader navigation claim. + +### Validation and known warnings + +All 301 original text nodes, 251 numeric occurrences and 47 keyed comparison groups +remain intact, including action relationships, SVG bytes and meter data. The old +Postmortem tag-bucket parity check normalizes only the four authorized ID tags; +independent action-record checks and exact allowed-transform equality remain strict. + +Initial lint: **87 errors → 0**. Four native IDs fix twelve semantic errors; the +approved compatibility directives account for 75 redundant-role diagnostics. +Warnings: **22 → 31**, not an unexplained baseline pass. Fifteen elsewhere are +unchanged; old Metrics seven specificity warnings are replaced by two in its new +CSS; Project Status adds nine specificity warnings; Postmortem adds five important +style warnings. These are sixteen warnings in accepted new CSS minus seven removed, +net nine. Contextual verdict/section and keyed-column overrides retain their approved +cascade. Postmortem's explicit ID/due font sizes and ID weight retain approved native +header/mobile presentation. No warning suppression or CSS reorder was applied; +current/prior breakpoint checks and pixel parity show no observed rendering defect. + +Final evidence includes check/build/full unit and browser suites, three frames at +four main widths plus 36 boundary captures, all nineteen HTML and Markdown smoke, +no-JS and growth checks, actual gallery cards, full-gallery interim variety, exact +source/thumbnail hashes and first-five live preservation. The integration remains +**unmerged and undeployed pending project-lead integrated review**. + +[Integrated review and machine-readable evidence](https://anacreon.ai/downloads/aa-template-revamp-1788686289312/integrated-batch03/index.html) +retain the original design approval provenance and distinguish fresh final-source +checks from reused unchanged-source evidence. No runtime, schema, billing, sandbox, +launch, infrastructure or dependency change is included. diff --git a/public/assets/template-thumbs/metrics-dashboard.png b/public/assets/template-thumbs/metrics-dashboard.png index b8f6e2c..80d144e 100644 Binary files a/public/assets/template-thumbs/metrics-dashboard.png and b/public/assets/template-thumbs/metrics-dashboard.png differ diff --git a/public/assets/template-thumbs/postmortem.png b/public/assets/template-thumbs/postmortem.png index 8c4905a..9035ab6 100644 Binary files a/public/assets/template-thumbs/postmortem.png and b/public/assets/template-thumbs/postmortem.png differ diff --git a/public/assets/template-thumbs/project-status.png b/public/assets/template-thumbs/project-status.png index 2296584..be55add 100644 Binary files a/public/assets/template-thumbs/project-status.png and b/public/assets/template-thumbs/project-status.png differ diff --git a/templates/manifest.ts b/templates/manifest.ts index d9d8d31..3f62c61 100644 --- a/templates/manifest.ts +++ b/templates/manifest.ts @@ -101,11 +101,12 @@ export const starterTemplateManifest = [ "slug": "postmortem", "category": "research", "name": "Incident Postmortem", - "description": "A blameless incident write-up: an inked impact strip carrying the four numbers that matter, a failure-rate chart with detection and mitigation marked, a timeline whose key beats are impact-start / detected / mitigated, the root cause stated in one sentence, contributing factors.", + "description": "A blameless incident atlas: impact accounting beside the failure trace, a time-indexed incident record, the complete root cause and contributing factors, then owned action items with due dates and states.", "type": "html", "content_file": "postmortem.html", "thumbnail": "/assets/template-thumbs/postmortem.png", - "slots": [] + "slots": [], + "thumbnail_viewport": 1280 }, { "slug": "report", @@ -132,21 +133,23 @@ export const starterTemplateManifest = [ "slug": "metrics-dashboard", "category": "status", "name": "Metrics Dashboard", - "description": "The recurring numbers review: one hero metric with a twelve-week trend, a row of KPI tiles carrying deltas and their comparisons, a channel breakdown, service levels metered against their targets, and a short note on what actually changed.", + "description": "A recurring performance sheet: a broad twelve-week trend beside a compact metric ledger, change commentary directly below, then a channel breakdown and service levels metered against their targets.", "type": "html", "content_file": "metrics-dashboard.html", "thumbnail": "/assets/template-thumbs/metrics-dashboard.png", - "slots": [] + "slots": [], + "thumbnail_viewport": 1280 }, { "slug": "project-status", "category": "status", "name": "Project Status", - "description": "Where a workstream actually stands: a verdict stated as a judgement with the reason behind it, a milestone rail with committed dates, scope metered against its totals, blockers with owners and ages, and a 'needs a human' section where every entry names one person.", + "description": "A decisions-first sponsor dispatch: the changed verdict beside two owned, dated asks, followed by committed milestones, scope totals, and blockers with their owners, ages and next decisions.", "type": "html", "content_file": "project-status.html", "thumbnail": "/assets/template-thumbs/project-status.png", - "slots": [] + "slots": [], + "thumbnail_viewport": 1280 }, { "slug": "service-health", diff --git a/templates/metrics-dashboard.html b/templates/metrics-dashboard.html index 4346044..d40fd9f 100644 --- a/templates/metrics-dashboard.html +++ b/templates/metrics-dashboard.html @@ -1,183 +1,21 @@ + - - + + Growth & reliability — Week 34 - + -
+
@@ -221,7 +59,7 @@

Weekly active workspaces

-
+

Artifacts published

38.2K12.0%

vs 34.1K last week

@@ -241,37 +79,49 @@

Support backlog

270

Open tickets · unchanged week on week

+
+ +
+

What changed this week

+
    +
  • Shared artifact links overtook partner integrations as the third-largest signup + channel, up 21.5% after link previews shipped on Monday.
  • +
  • Paid conversion slipped 0.3 points. The drop is concentrated in self-serve trials + that started during the 19 August ingest incident, not in the wider base.
  • +
  • The deploy freeze on ingest stays. Error budget is 81% consumed with 18 days to + run; the freeze lifts when it drops below 70%.
  • +

Signups by channel

Week 34 · attributed on first touch

- +
- - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - + + +
Five channels · 4,838 signups
ChannelSessionsSignupsConv.vs W33
Docs & API reference48,2101,9043.9%+14.2%
Organic search39,8841,2013.0%+6.8%
Shared artifact links27,4551,1434.2%+21.5%
Partner integrations11,0924023.6%−2.1%
Community & social9,6401882.0%−8.4%
ChannelSessionsSignupsConv.vs W33
Docs & API reference48,2101,9043.9%+14.2%
Organic search39,8841,2013.0%+6.8%
Shared artifact links27,4551,1434.2%+21.5%
Partner integrations11,0924023.6%−2.1%
Community & social9,6401882.0%−8.4%
Total136,2814,8383.6%+9.7%
Total136,2814,8383.6%+9.7%
@@ -308,22 +158,10 @@

Service levels

-
-

What changed this week

-
    -
  • Shared artifact links overtook partner integrations as the third-largest signup - channel, up 21.5% after link previews shipped on Monday.
  • -
  • Paid conversion slipped 0.3 points. The drop is concentrated in self-serve trials - that started during the 19 August ingest incident, not in the wider base.
  • -
  • The deploy freeze on ingest stays. Error budget is 81% consumed with 18 days to - run; the freeze lifts when it drops below 70%.
  • -
-
-
Figures are drawn from the analytics warehouse at 06:00 UTC daily; the service-level window is a rolling 30 days. Percentages compare with the equivalent prior period. Conversion is measured on signups, not sessions.
-
+
diff --git a/templates/postmortem.html b/templates/postmortem.html index bf69d6b..0938e8b 100644 --- a/templates/postmortem.html +++ b/templates/postmortem.html @@ -1,215 +1,37 @@ + - - + + Checkout was unavailable for 3 hours 47 minutes on 12 September - + -
+
-
+
Incident postmortem SEV-1
-

Checkout was unavailable for 3 hours 47 minutes on 12 September

Incident
INC-2026-041
Status
Resolved
Authors
D. Kaur, R. Idowu
Reviewed
18 Sep 2026
-

A dependency bump raised the payment-provider timeout from two seconds to thirty. When the -provider slowed, every stuck request held its connection fifteen times longer and the pool -saturated — three lines inside a forty-one file pull request.

-
+

Checkout was unavailable for 3 hours 47 minutes on 12 September

+ -
+

Impact

Duration
3h 47m

09:14 – 13:01 UTC

@@ -219,6 +41,9 @@

Impact

+

A dependency bump raised the payment-provider timeout from two seconds to thirty. When the +provider slowed, every stuck request held its connection fifteen times longer and the pool +saturated — three lines inside a forty-one file pull request.

Checkout failure rate · 0–60% · 09:00–14:00 UTC
@@ -236,7 +61,7 @@

Impact

13:01. Peak 52% — nine times worse than when the alert fired.

-
+

Timeline · 12 September, UTC

  1. 09:02
    @@ -303,29 +128,29 @@

    What went well

    - +
    - - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + - - + +
    Action items · 3 open, 1 complete
    IDActionOwnerDueStatus
    AI-1Alert on p99 checkout latency and on success rate, not p50 alone.M. Halvorsen19 SepDone
    AI-2Add a circuit breaker to the provider client, opening at 25% errors over 30 seconds.R. Idowu26 SepIn progress
    AI-3Treat timeout, retry and pool constants as behaviour changes in review — CODEOWNERS plus a +
    IDActionOwnerDueStatus
    AI-1Alert on p99 checkout latency and on success rate, not p50 alone.M. Halvorsen19 SepDone
    AI-2Add a circuit breaker to the provider client, opening at 25% errors over 30 seconds.R. Idowu26 SepIn progress
    AI-3Treat timeout, retry and pool constants as behaviour changes in review — CODEOWNERS plus a required note.Platform3 OctNot started
    AI-4Rewrite the checkout runbook to diagnose saturation before scaling, + Platform3 OctNot started
    AI-4Rewrite the checkout runbook to diagnose saturation before scaling, pool metrics first.D. Kaur10 OctNot started
    D. Kaur10 OctNot started
    @@ -334,6 +159,6 @@

    What went well

    Timestamps come from the incident channel and the deploy log; failure rates are the per-minute success-rate metric. -
+ diff --git a/templates/project-status.html b/templates/project-status.html index 0dacb7d..f3dab71 100644 --- a/templates/project-status.html +++ b/templates/project-status.html @@ -1,190 +1,25 @@ - - + + SOC 2 Type II readiness — status, week of 8 September - + -
+
- Project status · week 37 +
Project status · week 37

SOC 2 Type II readiness

-
+
Owner
Priya Raman
Reported
8 Sep 2026
Next review
15 Sep
@@ -192,7 +27,7 @@

SOC 2 Type II readiness

-
+

At risk

Changed from On track @@ -206,7 +41,35 @@

At risk

vendor reassigned our team — that one change is why this is amber.

-
+
+

Needs a human

+
    +
  1. + 01 +
    +

    Approve the second pen-test vendor, or accept the slip

    +

    Decision by Priya Raman + Needed by 12 September

    +

    The second vendor can start 22 September for £9,400 more. Doing nothing moves the + window to 15 November, pushing the report past the two enterprise renewals that asked + for it.

    +
    +
  2. +
  3. + 02 +
    +

    Sign off the standing-access model

    +

    Decision by Marcus Lee & Security + Needed by 19 September

    +

    Break-glass only, or named exceptions with a quarterly review — both are built. The + access review cannot close until one is chosen, and it is the last thing between us and + 104 of 104 controls.

    +
    +
  4. +
+
+ +
Milestones
3 of 7

complete · 1 in progress

Open blockers
3

1 needs a decision this week

Days to window
54

opens 1 November

@@ -258,65 +121,37 @@

Scope

Blockers

  1. -

    Pen-test vendor cannot start before 6 October

    +

    Pen-test vendor cannot start before 6 October

    Blocking

    Owner Dana WhitfieldOpen 11 days Blocks 2 milestones

    -

    Needs: approval to run the test with our second vendor at +

    Needs: approval to run the test with our second vendor at +£9,400, or a decision to move the observation window to 15 November.

  2. -

    Nine engineers still hold standing production access

    +

    Nine engineers still hold standing production access

    Blocking

    Owner Marcus LeeOpen 4 days Blocks Q3 access review

    -

    Needs: the standing-access model signed off. Break-glass +

    Needs: the standing-access model signed off. Break-glass tooling has been built and tested since 2 September — this is waiting on a decision, not on engineering.

  3. -

    Two subprocessors have no countersigned DPA

    +

    Two subprocessors have no countersigned DPA

    Watching

    Owner LegalOpen 23 days Blocks nothing yet

    -

    Needs: countersignature from both vendors. Chased three +

    Needs: countersignature from both vendors. Chased three times; escalate to their account teams if open on 22 September.

-
-

Needs a human

-
    -
  1. - 01 -
    -

    Approve the second pen-test vendor, or accept the slip

    -

    The second vendor can start 22 September for £9,400 more. Doing nothing moves the - window to 15 November, pushing the report past the two enterprise renewals that asked - for it.

    -

    Decision by Priya Raman - Needed by 12 September

    -
    -
  2. -
  3. - 02 -
    -

    Sign off the standing-access model

    -

    Break-glass only, or named exceptions with a quarterly review — both are built. The - access review cannot close until one is chosen, and it is the last thing between us and - 104 of 104 controls.

    -

    Decision by Marcus Lee & Security - Needed by 19 September

    -
    -
  4. -
-
- -
+ diff --git a/tests/e2e/template-table-semantics.spec.ts b/tests/e2e/template-table-semantics.spec.ts new file mode 100644 index 0000000..1acd302 --- /dev/null +++ b/tests/e2e/template-table-semantics.spec.ts @@ -0,0 +1,56 @@ +import { expect, test } from '@playwright/test'; + +const sandboxOrigin = process.env.E2E_CLOUD_SANDBOX_ORIGIN; + +for (const [slug, columns, expectedRows] of [ + ['metrics-dashboard', ['Channel', 'Sessions', 'Signups', 'Conv.', 'vs W33'], 6], + ['postmortem', ['ID', 'Action', 'Owner', 'Due', 'Status'], 4], +] as const) { + test(`${slug}: scoped native headers and accessible row/column relationships survive responsive display`, async ({ + page, + }) => { + await page.goto(`${sandboxOrigin}/templates/${slug}/frame`); + const table = page.getByRole('table'); + await expect(table).toHaveCount(1); + await expect(table.getByRole('columnheader')).toHaveText([...columns]); + const headers = table.locator('thead th'); + for (let index = 0; index < columns.length; index += 1) { + await expect(headers.nth(index)).toHaveAttribute('scope', 'col'); + } + const rows = table.getByRole('row'); + await expect(rows).toHaveCount(expectedRows + 1); + for (let index = 1; index <= expectedRows; index += 1) { + const row = rows.nth(index); + const rowHeader = row.getByRole('rowheader'); + await expect(rowHeader).toHaveCount(1); + expect(await rowHeader.evaluate((element) => element.tagName)).toBe('TH'); + await expect(rowHeader).toHaveAttribute('scope', 'row'); + const rowName = (await rowHeader.innerText()).trim(); + await expect(rowHeader).toHaveAccessibleName( + new RegExp(rowName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) + ); + const cells = row.getByRole('cell'); + await expect(cells).toHaveCount(columns.length - 1); + // Native scope + table row membership + matching column order, not role presence alone. + // CSS-only mobile labels must agree with the retained (visually clipped) column headers. + for (let column = 1; column < columns.length; column += 1) { + const cell = cells.nth(column - 1); + const columnName = columns[column]; + if (!columnName) throw new Error('Missing column header'); + await expect(cell).toHaveAttribute('data-mobile-label', columnName); + const value = (await cell.textContent())?.trim().replace(/\s+/g, ' ') ?? ''; + await expect(cell).toHaveAccessibleName( + new RegExp(value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) + ); + } + if (slug === 'postmortem') await expect(rowHeader).toHaveText(`AI-${index}`); + } + const tree = await table.ariaSnapshot(); + expect(tree).toContain('columnheader "'); + expect(tree).toContain('rowheader "'); + expect(tree).toContain('cell "'); + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe( + true + ); + }); +} diff --git a/tests/unit/template-table-semantics.test.ts b/tests/unit/template-table-semantics.test.ts new file mode 100644 index 0000000..bc4b0d6 --- /dev/null +++ b/tests/unit/template-table-semantics.test.ts @@ -0,0 +1,46 @@ +import { readFileSync } from 'node:fs'; +import { describe, expect, it } from 'vitest'; + +const source = (slug: string) => + readFileSync(new URL(`../../templates/${slug}.html`, import.meta.url), 'utf8'); + +// These two responsive tables intentionally retain explicit roles when CSS changes their display. +// Bound the exception to the known table inventory, rather than silencing future unrelated roles. +describe('responsive operational table semantics', () => { + it('uses four native scoped Postmortem row headers, not interactive roles on td', () => { + const html = source('postmortem'); + expect( + html.match( + /AI-[1-4]<\/th>/g + ) + ).toHaveLength(4); + expect(html).not.toMatch(/]*role="rowheader"/); + }); + + for (const [slug, inventory] of [ + [ + 'metrics-dashboard', + { table: 1, rowgroup: 3, row: 7, columnheader: 5, rowheader: 6, cell: 24 }, + ], + ['postmortem', { table: 1, rowgroup: 2, row: 5, columnheader: 5, rowheader: 4, cell: 16 }], + ] as const) { + it(`${slug} limits its compatibility exception to the documented role inventory`, () => { + const html = source(slug); + expect(html.match(/biome-ignore[^\n]*/g)).toEqual([ + 'biome-ignore-all lint/a11y/noRedundantRoles: Explicit table roles retain semantics when mobile CSS uses block/grid display. -->', + ]); + const counts: Record = {}; + for (const match of html.matchAll( + /<(table|thead|tbody|tfoot|tr|th|td)\b[^>]*\brole="([^"]+)"/g + )) { + const role = match[2]; + if (!role) throw new Error('Missing explicit role capture'); + counts[role] = (counts[role] ?? 0) + 1; + } + expect(counts).toEqual(inventory); + expect(html.match(/role="[^"]+"/g)).toHaveLength( + Object.values(inventory).reduce((sum, count) => sum + count, 0) + 1 + ); // One unchanged named SVG image, outside the table. + }); + } +});