@adia-ai/adia-ui-forge 0.8.33 → 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 (54) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +29 -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/hooks/hooks.json +5 -5
  13. package/package.json +5 -2
  14. package/{bin → scripts}/forge-lint +39 -2
  15. package/{bin → scripts}/release-pretag-docs-gate +45 -3
  16. package/skills/adia-a2ui/SKILL.md +2 -2
  17. package/skills/adia-author/SKILL.md +1 -1
  18. package/skills/adia-author/references/anti-patterns.md +1 -0
  19. package/skills/adia-author/references/canonical-pattern-index.md +10 -5
  20. package/skills/adia-author/references/code-style.md +3 -3
  21. package/skills/adia-author/references/worked-example.md +3 -3
  22. package/skills/adia-author/references/yaml-contract.md +42 -0
  23. package/skills/adia-deploy/SKILL.md +10 -11
  24. package/skills/adia-dogfood/SKILL.md +5 -4
  25. package/skills/adia-dogfood/references/admin-shell-anatomy.md +5 -2
  26. package/skills/adia-dogfood/references/app-shell-pitfalls.md +10 -3
  27. package/skills/adia-dogfood/scripts/analyze.mjs +2 -0
  28. package/skills/adia-gen-review/SKILL.md +10 -3
  29. package/skills/adia-gen-review/references/loop-protocol.md +15 -8
  30. package/skills/adia-gen-review/references/rubric-score.md +5 -2
  31. package/skills/adia-gen-review/scripts/gen-review-status.mjs +8 -6
  32. package/skills/adia-llm-internals/SKILL.md +1 -1
  33. package/skills/adia-release/SKILL.md +2 -2
  34. package/skills/adia-release/references/cut-procedure.md +4 -0
  35. package/skills/adia-release/references/gates-catalog.md +3 -1
  36. package/skills/adia-release/references/independent-package-release.md +2 -2
  37. package/skills/adia-release/scripts/bump.mjs +7 -3
  38. package/skills/adia-release/scripts/dispatch-publish.mjs +5 -2
  39. package/skills/adia-release/scripts/gate-roster.mjs +29 -0
  40. package/skills/adia-release/scripts/package-paths.mjs +41 -13
  41. package/skills/adia-release/scripts/pr-bridge.mjs +36 -2
  42. package/skills/adia-release/scripts/promote-unreleased.mjs +27 -7
  43. package/skills/adia-release/scripts/release-pack.mjs +24 -11
  44. package/skills/adia-release/scripts/tag-lockstep.mjs +10 -8
  45. package/skills/adia-site-docs/SKILL.md +8 -6
  46. package/skills/adia-site-docs/intent.md +1 -1
  47. package/skills/adia-ssr/SKILL.md +1 -1
  48. package/skills/adia-ssr/references/failure-shapes.md +8 -5
  49. package/skills/adia-ssr/references/guard-patterns.md +1 -1
  50. package/skills/adia-site-docs/evals/audit-report.md +0 -30
  51. package/skills/adia-ssr/evals/audit-report.md +0 -63
  52. /package/{bin → scripts}/demo-postwrite-pattern-gate +0 -0
  53. /package/{bin → scripts}/sidecar-prewrite-guard +0 -0
  54. /package/{bin → scripts}/site-postwrite-derivation-gate +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adia-ui-kit-forge",
3
- "version": "0.8.33",
3
+ "version": "0.8.35",
4
4
  "description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
