@adia-ai/adia-ui-forge 0.8.34 → 0.8.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +20 -0
  3. package/README.md +12 -4
  4. package/agents/a2ui-builder.md +12 -8
  5. package/agents/component-author.md +17 -12
  6. package/agents/framework-reviewer.md +18 -12
  7. package/agents/release-builder.md +15 -10
  8. package/commands/deploy.md +2 -0
  9. package/commands/dogfood.md +2 -0
  10. package/commands/gen-review.md +2 -0
  11. package/commands/release.md +3 -1
  12. package/package.json +4 -1
  13. package/scripts/forge-lint +38 -1
  14. package/scripts/release-pretag-docs-gate +45 -3
  15. package/skills/adia-a2ui/SKILL.md +2 -2
  16. package/skills/adia-author/SKILL.md +1 -1
  17. package/skills/adia-author/references/anti-patterns.md +1 -0
  18. package/skills/adia-author/references/code-style.md +3 -3
  19. package/skills/adia-author/references/worked-example.md +3 -3
  20. package/skills/adia-author/references/yaml-contract.md +42 -0
  21. package/skills/adia-deploy/SKILL.md +10 -11
  22. package/skills/adia-dogfood/SKILL.md +5 -4
  23. package/skills/adia-dogfood/references/admin-shell-anatomy.md +5 -2
  24. package/skills/adia-dogfood/references/app-shell-pitfalls.md +10 -3
  25. package/skills/adia-dogfood/scripts/analyze.mjs +2 -0
  26. package/skills/adia-gen-review/SKILL.md +10 -3
  27. package/skills/adia-gen-review/references/loop-protocol.md +15 -8
  28. package/skills/adia-gen-review/references/rubric-score.md +5 -2
  29. package/skills/adia-gen-review/scripts/gen-review-status.mjs +8 -6
  30. package/skills/adia-llm-internals/SKILL.md +1 -1
  31. package/skills/adia-release/SKILL.md +2 -2
  32. package/skills/adia-release/references/cut-procedure.md +4 -0
  33. package/skills/adia-release/references/gates-catalog.md +3 -1
  34. package/skills/adia-release/references/independent-package-release.md +2 -2
  35. package/skills/adia-release/scripts/bump.mjs +7 -3
  36. package/skills/adia-release/scripts/dispatch-publish.mjs +5 -2
  37. package/skills/adia-release/scripts/gate-roster.mjs +29 -0
  38. package/skills/adia-release/scripts/package-paths.mjs +41 -13
  39. package/skills/adia-release/scripts/pr-bridge.mjs +36 -2
  40. package/skills/adia-release/scripts/promote-unreleased.mjs +27 -7
  41. package/skills/adia-release/scripts/release-pack.mjs +24 -11
  42. package/skills/adia-release/scripts/tag-lockstep.mjs +10 -8
  43. package/skills/adia-site-docs/SKILL.md +8 -6
  44. package/skills/adia-site-docs/intent.md +1 -1
  45. package/skills/adia-ssr/SKILL.md +1 -1
  46. package/skills/adia-ssr/references/failure-shapes.md +8 -5
  47. package/skills/adia-ssr/references/guard-patterns.md +1 -1
  48. package/skills/adia-site-docs/evals/audit-report.md +0 -30
  49. package/skills/adia-ssr/evals/audit-report.md +0 -63
@@ -68,7 +68,7 @@ import os from 'node:os';
68
68
  import path from 'node:path';
69
69
  import process from 'node:process';
70
70
  import { assertMonorepoRoot } from './assert-monorepo-root.mjs';
71
- import { resolvePackageChangelog, PACKAGE_NAMES, PACKAGE_ROSTER } from './package-paths.mjs';
71
+ import { resolvePackageChangelog, PACKAGE_ROSTER } from './package-paths.mjs';
72
72
  import { GATE_ROSTER } from './gate-roster.mjs';
73
73
 
74
74
  const SCRIPT_DIR = path.dirname(new URL(import.meta.url).pathname);
@@ -81,7 +81,11 @@ const DEFAULT_DEPLOY_HOST = 'ui-kit.exe.xyz';
81
81
  const DEFAULT_NPM_SCOPE = '@adia-ai';
82
82
 
83
83
  // Single-sourced roster (H3, package-paths.mjs); order = publish order.
