@adia-ai/adia-ui-forge 0.8.34 → 0.8.36
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.
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +27 -0
- package/README.md +12 -4
- package/agents/a2ui-builder.md +12 -8
- package/agents/component-author.md +17 -12
- package/agents/framework-reviewer.md +18 -12
- package/agents/release-builder.md +15 -10
- package/commands/deploy.md +2 -0
- package/commands/dogfood.md +2 -0
- package/commands/gen-review.md +2 -0
- package/commands/release.md +3 -1
- package/package.json +4 -1
- package/scripts/forge-lint +38 -1
- package/scripts/release-pretag-docs-gate +45 -3
- package/skills/adia-a2ui/SKILL.md +2 -2
- package/skills/adia-author/SKILL.md +1 -1
- package/skills/adia-author/references/anti-patterns.md +1 -0
- package/skills/adia-author/references/code-style.md +3 -3
- package/skills/adia-author/references/worked-example.md +3 -3
- package/skills/adia-author/references/yaml-contract.md +42 -0
- package/skills/adia-deploy/SKILL.md +10 -11
- package/skills/adia-dogfood/SKILL.md +5 -4
- package/skills/adia-dogfood/references/admin-shell-anatomy.md +5 -2
- package/skills/adia-dogfood/references/app-shell-pitfalls.md +10 -3
- package/skills/adia-dogfood/scripts/analyze.mjs +2 -0
- package/skills/adia-gen-review/SKILL.md +10 -3
- package/skills/adia-gen-review/references/loop-protocol.md +15 -8
- package/skills/adia-gen-review/references/rubric-score.md +5 -2
- package/skills/adia-gen-review/scripts/gen-review-status.mjs +8 -6
- package/skills/adia-llm-internals/SKILL.md +1 -1
- package/skills/adia-release/SKILL.md +9 -8
- package/skills/adia-release/references/cut-procedure.md +16 -8
- package/skills/adia-release/references/gates-catalog.md +4 -2
- package/skills/adia-release/references/independent-package-release.md +13 -9
- package/skills/adia-release/references/recovery-paths.md +2 -2
- package/skills/adia-release/scripts/bump.mjs +7 -3
- package/skills/adia-release/scripts/dispatch-publish.mjs +5 -2
- package/skills/adia-release/scripts/gate-roster.mjs +29 -0
- package/skills/adia-release/scripts/package-paths.mjs +41 -13
- package/skills/adia-release/scripts/pr-bridge.mjs +36 -2
- package/skills/adia-release/scripts/promote-unreleased.mjs +27 -7
- package/skills/adia-release/scripts/release-pack.mjs +24 -11
- package/skills/adia-release/scripts/tag-lockstep.mjs +10 -8
- package/skills/adia-site-docs/SKILL.md +8 -6
- package/skills/adia-site-docs/intent.md +1 -1
- package/skills/adia-ssr/SKILL.md +1 -1
- package/skills/adia-ssr/references/failure-shapes.md +8 -5
- package/skills/adia-ssr/references/guard-patterns.md +1 -1
- package/skills/adia-site-docs/evals/audit-report.md +0 -30
- package/skills/adia-ssr/evals/audit-report.md +0 -63
|
@@ -92,8 +92,7 @@ reports "matches this allowlist row" as part of its finding and stops.
|
|
|
92
92
|
Never auto-fixed: `zero-area` (always human-eyeballed), `empty-control` on an
|
|
93
93
|
unrecognized component, native-primitive replacement (attribute-shape
|
|
94
94
|
decisions), card-header wrapper hoists (slot intent), any warning without an
|
|
95
|
-
allowlist row.
|
|
96
|
-
handler string inside `components/avatar/avatar.js` itself.
|
|
95
|
+
allowlist row.
|
|
97
96
|
**NEVER exceed 5 mechanical fixes per PR or apply a fix outside this
|
|
98
97
|
allowlist** — blast radius stays human-reviewable.
|
|
99
98
|
|
|
@@ -111,8 +110,10 @@ same session — harvested training chunks silently hold stale values otherwise.
|
|
|
111
110
|
|
|
112
111
|
## Findings home + PR shape
|
|
113
112
|
|
|
114
|
-
Reports and probe artifacts land in `qa/findings/` (
|
|
115
|
-
`qa/
|
|
113
|
+
Reports and probe artifacts land in `qa/findings/` (the geometry-probe
|
|
114
|
+
baseline lives at `scripts/qa/empty-instantiation-baseline.json`; there is
|
|
115
|
+
no visual-baseline directory — probes are geometry-only, gh#988). Commit
|
|
116
|
+
the report even on a zero-finding day — the paper
|
|
116
117
|
trail is how "used to be fine, now broken" is detected. PR title:
|
|
117
118
|
`dogfood: <YYYY-MM-DD> — <N> critical, <M> warning`; body = report excerpt +
|
|
118
119
|
auto-applied-fix checklist + left-for-human list.
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
Script: `scripts/dev/audit-shell-composition.mjs` (repo-local), npm gates
|
|
4
4
|
`audit:shell-composition{,:strict,:all}`. Static AST walk over
|
|
5
5
|
`apps/**/*.html`, `playgrounds/**/*.html`, `catalog/page-shells/**/*.html` —
|
|
6
|
-
no browser needed; pre-commit fast. The script
|
|
7
|
-
|
|
6
|
+
no browser needed; pre-commit fast. The script's own `PARTS` array is the
|
|
7
|
+
mechanical census — it has grown past this list (count it in
|
|
8
|
+
`scripts/dev/audit-shell-composition.mjs`, never from a hand-typed number
|
|
9
|
+
here); this numbered list is the human review standard, and the findings
|
|
10
|
+
table below samples common symptoms rather than the script's full roster.
|
|
8
11
|
Canonical source: the monorepo's `site/index.html` — the markup that renders
|
|
9
12
|
the live admin-dashboard example.
|
|
10
13
|
|
|
@@ -20,10 +20,17 @@ may stall — wait 30s, re-run.
|
|
|
20
20
|
| 4 | Top-level `await` without async setup wrap | `[setup-failed]` console error | `export default async function setup(host) { … }` |
|
|
21
21
|
| 5 | Vite import-analysis 500 on dynamic import | `[network-4xx] 500` for `./<name>.contents.js` | add `/* @vite-ignore */` to the dynamic import |
|
|
22
22
|
| 6 | icon-ui not imported despite `<icon-ui>` / `[icon=…]` / icon-rendering composites | `[icon-ui-missing]` | `import "/packages/web-components/components/icon/icon.js"` |
|
|
23
|
+
| 7 | `<admin-page-body>` emitted without its `<admin-page>` ancestor (gh#981) | *(no audit-app-shells.mjs tag — apps/-only script, doesn't sweep this surface)* | wrap in `<admin-page>` — `admin-page > admin-page-body { flex:1; … }` (`admin-shell.bespoke.css:144`) is a direct-child selector; without that literal parent, `admin-page-body` falls back to UA `display:inline` |
|
|
23
24
|
|
|
24
|
-
Secondary signals: `[collapsed-element]` (registered but 0px tall
|
|
25
|
-
`
|
|
26
|
-
`
|
|
25
|
+
Secondary signals: `[collapsed-element]` (registered but 0px tall —
|
|
26
|
+
`audit-app-shells.mjs`'s own threshold is <4px, so a shallower-but-still-broken
|
|
27
|
+
collapse won't trip it), `[network-4xx]` (typoed stylesheet href, missing
|
|
28
|
+
contents.html, stale `import.meta.url`). Row 7's specific case (gh#981, in
|
|
29
|
+
`site/site.js`'s router, not swept by this script at all): the 150px isn't
|
|
30
|
+
`admin-page-body`'s own height — it's a *replaced child* (an `<iframe>`)
|
|
31
|
+
whose `height:100%` can't resolve, so it falls back to the browser's
|
|
32
|
+
intrinsic default (300×150). The observable is a body rendering ~150px tall
|
|
33
|
+
with no console error, regardless of real content height.
|
|
27
34
|
|
|
28
35
|
## Composite → internal primitives (undiscoverable from the markup)
|
|
29
36
|
|
|
@@ -571,6 +571,8 @@ function renderReport(results, base) {
|
|
|
571
571
|
lines.push('4. **Synonym-attr / synonym-slot drift** — markers documented in `.claude/docs/conventions/attribute-api-migration.md`.');
|
|
572
572
|
lines.push('5. **Alert flex-row** — `alert-ui` with multiple bare `<text-ui>` children (need `<col-ui slot="content">` wrap).');
|
|
573
573
|
lines.push('6. **Console** — every `console.error` and `console.warn` during page load + 800ms settling.');
|
|
574
|
+
lines.push('7. **Missing component CSS** — a rendered `*-ui` element with no resolved `--{prefix}-*` custom property, meaning its per-component stylesheet never loaded (controls render unstyled).');
|
|
575
|
+
lines.push('8. **Unstyled popover** — an OPEN `[popover]` with transparent background AND zero padding (transparent-host components like `feed-ui` allowlisted).');
|
|
574
576
|
lines.push('');
|
|
575
577
|
|
|
576
578
|
return lines.join('\n');
|
|
@@ -35,8 +35,15 @@ directives are findings.
|
|
|
35
35
|
3. Zero P1 cosmetic findings (overflow entries auto-count as P1) — checked
|
|
36
36
|
mechanically.
|
|
37
37
|
4. Zero RENDER_FAILURE prompts; cycle `status: COMPLETE` — checked
|
|
38
|
-
mechanically
|
|
39
|
-
5. Human QA
|
|
38
|
+
mechanically.
|
|
39
|
+
5. **Human QA is per-sweep, not per-cycle** (spec-factory-dx-ws6-measurement.md
|
|
40
|
+
REQ-11, gh#1137 — retired from this exit gate 2026-08-12; the per-cycle
|
|
41
|
+
`humanQA` ledger field never held: null in 12 of 13 rows, and the one
|
|
42
|
+
populated row still said "gate pending"). The 5-sampled-prompts,
|
|
43
|
+
`passCount ≥ 4` bar is unchanged, but it now feeds `qa/dx/`'s R1 sweep
|
|
44
|
+
record (D5's induced-failure sample + D8's gallery term) instead of
|
|
45
|
+
blocking a single cycle's own exit condition. `gen-review-status.mjs
|
|
46
|
+
--check-exit` no longer reads `humanQA` off the ledger row.
|
|
40
47
|
|
|
41
48
|
## The Gen-Review Scorecard — the per-prompt output contract
|
|
42
49
|
|
|
@@ -182,7 +189,7 @@ map + FAILS/WORKS transpilation pairs:
|
|
|
182
189
|
| New primitive / native tag in canvas | `TAG_TO_COMPONENT` in the decompose script (`Native*` prefix for natives); coverage-audit must go green |
|
|
183
190
|
| New root-cause code | rubric-score.md table + `scores.schema.json` enum + `schemaVersion` bump |
|
|
184
191
|
| New safe attribute | `ATTR_ALLOWLIST` — static enums only, never freeform-text attrs |
|
|
185
|
-
| Threshold recalibration | rubric-score.md §Thresholds (pass-flip sweep) + the exit gate above |
|
|
192
|
+
| Threshold recalibration | rubric-score.md §Thresholds (pass-flip sweep) + the exit gate above + `EXCELLENCE_THRESHOLD` at `scripts/gen-review-status.mjs:31` — the only mechanical enforcer; skip it and `--check-exit` silently keeps the old floor |
|
|
186
193
|
|
|
187
194
|
## Posture
|
|
188
195
|
|
|
@@ -161,12 +161,16 @@ never get fix plans. Reads ONLY the decomposed file.
|
|
|
161
161
|
skill does not perform the edits.
|
|
162
162
|
3. **Regenerate**: `npm run gallery:generate`; confirm 0 console
|
|
163
163
|
errors/warnings in the canvas output.
|
|
164
|
-
4. **Human QA
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
164
|
+
4. **Human QA sample — per-sweep, not per-cycle** (retired from this
|
|
165
|
+
cycle's own COMPLETE gate 2026-08-12, spec-factory-dx-ws6-measurement.md
|
|
166
|
+
REQ-11, gh#1137). Operator reviews 5 random PASSING prompts against:
|
|
167
|
+
(a) serves the user's task? (b) right primary primitive? (c) would ship
|
|
168
|
+
unchanged? Record the result in the next `qa/dx/` sweep record's
|
|
169
|
+
`humanQA.{sampledPrompts,pass,fail}` (`node scripts/qa/dx-status.mjs`),
|
|
170
|
+
not on this cycle's ledger row. `failCount ≥ 2` still means the
|
|
171
|
+
thresholds are miscalibrated — recalibrate rubric-score.md §Thresholds
|
|
172
|
+
against the human judgments — it just no longer blocks THIS cycle's own
|
|
173
|
+
`status: COMPLETE`.
|
|
170
174
|
5. **Schema gate** (must exit 0 before touching the ledger):
|
|
171
175
|
|
|
172
176
|
```bash
|
|
@@ -175,8 +179,11 @@ never get fix plans. Reads ONLY the decomposed file.
|
|
|
175
179
|
|
|
176
180
|
6. **Update ledger** (`review/cycle-ledger.json`): `cycleNumber`,
|
|
177
181
|
`completedAt`, `engine`, `status`, `aggregate`
|
|
178
|
-
(passingCount/failingCount/renderFailureCount/meanScore/Δ)
|
|
179
|
-
|
|
182
|
+
(passingCount/failingCount/renderFailureCount/meanScore/Δ). `humanQA` is
|
|
183
|
+
RETIRED from this per-cycle row (step 4) — do not populate it here; a
|
|
184
|
+
stray value is harmless (ignored) but the field's home is now the
|
|
185
|
+
per-sweep `qa/dx/sweeps/*.json` record. Remove the `cycle-{N}.lock`
|
|
186
|
+
sentinel.
|
|
180
187
|
7. **Exit condition**:
|
|
181
188
|
|
|
182
189
|
```bash
|
|
@@ -22,8 +22,11 @@ Max score 105 (D1–D5 at 20 each = 100; D6 mechanical = 0 or +5).
|
|
|
22
22
|
**Recalibrating** (when human QA contradicts mechanical scores across 2+
|
|
23
23
|
cycles): sweep candidate threshold values and read the pass-flips at each step
|
|
24
24
|
against the human verdicts — never pick a round number by feel. A threshold
|
|
25
|
-
change must also update the exit gate in SKILL.md
|
|
26
|
-
|
|
25
|
+
change must also update the exit gate in SKILL.md AND the
|
|
26
|
+
`EXCELLENCE_THRESHOLD` constant at `scripts/gen-review-status.mjs:31` — that
|
|
27
|
+
constant is the only mechanical enforcer (`--check-exit` reads nothing else;
|
|
28
|
+
the schema carries no threshold), so missing it leaves the old floor silently
|
|
29
|
+
enforced. New cause codes / dimensions bump `schemaVersion` in
|
|
27
30
|
[scores.schema.json](scores.schema.json).
|
|
28
31
|
|
|
29
32
|
---
|
|
@@ -17,9 +17,14 @@
|
|
|
17
17
|
*
|
|
18
18
|
* Exit-condition (from scores.schema.json + SKILL.md §ExitCondition):
|
|
19
19
|
* - Every prompt PASSING (p1Count = 0 AND rubricScore.score ≥ 92)
|
|
20
|
-
* - humanQA.passCount ≥ 4 (of 5 sampled)
|
|
21
20
|
* - No RENDER_FAILURE prompts
|
|
22
21
|
* - Cycle status = COMPLETE (not OPEN or INTERRUPTED)
|
|
22
|
+
*
|
|
23
|
+
* humanQA is RETIRED from this per-cycle exit condition (spec-factory-dx-
|
|
24
|
+
* ws6-measurement.md REQ-11, gh#1137, 2026-08-12): the per-cycle ledger
|
|
25
|
+
* field never held (null in 12/13 rows), so it moved to a per-sweep
|
|
26
|
+
* obligation — `qa/dx/sweeps/*.json`'s `humanQA` field (dx-status.mjs)
|
|
27
|
+
* reads a 5-prompt sample per sweep instead of per cycle.
|
|
23
28
|
*/
|
|
24
29
|
|
|
25
30
|
import { readFileSync, existsSync } from 'node:fs';
|
|
@@ -85,11 +90,8 @@ function checkExitCondition() {
|
|
|
85
90
|
reasons.push(`Cycle ${latest.cycleNumber} status is "${latest.status}" (need COMPLETE)`);
|
|
86
91
|
}
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
} else if (latest.humanQA.passCount < 4) {
|
|
91
|
-
reasons.push(`Human QA pass count ${latest.humanQA.passCount}/5 (need ≥ 4)`);
|
|
92
|
-
}
|
|
93
|
+
// humanQA is RETIRED from this per-cycle check (REQ-11, gh#1137) — it's a
|
|
94
|
+
// per-sweep obligation now (qa/dx/sweeps/*.json), not a per-cycle gate.
|
|
93
95
|
|
|
94
96
|
const agg = latest.aggregate;
|
|
95
97
|
if (agg?.failingCount > 0) {
|
|
@@ -25,7 +25,7 @@ Consumers depend on: the `StreamChunk` union, `ChatResult` (`text` / `usage` / `
|
|
|
25
25
|
|
|
26
26
|
Three invariants override any cleanup instinct:
|
|
27
27
|
|
|
28
|
-
1. **
|
|
28
|
+
1. **Never collapse `stopReason` truncation values — and never invent a NEW normalization.** The one sanctioned mapping is OpenAI's own `finish_reason === 'stop'` → `end` (`openai.ts` `parseResponse`; adapter-contract.md §stopReason documents it as correct); everything else propagates raw. Providers emit `end` / `stop` / `max_tokens` / `length` / `MAX_TOKENS` / `tool_use`; the downstream truncation detector reads the raw value, so collapsing `max_tokens`/`length`/`MAX_TOKENS` to `end` hides truncation — a defect, not a cleanup.
|
|
29
29
|
2. **`buildRequest()` is the single source of upstream shape** for direct AND passthrough-proxy mode; the dispatcher swaps only the URL. Never fork it per proxy flavor.
|
|
30
30
|
3. **No real API key reaches the browser on a production host.** The same-origin passthrough proxy injects the key server-side; the sentinel-key + one-shot-warning path in `createAdapter()` must survive any refactor.
|
|
31
31
|
|
|
@@ -3,8 +3,9 @@ name: adia-release
|
|
|
3
3
|
description: >-
|
|
4
4
|
Release engineering for the @adia-ai lockstep monorepo. Use when asked to
|
|
5
5
|
cut and ship a release, promote [Unreleased] CHANGELOG entries, tag and push the
|
|
6
|
-
lockstep packages to origin, publish a 13-package release (11
|
|
7
|
-
libraries + 2 Claude Code plugins
|
|
6
|
+
lockstep packages to origin, publish a 13-package release (11
|
|
7
|
+
npm libraries + 2 Claude Code plugins, as of gh#607 — see
|
|
8
|
+
scripts/package-paths.mjs), batch-push piled-up release commits,
|
|
8
9
|
recover a cut that landed wrong or whose publish workflows didn't fire,
|
|
9
10
|
fix a check:lockstep bump failure or an F-N1 CHANGELOG-coverage warning,
|
|
10
11
|
verify the release gates without cutting anything, or author release
|
|
@@ -17,7 +18,7 @@ user-invocable: true
|
|
|
17
18
|
|
|
18
19
|
# adia-release
|
|
19
20
|
|
|
20
|
-
Release engineering for an @adia-ai-style lockstep monorepo: the `@adia-ai/*` packages on the roster (`scripts/package-paths.mjs`, the single source — 13 as of gh#607: 11 npm libraries plus the 2 Claude Code plugins under `packages/plugins/*`) version and publish together (class A; the plugins joined the lockstep 2026-07-15 after class-B independence let npm drift a full harness-reset behind the repo). Class B (independent versioning)
|
|
21
|
+
Release engineering for an @adia-ai-style lockstep monorepo: the `@adia-ai/*` packages on the roster (`scripts/package-paths.mjs`, the single source — 13 lockstep as of gh#607: 11 npm libraries plus the 2 Claude Code plugins under `packages/plugins/*`) version and publish together (class A; the plugins joined the lockstep 2026-07-15 after class-B independence let npm drift a full harness-reset behind the repo). Class B (independent versioning) has one member — `@adia-ai/adia-plugins` (gh#1133/gh#1160, ADR-0045), the npm-sourced marketplace manifest package, marked `lockstep: false` on the roster; it cuts on its own version line and its own tag, never the umbrella ([`references/independent-package-release.md`](references/independent-package-release.md)). The substrate — `scripts/release/*`, the `check:*` gates, the tag-triggered publish workflows — encodes the invariants; this skill routes, sequences, and stops at the judgment calls.
|
|
21
22
|
|
|
22
23
|
## Authorization — one go, gates do the rest (operator ruling 2026-07-17)
|
|
23
24
|
|
|
@@ -34,7 +35,7 @@ Mechanics: `release-pack.mjs --go` auto-confirms all checkpoints (it equals `--y
|
|
|
34
35
|
1. **Lockstep coherence** — every roster package bumps together (`check:lockstep`; the roster lives in `scripts/package-paths.mjs`, currently `web-components`, `web-modules`, `llm`, `agent`, `persona`, `a2ui-{runtime,compose,corpus,mcp,retrieval,validator}`, and the plugins `adia-ui-{factory,forge}`) (each plugin's `.claude-plugin/plugin.json` version moves with its package.json — `bump.mjs` handles both; `verify:plugins` gates the sync).
|
|
35
36
|
2. **PATCH-cut asymmetry** — internal `@adia-ai/*` ranges hold at `^X.Y.0` during PATCH cuts; only MINOR bumps the floor. `^0.0.x` is forbidden (pre-1.0 caret locks exact — shipped a real stale-sibling bug).
|
|
36
37
|
3. **Release commits land via PR, never a direct push to `main`** (repo policy, operator ruling 2026-07-12): commit on `release/vX.Y.Z` → PR → CI → merge — THEN tag at `main`'s post-merge HEAD, not at the bump commit; post-bump fixes merge before tagging and belong in the tarball. Exception: batch push tags each version at its own release-merge SHA.
|
|
37
|
-
4. **One umbrella + one per-package tag per cut** (`vX.Y.Z` +
|
|
38
|
+
4. **One umbrella + one per-package tag per cut** (`vX.Y.Z` + 13 × `<pkg>-vX.Y.Z`, one per lockstep-roster package — `scripts/package-paths.mjs`); publish workflows key off the per-package tags. Push tags **one per `git push`** — a batched multi-tag push drops the trigger event.
|
|
38
39
|
5. **F-N1 (`check:release --all-pending`) per-package clean** — the umbrella-tag mismatch error is expected noise. Coverage is mechanized at cut time: Step 4f (`check-release.mjs --pending-version X.Y.Z --fix`) runs the SAME matcher pre-PR and auto-appends verified Maintenance bullets, so a post-tag warn means something novel — stop and investigate, don't loop enrichment PRs.
|
|
39
40
|
6. **`npm dist-tag latest` is set by publish order** — batch pushes publish oldest first and WAIT for settle.
|
|
40
41
|
7. **A breaking (MINOR) cut MUST ship its MIGRATION GUIDE section in the same cycle** — MINOR is reserved for removed/renamed API symbols; everything else, including visible behavior changes, stays PATCH.
|
|
@@ -58,7 +59,7 @@ The release is done only when reality confirms it: **the npm registry, the GH re
|
|
|
58
59
|
|
|
59
60
|
| Task shape | Done when |
|
|
60
61
|
| --- | --- |
|
|
61
|
-
| Lockstep cut / handoff | `npm view @adia-ai/<pkg> version` = X.Y.Z for all
|
|
62
|
+
| Lockstep cut / handoff | `npm view @adia-ai/<pkg> version` = X.Y.Z for all 13 lockstep packages AND `dist-tags.latest` = X.Y.Z AND a deployed content file (not an SPA route) serves real bytes |
|
|
62
63
|
| Batch push | every batched tag on `git ls-remote --tags origin` + every version on the registry, `latest` on the newest |
|
|
63
64
|
| Verify-only | the failing gate re-runs green |
|
|
64
65
|
| Recovery | the trip-wire that surfaced the issue passes |
|
|
@@ -74,7 +75,7 @@ Every cut reports, whether it ran inline or via `release-builder`:
|
|
|
74
75
|
| --- | --- |
|
|
75
76
|
| Version | X.Y.Z — all roster packages at this version (`check:lockstep`) |
|
|
76
77
|
| Commit / PR | release commit SHA, PR # (merged) |
|
|
77
|
-
| Tags | umbrella `vX.Y.Z` +
|
|
78
|
+
| Tags | umbrella `vX.Y.Z` + 13 per-package tags pushed (or: which are still pending, and why) |
|
|
78
79
|
| Registry | `npm view @adia-ai/<pkg> version` per package, cited (not "publish workflow green") |
|
|
79
80
|
| `dist-tags.latest` | confirmed = X.Y.Z |
|
|
80
81
|
| Deploy | dispatched (`deploy-site.yml` run URL) / N/A this cut |
|
|
@@ -93,9 +94,9 @@ assumed pass, or "published" without the actual `npm view` output.
|
|
|
93
94
|
|
|
94
95
|
## Mechanization (bundled `scripts/`, stdlib Node, all support `--dry`)
|
|
95
96
|
|
|
96
|
-
`release-pack.mjs` walks the cycle in two phases per invariant 3 — `--mode cut` / `--mode from-scratch` promote `[Unreleased]` (BOTH modes now — a peer's hand-authored section must be promoted whichever mode cut it, and a loud guard blocks the bump if any roster package still carries non-empty `[Unreleased]` content after promotion), run Step 4f (pre-tag coverage `--fix` with the authoritative F-N1 matcher), and stop at the release commit (PR → merge); `--mode handoff` tags/publishes/deploys from post-merge main. **`--go` is the standard invocation for an operator-initiated release** — the single authorization covers the cycle; evidence blocks print as a log; granular `--yes`/`--push`/`--publish` remain for cautious manual runs (`--push` still refuses to auto-fire past any F-N1 finding). `--mode batch` is not implemented — it hard-rejects with a pointer to [`recovery-paths.md`](references/recovery-paths.md) §Scenario 2 rather than silently misbehaving; a real batch tags each version at its own release-merge SHA, which this single-version orchestrator has no model for. Pre-flight (Step 3) runs the full
|
|
97
|
+
`release-pack.mjs` walks the cycle in two phases per invariant 3 — `--mode cut` / `--mode from-scratch` promote `[Unreleased]` (BOTH modes now — a peer's hand-authored section must be promoted whichever mode cut it, and a loud guard blocks the bump if any roster package still carries non-empty `[Unreleased]` content after promotion), run Step 4f (pre-tag coverage `--fix` with the authoritative F-N1 matcher), and stop at the release commit (PR → merge); `--mode handoff` tags/publishes/deploys from post-merge main. **`--go` is the standard invocation for an operator-initiated release** — the single authorization covers the cycle; evidence blocks print as a log; granular `--yes`/`--push`/`--publish` remain for cautious manual runs (`--push` still refuses to auto-fire past any F-N1 finding). `--mode batch` is not implemented — it hard-rejects with a pointer to [`recovery-paths.md`](references/recovery-paths.md) §Scenario 2 rather than silently misbehaving; a real batch tags each version at its own release-merge SHA, which this single-version orchestrator has no model for. Pre-flight (Step 3) runs the full 28-gate roster from the single shared list in `scripts/gate-roster.mjs` — the same list [`cut-procedure.md`](references/cut-procedure.md) §3.1 transcribes, so a subset run requires editing that one file, not two.
|
|
97
98
|
|
|
98
|
-
The pieces are callable alone: `bump.mjs` (version fields + the factory `.mcp.json` a2ui-mcp pin, invariant 8), `promote-unreleased.mjs` / `insert-stub.mjs` (CHANGELOG blocks), `tag-lockstep.mjs` (
|
|
99
|
+
The pieces are callable alone: `bump.mjs` (version fields + the factory `.mcp.json` a2ui-mcp pin, invariant 8), `promote-unreleased.mjs` / `insert-stub.mjs` (CHANGELOG blocks), `tag-lockstep.mjs` (umbrella + one tag per roster package — 14 today, `--delete` to move), `dispatch-publish.mjs` (publish workflows; `--verify-triggered` re-dispatches missing AND dead — cancelled/failed/timed-out — runs, each gated behind an npm-registry check so an already-published version is never re-dispatched (gh#763); `--after` enforces batch ordering — dispatch output states what WAS done, never a to-do phrased as if it hadn't fired), and `pr-bridge.mjs` (the two-phase bridge: pushes the release branch, opens the PR, waits out CI, and merges ONLY on all-non-fail-soft-checks-green + zero unresolved threads + no changes-requested; any other state stops with evidence — §5.7 mechanized, `--dry` to preview the decision). All fail fast outside a monorepo root (`assert-monorepo-root.mjs`); fork-configurable via `--host` / `--scope`. All 6 CLI scripts (plus `scripts/release/check-release.mjs`) have a `selftest` mode wired into CI's Plugin bin selftests step; the 3 helper modules (`assert-monorepo-root`, `gate-roster`, `package-paths`) are exercised through the CLIs' selftests, not their own.
|
|
99
100
|
|
|
100
101
|
Site deploy (Step 10 of the handoff) dispatches `deploy-site.yml` (its own pre-flight verify → snapshot → hardened rsync → post-deploy verify → auto-rollback), never a raw local `rsync` — H1 (forge-campaign gh#268 audit): the script had drifted into bypassing that pipeline even though this doc already taught the workflow-dispatch path. The dispatch rides the cycle's single authorization (`--go`, or `--publish` on a manual run); the workflow's own GitHub environment gate is the human stop for the deploy itself.
|
|
101
102
|
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
> handoff). Companions: [`gates-catalog.md`](gates-catalog.md) (gate roster +
|
|
5
5
|
> failure routing), [`changelog-discipline.md`](changelog-discipline.md) (promotion
|
|
6
6
|
> + F-N1 enrichment), [`recovery-paths.md`](recovery-paths.md) (when it goes wrong).
|
|
7
|
-
> The concrete gate names,
|
|
8
|
-
>
|
|
7
|
+
> The concrete gate names, the roster's package paths (`scripts/package-paths.mjs`,
|
|
8
|
+
> 13 lockstep as of gh#607), and `ui-kit.exe.xyz` deploy are the @adia-ai
|
|
9
|
+
> monorepo's worked example of the portable discipline. `$REPO` = repo root.
|
|
9
10
|
|
|
10
11
|
Two entry variants, converging at Step 5:
|
|
11
12
|
|
|
@@ -113,6 +114,10 @@ npm run check:token-semantics-sync # 21 adia-tokens generated refs v
|
|
|
113
114
|
npm run check:demo-routes # 22 demo surfaces routed + patterns indexed
|
|
114
115
|
npm run check:brand-assets # 23 brand mark token-driven, not baked raster
|
|
115
116
|
node scripts/release/check-cut-hygiene.mjs --version <mode-dependent> # 24 README CDN-pin + version currency — CUT modes pre-flight at the PREVIOUS version (the README claim is exact-match and only moves at the Step-4 bump; Step 4g re-proves at the cut version), HANDOFF pre-flights at the CUT version (post-merge, the claim already moved)
|
|
117
|
+
python3 packages/plugins/adia-ui-factory/scripts/adia-scaffold selftest # 25 scaffold specifiers resolve in packed @adia-ai/web-components + @adia-ai/web-modules tarballs (gh#1132)
|
|
118
|
+
node scripts/release/check-dx-sweep-freshness.mjs # 26 DX sweep fresh + not regression-RED (gh#1137 REQ-05 — FLAGGED, needs adia-release confirmation; see the script's own header)
|
|
119
|
+
npm run eval:diff -- --engine free-form # 27 fresh free-form eval run (evals/health input, gh#1135)
|
|
120
|
+
node scripts/release/write-eval-health.mjs --version <cut> # 28 evals/health/<version>.json committed, AC-01/AC-02 run for real (gh#1135, WS-4 SPEC REQ-06)
|
|
116
121
|
```
|
|
117
122
|
|
|
118
123
|
Any red → route via [`gates-catalog.md`](gates-catalog.md); fix at the source, re-run the narrowest gate, then re-run the full sequence. The canonical miss: a cut that ran 7 of the gates shipped a stale-embeddings defect that surfaced a day later and cost a tag-move recovery.
|
|
@@ -266,7 +271,7 @@ The operator's initiating instruction covers the whole cycle — no per-step re-
|
|
|
266
271
|
|
|
267
272
|
| Evidence logged before | Content | Why it's still printed |
|
|
268
273
|
| --- | --- | --- |
|
|
269
|
-
| Tagging (Step 6) | The planned tag list (umbrella +
|
|
274
|
+
| Tagging (Step 6) | The planned tag list (umbrella + 13 per-package) | The log line a recovery diagnoses from |
|
|
270
275
|
| Pushing (Step 8) | The Step 7 F-N1 output + tag list + `origin/main..HEAD` count | F-N1's first real evidence — and its ERROR path still hard-stops unconditionally |
|
|
271
276
|
| Publishing (Step 9) | The current registry snapshot (versions + `dist-tags.latest`) | Ordering is verified against what's LIVE, mechanically |
|
|
272
277
|
| Deploying (Step 10) | The `deploy-site.yml` dispatch (never a raw rsync) | The workflow carries its own GitHub-environment human gate |
|
|
@@ -281,7 +286,7 @@ After the bump + lockfile, run the AUTHORITATIVE F-N1 matcher against the workin
|
|
|
281
286
|
node scripts/release/check-release.mjs --pending-version X.Y.Z --fix
|
|
282
287
|
```
|
|
283
288
|
|
|
284
|
-
Stage its CHANGELOG edits into the release commit (the Step-5 allowlist already covers `CHANGELOG.md`). It re-verifies its own output with the same matcher before writing — a `--fix` that doesn't satisfy the checker is a hard error, not a silent pass.
|
|
289
|
+
Stage its CHANGELOG edits into the release commit (the Step-5 allowlist already covers `CHANGELOG.md`). It re-verifies its own output with the same matcher before writing — a `--fix` that doesn't satisfy the checker is a hard error, not a silent pass. (The former `check:changelog-coverage` gate — a different matcher and a 9-package roster missing the 2 plugins — cost the v0.8.5 cut 3 enrichment PRs and 3 tag rewrites after "coverage clean" at cut time; it was deleted 2026-07-19, so `check-release.mjs --pending-version` is now the only pre-tag coverage check.)
|
|
285
290
|
|
|
286
291
|
## §Step 6 — Tag
|
|
287
292
|
|
|
@@ -289,7 +294,7 @@ Log the planned tag list (evidence table above), then tag **at `main`'s post-mer
|
|
|
289
294
|
|
|
290
295
|
```bash
|
|
291
296
|
node "${CLAUDE_PLUGIN_ROOT}/skills/adia-release/scripts/tag-lockstep.mjs" \
|
|
292
|
-
--version X.Y.Z # umbrella vX.Y.Z +
|
|
297
|
+
--version X.Y.Z # umbrella vX.Y.Z + 13 <pkg>-vX.Y.Z (11 npm + 2 plugins, 2026-07-15 policy)
|
|
293
298
|
```
|
|
294
299
|
|
|
295
300
|
## §Step 7 — F-N1 release trip-wire
|
|
@@ -330,8 +335,9 @@ node "${CLAUDE_PLUGIN_ROOT}/skills/adia-release/scripts/dispatch-publish.mjs" \
|
|
|
330
335
|
Wait for the workflows to settle, then verify against the **registry**, never the workflow's green check:
|
|
331
336
|
|
|
332
337
|
```bash
|
|
333
|
-
for pkg in web-components web-modules llm a2ui-runtime a2ui-compose
|
|
334
|
-
a2ui-mcp a2ui-retrieval a2ui-validator adia-ui-factory
|
|
338
|
+
for pkg in web-components web-modules llm agent persona a2ui-runtime a2ui-compose \
|
|
339
|
+
a2ui-corpus a2ui-mcp a2ui-retrieval a2ui-validator adia-ui-factory \
|
|
340
|
+
adia-ui-forge; do
|
|
335
341
|
echo -n "$pkg: "; npm view "@adia-ai/$pkg" version
|
|
336
342
|
done
|
|
337
343
|
npm view @adia-ai/web-components dist-tags.latest # must equal X.Y.Z
|
|
@@ -342,7 +348,9 @@ Zero workflows fired after a tag push → [`recovery-paths.md`](recovery-paths.m
|
|
|
342
348
|
## §Step 10 — GH releases + site deploy dispatch
|
|
343
349
|
|
|
344
350
|
```bash
|
|
345
|
-
for pkg in
|
|
351
|
+
for pkg in web-components web-modules llm agent persona a2ui-runtime a2ui-compose \
|
|
352
|
+
a2ui-corpus a2ui-mcp a2ui-retrieval a2ui-validator adia-ui-factory \
|
|
353
|
+
adia-ui-forge; do
|
|
346
354
|
gh release create "$pkg-vX.Y.Z" --title "@adia-ai/$pkg vX.Y.Z" --notes-file <body>.md
|
|
347
355
|
done
|
|
348
356
|
# Site deploy goes through the pipeline, never a raw rsync. The dispatch is
|
|
@@ -14,7 +14,7 @@ Row layout per gate: **What** · **Typical failure** · **Recovery**.
|
|
|
14
14
|
|
|
15
15
|
### `npm run check:lockstep`
|
|
16
16
|
|
|
17
|
-
- **What:** all
|
|
17
|
+
- **What:** all 13 lockstep `@adia-ai/*` packages declare the same `version` (the class-B `adia-plugins` package is excluded — `lockstep: false`, `scripts/package-paths.mjs`); internal `@adia-ai/*` dep ranges match policy (`^X.Y.0` during PATCH cycles, bumped at MINOR).
|
|
18
18
|
- **Typical failure:** one package forgot to bump; a peer edited an internal range mid-PATCH; a `^0.0.x` range slipped in.
|
|
19
19
|
- **Recovery:** version drift → `` `${CLAUDE_PLUGIN_ROOT}/skills/adia-release/scripts/bump.mjs` ``; range drift → `npm run check:lockstep:fix` auto-aligns, then re-run.
|
|
20
20
|
- **Why `^0.0.x` is forbidden:** npm pre-1.0 semver only widens the caret when major+minor aren't both zero — `^0.0.6` resolves to `>=0.0.6 <0.0.7`, locked to exactly 0.0.6. An internal dep pinned that way silently installs a *stale* sibling on every fresh `npm i` (this shipped a real ~4-day-latent bug before the lockstep policy). The `^X.Y.0` floor (Y≥1) widens correctly across patches; trust the gate, don't reason about caret semantics by hand. Moot at 1.0.0.
|
|
@@ -153,6 +153,8 @@ The two `audit:*` probes are soft-fail pre-cut (exit-1 only on criticals); findi
|
|
|
153
153
|
- **What:** the vitest suite (~1000+ tests).
|
|
154
154
|
- **Stale-test failure:** the test asserts a behavior a peer deliberately changed (CHANGELOG-documented) without updating the assertion. Tell it apart by reading assertion vs CHANGELOG vs source: if the code matches the CHANGELOG's described behavior, the test is stale — update the assertion (see [`recovery-paths.md`](recovery-paths.md) §Scenario 5). Real regression → fix the regression.
|
|
155
155
|
- **Parallel-contention flake:** heavy web-modules composite suites can fail under full parallelism on a loaded machine (`signals: drain loop exceeded 100 iterations`). Load-dependent, not a code defect. Sequential is the source of truth, and **the roster gate now runs it directly** (`npm run test:unit:serial` = `vitest run --no-file-parallelism`, gate 4 since 2026-07-19) — a parallel `test:unit` flake outside the roster still isn't a blocker, and don't raise the drain guard.
|
|
156
|
+
- **Exit 143 (SIGTERM):** the vitest process was KILLED (resource pressure / a stray terminator), not a test failure — re-run the gate directly (`npx vitest run --no-file-parallelism`) before diagnosing anything; a clean re-run means transient, proceed (v0.8.34 handoff hit this).
|
|
157
|
+
- **First-time-at-cut failures are REAL (v0.8.34):** this serial suite runs tests PR CI never does — `exit-gate.corpus` (dialect-catalog conformance over real harvested chunks) surfaces yaml-schema drift (e.g. an array prop missing `items.type`, the command/combobox `DynamicStringList` mis-map) only HERE, potentially weeks after the yaml edit merged green. Treat such a failure as a genuine latent defect to root-cause at the yaml SoT, never as release-blocking noise. (Structural fix — promoting the corpus batch into PR CI — tracked as a follow-up.)
|
|
156
158
|
|
|
157
159
|
### `npm run eval:diff -- --engine zettel`
|
|
158
160
|
|
|
@@ -202,7 +204,7 @@ npm run check:demo-shells
|
|
|
202
204
|
|
|
203
205
|
Add `verify:corpus` + `check:embeddings-fresh` if chunks were touched; `check:lightningcss-build` if CSS was touched; F-N1 if unpushed release tags exist.
|
|
204
206
|
|
|
205
|
-
**Full pre-cut sweep** — the
|
|
207
|
+
**Full pre-cut sweep** — the 28-gate roster in [`cut-procedure.md`](cut-procedure.md) §Step 3, sourced from `` `${CLAUDE_PLUGIN_ROOT}/skills/adia-release/scripts/gate-roster.mjs` `` (the ONE list; `release-pack.mjs` imports and runs it in full — a subset run is impossible without editing that file). ~90s wall time.
|
|
206
208
|
|
|
207
209
|
**Omnibus** — `npm run check` invokes everything. Heavy; use when re-baselining a stale checkout.
|
|
208
210
|
|
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
> Load when releasing a package versioned **independently** of the lockstep set —
|
|
4
4
|
> excluded from the lockstep gate, no umbrella tag, no demo-site deploy.
|
|
5
|
-
> **Class B
|
|
6
|
-
>
|
|
7
|
-
> lockstep
|
|
8
|
-
>
|
|
9
|
-
>
|
|
10
|
-
>
|
|
5
|
+
> **Class B's current member is `@adia-ai/adia-plugins`** (gh#1133/gh#1160,
|
|
6
|
+
> ADR-0045) — the npm-sourced marketplace manifest package, marked
|
|
7
|
+
> `lockstep: false` on the roster (`scripts/package-paths.mjs`). It's the
|
|
8
|
+
> first member since the 2026-07-15 policy change (operator ruling) that
|
|
9
|
+
> emptied the class: the Claude Code plugins under `packages/plugins/*`
|
|
10
|
+
> joined the lockstep after class-B independence let npm drift a full
|
|
11
|
+
> harness-reset behind the repo (npm served forge 0.1.3/factory 0.2.4
|
|
12
|
+
> pre-reset content while the rewritten estate sat unpublished at a
|
|
13
|
+
> regressed 0.1.0). This procedure covers both onboarding a NEW class-B
|
|
14
|
+
> package and a routine cut of an existing one (adia-plugins). The
|
|
11
15
|
> lockstep cut is [`cut-procedure.md`](cut-procedure.md).
|
|
12
16
|
|
|
13
17
|
## §Two release classes in one monorepo
|
|
@@ -15,7 +19,7 @@
|
|
|
15
19
|
| | Class A — lockstep cut | Class B — independent package |
|
|
16
20
|
| --- | --- | --- |
|
|
17
21
|
| Versioning | whole set bumps together | own version line per package |
|
|
18
|
-
| Lockstep gate | enforced (`check:lockstep`
|
|
22
|
+
| Lockstep gate | enforced (`check:lockstep` 13/13) | **excluded** — a class-B package is not listed in `check-lockstep.mjs`'s `PACKAGES` (`adia-plugins`, the current member, is filtered out via `lockstep: false` — `scripts/package-paths.mjs`) |
|
|
19
23
|
| Umbrella tag | `vX.Y.Z` + per-package | **none** — per-package tags only (versions differ) |
|
|
20
24
|
| `dist-tag` ordering | cross-package publish order matters | N/A |
|
|
21
25
|
| Demo-site deploy | yes | **none** |
|
|
@@ -39,11 +43,11 @@ Substrate fixes (release scripts / lockfile / CHANGELOG), landed once as a norma
|
|
|
39
43
|
4. **Tag at the published commit** — `git tag <pkg>-vX.Y.Z` per package; versions differ; no umbrella. Dry-run the trip-wire over the tags (`node scripts/release/check-release.mjs <tags>`) before pushing. If the shared working tree is on a peer's branch, push tags from a throwaway worktree on `origin/main`.
|
|
40
44
|
5. **Push the tags** → the per-package workflows run `npm ci → verify:plugins → npm publish --access public`.
|
|
41
45
|
6. **Verify against npm, not the workflow:** `npm view @adia-ai/<pkg> version` returns the new independent version for each package. Watch runs (`gh run watch <id> --exit-status`), but the registry is the source of truth.
|
|
42
|
-
7. **Marketplace cut-over**
|
|
46
|
+
7. **Marketplace cut-over** — per ADR-0045 the distribution channel is the npm-sourced manifest package `@adia-ai/adia-plugins` (no public git marketplace repo — that shape was considered and rejected). Bump/publish the manifest package so its `marketplace.json` entries reference the new plugin versions; consumers add the marketplace from npm, never from a git repo.
|
|
43
47
|
|
|
44
48
|
## §Verify target
|
|
45
49
|
|
|
46
|
-
The published package(s) on the **npm registry** at their independent versions, plus
|
|
50
|
+
The published package(s) on the **npm registry** at their independent versions, plus the npm-published `@adia-ai/adia-plugins` manifest referencing the new versions (ADR-0045). NOT "all 13 lockstep packages + the demo site" — that's class A.
|
|
47
51
|
|
|
48
52
|
## §Gotchas (from the first independent cut, factory v0.2.2 + forge v0.1.2)
|
|
49
53
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
1. Verify the skip: `npm view <pkg> versions --json | tail` (no X+1 on npm) + `git tag --list 'vX.Y.*'` (no tags). Run pre-flight at the peer's commit to confirm it's shippable.
|
|
19
19
|
2. Correct the version via a **new commit on top** (not amend — the peer's commit stays for history).
|
|
20
|
-
3. Sweep every occurrence of the wrong version:
|
|
20
|
+
3. Sweep every occurrence of the wrong version: 13 × package.json, 13 × CHANGELOG (headers + body refs — the lockstep roster, `scripts/package-paths.mjs`), any doc/CSS-comment refs, then regenerate the lockfile. Preserve filename references that intentionally encode the original label.
|
|
21
21
|
4. Commit as `fix(release): correct vX.Y.Z+1 version-skip → vX.Y.Z` documenting the discovery, then resume [`cut-procedure.md`](cut-procedure.md) at Step 5.
|
|
22
22
|
|
|
23
23
|
## §Scenario 2 — Batch push
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
|
|
64
64
|
## §Scenario 7 — Tags pushed, ZERO publish workflows fired
|
|
65
65
|
|
|
66
|
-
**Shape:** all
|
|
66
|
+
**Shape:** all 14 tags exist on origin (umbrella + one per lockstep-roster package — `scripts/package-paths.mjs`), but no `publish-<pkg>.yml` run exists for them; npm latest unchanged; nothing errored.
|
|
67
67
|
|
|
68
68
|
**Root cause:** pushing many tags in **one** `git push` fires a single batched create event that GitHub Actions routinely drops. Re-pushing is a no-op (the tags already exist remotely).
|
|
69
69
|
|
|
@@ -20,17 +20,21 @@
|
|
|
20
20
|
import fs from 'node:fs';
|
|
21
21
|
import path from 'node:path';
|
|
22
22
|
import process from 'node:process';
|
|
23
|
-
import {
|
|
23
|
+
import { PACKAGE_ROSTER } from './package-paths.mjs';
|
|
24
24
|
|
|
25
25
|
// Single-sourced roster (H3, package-paths.mjs). Each plugin also carries a
|
|
26
26
|
// .claude-plugin/plugin.json whose version MUST move with package.json —
|
|
27
27
|
// plugin.json is the /plugin-update cache key (verify:plugins gates the sync).
|
|
28
|
-
|
|
28
|
+
// Filtered to `lockstep !== false`: a class-B package (gh#1133's
|
|
29
|
+
// adia-plugins) bumps on its own independent version line, never via this
|
|
30
|
+
// lockstep --from/--to sweep. See package-paths.mjs's `lockstep` field note.
|
|
31
|
+
const LOCKSTEP_ROSTER = PACKAGE_ROSTER.filter((p) => p.lockstep !== false);
|
|
32
|
+
const PACKAGES = LOCKSTEP_ROSTER.map((p) => p.dir);
|
|
29
33
|
|
|
30
34
|
// Sibling manifests bumped in the same pass as package.json (path relative to
|
|
31
35
|
// the package dir) — derived from the roster's plugin flag.
|
|
32
36
|
const SIBLING_MANIFESTS = Object.fromEntries(
|
|
33
|
-
|
|
37
|
+
LOCKSTEP_ROSTER.filter((p) => p.plugin).map((p) => [p.dir, '.claude-plugin/plugin.json']),
|
|
34
38
|
);
|
|
35
39
|
|
|
36
40
|
// Cross-package EXACT pins bumped in the same pass — a different shape from a
|
|
@@ -20,14 +20,17 @@
|
|
|
20
20
|
import { execFileSync } from 'node:child_process';
|
|
21
21
|
import process from 'node:process';
|
|
22
22
|
import { assertMonorepoRoot } from './assert-monorepo-root.mjs';
|
|
23
|
-
import {
|
|
23
|
+
import { PACKAGE_ROSTER } from './package-paths.mjs';
|
|
24
24
|
|
|
25
25
|
// Instance data — fork-configurable. The npm scope the lockstep roster publishes under.
|
|
26
26
|
// Default preserves @adia-ai behavior; override via --scope or $ADIA_NPM_SCOPE.
|
|
27
27
|
const DEFAULT_SCOPE = '@adia-ai';
|
|
28
28
|
|
|
29
29
|
// Single-sourced roster (H3, package-paths.mjs); order = dispatch order.
|
|
30
|
-
|
|
30
|
+
// Filtered to `lockstep !== false`: a class-B package (gh#1133's
|
|
31
|
+
// adia-plugins) publishes via its own manual cut (independent-package-
|
|
32
|
+
// release.md), never this lockstep dispatch loop.
|
|
33
|
+
const PACKAGES = PACKAGE_ROSTER.filter((p) => p.lockstep !== false).map((p) => p.name);
|
|
31
34
|
|
|
32
35
|
function parseArgs(argv) {
|
|
33
36
|
const args = {
|
|
@@ -64,6 +64,35 @@ export const GATE_ROSTER = [
|
|
|
64
64
|
// v0.7.13-retro hygiene checker — README CDN pins / "Current version"
|
|
65
65
|
// claims vs the cut version; branch/worktree limbo prints as warns (H2).
|
|
66
66
|
{ n: 24, cmd: 'node scripts/release/check-cut-hygiene.mjs', what: 'README CDN-pin + version currency', versionArg: true },
|
|
67
|
+
// gh#1132 (factory-dx-ws1-boot SPEC, REQ-04): npm-packs BOTH
|
|
68
|
+
// @adia-ai/web-components and @adia-ai/web-modules and resolves every
|
|
69
|
+
// specifier the scaffold templates emit against the extracted tarballs'
|
|
70
|
+
// real exports maps — the same blast radius gh#296's
|
|
71
|
+
// exports-wildcard-resolution.mjs gate covers, applied to the factory
|
|
72
|
+
// plugin's own templates instead of a consumer's hand-written import.
|
|
73
|
+
{ n: 25, cmd: 'python3 packages/plugins/adia-ui-factory/scripts/adia-scaffold selftest', what: 'scaffold specifiers resolve in packed tarballs' },
|
|
74
|
+
// gh#1137 (factory-dx-ws6-measurement SPEC, REQ-05) — FLAGGED FOR
|
|
75
|
+
// CONFIRMATION: this entry was authored by the WS-6 build without a live
|
|
76
|
+
// adia-release sign-off (no operator was available mid-build to confirm
|
|
77
|
+
// the exact freshness window / regression semantics). Asserts a
|
|
78
|
+
// qa/dx/sweeps/ record exists dated within this cut's window AND its
|
|
79
|
+
// verdict is not a regression-RED (a plain floors<=1 baseline RED does
|
|
80
|
+
// NOT block a cut — only a floor that DROPPED since the prior sweep
|
|
81
|
+
// does). CONFIRMED by adia-release on the first live cut (v0.8.35,
|
|
82
|
+
// 2026-08-13): semantics hold, with one correction — the previous-cut
|
|
83
|
+
// comparison excludes the in-flight target version (self-reference fired
|
|
84
|
+
// on the handoff re-run, since the promoted heading was already on main).
|
|
85
|
+
{ n: 26, cmd: 'node scripts/release/check-dx-sweep-freshness.mjs', targetVersionArg: true, what: 'DX sweep fresh + not regression-RED' },
|
|
86
|
+
// gh#1135 (WS-4 SPEC REQ-06): a fresh free-form eval run feeds the health
|
|
87
|
+
// record gate 28 writes — without it, "latest" under evals/mcp/runs/ could
|
|
88
|
+
// be a stale leftover from an earlier ad-hoc run, not this cut's own state.
|
|
89
|
+
{ n: 27, cmd: 'npm run eval:diff -- --engine free-form', what: 'fresh free-form eval run (evals/health input)' },
|
|
90
|
+
// REQ-06: commits evals/health/<version>.json — the version this record
|
|
91
|
+
// names is the CUT's target version from the start, never the
|
|
92
|
+
// pre/post-bump `hygieneVersion` gate 24 needs (a claim-validation
|
|
93
|
+
// concern this is not) — hence `targetVersionArg` rather than
|
|
94
|
+
// `versionArg`, a distinct flag release-pack.mjs's step3PreFlight reads.
|
|
95
|
+
{ n: 28, cmd: 'node scripts/release/write-eval-health.mjs', what: 'evals/health/<version>.json committed, AC-01/AC-02 run for real', targetVersionArg: true },
|
|
67
96
|
];
|
|
68
97
|
|
|
69
98
|
// -- CLI ------------------------------------------------------------------
|
|
@@ -42,24 +42,52 @@ import path from 'node:path';
|
|
|
42
42
|
// Order is the canonical publish/tag order (release-pack's historical order);
|
|
43
43
|
// consumers needing a different ordering (check-lockstep sorts by path for
|
|
44
44
|
// stable output) re-sort locally.
|
|
45
|
+
//
|
|
46
|
+
// `lockstep` (added gh#1133, onboarding the first class-B member since the
|
|
47
|
+
// 2026-07-15 policy emptied that class — independent-package-release.md):
|
|
48
|
+
// `true` (or omitted — every pre-2026-08 entry defaults true below) means the
|
|
49
|
+
// package rides the coordinated cut — version-match/caret gate
|
|
50
|
+
// (check-lockstep.mjs), the umbrella tag, the --pending-version sweep, bump.mjs's
|
|
51
|
+
// --from/--to pass, the dispatch-publish loop, and generate-release-notes.mjs's
|
|
52
|
+
// notes. `false` means class B: its own version line, its own manual tag +
|
|
53
|
+
// publish (independent-package-release.md), NEVER the umbrella tag or a
|
|
54
|
+
// lockstep bump/dispatch/notes pass. The ONE exception: the F-N1 release
|
|
55
|
+
// trip-wire (check-release.mjs's per-tag `checkTag` lookup) reads the FULL
|
|
56
|
+
// roster unfiltered — every pushed tag, lockstep or not, still needs its
|
|
57
|
+
// package.json/CHANGELOG validated, so it must recognize a class-B tag too.
|
|
58
|
+
// Every lockstep-scoped consumer must filter `p.lockstep !== false` itself
|
|
59
|
+
// (this module intentionally does NOT pre-filter PACKAGE_NAMES/PACKAGE_DIRS —
|
|
60
|
+
// they stay full-roster projections so a consumer's own filter is visible at
|
|
61
|
+
// its point of use, not hidden upstream).
|
|
45
62
|
export const PACKAGE_ROSTER = [
|
|
46
|
-
{ name: 'web-components', dir: 'packages/web-components' },
|
|
47
|
-
{ name: 'web-modules', dir: 'packages/web-modules' },
|
|
48
|
-
{ name: 'llm', dir: 'packages/llm' },
|
|
49
|
-
{ name: 'agent', dir: 'packages/agent' },
|
|
50
|
-
{ name: 'persona', dir: 'packages/persona' },
|
|
51
|
-
{ name: 'a2ui-runtime', dir: 'packages/a2ui/runtime' },
|
|
52
|
-
{ name: 'a2ui-compose', dir: 'packages/a2ui/compose' },
|
|
53
|
-
{ name: 'a2ui-corpus', dir: 'packages/a2ui/corpus' },
|
|
54
|
-
{ name: 'a2ui-mcp', dir: 'packages/a2ui/mcp' },
|
|
55
|
-
{ name: 'a2ui-retrieval', dir: 'packages/a2ui/retrieval' },
|
|
56
|
-
{ name: 'a2ui-validator', dir: 'packages/a2ui/validator' },
|
|
63
|
+
{ name: 'web-components', dir: 'packages/web-components', lockstep: true },
|
|
64
|
+
{ name: 'web-modules', dir: 'packages/web-modules', lockstep: true },
|
|
65
|
+
{ name: 'llm', dir: 'packages/llm', lockstep: true },
|
|
66
|
+
{ name: 'agent', dir: 'packages/agent', lockstep: true },
|
|
67
|
+
{ name: 'persona', dir: 'packages/persona', lockstep: true },
|
|
68
|
+
{ name: 'a2ui-runtime', dir: 'packages/a2ui/runtime', lockstep: true },
|
|
69
|
+
{ name: 'a2ui-compose', dir: 'packages/a2ui/compose', lockstep: true },
|
|
70
|
+
{ name: 'a2ui-corpus', dir: 'packages/a2ui/corpus', lockstep: true },
|
|
71
|
+
{ name: 'a2ui-mcp', dir: 'packages/a2ui/mcp', lockstep: true },
|
|
72
|
+
{ name: 'a2ui-retrieval', dir: 'packages/a2ui/retrieval', lockstep: true },
|
|
73
|
+
{ name: 'a2ui-validator', dir: 'packages/a2ui/validator', lockstep: true },
|
|
57
74
|
// Plugins joined the lockstep 2026-07-15 (check-lockstep.mjs POLICY note);
|
|
58
75
|
// each carries a .claude-plugin/plugin.json that bumps with package.json.
|
|
59
|
-
{ name: 'adia-ui-factory', dir: 'packages/plugins/adia-ui-factory', plugin: true },
|
|
60
|
-
{ name: 'adia-ui-forge', dir: 'packages/plugins/adia-ui-forge',
|
|
76
|
+
{ name: 'adia-ui-factory', dir: 'packages/plugins/adia-ui-factory', lockstep: true, plugin: true },
|
|
77
|
+
{ name: 'adia-ui-forge', dir: 'packages/plugins/adia-ui-forge', lockstep: true, plugin: true },
|
|
78
|
+
// adia-plugins is class B (gh#1133, ADR-0045/spec-factory-dx-ws2): the npm-
|
|
79
|
+
// sourced marketplace manifest package. No lockstep content (a roster of
|
|
80
|
+
// npm sources, no code) and REQ-03's unpinned sources mean it republishes
|
|
81
|
+
// only on its own roster change — cuts independently, own version line,
|
|
82
|
+
// never the umbrella tag. Not a Claude Code plugin itself (no `plugin.json`
|
|
83
|
+
// sidecar), so no `plugin: true`.
|
|
84
|
+
{ name: 'adia-plugins', dir: 'packages/plugins/adia-plugins', lockstep: false },
|
|
61
85
|
];
|
|
62
86
|
|
|
87
|
+
// Full-roster projections — every registered package, lockstep or not. A
|
|
88
|
+
// lockstep-scoped consumer (bump, tag-lockstep, dispatch-publish, the
|
|
89
|
+
// version-match gate, the notes generator, the docs gate) must filter
|
|
90
|
+
// `.lockstep !== false` itself; see the `lockstep` field note above.
|
|
63
91
|
export const PACKAGE_NAMES = PACKAGE_ROSTER.map((p) => p.name);
|
|
64
92
|
export const PACKAGE_DIRS = PACKAGE_ROSTER.map((p) => p.dir);
|
|
65
93
|
|