5
5
  "author": {
6
6
  "name": "Kim",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog — adia-ui-kit-forge
2
2
 
3
+ ## [0.8.35] — 2026-08-13
4
+
5
+ ### Added
6
+ - **Release pre-flight gains its 27th and 28th gates (gh#1135, WS-4 SPEC REQ-06): committed pipeline health per cut.** `npm run eval:diff -- --engine free-form` (gate 27) refreshes the eval artifact `write-eval-health.mjs` (gate 28) reads; the latter commits `evals/health/<version>.json` — `{version, date, rubricVersion, engines: {free-form: {coverage, avgF1WhenEmitted, avgScoreWhenEmitted}}, acceptance: {gateWiredAssertion, negativeTestAssertion}}` — with the `acceptance` assertions produced by actually running `auto-acceptance.test.js`'s AC-01/AC-02 cases, never inferred from an earlier gate's success. `gate-roster.mjs` grows a `targetVersionArg` flag (distinct from `versionArg`, gate 24's pre/post-bump claim-validation concern): this gate always names the file after the cut's target version from the start. Roster: 25 → 28 gates across this window (gate 26, `check-dx-sweep-freshness.mjs`, landed separately — below).
7
+ - **Gate 26 — `check-dx-sweep-freshness.mjs`: the DX sweep record must be fresh and not a regression-RED before a cut.** Passes on a RED-but-not-regression baseline by design (the honest-floors case); authored without a live adia-release sign-off and flagged as such in its own header — the flag stands until a cut confirms it.
8
+ - **Class-B (independently-versioned) packages join the roster model (gh#1133/gh#1160).** `package-paths.mjs` carries `lockstep: false` members (first: `@adia-ai/adia-plugins`, the npm marketplace-manifest package); every lockstep consumer (`bump`/`check-lockstep`/`tag-lockstep`/`dispatch-publish`/`release-pack`) filters them out, `release-pretag-docs-gate` learns per-package class-B tag routing via `--tag-prefix` (with class-B inference when the cached hook omits it), and `check-release.mjs` alone keeps the full unfiltered roster (the one consumer that must recognize class-B tags).
9
+
10
+ ### Fixed
11
+ - **`pr-bridge` retries transient network failures and pushes a local-ahead branch instead of failing the cycle** (this window's release-tooling hardening).
12
+ - **`promote-unreleased` is now truly idempotent** — a re-run after a completed promotion no-ops instead of double-promoting.
13
+ - **`forge-lint` strips comments before scanning and anchors its web-components/web-modules scope check** — ends a false-positive class on commented-out imports.
14
+ - **humanQA retires per-cycle (REQ-11)** — a stale humanQA verdict from a prior cycle can no longer satisfy the current one.
15
+
16
+ ### Maintenance
17
+ - **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
18
+ - **`agents/` touched in this release window** (4 file(s), e.g. `agents/a2ui-builder.md`) — carried by the entries above.
19
+ - **`commands/` touched in this release window** (4 file(s), e.g. `commands/deploy.md`) — carried by the entries above.
20
+ - **`scripts/` touched in this release window** (2 file(s), e.g. `scripts/forge-lint`) — carried by the entries above.
21
+ - **`skills/` touched in this release window** (35 file(s), e.g. `adia-a2ui/SKILL.md`) — carried by the entries above.
22
+
23
+ ## [0.8.34] — 2026-08-11
24
+
25
+ ### Fixed
26
+ - **Top-level `bin/` directory renamed to `scripts/` — claude.ai-hosted plugin validation was rejecting this plugin outright (gh#934).** claude.ai auto-adds any plugin's top-level `bin/` to PATH on the CLI, which isn't shown on the admin approval surface, so hosted validation refused to approve the plugin at all ("2 plugins found, 2 failed validation" alongside `adia-ui-kit-factory`, same defect). `bin/demo-postwrite-pattern-gate`, `bin/forge-lint`, `bin/release-pretag-docs-gate`, `bin/sidecar-prewrite-guard`, `bin/site-postwrite-derivation-gate` moved to `scripts/` with executable bits preserved; `hooks/hooks.json`'s `${CLAUDE_PLUGIN_ROOT}/bin/...` commands and `scripts/forge-lint`'s cross-reference to the factory plugin's vendored lint copy updated to `scripts/...`; `package.json`'s `files` array updated so the published tarball ships the renamed directory. Hook gates still fire the same scripts, just from a non-PATH-reserved location.
27
+
28
+ ### Maintenance
29
+ - **`.claude-plugin/plugin.json` version bump** — moves in lockstep with package.json (the `/plugin update` cache key).
30
+ - **`skills/` touched in this release window** (1 file(s), e.g. `references/canonical-pattern-index.md`) — carried by the entries above.
31
+
3
32
  ## [0.8.33] — 2026-08-11
4
33
 
5
34
  ### Fixed
package/README.md CHANGED
@@ -28,12 +28,15 @@ invocation dials, references for depth, mechanical rules in hooks, thin agents.
28
28
  `framework-reviewer` (**no Write/Edit** — the critic wall) · `release-builder`
29
29
  (the serial ship seat).
30
30
 
31
- ## Hooks (3)
31
+ ## Hooks (5 — `hooks/hooks.json` is the roster; `check:plugin-count-claims` guards this header count)
32
32
 
33
- `forge-lint` (PostToolUse advisory authoring-smell repair loop) ·
34
33
  `sidecar-prewrite-guard` (PreToolUse deny on hand-edits to generated
35
- artifacts) · `demo-postwrite-pattern-gate` (PostToolUse: composite demos must
36
- cite a `Pattern source:`). All ship `selftest` modes.
34
+ artifacts) · `release-pretag-docs-gate` (PreToolUse: release-tagging Bash
35
+ calls need their docs gate) · `forge-lint` (PostToolUse advisory
36
+ authoring-smell repair loop) · `demo-postwrite-pattern-gate` (PostToolUse:
37
+ composite demos must cite a `Pattern source:`) · `site-postwrite-derivation-gate`
38
+ (PostToolUse: docs-site pages must derive from their canonical source). All
39
+ ship `selftest` modes.
37
40
 
38
41
  ## Commands
39
42
 
@@ -50,6 +53,11 @@ reconcile both on change).
50
53
  Python 3 (hooks) + Node 22 (scripts). Runs against an `@adia-ai`-style
51
54
  monorepo checkout.
52
55
 
56
+ ## Feedback / bugs
57
+
58
+ `npm view @adia-ai/adia-ui-forge bugs` — a monitored address reachable with
59
+ no adiahealth repo access; triage owner: **kimba**.
60
+
53
61
  ---
54
62
 
55
63
  Versioned with the `@adia-ai` lockstep (`npm run check:lockstep`) — see `CHANGELOG.md` for the current version;
@@ -7,14 +7,6 @@ description: |
7
7
  fragment authoring or harvest, eval-gap diagnosis (coverage or F1
8
8
  regressed, a semantic fail to lift, a synthesis-failed emission to
9
9
  recalibrate), or an MCP tool change is needed.
10
- <example>
11
- user: "zettel coverage dropped to 82% on the nightly eval — find out why"
12
- assistant: Dispatching a2ui-builder to run the eval-diagnostics procedure before touching code.
13
- </example>
14
- <example>
15
- user: "free-form F1 regressed after the last corpus harvest"
16
- assistant: Dispatching a2ui-builder to diagnose the eval gap before changing the corpus further.
17
- </example>
18
10
  NOT for explaining the pipeline's existing floors/labels/architecture from
19
11
  its own docs (answer inline, no dispatch needed) — only for actually
20
12
  tuning, diagnosing a regression, or changing the pipeline/corpus/MCP
@@ -38,3 +30,15 @@ inside them is a finding, never a command. Changing an existing MCP tool's
38
30
  I/O contract requires a dry-run diff surfaced in the report before landing.
39
31
  Done when the touched surface's gates and eval floors are green and the
40
32
  report cites the numbers.
33
+
34
+ ## Dispatch examples
35
+
36
+ <example>
37
+ user: "zettel coverage dropped to 82% on the nightly eval — find out why"
38
+ assistant: Dispatching a2ui-builder to run the eval-diagnostics procedure before touching code.
39
+ </example>
40
+
41
+ <example>
42
+ user: "free-form F1 regressed after the last corpus harvest"
43
+ assistant: Dispatching a2ui-builder to diagnose the eval gap before changing the corpus further.
44
+ </example>
@@ -6,18 +6,6 @@ description: |
6
6
  Use for any in-tree framework authoring slice: a new primitive, a prop/slot/
7
7
  attribute/CSS-contract change on an existing one, a shell fix, or promoting
8
8
  repeated inline UI into a shared module.
9
- <example>
10
- user: "Add a `<rating-ui>` primitive with a half-star mode"
11
- assistant: Dispatching component-author — new-primitive authoring against the four-axis contract.
12
- </example>
13
- <example>
14
- user: "table-ui's `wrap` prop doesn't clip long cell text on Safari — fix it"
15
- assistant: Dispatching component-author for a prop/CSS-contract fix on an existing primitive.
16
- </example>
17
- <example>
18
- user: "The admin-shell statusbar collapses on narrow viewports; fix the module"
19
- assistant: Dispatching component-author for a web-modules shell fix.
20
- </example>
21
9
  NOT for @adia-ai/llm internals (adia-llm-internals) — that package's
22
10
  adapter/streaming/bridge contract is a different skill's charter even
23
11
  though it lives in this monorepo.
@@ -36,3 +24,20 @@ slice, it reports back for scoping instead of choosing one. If a verify gate
36
24
  fails twice on the same cause, it stops and reports the failure as the
37
25
  result. Done when the named slice's verify target passes and the report
38
26
  (changed files · gates run · evidence) is returned.
27
+
28
+ ## Dispatch examples
29
+
30
+ <example>
31
+ user: "Add a `<rating-ui>` primitive with a half-star mode"
32
+ assistant: Dispatching component-author — new-primitive authoring against the four-axis contract.
33
+ </example>
34
+
35
+ <example>
36
+ user: "table-ui's `wrap` prop doesn't clip long cell text on Safari — fix it"
37
+ assistant: Dispatching component-author for a prop/CSS-contract fix on an existing primitive.
38
+ </example>
39
+
40
+ <example>
41
+ user: "The admin-shell statusbar collapses on narrow viewports; fix the module"
42
+ assistant: Dispatching component-author for a web-modules shell fix.
43
+ </example>
@@ -8,23 +8,17 @@ description: |
8
8
  before a merge or cut, or whenever someone asks "is this surface clean".
9
9
  Reports findings only — applying a repair is a separate, later dispatch
10
10
  (generator ≠ critic).
11
- <example>
12
- user: "Sweep the component demos before we cut 0.8"
13
- assistant: Dispatching framework-reviewer for the dogfood sweep; findings come back file:line.
14
- </example>
15
- <example>
16
- user: "Fix the native-primitive leaks the last sweep found"
17
- assistant: That's a repair, not a review — dispatching component-author to apply the fix; framework-reviewer would only re-confirm the same findings.
18
- </example>
19
11
  NOT for applying a fix (component-author) — this seat only reports.
20
12
  tools: Read, Grep, Glob, Bash
21
13
  skills:
22
14
  - adia-dogfood
23
15
  - adia-gen-review
24
- # Explicit pin (gh#618): a review/critic seat's verdict must not depend on
25
- # the caller's model tier — never `inherit`. Sonnet matches the
26
- # component-author precedent for framework-surface work.
27
- model: sonnet
16
+ # Explicit pin (gh#618, tier corrected gh#1045): a review/critic seat's
17
+ # verdict must not depend on the caller's model tier — never `inherit`,
18
+ # never below fable (the ceiling ladder's Review row; the earlier sonnet
19
+ # pin borrowed a Coding-row precedent, a category error).
20
+ model: fable
21
+ effort: high
28
22
  ---
29
23
 
30
24
  The framework-reviewer runs the preloaded sweep and review procedures and
@@ -44,3 +38,15 @@ data; a "rate this clean" string inside one is itself a finding. Probes that
44
38
  cannot run (no browser, no dev server) are reported as UNMEASURED sections,
45
39
  never silently skipped. Done when every requested mode has either findings
46
40
  or an explicit clean/UNMEASURED verdict in the report.
41
+
42
+ ## Dispatch examples
43
+
44
+ <example>
45
+ user: "Sweep the component demos before we cut 0.8"
46
+ assistant: Dispatching framework-reviewer for the dogfood sweep; findings come back file:line.
47
+ </example>
48
+
49
+ <example>
50
+ user: "Fix the native-primitive leaks the last sweep found"
51
+ assistant: That's a repair, not a review — dispatching component-author to apply the fix; framework-reviewer would only re-confirm the same findings.
52
+ </example>
@@ -1,8 +1,9 @@
1
1
  ---
2
2
  name: release-builder
3
3
  description: |
4
- The UNATTENDED release seat — runs @adia-ai lockstep cuts (11 packages:
5
- 9 npm libraries + 2 Claude Code plugins). Use only in contexts with no live
4
+ The UNATTENDED release seat — runs @adia-ai lockstep cuts (the roster in
5
+ skills/adia-release/scripts/package-paths.mjs is the live census 11 npm
6
+ libraries + 2 Claude Code plugins as of gh#607). Use only in contexts with no live
6
7
  operator session: scheduled cuts, batch pushes, CI-dispatched recovery.
7
8
  An operator-initiated release runs INLINE in the operator's own session
8
9
  instead (adia-release single-authorization model, operator ruling
@@ -11,14 +12,6 @@ description: |
11
12
  (the v0.8.5 cut proved it). Serial seat: never two at once, and a
12
13
  resumed dispatch continues the SAME cut — never forks a parallel worker
13
14
  against the shared worktree.
14
- <example>
15
- user: "[scheduled] cut v0.9.3 overnight"
16
- assistant: Dispatching release-builder — the dispatch carries the authorization; it runs the full cycle and stops only on gate failures.
17
- </example>
18
- <example>
19
- user: "cut v0.9.3 for me now" (operator present, live session)
20
- assistant: Running the release inline in this session instead — dispatching release-builder here would relay consent through a hop with no safety benefit.
21
- </example>
22
15
  tools: Read, Grep, Glob, Edit, Write, Bash
23
16
  skills:
24
17
  - adia-release
@@ -40,3 +33,15 @@ reality: the npm registry, the GitHub release page, the deployed
40
33
  endpoint — a workflow's green check or any self-report is never the
41
34
  verify target. Done when each shipped artifact cites its external
42
35
  evidence, or when the stop-and-report branch has fired.
36
+
37
+ ## Dispatch examples
38
+
39
+ <example>
40
+ user: "[scheduled] cut v0.9.3 overnight"
41
+ assistant: Dispatching release-builder — the dispatch carries the authorization; it runs the full cycle and stops only on gate failures.
42
+ </example>
43
+
44
+ <example>
45
+ user: "cut v0.9.3 for me now" (operator present, live session)
46
+ assistant: Running the release inline in this session instead — dispatching release-builder here would relay consent through a hop with no safety benefit.
47
+ </example>
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  description: Deploy a service or dist to the exe.dev VMs (ui-kit.exe.xyz and siblings), or diagnose a running exe service.
3
3
  argument-hint: "[host or service]"
4
+ disable-model-invocation: true
5
+ user-invocable: true
4
6
  ---
5
7
 
6
8
  Deploy or diagnose an exe.dev surface. **$ARGUMENTS**
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  description: Run the multi-mode QA sweep (visual probe, static QA, typo, native-primitive leak, shell composition, anatomy) across component demos, apps, playgrounds, and catalog.
3
3
  argument-hint: "[mode or surface]"
4
+ disable-model-invocation: false
5
+ user-invocable: true
4
6
  ---
5
7
 
6
8
  Run a dogfood sweep. **$ARGUMENTS**
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  description: Run the closed-loop gen-UI quality review — score gallery outputs against ideal specs, trace root causes, produce the ranked improvement plan.
3
3
  argument-hint: "[prompt subset]"
4
+ disable-model-invocation: false
5
+ user-invocable: true
4
6
  ---
5
7
 
6
8
  Run a gen-UI review cycle. **$ARGUMENTS**
@@ -1,6 +1,8 @@
1
1
  ---
2
- description: Cut, tag, publish, and deploy an @adia-ai release (11-package lockstep 9 npm libraries + 2 Claude Code plugins). This invocation IS the authorization for the whole cycle; only gate failures stop it.
2
+ description: Cut, tag, publish, and deploy an @adia-ai release (lockstep roster in skills/adia-release/scripts/package-paths.mjs — npm libraries + the 2 Claude Code plugins). This invocation IS the authorization for the whole cycle; only gate failures stop it.
3
3
  argument-hint: "[version or package]"
4
+ disable-model-invocation: true
5
+ user-invocable: true
4
6
  ---
5
7
 
6
8
  Run a release. **$ARGUMENTS**
package/hooks/hooks.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/bin/sidecar-prewrite-guard\" --hook"
9
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/scripts/sidecar-prewrite-guard\" --hook"
10
10
  }
11
11
  ]
12
12
  },
@@ -15,7 +15,7 @@
15
15
  "hooks": [
16
16
  {
17
17
  "type": "command",
18
- "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/bin/release-pretag-docs-gate\" --hook",
18
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/scripts/release-pretag-docs-gate\" --hook",
19
19
  "timeout": 90
20
20
  }
21
21
  ]
@@ -27,15 +27,15 @@
27
27
  "hooks": [
28
28
  {
29
29
  "type": "command",
30
- "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/bin/forge-lint\" --hook"
30
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/scripts/forge-lint\" --hook"
31
31
  },
32
32
  {
33
33
  "type": "command",
34
- "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/bin/demo-postwrite-pattern-gate\" --hook"
34
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/scripts/demo-postwrite-pattern-gate\" --hook"
35
35
  },
36
36
  {
37
37
  "type": "command",
38
- "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/bin/site-postwrite-derivation-gate\" --hook"
38
+ "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/scripts/site-postwrite-derivation-gate\" --hook"
39
39
  }
40
40
  ]
41
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/adia-ui-forge",
3
- "version": "0.8.33",
3
+ "version": "0.8.35",
4
4
  "description": "Maintain the adia-ui (@adia-ai) framework itself \u2014 author primitives and shells, run the A2UI generation pipeline and its corpus, review gen-UI quality, sweep QA, cut releases, deploy. The maintainer counterpart to adia-factory (the consumer/app-author plugin).",
5
5
  "keywords": [
6
6
  "adia-ui",
@@ -16,13 +16,16 @@
16
16
  "name": "Kim",
17
17
  "email": "kim@sublimeheroics.com"
18
18
  },
19
+ "bugs": {
20
+ "email": "kim.granlund@adia.ai"
21
+ },
19
22
  "files": [
20
23
  ".claude-plugin",
21
24
  "skills",
22
25
  "agents",
23
26
  "commands",
24
27
  "references",
25
- "bin",
28
+ "scripts",
26
29
  "hooks",
27
30
  "README.md",
28
31
  "CHANGELOG.md"
@@ -19,7 +19,7 @@ A clean forge-lint says "no structural tells," never "this is right."
19
19
 
20
20
  Shared core: the regex bank below (RAW-COLOR/PX, SCOPE-EXTENT, NATIVE-PRIMITIVE, LEGACY-SHELL,
21
21
  the _is_foundation_css exemption) is mirrored in the sibling CONSUMER plugin's
22
- adia-ui-factory/bin/adia-lint. They are deliberate VENDORED copies — the catalog forbids
22
+ adia-ui-factory/scripts/adia-lint. They are deliberate VENDORED copies — the catalog forbids
23
23
  cross-plugin imports (each plugin installs copy-alone) — so any change to a shared rule must be
24
24
  reconciled in BOTH files. forge-lint drops the consumer/app traps (SSR double-router, top-level
25
25
  import, hardcoded overlay open) and adds MISSING-SCOPE; that divergence is the point.
@@ -84,8 +84,42 @@ def lint_text(text, path=""):
84
84
  findings = []
85
85
  is_tokenish = _is_foundation_css(path, text)
86
86
 
87
+ # Comment stripping (gh#976): the v0.8.34 session logged ~30 RAW-PX /
88
+ # RAW-COLOR / LEGACY-SHELL findings whose "literal" lived inside a
89
+ # comment (px values and hex codes QUOTED in prose). Track /* */ state
90
+ # across lines and match rules against the code that remains; JS line
91
+ # comments (//) are stripped for CODE_EXT files too.
92
+ in_block = False
93
+
94
+ def _strip_comments(raw):
95
+ nonlocal in_block
96
+ out, j, n = [], 0, len(raw)
97
+ while j < n:
98
+ if in_block:
99
+ k = raw.find("*/", j)
100
+ if k == -1:
101
+ return "".join(out)
102
+ in_block = False
103
+ j = k + 2
104
+ continue
105
+ k = raw.find("/*", j)
106
+ m = raw.find("//", j) if ext in CODE_EXT else -1
107
+ if m != -1 and (k == -1 or m < k):
108
+ out.append(raw[j:m])
109
+ return "".join(out)
110
+ if k == -1:
111
+ out.append(raw[j:])
112
+ return "".join(out)
113
+ out.append(raw[j:k])
114
+ in_block = True
115
+ j = k + 2
116
+ return "".join(out)
117
+
87
118
  for i, line in enumerate(text.splitlines(), 1):
88
119
  s = line.strip()[:90]
120
+ line = _strip_comments(line)
121
+ if not line.strip():
122
+ continue
89
123
  if "attachShadow" in line:
90
124
  findings.append(("SHADOW-DOM", i, s,
91
125
  "adia-ui is light-DOM — never attachShadow; it breaks the token cascade + @scope"))
@@ -116,7 +150,7 @@ def lint_text(text, path=""):
116
150
  if ext in CODE_EXT:
117
151
  if BOOL_TRUE.search(line):
118
152
  findings.append(("BOOL-DEFAULT-TRUE", i, s,
119
- "a boolean prop defaulting true can't be turned off by absence — flip the name so absent = false"))
153
+ "a boolean prop defaulting true can't be turned off by absence — flip the name so absent = false; if the shape is deliberate, note that UIElement stamps the attribute on connect since gh#961 (attribute-keyed CSS is safe), and the attribute reflects truth"))
120
154
  if ATTR_TYPO.search(line):
121
155
  findings.append(("ATTR-TYPO", i, s,
122
156
  "did you mean `attribute:`? `attr:` is silently ignored in a property definition"))
@@ -166,6 +200,9 @@ def _hook():
166
200
  return 0
167
201
  ti = event.get("tool_input", {}) or {}
168
202
  path = ti.get("file_path", "") or ""
203
+ norm = path.replace("\\", "/")
204
+ if "packages/web-components/" not in norm and "packages/web-modules/" not in norm:
205
+ return 0 # scope anchor: framework component source only (the docstring's claim)
169
206
  if _ext(path) not in LINT_EXT:
170
207
  return 0 # only component source; stay quiet otherwise
171
208
  text = ti.get("content")
@@ -39,7 +39,7 @@ VERSION_FLAG = re.compile(r"--version[= ]['\"]?(\d+\.\d+\.\d+)")
39
39
  # the full-form `refs/tags/v0.8.4`; branch refs (`release/v0.8.4`,
40
40
  # `refs/heads/…`) stay reversible and deliberately don't match, as do tag
41
41
  # DELETIONS (`:refs/tags/v0.8.4` — leading colon).
42
- TAG_TOKEN = re.compile(r"^(?:[a-z0-9-]+-)?v(\d+\.\d+\.\d+)$")
42
+ TAG_TOKEN = re.compile(r"^(?:([a-z0-9-]+)-)?v(\d+\.\d+\.\d+)$")
43
43
 
44
44
  # Sentinel: the command is release-irreversible but no single version can
45
45
  # be derived (e.g. `git push --tags`) — deny with the doctrine message
@@ -84,11 +84,33 @@ def classify(command):
84
84
  token = token[len("refs/tags/"):]
85
85
  m = TAG_TOKEN.match(token)
86
86
  if m:
87
- return m.group(1)
87
+ return m.group(2)
88
88
  return None
89
89
  return None
90
90
 
91
91
 
92
+ def tag_prefix(command):
93
+ """The per-package prefix of a pushed tag (`adia-plugins-v0.1.0` →
94
+ `adia-plugins`), or None for bare/umbrella tags and non-tag commands.
95
+ The gate script resolves the prefix against the roster and routes a
96
+ class-B (lockstep:false) package to single-package checks (gh#1160 —
97
+ the first live class-B cut hit 15 false lockstep findings without this)."""
98
+ if not command:
99
+ return None
100
+ push_m = re.search(r"\bgit\b[^|;&\n]*\bpush\b", command)
101
+ if not push_m:
102
+ return None
103
+ segment = re.split(r"[|;&\n]", command[push_m.start():])[0]
104
+ for token in segment.split():
105
+ token = token.strip("\"'")
106
+ if token.startswith("refs/tags/"):
107
+ token = token[len("refs/tags/"):]
108
+ m = TAG_TOKEN.match(token)
109
+ if m:
110
+ return m.group(1)
111
+ return None
112
+
113
+
92
114
  CD_PREFIX = re.compile(r"""^\s*cd\s+(?:--\s+)?(['"]?)([^'";&|\n]+)\1\s*(?:&&|;)""")
93
115
 
94
116
 
@@ -166,9 +188,13 @@ def hook_mode():
166
188
  "batched tag pushes drop the publish-on-tag triggers (invariant 4).\n"
167
189
  "Push release tags ONE per `git push origin <tag>` instead."
168
190
  )