84
- const PACKAGES = PACKAGE_NAMES;
84
+ // Filtered to `lockstep !== false`: a class-B package (gh#1133's
85
+ // adia-plugins) cuts independently — this orchestrator never touches it.
86
+ // See package-paths.mjs's `lockstep` field note.
87
+ const LOCKSTEP_ROSTER = PACKAGE_ROSTER.filter((p) => p.lockstep !== false);
88
+ const PACKAGES = LOCKSTEP_ROSTER.map((p) => p.name);
85
89
 
86
90
  function parseArgs(argv) {
87
91
  const args = {
@@ -166,14 +170,14 @@ function parseArgs(argv) {
166
170
  if (args.mode === 'from-scratch' && (args.substantivePackages || args.stubPackages)) {
167
171
  // Flags accept both name form (a2ui-corpus) and path form (a2ui/corpus);
168
172
  // normalize to name form for the roster set-difference.
169
- const toName = (p) => (PACKAGE_NAMES.includes(p) ? p : p.replaceAll('/', '-'));
173
+ const toName = (p) => (PACKAGES.includes(p) ? p : p.replaceAll('/', '-'));
170
174
  const covered = new Set([
171
175
  ...(args.substantivePackages ?? []).map(toName),
172
176
  ...(args.stubPackages ?? []).map(toName),
173
177
  ]);
174
- const missing = PACKAGE_NAMES.filter((p) => !covered.has(p));
178
+ const missing = PACKAGES.filter((p) => !covered.has(p));
175
179
  if (missing.length > 0) {
176
- console.error(`error: --mode from-scratch covers only ${covered.size} of the ${PACKAGE_NAMES.length} lockstep`);
180
+ console.error(`error: --mode from-scratch covers only ${covered.size} of the ${PACKAGES.length} lockstep`);
177
181
  console.error(' packages — Step 4e (generate-release-notes) would die on a missing');
178
182
  console.error(` [${args.version}] CHANGELOG section in the ${missing.length} ride-along(s):`);
179
183
  console.error(` ${missing.join(', ')}`);
@@ -367,7 +371,7 @@ function shCapture(cmd, args) {
367
371
  // regenerations that simply run again.
368
372
  function detectHalfCut(args) {
369
373
  if (args.mode === 'handoff' || args.dry) return false;
370
- const versions = PACKAGE_ROSTER.map(({ name, dir }) => {
374
+ const versions = LOCKSTEP_ROSTER.map(({ name, dir }) => {
371
375
  const p = path.join(REPO, dir, 'package.json');
372
376
  return { name, version: JSON.parse(fs.readFileSync(p, 'utf8')).version };
373
377
  });
@@ -452,7 +456,16 @@ function step3PreFlight(args) {
452
456
  console.log(`\n ${g.n}/${GATE_ROSTER.length}. ${g.cmd} # ${g.what} — [resume] deferred to Step 4g (notes not regenerated yet)`);
453
457
  continue;
454
458
  }
455
- const cmd = g.versionArg ? `${g.cmd} --version ${hygieneVersion}` : g.cmd;
459
+ // targetVersionArg (gh#1135, REQ-06) is a distinct flag from versionArg:
460
+ // write-eval-health.mjs NAMES a new file after the cut's target version
461
+ // from the very start — there is no pre/post-bump claim to reconcile
462
+ // the way gate 24's README-currency check has, so it always takes
463
+ // `args.version` verbatim regardless of mode or resume.
464
+ const cmd = g.versionArg
465
+ ? `${g.cmd} --version ${hygieneVersion}`
466
+ : g.targetVersionArg
467
+ ? `${g.cmd} --version ${args.version}`
468
+ : g.cmd;
456
469
  console.log(`\n ${g.n}/${GATE_ROSTER.length}. ${cmd} # ${g.what}`);
457
470
  try {
458
471
  sh(cmd, args, { stdio: 'inherit' });
@@ -678,7 +691,7 @@ function step5Commit(args) {
678
691
  'packages/genui/adia-catalog/base.json',
679
692
  'packages/genui/adia-catalog/adia-pack.json',
680
693
  'packages/genui/adia-catalog/catalog-data.js',
681
- ...PACKAGE_ROSTER.flatMap(({ name, dir, plugin }) => {
694
+ ...LOCKSTEP_ROSTER.flatMap(({ name, dir, plugin }) => {
682
695
  // Roster-driven (H3): each package stages its manifest + CHANGELOG;
683
696
  // plugins also stage .claude-plugin/plugin.json (the /plugin-update
684
697
  // cache key, moved by bump.mjs); factory additionally pins a2ui-mcp in
@@ -1026,7 +1039,7 @@ async function main() {
1026
1039
  // the two apart, so the ruling lives here — still BEFORE the pre-flight.
1027
1040
  if (args.mode === 'from-scratch' && !args.resume && !args.substantivePackages && !args.stubPackages) {
1028
1041
  console.error('error: --mode from-scratch needs --substantive-packages and/or --stub-packages');
1029
- console.error(` covering all ${PACKAGE_NAMES.length} lockstep packages — with neither, no CHANGELOG gets`);
1042
+ console.error(` covering all ${PACKAGES.length} lockstep packages — with neither, no CHANGELOG gets`);
1030
1043
  console.error(` a [${args.version}] section and Step 4e (generate-release-notes) dies after`);
1031
1044
  console.error(' the ~15-min pre-flight (gh#765). A resumed half-cut tree is exempt,');
1032
1045
  console.error(' but this tree is not half-cut (versions are not at the cut version).');
@@ -1157,7 +1170,7 @@ function selftest() {
1157
1170
  // after detectHalfCut, still before the pre-flight.
1158
1171
  const rejectShapes = [
1159
1172
  { flags: '--substantive x --xref y --stub-packages llm', marker: 'ride-along' },
1160
- { flags: `--stub-packages ${PACKAGE_NAMES.join(',')}`, marker: '--substantive and --xref' },
1173
+ { flags: `--stub-packages ${PACKAGES.join(',')}`, marker: '--substantive and --xref' },
1161
1174
  { flags: '', marker: 'needs --substantive-packages and/or --stub-packages' },
1162
1175
  ];
1163
1176
  for (const { flags, marker } of rejectShapes) {
@@ -1181,7 +1194,7 @@ function selftest() {
1181
1194
 
1182
1195
  // …and a fully covered from-scratch roster (substantive ∪ stub = all
1183
1196
  // packages) must pass the guard and assemble its dry plan normally.
1184
- const stubs = PACKAGE_NAMES.filter((p) => p !== 'web-components').join(',');
1197
+ const stubs = PACKAGES.filter((p) => p !== 'web-components').join(',');
1185
1198
  let coveredOut;
1186
1199
  try {
1187
1200
  coveredOut = execSync(
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- // tag-lockstep.mjs — create 12 lockstep tags (umbrella vX.Y.Z + 11
3
- // per-package <pkg>-vX.Y.Z, including the 2 plugin packages that joined
4
- // the lockstep 2026-07-15) at HEAD or at a specified SHA.
2
+ // tag-lockstep.mjs — create the lockstep tag set (umbrella vX.Y.Z + one
3
+ // per-package <pkg>-vX.Y.Z per roster entry package-paths.mjs is the
4
+ // live census; 14 tags as of gh#607) at HEAD or at a specified SHA.
5
5
  //
6
6
  // Usage:
7
7
  // node tag-lockstep.mjs --version 0.6.22
@@ -15,11 +15,13 @@
15
15
  import { execSync } from 'node:child_process';
16
16
  import process from 'node:process';
17
17
  import { assertMonorepoRoot } from './assert-monorepo-root.mjs';
18
- import { PACKAGE_NAMES } from './package-paths.mjs';
18
+ import { PACKAGE_ROSTER } from './package-paths.mjs';
19
19
 
20
20
  // The roster is single-sourced in package-paths.mjs (H3) — the `adia-ui-*-v*`
21
21
  // tags trigger publish-adia-ui-{factory,forge}.yml like every other package.
22
- const PER_PACKAGE_NAMES = PACKAGE_NAMES;
22
+ // Filtered to `lockstep !== false`: a class-B package (gh#1133's
23
+ // adia-plugins) tags independently, never via this umbrella lockstep set.
24
+ const PER_PACKAGE_NAMES = PACKAGE_ROSTER.filter((p) => p.lockstep !== false).map((p) => p.name);
23
25
 
24
26
  function parseArgs(argv) {
25
27
  const args = { version: null, at: null, deleteMode: false, dry: false, repo: process.cwd() };
@@ -91,7 +93,7 @@ function main() {
91
93
  const perPkg = tags.filter((t) => t !== `v${args.version}`);
92
94
  console.log(`\n[next] run F-N1:`);
93
95
  console.log(` node scripts/release/check-release.mjs --all-pending`);
94
- console.log(`\n[next] when F-N1 is 9/9 clean, push main + tags ONE-AT-A-TIME:`);
96
+ console.log(`\n[next] when F-N1 is clean across the roster, push main + tags ONE-AT-A-TIME:`);
95
97
  console.log(` # A single \`git push origin <all tags>\` can trigger ZERO publish-on-tag`);
96
98
  console.log(` # workflows (the GitHub batch-push skip — it bit the v0.7.14 cut).`);
97
99
  console.log(` # Push each per-package tag separately so each publish-<pkg>.yml fires.`);
@@ -109,9 +111,9 @@ function selftest() {
109
111
  // Derive from the roster (package-paths.mjs is the single source) — a
110
112
  // hard-coded count here is exactly the drift gh#612 removed from the docs;
111
113
  // the v0.8.26 cut caught this one when agent+persona joined (11 → 13).
112
- const expected = PACKAGE_NAMES.length + 1; // umbrella + one per package
114
+ const expected = PER_PACKAGE_NAMES.length + 1; // umbrella + one per package
113
115
  if (tags.length !== expected) {
114
- console.error(`selftest FAIL: expected ${expected} tags (umbrella + ${PACKAGE_NAMES.length} per-package), got ${tags.length}`); process.exit(1);
116
+ console.error(`selftest FAIL: expected ${expected} tags (umbrella + ${PER_PACKAGE_NAMES.length} per-package), got ${tags.length}`); process.exit(1);
115
117
  }
116
118
  if (tags[0] !== 'v1.2.3') {
117
119
  console.error('selftest FAIL: umbrella tag must be first'); process.exit(1);
@@ -2,7 +2,8 @@
2
2
  name: adia-site-docs
3
3
  description: >-
4
4
  Review or author pages under site/pages/{architecture,getting-started,
5
- guides,patterns,reference}/ — the 34-page docs site. Use when asked to add
5
+ guides,patterns,reference}/ — the docs site (count the pages on disk; it
6
+ grows). Use when asked to add
6
7
  or edit a getting-started/architecture/guides/patterns/reference page,
7
8
  review a site docs page for consistency, fix a callout that reads as plain
8
9
  text, or explain why an inline-code chip or a demo gallery looks broken.
@@ -24,7 +25,7 @@ guides: prose + `<code-ui>` + tables, no live demos) and reference/gallery
24
25
  (patterns, reference: the same skeleton plus `<preview-ui>` demo rows and a
25
26
  near-universal closing "Guidance for agents" callout).
26
27
 
27
- Full decomposition, the 4 concrete rules, and the training-harvest-surface
28
+ Full decomposition, the convention rules, and the training-harvest-surface
28
29
  boundary this skill does NOT cover: read
29
30
  [`../../../../../.claude/docs/conventions/site-pages-authoring.md`](../../../../../.claude/docs/conventions/site-pages-authoring.md)
30
31
  in full before authoring or reviewing — it is the source of record; this
@@ -37,8 +38,8 @@ skill routes to it and enforces it, it does not restate it.
37
38
  | New page in an owned category | Read the convention doc's template section; copy the shared skeleton from a sibling page in the same category (narrative archetype vs. reference/gallery archetype). |
38
39
  | Callout / "meta content" block | `<alert-ui variant="warning\|info\|...">` with `<div slot="content">` (never `<span>` — the transpiler only treats `p`/`div`/`ul`/`ol` as prose; a `<span>` silently reorders mixed inline content on regen) for rich text — never a bare `data-*` attribute. A whole multi-heading section aimed at a different reader (not a short callout) is NOT `alert-ui`'s job either — wrong shape — the convention doc's rule 2 carries the working treatment (eyebrow `<tag-ui>` title-row, TKT-0011). |
39
40
  | Tamed admin-shell demo | Add `class="demo-frame"` to the shell instance + a page-local `<style>` block setting only `--demo-frame-height` (and any genuinely page-specific extra). That's `site/site.css`'s `.demo-frame` utility already covering `position`/`border`/`overflow`/`.demo-body` padding. |
40
- | A surface needs to read as "its own distinct object" against the page background (a chip, a pill) | Reuse `--a-canvas-well-strong` (`packages/web-components/styles/colors/semantics/core.css`) — verified ≥3:1 (WCAG 2.2 SC 1.4.11) in both schemes. `--a-canvas-well` alone is for a subtly-sunken panel; a new candidate token always runs through `color:color-verify` first. |
41
- | "Is this page consistent?" / review request | Check the page against the convention doc's rules 1–4 by name; a finding names the specific rule violated, not just "this looks off." |
41
+ | A surface needs to read as "its own distinct object" against the page background (a chip, a pill) | Reuse `--a-canvas-well-strong` (`packages/web-components/styles/colors/semantics/core.css`) — verified ≥3:1 (WCAG 2.2 SC 1.4.11) in both schemes. `--a-canvas-well` alone is for a subtly-sunken panel; for a NEW candidate token, text/link AA pairs are gated by `npm run verify:contrast` — a non-text 3:1 (SC 1.4.11) check has no mechanical runner today, so prove that ratio by hand and cite it in the PR. |
42
+ | "Is this page consistent?" / review request | Check the page against the convention doc's numbered rules by name (the doc's own headings are the roster — it has grown past four); a finding names the specific rule violated, not just "this looks off." |
42
43
  | Anything touching a real UI primitive not already listed above | Audit `packages/web-components/components/` before inventing markup (this repo's standing rule) — a fake `data-*`/`class` convention with no CSS is exactly the defect class this skill exists to prevent. |
43
44
 
44
45
  ## Verify after any change
@@ -47,8 +48,9 @@ skill routes to it and enforces it, it does not restate it.
47
48
  - `node scripts/build/site-a2ui.mjs --page <route>` for every page whose
48
49
  **markup** changed — regenerates the compiled A2UI artifact the
49
50
  docs-transpiler produces from this source; a CSS-only fix needs no regen.
50
- - `color:color-verify` for any new or changed token used for text or
51
- UI-component contrast prove the ratio, don't estimate it.
51
+ - `npm run verify:contrast` for any new or changed token used for text or
52
+ link contrast (that gate covers text/link AA pairs only — a non-text 3:1
53
+ claim needs a hand-proved, cited ratio; no mechanical runner exists).
52
54
  - `npm run check:lightningcss-build` after any CSS change (`site/site.css`
53
55
  or a component's own `.css`).
54
56
  - **Visually verify any `alert-ui`/rich-slotted-content change in a
@@ -37,7 +37,7 @@ markup that silently renders as plain paragraphs), a hand-rolled
37
37
  independently reinvented the same "tame this admin-shell demo" CSS),
38
38
  and a background token picked for its "feels dark and subtle" name
39
39
  rather than its actual measured contrast (inline `<code>` used
40
- `--a-canvas-well`, verified via `color:color-verify` at ~1.1:1 against
40
+ `--a-canvas-well`, hand-measured at ~1.1:1 against
41
41
  the page background — WCAG 2.2 SC 1.4.11 wants ≥3:1). All three are
42
42
  now fixed at the shared-CSS/token level (cascades to all 34 pages),
43
43
  but a NEW page authored without this skill's guidance would
@@ -116,7 +116,7 @@ this one component:** before answering "yes, known issue, shape 2" for ANY new
116
116
  report, grep the component's own `static template` — if it's the literal
117
117
  `() => null`, shape 2 cannot be the cause, no matter how closely the symptom
118
118
  matches the old description. [`failure-shapes.md`](references/failure-shapes.md)
119
- §2 has the full survey (150 components checked) and cites exactly why every
119
+ §2 has the full survey (150 components at the 2026-07 survey — the census has since grown) and cites exactly why every
120
120
  current children-accepting component is unaffected.
121
121
 
122
122
  ## Corpus of record
@@ -1,10 +1,11 @@
1
1
  # SSR failure shapes — symptom → root cause → status
2
2
 
3
- Three distinct root-cause classes have surfaced from real SSR consumers (adiav2's
3
+ The §-numbered root-cause classes below (count the `##` headings the list
4
+ grows) have surfaced from real SSR consumers (adiav2's
4
5
  `admin-portal-fe` and `factory-dashboard`, server-rendering AdiaUI via Astro 5 +
5
6
  `custom-elements-ssr`, which runs on linkedom — a DOM shim with no layout engine and
6
7
  missing many browser APIs). A new SSR bug report almost always maps onto one of
7
- these three; misclassifying it (e.g. treating a measurement-timing bug as a missing-API
8
+ them; misclassifying it (e.g. treating a measurement-timing bug as a missing-API
8
9
  bug) sends the fix to the wrong place. Check symptom against this table first.
9
10
 
10
11
  ## 1 · Browser-only API called unconditionally → crash
@@ -19,8 +20,10 @@ not a partial/quirky implementation, an absence. Any unconditional call throws
19
20
  `TypeError` or `ReferenceError` (undefined global) immediately.
20
21
 
21
22
  **Status: FIXED** (gh#285, PR #292, merged 2026-07-17). `UIElement`'s constructor
22
- (`packages/web-components/core/element.js`) and 24 component/trait/module files had
23
- this shape. The fix pattern (feature-detect + fallback matched to how the reference is
23
+ (`packages/web-components/core/element.js`) plus a sweep of component/trait/module
24
+ files had this shape the per-file tally is
25
+ [`status-ledger.md`](status-ledger.md)'s #285 row (the ledger, not this line, is
26
+ the count of record). The fix pattern (feature-detect + fallback matched to how the reference is
24
27
  used downstream) is [`guard-patterns.md`](guard-patterns.md) — apply that pattern to
25
28
  any NEW file that construct-calls one of these APIs; don't re-derive the shape from
26
29
  scratch.
@@ -50,7 +53,7 @@ projected text, does lose it), but **every named example in the issue currently
50
53
  has `static template = () => null`**: `admin-shell`, `admin-sidebar`, `nav-ui`,
51
54
  `text-ui`, `badge-ui`, `avatar-ui` all skip `stamp()` entirely (`if (result)
52
55
  stamp(result, this)` — `null` never enters the branch). A framework-wide survey
53
- (150 components) found every component with a NON-null template derives its
56
+ (150 components at the time) found every component with a NON-null template derives its
54
57
  visible content from properties/attributes only (`check-ui`'s `label=`,
55
58
  `switch-ui`'s `label=`/`hint=`, `skip-nav`'s `text=`) — never from light-DOM
56
59
  children — so the destructive replace, where it does fire, only ever regenerates
@@ -92,7 +92,7 @@ The shipped guard is `scripts/dev/audit-template-child-conflict.mjs`: it flags a
92
92
  NEW component that pairs a non-null `static template` with a yaml `slots.default`
93
93
  entry (critical) or a body-text usage example (advisory) — i.e. it prevents the
94
94
  conflict shape from being reintroduced, rather than patching the render lifecycle
95
- every one of the 150 components goes through. **A component author who hits this
95
+ every component goes through (150 at the 2026-07 survey; the census grows). **A component author who hits this
96
96
  audit's finding fixes it by making the template `() => null`** (the pattern every
97
97
  current children-accepting component already uses — compose via CSS + `render()`'s
98
98
  own surgical DOM manipulation, matching `avatar-ui`'s `#imgEl`/`#initialsEl`
@@ -1,30 +0,0 @@
1
- # skill-review — adia-site-docs
2
-
3
- Skill: packages/plugins/adia-ui-forge/skills/adia-site-docs/SKILL.md · Standards: skill-authoring-standards · Lint: clean
4
- Verdict: PASS (no blocking finding)
5
-
6
- Lint verbatim: `skill-postwrite-invocation-lint · clean · .../adia-site-docs/SKILL.md`
7
-
8
- | ID | Verdict | Severity | Evidence (file:line) | Fix |
9
- |----|---------|----------|----------------------|-----|
10
- | R1 | PASS | — | SKILL.md:40 ("Never restate position/border/overflow…"), :41 (`--a-canvas-well-strong` verified ≥3:1), :43 (audit primitives before inventing markup) — each survives deletion; removing any re-admits a concrete defect class. | — |
11
- | R2 | PASS | — | Desc SKILL.md:4-8 front-loads verbatim user phrasings ("add or edit a … page", "review a site docs page", "fix a callout that reads as plain text"); fences use the parseable `NOT for X (owner)` form :9-12. Corpus routing (evals/routing-corpus.json) covers 16 should-fire + 6 adversarial. | — |
12
- | R3 | PASS w/ note | minor | Species=procedural (intent.md:3); dials explicit and agree (SKILL.md:13-14); name head `adia-site-docs` is a domain-noun, not the generic zero-derivation verb the standard prescribes for procedural — but it matches the whole plugin's `adia-<domain>` grammar (sibling adia-author is identically formed). Consistent within the estate; flagged only for the record. | Keep — estate naming convention governs; no change. |
13
- | R4 | PASS w/ note | minor | Load-bearing rows instantiate concrete actions (SKILL.md:38-43). Negative imperatives run to ~4 ("do NOT invent" :38, "never a bare data-*" :39, "Never restate" :40, "don't reach for a raw ramp step without color-verify" :41) — at/over the ≤3 hard-gate guideline. | Optional: demote the two style-choice negatives (:38, :41) to positive form; reserve NEVER for :39/:40 catastrophic invariants. |
14
- | R5 | PASS | — | Deliberately routes to `.claude/docs/conventions/site-pages-authoring.md` (SKILL.md:28-32) rather than copying rules 1-4; convention doc confirmed present with matching `### 1..4` headings. Drift pair avoided by design — the strongest dimension. | — |
15
- | R6 | PASS | — | Task-shape contract table up front (SKILL.md:34-43); verify steps + stopping predicate at tail (:45-58); body 59 lines (well under 500 / 5,000-token head); reference one level deep. | — |
16
- | R7 | PASS w/ gap | minor | Output contract present (review finding "cites the specific rule … it violates" :57-58); stopping predicate present ("Done when …" :56). No *named failure branches* (e.g. "if `check:links` cannot run → report blocker, do not mark done"). | Add one failure branch to the Verify section for a check that cannot run. |
17
- | R8 | PASS | — | Numeric anchors on load-bearing dims: "34-page" (:5,20), "≥3:1 (WCAG 2.2 SC 1.4.11)" (:41), "rules 1-4" (:42,57). No vague quantifiers on load-bearing lines. | — |
18
-
19
- ## Additional evidence (non-scored hygiene)
20
-
21
- - **Phantom fence paths** (minor): description fences `site/pages/examples/**` and `site/pages/gen-ui/**` (SKILL.md:11); neither directory currently exists under `site/pages/` (only architecture, getting-started, guides, patterns, reference). The fence spends description budget on surfaces that are not yet present. Keep if these are planned training-harvest surfaces (intent.md:52 treats them as governed by composition-and-examples.md); otherwise trim to reclaim characters. Not blocking — the fence is still correct if/when those surfaces land, and adversarial-02 tests it.
22
- - **intent.md citation drift** (minor, not in payload): intent.md:64 cites `evals/evals.json`, but the shipped corpus is `evals/routing-corpus.json`. intent.md is a forge artifact, not skill payload, so it does not affect triggering — but repair the citation in the same edit to keep the record honest.
23
-
24
- ## Top 3
25
-
26
- 1. (minor) R7 — add one named failure branch to the Verify section (a check that cannot run → report blocker, do not mark done); procedural bodies owe an explicit failure branch, currently absent (SKILL.md:45-58).
27
- 2. (minor) R4 — negative-imperative count sits at ~4; demote the two style-choice negatives (:38 section shape, :41 ramp step) to positive phrasing, reserving hard gates for the two real invariants (:39 fabricated data-*, :40 restated demo-frame CSS).
28
- 3. (minor) Phantom fence — reconcile `site/pages/examples/**` and `site/pages/gen-ui/**` (SKILL.md:11): confirm they are planned surfaces or trim the fence; and fix the `evals.json` → `routing-corpus.json` citation in intent.md:64.
29
-
30
- No blocking or major findings. The skill's reference-don't-restate discipline (R5) and measured contrast anchor (R8) are its strongest features.
@@ -1,63 +0,0 @@
1
- # adia-ssr skill audit (FLOOR)
2
-
3
- Skill: `packages/plugins/adia-ui-forge/skills/adia-ssr/` · Standards: skill-authoring-standards · Lint: clean
4
- Verdict: **PASS**
5
-
6
- Species: knowledge (`disable-model-invocation: false`, `user-invocable: false`) — sibling in
7
- shape to `packages/plugins/adia-ui-factory/skills/adia-tokens/`, confirmed.
8
-
9
- | ID | Verdict | Severity | Evidence (file:line) | Fix |
10
- |----|---------|----------|----------------------|-----|
11
- | R1 Behavior delta | PASS | — | `SKILL.md:67-73` (caveat: don't invent a component-local workaround for gh#284 — deleting it removes the one line steering Claude away from a plausible wrong answer); `SKILL.md:36-38` (gh#288 dependency on gh#284 — deleting it, Claude could treat #288 as independently actionable); `SKILL.md:51` (test-without-linkedom consult row — deleting it loses the exact routing signal to the one file that explains why the repo's default test env can't reproduce SSR bugs) | none |
12
- | R2 Trigger fidelity | PASS | — | Description (`SKILL.md:3-10`) phrasings "does X work under SSR", "why does X crash/disappear when server-rendered", "is this connect-time read safe" are the literal `should_route_to_ssr: true` phrases in `evals/routing-corpus.json:20,35,90`; fences ("NOT for implementing a fix (adia-author) or consumer host/hydration wiring (adia-host...)") correctly repel `ssr-adversarial-01/02/05` (routing-corpus.json:104-107, 110-114, 130-135) | none |
13
- | R3 Species/dial agreement | PASS | — | `SKILL.md:11-12` both dials explicit and correct for knowledge species; name `adia-ssr` follows the established local `adia-*` topic-noun convention (matches sibling `adia-tokens`, `adia-a2ui`) rather than the generic `x-patterns` grammar — acceptable under the project's own precedent | none |
14
- | R4 Register | PASS | — | Load-bearing lines cite exact file:line, PR, and issue numbers rather than describing generically, e.g. `SKILL.md:63-66` ("`UIElement.connectedCallback`... calls `stamp(result, this)`... currently line 194") — verified accurate, see Notes | none |
15
- | R5 No restatement | PASS | — | No drift-pair found against `component-token-contract.md` / `component-implementation-patterns.md` / AGENTS.md — none cover SSR. Pack explicitly fences out generic web-components-SSR theory (`SKILL.md:97-99`), so it doesn't restate model-general knowledge either | none |
16
- | R6 Position | MINOR | minor | Body is only ~108 lines (~2,000 tokens, well inside the 5,000-token survival window, so no practical compaction risk) — but structurally, "Deviation doctrine" and "Boundaries" (`SKILL.md:75-99`, gate-shaped content) sit *after* the "Worked example" (`SKILL.md:55-74`), inverted from the "contracts/gates first, examples last" rule | Move Deviation doctrine + Boundaries above the Worked example on next semantic edit; not urgent given total size |
17
- | R8 Quantities | PASS | — | `127+ primitives`, `24 component/trait/module files`, `12 files` calling `this.internals.*`, `~110-line shim`, dated `2026-07-17`, gh#284-288 — all load-bearing counts are numeric, none vague | none |
18
-
19
- R7 (Contracts): N/A — knowledge species, not procedural/command.
20
-
21
- ## Notes — factual grounding (beyond the R1-R8 checklist, but relevant to a knowledge pack's core promise)
22
-
23
- Spot-checked every concrete claim against the actual repo state rather than trusting the pack's
24
- own self-description:
25
-
26
- - `packages/web-components/core/template.js:194` — `export function stamp(result, container)` is
27
- exactly where `failure-shapes.md` and the Worked example say it is.
28
- - `packages/web-components/core/element.js` — `attachInternals` shim (`this.internals = typeof
29
- this.attachInternals === 'function' ? this.attachInternals() : NOOP_INTERNALS`),
30
- `adoptedStyleSheets` guard (`if (!('adoptedStyleSheets' in document)) return;`), and the
31
- `connectedCallback` → `stamp()` call all match `guard-patterns.md` and `failure-shapes.md`
32
- verbatim.
33
- - `packages/web-modules/shell/admin-sidebar/admin-sidebar.js` — `#syncCollapsedFromWidth` (zero-rect
34
- `return` before the decision) and `#setupChildResizeObserver` (`typeof ResizeObserver ===
35
- 'undefined'` guard, deferred correction) match `guard-patterns.md` §3's cited code exactly,
36
- including `SNAP_THRESHOLD`.
37
- - `packages/web-components/core/element.test.js:259` — the `describe('UIElement — SSR
38
- browser-API absence (gh#285)'` block matches `test-without-linkedom.md`'s cited delete/try/finally
39
- pattern.
40
- - `git log`: PR #292 (gh#285) and PR #290 (gh#286) both merged 2026-07-17, matching every date
41
- cited in `status-ledger.md` and `consumer-workarounds.md`.
42
- - No `linkedom` in any `package.json` in the tree — confirms `test-without-linkedom.md`'s central
43
- claim.
44
- - Live `gh issue view` for 284-288 today: #284 OPEN, #285 CLOSED, #286 CLOSED, #287 OPEN, #288
45
- OPEN — matches `status-ledger.md`'s table exactly, row for row, including the "#287 is
46
- unrelated" framing.
47
-
48
- Every citable fact in this pack checked out. This is unusually high grounding for a hand-authored
49
- knowledge pack — worth naming as the standard other `adia-*` knowledge skills should be held to.
50
-
51
- ## Top 3
52
-
53
- 1. **Ship as-is.** Zero blocking or major findings; lint clean; every code/issue citation
54
- independently verified against the live repo and `gh issue view` — the pack's core promise
55
- ("cited to the actual shipped/open code") is actually true today, not just claimed.
56
- 2. **Routing corpus is well-formed and matches its own spec** — 12 trigger / 5 adversarial phrases
57
- (29.4% adversarial, spec says ~29%), all 5 reference files covered by `expected_shape`, and the
58
- 3 adversarial near-misses (gh#287 bundler bug, a2ui pipeline, generic hydration theory) are
59
- genuinely hard boundary cases, not straw men.
60
- 3. **One minor, non-blocking structural nit (R6):** the gate-shaped "Deviation doctrine" and
61
- "Boundaries" sections trail the "Worked example" instead of leading it. Harmless at this body
62
- size (~2K tokens, nowhere near the 5K compaction cutoff) — fix opportunistically on the next
63
- semantic edit to this file, not worth a dedicated pass.