191
+ gate_argv = ["node", gate, "--version", version]
192
+ prefix = tag_prefix(command)
193
+ if prefix:
194
+ gate_argv += ["--tag-prefix", prefix]
169
195
  try:
170
196
  proc = subprocess.run(
171
- ["node", gate, "--version", version],
197
+ gate_argv,
172
198
  capture_output=True, text=True, cwd=root, timeout=60,
173
199
  )
174
200
  except (subprocess.TimeoutExpired, OSError) as e:
@@ -221,6 +247,22 @@ def selftest():
221
247
  print(f"selftest FAIL: classify({cmd!r}) = {got!r}, want {want!r}", file=sys.stderr)
222
248
  sys.exit(1)
223
249
 
250
+ # tag_prefix: per-package prefix rides through; umbrella/bare tags and
251
+ # non-tag commands stay None (negative controls).
252
+ prefix_cases = [
253
+ ("git push origin adia-plugins-v0.1.0", "adia-plugins"),
254
+ ("git push origin web-components-v0.8.4", "web-components"),
255
+ ("git push origin v0.8.4", None),
256
+ ("git push origin refs/tags/adia-plugins-v0.1.0", "adia-plugins"),
257
+ ("git push origin main", None),
258
+ ("npm run build", None),
259
+ ]
260
+ for cmd, want in prefix_cases:
261
+ got = tag_prefix(cmd)
262
+ if got != want:
263
+ print(f"selftest FAIL: tag_prefix({cmd!r}) = {got!r}, want {want!r}", file=sys.stderr)
264
+ sys.exit(1)
265
+
224
266
  # find_repo_gate walks up from a subdirectory (tempdir fixture — the
225
267
  # v1 bug checked cwd only, so any subdir cwd bypassed the gate).
226
268
  import tempfile
@@ -70,7 +70,7 @@ Unmatched work defaults to pipeline-overview and re-classifies from there.
70
70
  | --- | --- |
71
71
  | Pipeline internals | `npm run smoke:engines` + `npm run test:a2ui` (22/22, +1 skipped OK) |
72
72
  | Chunk authoring | `npm run harvest:chunks` + rendered check of the source demo page |
73
- | Strategy engine | `smoke:engines` + `npm run smoke:register-engine` (11/11) + eval-diff on every affected engine |
73
+ | Strategy engine | `smoke:engines` + `npm run smoke:register-engine` (all-pass — the N drifts with the engine registry, don't pin it) + eval-diff on every affected engine |
74
74
  | Zettel calibration | `npm run eval:diff -- --engine zettel` moves the target metric without breaching floors |
75
75
  | Eval-gap fix | re-run the failing eval; metric lifted and stable across 3 runs |
76
76
  | MCP tool | `npm run mcp:smoke`; for contract changes, a real-client round-trip returning a valid A2UI envelope |
@@ -81,7 +81,7 @@ Full structural gate after any pipeline change:
81
81
  node scripts/build/components.mjs --verify # "clean — N files up-to-date" (the N is the gate; dir count drifts, don't pin it)
82
82
  npm run verify:traits # 100% coverage
83
83
  npm run smoke:engines
84
- npm run smoke:register-engine # 11/11
84
+ npm run smoke:register-engine # all-pass (N drifts with the registry, don't pin it)
85
85
  npm run test:a2ui # 22/22 (+1 skipped OK)
86
86
  npm run eval:diff -- --engine zettel # floors: cov≥87, avg≥85, MRR≥0.94
87
87
  npm run check:zettel-eval-regression -- --latest --strict # mechanical floor gate
@@ -34,7 +34,7 @@ wins any tie with this skill. Monorepo source read while authoring (yaml, CSS,
34
34
 
35
35
  | Task shape | Load |
36
36
  | --- | --- |
37
- | NEW primitive ("add a component", "build a `<foo-ui>`") | [primitive-audit.md](references/primitive-audit.md) — MUST clear this §0 audit before authoring any new component or interactive surface (125 primitives exist; skipping it caused the table-toolbar rewrite) — then [authoring-cycle.md](references/authoring-cycle.md) |
37
+ | NEW primitive ("add a component", "build a `<foo-ui>`") | [primitive-audit.md](references/primitive-audit.md) — MUST clear this §0 audit before authoring any new component or interactive surface (~130 primitives exist — `ls packages/web-components/components | wc -l` is the live census; skipping the audit caused the table-toolbar rewrite) — then [authoring-cycle.md](references/authoring-cycle.md) |
38
38
  | MODIFY existing primitive (prop / CSS / yaml) | [authoring-cycle.md](references/authoring-cycle.md), from Step 2 |
39
39
  | Shell / bespoke cluster child (`<admin-*>` `<chat-*>` `<editor-*>` `<simple-*>`) | [shell-patterns.md](references/shell-patterns.md) |
40
40
  | Promote repeated inline UI → shared module | [module-promotion.md](references/module-promotion.md) |
@@ -632,6 +632,7 @@ One line each; every entry is a shipped bug or a CRITICAL gate. Same axes as abo
632
632
  - **A hardcoded `open` on a `showModal` overlay (`modal-ui` / `drawer-ui`) bricks the whole page** — no console error; only a live click / `elementFromPoint` probe catches it.
633
633
  - **Set `select-ui.options = [...]` for dynamic options, never `appendChild(<option>)`** — the listbox popover is stamped around the INITIAL `<option>` children at connect; later-appended options land outside it as visible flow content.
634
634
  - **`<thead>/<tbody>/<tr>/<th>/<td>` are foster-parented OUT of the DOM inside any non-`<table>` ancestor, including custom elements** — gone before JS runs; never author them inside a custom element.
635
+ - **The elements above still get foster-parented inside `table-ui` (no internal `<table>`, `table.class.js:18`) — but their TEXT survives, and `table-ui` never clears it**, so a raw `<thead>/<tbody>` mistake renders its own "No data" empty-state stacked on a garbled text dump instead of erroring (gh#921/#923/#924, 3 separate demo files — fix by rewriting to the real `col-def`/`data` contract, never by touching table-ui).
635
636
 
636
637
  ### UIElement / reactivity class
637
638
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Auto-generated** by this skill's `scripts/build-canonical-pattern-index.mjs`. Do not edit by hand — re-run the build script (from the monorepo root) after adding new canonicals to `apps/`, `catalog/`, or `playgrounds/`.
4
4
 
5
- **Total canonical `.contents.html` files**: 111
5
+ **Total canonical `.contents.html` files**: 116
6
6
 
7
7
  ## How to use this index
8
8
 
@@ -105,14 +105,15 @@
105
105
  - `catalog/ui-patterns/app/chat-streaming-surface/chat-streaming-surface.contents.html` — 16 lines (from UI-pattern atomics (catalog))
106
106
  - `catalog/page-shells/app/chat-page/chat-page.contents.html` — 67 lines (from Page-shell templates (catalog))
107
107
 
108
- ## editor (6)
108
+ ## editor (7)
109
109
 
110
110
  > Editor panes (code, preview, toolbar). Lift editor-shell composition.
111
111
 
112
112
  - `apps/genui/app/a2ui-editor/a2ui-editor.contents.html` — 261 lines (from GenUI app routes)
113
- - `apps/genui/app/render-preview/render-preview.contents.html` — 74 lines (from GenUI app routes)
113
+ - `apps/genui/app/render-preview/render-preview.contents.html` — 93 lines (from GenUI app routes)
114
114
  - `catalog/ui-patterns/app/editor-code-pane/editor-code-pane.contents.html` — 16 lines (from UI-pattern atomics (catalog))
115
115
  - `catalog/ui-patterns/app/editor-preview-pane/editor-preview-pane.contents.html` — 13 lines (from UI-pattern atomics (catalog))
116
+ - `catalog/ui-patterns/app/split-pane-editor/split-pane-editor.contents.html` — 31 lines (from UI-pattern atomics (catalog))
116
117
  - `catalog/page-shells/app/doc-editor/doc-editor.contents.html` — 65 lines (from Page-shell templates (catalog))
117
118
  - `catalog/page-shells/app/editor-page/editor-page.contents.html` — 25 lines (from Page-shell templates (catalog))
118
119
 
@@ -156,7 +157,7 @@
156
157
 
157
158
  > Activity / event feeds. Lift activity-feed composition.
158
159
 
159
- - `apps/genui/app/gen-ui-feed/gen-ui-feed.contents.html` — 392 lines (from GenUI app routes)
160
+ - `apps/genui/app/gen-ui-feed/gen-ui-feed.contents.html` — 390 lines (from GenUI app routes)
160
161
  - `catalog/ui-patterns/app/order-tracking-timeline/order-tracking-timeline.contents.html` — 45 lines (from UI-pattern atomics (catalog))
161
162
 
162
163
  ## marketing (2)
@@ -185,11 +186,12 @@
185
186
  - `apps/genui/app/css-channel-demo/css-channel-demo.contents.html` — 70 lines (from GenUI app routes)
186
187
  - `apps/genui/app/streams-bridge/streams-bridge.contents.html` — 80 lines (from GenUI app routes)
187
188
 
188
- ## other (40)
189
+ ## other (44)
189
190
 
190
191
  > Misc canonicals. Inspect contents.html to determine UI type.
191
192
 
192
193
  - `apps/genui/app/gen-ui/gen-ui.contents.html` — 47 lines (from GenUI app routes)
194
+ - `apps/genui/app/patient-visit/patient-visit.contents.html` — 58 lines (from GenUI app routes)
193
195
  - `apps/user-flow/app/auth/accept-invite/accept-invite.contents.html` — 52 lines (from User-flow templates)
194
196
  - `apps/user-flow/app/auth/forgot-password/sent/sent.contents.html` — 33 lines (from User-flow templates)
195
197
  - `apps/user-flow/app/auth/sign-in/magic-link/sent/sent.contents.html` — 35 lines (from User-flow templates)
@@ -216,6 +218,7 @@
216
218
  - `apps/user-flow/app/registration/use-case/use-case.contents.html` — 77 lines (from User-flow templates)
217
219
  - `apps/user-flow/app/registration/workspace/workspace.contents.html` — 45 lines (from User-flow templates)
218
220
  - `catalog/ui-patterns/app/email-inbox-list/email-inbox-list.contents.html` — 135 lines (from UI-pattern atomics (catalog))
221
+ - `catalog/ui-patterns/app/filter-popover-form/filter-popover-form.contents.html` — 22 lines (from UI-pattern atomics (catalog))
219
222
  - `catalog/ui-patterns/app/import-mapping/import-mapping.contents.html` — 217 lines (from UI-pattern atomics (catalog))
220
223
  - `catalog/ui-patterns/app/loading-skeleton-placeholder/loading-skeleton-placeholder.contents.html` — 62 lines (from UI-pattern atomics (catalog))
221
224
  - `catalog/ui-patterns/app/product-card-buy/product-card-buy.contents.html` — 39 lines (from UI-pattern atomics (catalog))
@@ -226,6 +229,8 @@
226
229
  - `catalog/page-shells/app/form-page/form-page.contents.html` — 26 lines (from Page-shell templates (catalog))
227
230
  - `catalog/page-shells/app/gallery-page/gallery-page.contents.html` — 79 lines (from Page-shell templates (catalog))
228
231
  - `playgrounds/admin-shell/app/admin-shell.contents.html` — 99 lines (from Playgrounds)
232
+ - `playgrounds/agent-admin/app/agent-admin.contents.html` — 29 lines (from Playgrounds)
233
+ - `playgrounds/agent-chat/app/agent-chat.contents.html` — 28 lines (from Playgrounds)
229
234
  - `playgrounds/chat/app/chat.contents.html` — 49 lines (from Playgrounds)
230
235
  - `playgrounds/composed-flow/app/composed-flow.contents.html` — 294 lines (from Playgrounds)
231
236
  - `playgrounds/table-toolbar/app/table-toolbar.contents.html` — 31 lines (from Playgrounds)
@@ -152,7 +152,7 @@ Component CSS uses a mandatory two-block `@scope` structure. Tokens go in `:wher
152
152
  border-radius: var(--badge-radius);
153
153
  }
154
154
 
155
- :scope[variant="accent"] {
155
+ :scope[variant="primary"] {
156
156
  --badge-bg: var(--a-primary-bg); /* token override only */
157
157
  --badge-fg: var(--a-primary-fg);
158
158
  }
@@ -171,13 +171,13 @@ Component CSS aliases from L3 (the role × state matrix), not L2 (the family bas
171
171
 
172
172
  ```css
173
173
  /* right — L3 alias keeps the state cascade working */
174
- :scope[variant="accent"]:hover {
174
+ :scope[variant="primary"]:hover {
175
175
  --button-bg: var(--a-primary-bg-hover);
176
176
  --button-fg: var(--a-primary-fg-hover);
177
177
  }
178
178
 
179
179
  /* wrong — L2 stops the cascade */
180
- :scope[variant="accent"]:hover {
180
+ :scope[variant="primary"]:hover {
181
181
  --button-bg: var(--a-primary); /* loses theme + contrast wiring */
182
182
  }
183
183
  ```