zz-meridian 0.9.0 → 0.11.0
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/README.md +9 -1
- package/dist/adopt.js +2 -1
- package/dist/cli.js +2 -0
- package/dist/create.js +3 -2
- package/dist/imports.js +32 -0
- package/dist/migrations.js +17 -0
- package/dist/session.js +18 -3
- package/package.json +1 -1
- package/payload/CHANGELOG.md +63 -0
- package/payload/CONTRIBUTING.md +2 -1
- package/payload/README.md +11 -3
- package/payload/app/(dashboard)/(overview)/README.md +1 -1
- package/payload/app/(dashboard)/(overview)/page.tsx +1 -1
- package/payload/app/(dashboard)/analytics/page.tsx +1 -1
- package/payload/app/(dashboard)/requests/README.md +1 -1
- package/payload/app/embed/health/view.tsx +4 -2
- package/payload/app/system/preview/[section]/[card]/keys.ts +0 -1
- package/payload/app/system/preview/[section]/[card]/stage.tsx +1 -1
- package/payload/docs/distribution.md +9 -1
- package/payload/docs/skill-evals.md +65 -0
- package/payload/docs/surfaces.md +1 -1
- package/payload/package.json +1 -1
- package/payload/scripts/assistant.ts +204 -169
- package/payload/scripts/audit.ts +23 -6
- package/payload/scripts/check.ts +33 -2
- package/payload/scripts/interactions.ts +3 -0
- package/payload/scripts/keyboard.ts +5 -3
- package/payload/scripts/lib/aliases.ts +28 -0
- package/payload/scripts/lib/chrome.ts +6 -0
- package/payload/scripts/lib/coverage.ts +8 -0
- package/payload/scripts/lib/sample.ts +20 -0
- package/payload/scripts/shot.ts +43 -2
- package/payload/scripts/verify.ts +31 -17
- package/payload/skills/zz-meridian/SKILL.md +123 -81
- package/payload/skills/zz-meridian/references/customize.md +47 -14
- package/payload/skills/zz-meridian/references/existing-project.md +86 -12
- package/payload/skills/zz-meridian/references/standard.md +162 -0
- package/payload/skills/zz-meridian/references/update.md +13 -6
- package/payload/skills/zz-meridian/references/validation.md +8 -4
- package/payload/src/components/base/surface/README.md +1 -1
- package/payload/src/components/base/use-share-view.ts +9 -0
- package/payload/src/components/patterns/data-table/README.md +3 -3
- package/payload/src/components/patterns/data-table/index.tsx +21 -13
- package/payload/src/components/patterns/filter-bar/index.tsx +1 -1
- package/payload/src/components/patterns/rail/README.md +1 -1
- package/payload/src/data/collections.ts +3 -1
- package/payload/src/lib/format.ts +2 -2
- package/payload/src/lib/shared-context.ts +3 -1
- package/payload/src/system/atlas-shell.tsx +1 -1
- package/payload/src/system/card-stage.tsx +2 -1
- package/payload/src/system/fixtures/sample.ts +4 -0
- package/payload/src/system/preview-loaders.ts +0 -1
- package/payload/src/system/registry.ts +0 -1
- package/payload/src/system/sample-cells.tsx +1 -1
- package/payload/src/views/console-chrome.tsx +17 -7
- package/payload/src/views/health.tsx +3 -9
- package/payload/tests/check-aliases.test.ts +20 -0
- package/payload/tests/console-chrome.test.tsx +19 -0
- package/payload/tests/format.test.ts +3 -0
- package/payload/tests/shared-context.test.tsx +11 -0
- package/payload/tests/verify-sample-surfaces.test.ts +26 -0
- package/payload/tests/verify-suite-outcome.test.ts +11 -1
- package/payload/src/components/charts/timeline/README.md +0 -74
- package/payload/src/components/charts/timeline/index.tsx +0 -148
- package/payload/src/components/charts/timeline/preview.tsx +0 -27
package/README.md
CHANGED
|
@@ -9,7 +9,15 @@ dashboard depends on it afterwards.
|
|
|
9
9
|
Give your coding agent (Codex, Claude Code, or any agent that can run a shell) this, with what you want in your own
|
|
10
10
|
words at the end:
|
|
11
11
|
|
|
12
|
-
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words].
|
|
12
|
+
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words]. Done when its hand-over says the Meridian standard is met, or names what only I can decide or provide.
|
|
13
|
+
|
|
14
|
+
In Claude Code or Codex, send it as a goal (`/goal Run npx zz-meridian@latest skill --global, then …`): the agent keeps
|
|
15
|
+
working until the condition holds, and a separate model checks it after every turn against the hand-over, which quotes
|
|
16
|
+
its evidence. The sentence says what you want; the skill carries how good it has to be. It builds, renders every view
|
|
17
|
+
at phone and desktop width in both themes, scores each one on a scoreboard of floors (measured by `pnpm verify --full`)
|
|
18
|
+
and craft (judged on the renders), and improves it round by round until nothing is weak, deciding what it can find out
|
|
19
|
+
and recording each decision it made for you. You get the finished product, the renders, and the few questions only you
|
|
20
|
+
can answer.
|
|
13
21
|
|
|
14
22
|
The skill picks the command from what you said and what is in the folder, and names it before running anything:
|
|
15
23
|
`adopt` to change this Next.js App Router project in place ("make this admin panel look professional"), `create` for a
|
package/dist/adopt.js
CHANGED
|
@@ -324,7 +324,8 @@ Meridian ${VERSION} is in ${root}.
|
|
|
324
324
|
agent context: AGENTS.md has the managed block; docs/brief.md ${briefWritten ? 'is the empty brief to fill in' : 'was kept as it is'}
|
|
325
325
|
types: ${typed}${notes.length ? `\n notes:\n${notes.map((n) => ` - ${n}`).join('\n')}` : ''}
|
|
326
326
|
|
|
327
|
-
Next: follow .agents/skills/zz-meridian/references/existing-project.md, Route A, from step 2 (step 1 was this)
|
|
327
|
+
Next: follow .agents/skills/zz-meridian/references/existing-project.md, Route A, from step 2 (step 1 was this), to the
|
|
328
|
+
standard in references/standard.md. The
|
|
328
329
|
template to read from is https://github.com/zhixuan312/zz-meridian/tree/v${VERSION}. Import Meridian's components as
|
|
329
330
|
'@meridian/components/…'. Before the first ${pm} run verify, read step 5: verify presses every control, Delete included.`);
|
|
330
331
|
return 0;
|
package/dist/cli.js
CHANGED
|
@@ -103,7 +103,9 @@ function main() {
|
|
|
103
103
|
const roots = values.global ? [os.homedir()] : [process.cwd()];
|
|
104
104
|
for (const r of roots)
|
|
105
105
|
installSkill(r);
|
|
106
|
+
const skill = path.join(roots[0], '.claude/skills/zz-meridian/SKILL.md');
|
|
106
107
|
console.log(`The zz-meridian skill is in ${values.global ? path.join(os.homedir(), '.agents/skills') + ' and ' + path.join(os.homedir(), '.claude/skills') : '.agents/skills and .claude/skills'}. Codex may need a restart to list it.`);
|
|
108
|
+
console.log(`To follow it now, read ${skill} and the references beside it: it says how to build what was asked and when it is done.`);
|
|
107
109
|
return 0;
|
|
108
110
|
}
|
|
109
111
|
console.error(`zz-meridian: unknown command "${command}"\n\n${HELP}`);
|
package/dist/create.js
CHANGED
|
@@ -76,8 +76,9 @@ export function create(o) {
|
|
|
76
76
|
${name} is a new Meridian ${VERSION} dashboard in ${root}.
|
|
77
77
|
skill: .agents/skills/zz-meridian (Codex) and .claude/skills/zz-meridian (Claude Code)
|
|
78
78
|
|
|
79
|
-
Next: follow .agents/skills/zz-meridian/SKILL.md from step
|
|
80
|
-
the pages, then ${pm} run verify
|
|
79
|
+
Next: follow .agents/skills/zz-meridian/SKILL.md from step 3's brief (the template is fetched and branded): the brief,
|
|
80
|
+
step 4's colour check, then data and the pages, then the loop in references/standard.md until ${pm} run verify --full ends with "the project meets the
|
|
81
|
+
Meridian standard" and no view on the scoreboard is Weak.`);
|
|
81
82
|
return 0;
|
|
82
83
|
}
|
|
83
84
|
function fail(msg) {
|
package/dist/imports.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import specifiers in a common form, so two copies of a module that differ only in how they name the same modules
|
|
3
|
+
* (`'../../ui/badge/index'` beside `'@/components/ui/badge'`) compare equal. `update` uses it to tell a file the team
|
|
4
|
+
* only re-styled from one it changed (issue #16). Pure: the caller passes the aliases it read.
|
|
5
|
+
*/
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
/** The project's `@/*`-style aliases from its tsconfig's `paths` (best effort; a file it cannot read gives none). */
|
|
8
|
+
export function aliasesOf(tsconfig) {
|
|
9
|
+
const out = new Map([['@meridian/', 'src/']]);
|
|
10
|
+
if (!tsconfig)
|
|
11
|
+
return out;
|
|
12
|
+
// `"@/*": ["./src/*"]` maps `@/` to `src/`; `"@/*": ["./*"]` maps it to the project root.
|
|
13
|
+
for (const m of tsconfig.matchAll(/"(@[\w-]*)\/\*"\s*:\s*\[\s*"([^"*]*)\*"/g))
|
|
14
|
+
out.set(`${m[1]}/`, m[2].replace(/^\.\//, ''));
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
/** `text` with every literal module specifier rewritten as the project path it names, extension and `/index` dropped. */
|
|
18
|
+
export function canonicalImports(rel, text, aliases) {
|
|
19
|
+
const canonical = (spec) => {
|
|
20
|
+
let to = null;
|
|
21
|
+
if (spec.startsWith('.'))
|
|
22
|
+
to = path.posix.normalize(path.posix.join(path.posix.dirname(rel), spec));
|
|
23
|
+
else
|
|
24
|
+
for (const [alias, dir] of aliases)
|
|
25
|
+
if (spec.startsWith(alias)) {
|
|
26
|
+
to = path.posix.normalize(dir + spec.slice(alias.length));
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
return to === null ? spec : to.replace(/\.(tsx?|jsx?|mjs)$/, '').replace(/\/index$/, '');
|
|
30
|
+
};
|
|
31
|
+
return text.replace(/(\bfrom\s*|\bimport\s*\(\s*|\bimport\s+)(['"])([^'"\n]+)\2/g, (_m, lead, q, spec) => `${lead}${q}${canonical(spec)}${q}`);
|
|
32
|
+
}
|
package/dist/migrations.js
CHANGED
|
@@ -213,6 +213,23 @@ export const RELEASE_MIGRATIONS = [
|
|
|
213
213
|
instructions: 'Read "Legible" in references/agents.md and "A shared context" in references/customize.md. Build the view\'s context with the fields of `SharedContext` from `src/lib/shared-context.ts` (scope, freshness, each figure with its unit, change and definition, what code finds, what the data cannot say) in a pure function beside the view, and pass it alone: `useShareView(context)`. Both agents read it: an MCP host and the console\'s assistant.',
|
|
214
214
|
checks: GATE_AND_BUILD,
|
|
215
215
|
},
|
|
216
|
+
{
|
|
217
|
+
id: 'assistant-view-tools',
|
|
218
|
+
since: '0.10.0',
|
|
219
|
+
applies: (root) => {
|
|
220
|
+
const route = text(root, 'app/api/assistant/route.ts');
|
|
221
|
+
const tools = text(root, 'src/lib/assistant/tools.ts');
|
|
222
|
+
const respond = text(root, 'src/lib/assistant/respond.ts');
|
|
223
|
+
if (route === null || tools === null || respond === null)
|
|
224
|
+
return null;
|
|
225
|
+
// The 0.9.0 assistant takes the views and tells the model its limits; one kept from before does neither.
|
|
226
|
+
const stale = [...(/\bViewTool\b/.test(tools) ? [] : ['src/lib/assistant/tools.ts']), ...(/\blimitsOf\b/.test(respond) ? [] : ['src/lib/assistant/respond.ts']), ...(/\bviews\s*:/.test(route) ? [] : ['app/api/assistant/route.ts'])];
|
|
227
|
+
return stale.length > 0 ? stale : null;
|
|
228
|
+
},
|
|
229
|
+
summary: "The assistant's route-side code predates view tools and its limits.",
|
|
230
|
+
instructions: 'Read "Adding an MCP server later" in example:docs/assistant.md. Bring `src/lib/assistant/tools.ts` and `src/lib/assistant/respond.ts` over from the release: `assistantTools(collections, writer, guard, views)` offers every view in `src/views/tools.ts` as a read-only `view_<name>` tool, `respond` lists what the assistant cannot do or see (`limitsOf`) and passes the views on, and the guard may take a `record`. Then pass `views` from the assistant route to `respond`: the template\'s `viewTools`, an adopted project\'s own view tools (`ViewTool` in `src/lib/shared-context.ts`), or none.',
|
|
231
|
+
checks: GATE_AND_BUILD,
|
|
232
|
+
},
|
|
216
233
|
{
|
|
217
234
|
id: 'agent-reads-section',
|
|
218
235
|
since: '0.9.0',
|
package/dist/session.js
CHANGED
|
@@ -8,6 +8,7 @@ import fs from 'node:fs';
|
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { managedBlock } from './context.js';
|
|
10
10
|
import { inside, packageManager, run as spawn, sha256 } from './files.js';
|
|
11
|
+
import { aliasesOf, canonicalImports } from './imports.js';
|
|
11
12
|
import { changedPaths, takeInventory } from './inventory.js';
|
|
12
13
|
import { renderMergeReport } from './merge-report.js';
|
|
13
14
|
import { releaseMigrations } from './migrations.js';
|
|
@@ -145,6 +146,7 @@ function plan(ctx, manifest, startedAt) {
|
|
|
145
146
|
if (!isSafePath(p) || FORBIDDEN.test(p))
|
|
146
147
|
throw new Refusal(`unsafe path ${JSON.stringify(p)}; nothing was written`);
|
|
147
148
|
const sourcePayload = new Set(source.payload);
|
|
149
|
+
const aliases = aliasesOf(readText(root, 'tsconfig.json'));
|
|
148
150
|
const operations = [];
|
|
149
151
|
const retired = [];
|
|
150
152
|
const targetFiles = {};
|
|
@@ -159,7 +161,16 @@ function plan(ctx, manifest, startedAt) {
|
|
|
159
161
|
const disk = probe(root, p);
|
|
160
162
|
if (disk.unsafe && (managed || keptReason.has(p)))
|
|
161
163
|
throw new Refusal(`${p} is a symbolic link or not a regular file; nothing was written`);
|
|
162
|
-
|
|
164
|
+
// A managed module the team only re-styled (its imports named another way, nothing else changed) is untouched: the
|
|
165
|
+
// release's copy replaces it instead of staging a merge nobody needs (issue #16).
|
|
166
|
+
let diskHash = disk.side.hash;
|
|
167
|
+
if (managed && recorded && diskHash && diskHash !== recorded && /\.(?:tsx?|jsx?|mjs)$/.test(p) && fs.existsSync(inside(source.tree, p))) {
|
|
168
|
+
const ours = readText(root, p);
|
|
169
|
+
const base = fs.readFileSync(inside(source.tree, p), 'utf8');
|
|
170
|
+
if (ours !== null && canonicalImports(p, ours, aliases) === canonicalImports(p, base, aliases))
|
|
171
|
+
diskHash = recorded;
|
|
172
|
+
}
|
|
173
|
+
const { disposition, action } = classify({ recorded: recorded, target: targetHash, disk: diskHash, managed, kept: keptReason.has(p) });
|
|
163
174
|
operations.push({ path: p, disposition, action, base: sideOf(recorded), ours: disk.side, target: sideOf(targetHash), applied: false, appliedHash: null });
|
|
164
175
|
if (disposition === 'retired-kept')
|
|
165
176
|
retired.push({ path: p, baselineHash: recorded, reason: keptReason.get(p) });
|
|
@@ -296,9 +307,13 @@ export function start(ctx, o) {
|
|
|
296
307
|
return refuse(`updates start from 0.3.0; this project is on ${manifest.version}`);
|
|
297
308
|
if (!/^\d+\.\d+\.\d+$/.test(ctx.version))
|
|
298
309
|
return refuse(`the running version ${JSON.stringify(ctx.version)} must look like 1.2.3`);
|
|
299
|
-
|
|
300
|
-
|
|
310
|
+
// Already current is not a refusal: there is nothing to do, and the run that asked has its answer.
|
|
311
|
+
if (manifest.version === ctx.version) {
|
|
312
|
+
log(`zz-meridian update: already at ${ctx.version}; nothing to update`);
|
|
313
|
+
return 0;
|
|
301
314
|
}
|
|
315
|
+
if (!isNewer(ctx.version, manifest.version))
|
|
316
|
+
return refuse(`this project is on ${manifest.version}, newer than this package (${ctx.version}); run npx zz-meridian@latest update`);
|
|
302
317
|
const git = spawn('git', ['status', '--porcelain'], root, true);
|
|
303
318
|
const dirty = git.status === 0 ? (git.stdout ?? '').split('\n').filter(Boolean).length : 0;
|
|
304
319
|
if (o.dryRun) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zz-meridian",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Bring ZZ Meridian, a dashboard design system, into a Next.js project, or start a new dashboard on it. Copies the files in; nothing depends on this package at runtime.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/payload/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
Every release of ZZ Meridian, newest first. Versions follow semver: a removed or renamed token, prop or card is major; a new card, token or variant is minor; a corrected value is a patch. Each entry says what breaks and what to do instead.
|
|
4
4
|
|
|
5
|
+
## [0.11.0] · 2026-10-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **The standard the sentence never states.** The skill's `references/standard.md` holds what one sentence leaves out: the register a product UI answers to, the defaults that read as generated, and a scoreboard kept in `out/standard/` for every view. The scoreboard has floors measured by `pnpm verify --full`, and craft judged on renders at 1440 and 390px in both themes (fit, hierarchy, typography, whitespace, colour, motion, responsive, navigation, copy, states, agents, originality). The agent runs the loop until `--full` ends with `the project meets the Meridian standard` and no view is Weak. Mechanical questions it settles itself; judgment calls it records with a recommendation, proceeding when cheap to reverse. Push, release, deploy, production data and the feedback issue wait for a yes.
|
|
10
|
+
|
|
11
|
+
- **How the skill is evaluated.** `docs/skill-evals.md`: four levels by cost (static checks every change; decision probes, an agent reading the skill in a scenario's folder and stopping before the first write, for a change to the route, the decisions or the standard; planted defects for a change to the loop; end to end weekly), seven scenarios with what a right answer does, and how a finding is counted. Two fixture apps for them in `cli/test/`: `fixture-crumb-ops` (Next.js App Router over its own orders API, with server actions that delete) and `fixture-vite-rota` (Vite and React Router, one browser read); neither ships.
|
|
12
|
+
|
|
13
|
+
- **One protagonist is a rule, not only a judgement.** `check.ts` fails a file that renders a second `FeaturedMetric`. A planted second one went unscored when an agent judged the renders by eye.
|
|
14
|
+
- **The console's rail takes the request's data from the layout.** `ConsoleRail` passes its props through (`user`, `signOut`, `workspace`, `scopes`) and both it and `ConsolePalette` take `only`, the hrefs a person may see. A product filtered `nav` or set its session's person by editing `src/views/console-chrome.tsx`, a file Meridian manages; a console with no sign-in showed the sample person and a Sign out to nowhere. Now the team's own layout passes them.
|
|
15
|
+
- **`shot.ts --press "<name>"`** opens a dialog, sheet, menu or popover before the shot, with the mouse, as a person does; repeated, it presses in order. A view that only a press shows can now be rendered and scored.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **An update already on the running version has nothing to do, and says so.** `update` and its dry run print `already at <version>; nothing to update` and exit 0, where they refused with exit 1 as if something were wrong.
|
|
20
|
+
- **The sentence ends with its condition, and is meant for `/goal`.** `… to: [what you want]. Done when its hand-over says the Meridian standard is met, or names what only I can decide or provide.` The model a goal uses to check the work reads the sentence and the transcript, never the skill, so the hand-over quotes verify's last line, the coverage line, the scoreboard count, the decisions made, what did not run, and the commits.
|
|
21
|
+
- **The skill decides from its drafts instead of asking.** Step 2 turns the homework into recorded decisions; the one question left is the route, when two fit. A brand hue too near a status hue moves to the nearest safe hue, with the brand kept in the logo mark. A missing tool no longer stops the build: what cannot run is reported as not run, and the standard as not yet proven.
|
|
22
|
+
- **`skill` prints the path to read.** After installing, it names the `SKILL.md` to read now, since a running agent may not list a skill installed mid-session.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **What the agents are told about freshness names the right zone.** `freshnessOf` wrote the time in the product's reporting zone and labelled it "UTC", so a product in Asia/Singapore told both agents that 17:30 local was 17:30 UTC. It names `app.timezone`.
|
|
27
|
+
- **An amount keeps one precision.** `formatCost` gave two decimals under 1,000 and none above, so a column read "$997.00" over "$1,269"; it gives two at every size ("$1,269.40"). `formatCostCompact` stays for dense tiles.
|
|
28
|
+
- **The gate reads an adopted project's imports.** `check.ts` took `@/` to mean `src/`, so in an adopted project, where `@/` is the team's root and Meridian is `@meridian/`, every module imported the documented way read as dormant ("exports X, which nothing a product keeps imports"), and a project had to rewrite its imports as relative paths to pass. It now resolves imports through the project's tsconfig `paths` (`scripts/lib/aliases.ts`).
|
|
29
|
+
- **verify reports a bad configuration instead of crashing on it.** An early exit (a `navigationChecks` or `smokeRoutes` entry naming a route that is gone) threw `Cannot access 'suites' before initialization` and hid the reason; it now prints each configuration failure and the coverage line.
|
|
30
|
+
- **The coverage line says which suites failed.** A suite that ran and failed was listed under `not run`, as if skipped; it is now `failed: <suites>`, after `not run`.
|
|
31
|
+
- **A phone card's status and facts stay in their place.** The status badge took one of the card's six tracks, narrower than a badge at 390px, so it ran left over a long title and sat short of the card's edge; it takes two, as the layout meant. A long fact ends in an ellipsis instead of running over the fact beside it. The sample's customer column caps its width, so a long name no longer pushes the Requests table past its card at 1440px.
|
|
32
|
+
- **A product can reach "the project meets the Meridian standard".** The assistant walk-through and the live checks drove the template's own sample pages (Overview, Members, API keys, Settings), so a product that replaced them — every product the skill builds — failed the walk-through or ended `not run: live`, and `--full` could never print the outcome its stop condition asks for. The walk-through now checks what every product shares on its own rail: no agent control while off, on every rail route and embed view, 12 in the template where it was 8; the panel, a reply, the page the model was told, markdown, the thread across navigation, Clear, the layout, a refused key, the key never reaching the browser. It drives each sample page only while its files are there (`scripts/lib/sample.ts`), printing `n/a` with the reason otherwise; Meridian's own repository, which has every one, walks all of them. Without the sample Members page, verify prints `n/a live data` instead of running the live checks, and it no longer counts against the outcome; a product's own live pages prove themselves through `browserChecks`.
|
|
33
|
+
- **The skill names what its route needs, from what the probes met.** `create .` works in an empty folder; timezone, currency and the meaning of the request's own terms are recorded decisions; a view's verdict is its lowest criterion; the error state without a fake API is shown by making the read throw for one render. An update already on the running version stops there. The `optional:` and `example:` path prefixes are explained, a project's own copy of the skill is the one to follow, and Route A2 no longer names a `--product` flag `create` does not have. An existing product is learned first, its production addresses found before anything runs, its pages shot "before", and what must survive listed as a floor; Route B renders its "before" from a copy, and a read moved from the browser to the server carries neither cookies nor CORS. `create` and `adopt` end by pointing at the standard, not at `verify` passing. From the second round: the last round needs no round after it; originality comes from how asked-for content is shown, never from adding content; a view's states are scored under it and the shell is one row; the dev server is stopped by its own process id; the rail's signed-in person is never the sample's; an API address overrides `.env` through the environment and is not a `dataUrls` entry; a rebrand that lands near a status hue runs `brand` again with the nearest safe hue. From a built brownfield run and a planted-defect run: an adopted project turns on Cache Components and wraps its shell in `<Suspense>` when detail ids come at request time; a product formatter lives in a file of its own, and a Meridian file it must change goes in the keep register; the theme default is set through `brand --theme`; a navigation probe works at 390px; a request to evaluate only has a route of its own; a criterion not yet judged is not a pass. From the built greenfield run: `create` points at step 3's brief, not step 5; a page specification has a shape to start from; the shared context's 2,400-character budget is stated; the dev server is started as Next itself, so stopping its id stops it. From a third round of decision probes: the existing-project route starts with "Before you change anything", not with `adopt`; Cache Components means `partialPrefetching` too; a render server in a project with a fake API is started with its address; an npm project passes flags after `--`; a currency is evidence of the zone; a browser-fetching app's "before" needs a time budget and a fake API that allows its origin; Route B's new project takes Route A's verify steps.
|
|
34
|
+
- **The skill's screenshots reach the dev server.** Step 6 started `pnpm dev`, on port 3000, then ran `scripts/shot.ts`, which reads port 3100. It now starts `pnpm dev --port 3100`.
|
|
35
|
+
|
|
36
|
+
### Breaking
|
|
37
|
+
|
|
38
|
+
- **`formatCost` prints cents at every size.** An amount of 1,000 or more reads "$1,269.40" where it read "$1,269". A product that pinned the old string in a test, or laid a column out for the shorter figure, updates it; `formatCostCompact` is the short form.
|
|
39
|
+
|
|
40
|
+
## [0.10.0] · 2026-10-07
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- **`audit --atlas`.** The browser audit over the Design Atlas: every card's page and its bare preview, at 1440 and 390px in both themes, about ten minutes. Not part of `pnpm verify`, which stays fast (issue #9).
|
|
45
|
+
- **`ShareContext`.** `useShareView` as a component that renders nothing, for a server page with no client view (issue #17).
|
|
46
|
+
- **A database guide.** `references/existing-project.md` covers a pool that survives a dropped connection, a transaction pooler, schema changes on start, and a role that cannot create (issues #16, #17).
|
|
47
|
+
- **`assistant-view-tools` migration.** `update` reports an assistant whose route-side code predates view tools and its limits (issue #17).
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- **Export is offered on a phone.** The Overview's and Analytics' Export were hidden below 640px; a page's actions are offered on every width (issue #13).
|
|
52
|
+
- **`update` sees past import style.** A managed module whose only difference from its release copy is how its imports are written (`@/…` for `../../…`) is untouched, not a merge (issue #16).
|
|
53
|
+
- **A specimen is not the page.** The audit keeps a card preview's own headings and scroll regions out of the page's outline and its one scroller (issue #8).
|
|
54
|
+
- **A control's role needs its keys.** `scripts/check.ts` fails an element that claims a control's role (`button`, `tab`, `switch` and the rest) with no `onKeyDown` (issue #11).
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
|
|
58
|
+
- **A narrow table becomes cards on any screen.** `DataTable`'s card list follows the table's own width (under 640px), as `hideBelow` does, so a table in a half-width row or beside the assistant's column no longer runs past its frame. Found by the first `audit --atlas`, with the two below.
|
|
59
|
+
- **An active filter's label reads.** A filter that is on keeps its name in `ink-2` on the accent tint; `ink-3` fell to 4.04:1 in light.
|
|
60
|
+
- **A selected row's facts read on a phone.** On the accent wash, a card's facts step up to `ink-2`; `ink-3` fell to 4.43:1 in light.
|
|
61
|
+
- **The presses count a file chooser.** A file picker's button opens the system's chooser, which changes nothing in the DOM; the presses now intercept it and count it as an answer (issue #16).
|
|
62
|
+
- **verify's assistant-off run ignores `.env.local`.** It blanks every name the assistant reads, set in the shell or not (issue #16).
|
|
63
|
+
|
|
64
|
+
### Breaking
|
|
65
|
+
|
|
66
|
+
- **`Timeline` is removed.** No page used it, and a card exists because a page needs it (`CONTRIBUTING.md`). Import nothing from `src/components/charts/timeline`.
|
|
67
|
+
|
|
5
68
|
## [0.9.0] · 2026-10-07
|
|
6
69
|
|
|
7
70
|
### Added
|
package/payload/CONTRIBUTING.md
CHANGED
|
@@ -85,9 +85,10 @@ Write the status on the line under the title: `Status: beta`.
|
|
|
85
85
|
| `pnpm tokens` | Generates the token CSS and the Tailwind bridge from `tokens/` (`--check` only compares) | After any token change |
|
|
86
86
|
| `node scripts/contrast.ts [--all]` | Every specified foreground on its background, in every theme and accent, and the chart palette's colour-vision checks | Gate |
|
|
87
87
|
| `node scripts/registry.ts` | Regenerates the Atlas registry from the card folders (`--check` only compares) | After adding or renaming a card |
|
|
88
|
-
| `node scripts/check.ts` | Every card has its README and preview, every README follows the anatomy, no literal colour in components, every token a spec names exists and is written with its own value,
|
|
88
|
+
| `node scripts/check.ts` | Every card has its README and preview, every README follows the anatomy, no literal colour in components, every token a spec names exists and is written with its own value, every embed view a document offers is a route, and an element that claims a control's role has a key handler | Gate |
|
|
89
89
|
| `pnpm typecheck`, `pnpm test` | TypeScript and the behaviour tests | Gate |
|
|
90
90
|
| `node scripts/audit.ts` | With the app running: every page and embed view at 2560, 1440, 1024, 768 and 390px in both themes (embeds at 720 and 420 on a simulated host ground). Fails on sideways scroll, text clipped without an ellipsis, a control with no accessible name, more than one page scroller, rendered text under its WCAG minimum, a Tab stop with no visible focus ring (it presses Tab through the page), and any uncaught exception or console error. Prints the design metrics: type sizes, weights, radii and the hierarchy ratio | Before release |
|
|
91
|
+
| `node scripts/audit.ts --atlas` | With the app running: the same audit over the Design Atlas, every card's page and its bare preview, at 1440 and 390px in both themes, about ten minutes. Not part of `pnpm verify`, which stays fast: a card's preview is where a defect in its own box shows, so run it after changing a component | After changing a component |
|
|
91
92
|
| `node scripts/interactions.ts` | With the app running: presses every control on every page (mouse at 1440px, taps at 390px) and follows every link. Fails on a control that changes nothing, one something covers, and a link that answers 4xx | Before release |
|
|
92
93
|
| `pnpm verify` | The gate once, one production build, the route policy, the size checks and a smoke of up to three routes on desktop and the phone drawer; ends with a coverage line, and the report is in `out/verify.txt` | Before finishing any change |
|
|
93
94
|
| `pnpm verify --full` | The navigation of every rail route, then every exhaustive suite: the audit, every control pressed and link followed, the keyboard walk, the assistant, the live data and Web Vitals | After a change to shared components, the shell or data, and before release |
|
package/payload/README.md
CHANGED
|
@@ -72,8 +72,8 @@ Dark is the default, written on `:root`; the light theme follows the operating s
|
|
|
72
72
|
| `docs/` | Guides: surfaces, agents, the assistant, starting a dashboard, data display, voice, the benchmark |
|
|
73
73
|
| `decisions/` | One record per lasting decision |
|
|
74
74
|
| `scripts/` | Generators, gates, `brand.ts` and `verify.ts` (see `CONTRIBUTING.md`) |
|
|
75
|
-
| `skills/zz-meridian/` | The agent skill (Claude Code, Codex) that builds dashboards on this template or brings it into yours |
|
|
76
|
-
| `cli/` | The `zz-meridian` npm package: `create`, `adopt`, `update`, `brand` and `skill`, its build, its smoke test and the fixture
|
|
75
|
+
| `skills/zz-meridian/` | The agent skill (Claude Code, Codex) that builds dashboards on this template or brings it into yours, to the standard in `references/standard.md`; how it is evaluated is `docs/skill-evals.md` |
|
|
76
|
+
| `cli/` | The `zz-meridian` npm package: `create`, `adopt`, `update`, `brand` and `skill`, its build, its smoke test and the fixture apps (`docs/distribution.md`) |
|
|
77
77
|
| `.github/workflows/release.yml` | The release, each check once: a timed default verify and the consumer path from the tarball (the release before updated; the last three weekly), then npm with provenance, the registry's bytes and provenance checked, then the tag (`.claude/commands/release.md`) |
|
|
78
78
|
| `.github/workflows/weekly.yml` | Weekly, never at release: `verify --full --perf` (perf a report) and the consumer smoke's recovery and failure cases; nothing waits on it |
|
|
79
79
|
| `Dockerfile`, `captain-definition` | The demo deployment: the template and the Atlas behind `DEMO_PASSWORD` (`proxy.ts`, `app/sign-in/README.md`), deployed to CapRover from this repository; never in the package |
|
|
@@ -83,7 +83,15 @@ Dark is the default, written on `:root`; the light theme follows the operating s
|
|
|
83
83
|
Give your coding agent (Codex, Claude Code, or any agent that can run a shell) this, with what you want in your own
|
|
84
84
|
words at the end:
|
|
85
85
|
|
|
86
|
-
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words].
|
|
86
|
+
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words]. Done when its hand-over says the Meridian standard is met, or names what only I can decide or provide.
|
|
87
|
+
|
|
88
|
+
In Claude Code or Codex, send it as a goal (`/goal Run npx zz-meridian@latest skill --global, then …`): the agent keeps
|
|
89
|
+
working until the condition holds, and a separate model checks it after every turn against the hand-over, which quotes
|
|
90
|
+
its evidence. The sentence says what you want; the skill carries how good it has to be. It builds, renders every view
|
|
91
|
+
at phone and desktop width in both themes, scores each one on a scoreboard of floors (measured by `pnpm verify --full`)
|
|
92
|
+
and craft (judged on the renders), and improves it round by round until nothing is weak, deciding what it can find out
|
|
93
|
+
and recording each decision it made for you. You get the finished product, the renders, and the few questions only you
|
|
94
|
+
can answer.
|
|
87
95
|
|
|
88
96
|
You do not choose between the package's commands; the skill does, from what you said and what is in the folder, and
|
|
89
97
|
names the route before it runs anything:
|
|
@@ -17,7 +17,7 @@ Status: beta
|
|
|
17
17
|
|
|
18
18
|
Everything in rows 1 and 2 shares one Meridian: point at a day in either chart and the featured figure, the tiles and both charts read that day.
|
|
19
19
|
|
|
20
|
-
Below 1024px every row stacks: the featured card first, then the tiles (two across from 34rem, one below), then the cards. At 390px the masthead's actions wrap under the title
|
|
20
|
+
Below 1024px every row stacks: the featured card first, then the tiles (two across from 34rem, one below), then the cards. At 390px the masthead's actions wrap under the title: the period select, then Export. A page's actions are offered on every width, as the request log's export is: a person on a phone may want the CSV too (issue #13).
|
|
21
21
|
|
|
22
22
|
## States
|
|
23
23
|
|
|
@@ -47,7 +47,7 @@ async function Actions({ searchParams }: { searchParams: SearchParams }) {
|
|
|
47
47
|
return (
|
|
48
48
|
<>
|
|
49
49
|
<Suspense><PeriodSelect value={period} /></Suspense>
|
|
50
|
-
<ExportButton rows={data.series} filename={`overview-${period}.csv`} noun="days"
|
|
50
|
+
<ExportButton rows={data.series} filename={`overview-${period}.csv`} noun="days" />
|
|
51
51
|
</>
|
|
52
52
|
);
|
|
53
53
|
}
|
|
@@ -47,7 +47,7 @@ async function Actions({ searchParams }: { searchParams: SearchParams }) {
|
|
|
47
47
|
return (
|
|
48
48
|
<>
|
|
49
49
|
<Suspense><PeriodSelect value={period} /></Suspense>
|
|
50
|
-
<ExportButton rows={data.series} filename={`analytics-${period}.csv`} noun="days"
|
|
50
|
+
<ExportButton rows={data.series} filename={`analytics-${period}.csv`} noun="days" />
|
|
51
51
|
</>
|
|
52
52
|
);
|
|
53
53
|
}
|
|
@@ -10,7 +10,7 @@ Status: beta
|
|
|
10
10
|
|---|---|---|---|
|
|
11
11
|
| Masthead | PageFrame: kicker "ZZ Meridian · Production", title "Requests", one sentence, Freshness, Export CSV | One band | Title, sentence, then Freshness and Export on their own row |
|
|
12
12
|
| 1 | Row `tiles`: three Metric tiles for what the filters let through: requests (emphasis), errors and limits, latency p95, each with its 5-minute shape over the last hour and the last half hour against the one before | Three across | One column |
|
|
13
|
-
| 2 | Data table with a Filter bar in its toolbar: search, Status, Method, Region, the result count | Columns: Request (grow), Status, Latency, Customer
|
|
13
|
+
| 2 | Data table with a Filter bar in its toolbar: search, Status, Method, Region, the result count | Columns: Request (grow), Status, Latency, Customer and Region (once the table is 896px wide), Size (1152px), Received; a table under 640px wide is the card list | Card list: route and status, then latency, customer and when |
|
|
14
14
|
|
|
15
15
|
## States
|
|
16
16
|
|
|
@@ -7,7 +7,9 @@ import { EmbedFrame } from '@/components/patterns/embed-frame';
|
|
|
7
7
|
import { Freshness } from '@/components/patterns/freshness';
|
|
8
8
|
import { AskAbout } from '@/components/patterns/ask-about';
|
|
9
9
|
import { StatusList } from '@/components/patterns/status-list';
|
|
10
|
-
import {
|
|
10
|
+
import { ShareContext } from '@/components/base/use-share-view';
|
|
11
|
+
import { HealthBody } from '@/views/health';
|
|
12
|
+
import { healthContext } from '@/views/health-context';
|
|
11
13
|
import { formatRelative } from '@/lib/format-date';
|
|
12
14
|
import type { Incident } from '@/components/patterns/incident-card';
|
|
13
15
|
import type { Service } from '@/components/patterns/status-list';
|
|
@@ -22,7 +24,7 @@ export function EmbedHealth(p: Props) {
|
|
|
22
24
|
<HealthBody {...p} />
|
|
23
25
|
) : (
|
|
24
26
|
<div className="flex flex-col gap-3">
|
|
25
|
-
<
|
|
27
|
+
<ShareContext context={healthContext(p)} />
|
|
26
28
|
{p.current ? (
|
|
27
29
|
<Banner
|
|
28
30
|
tone="warning"
|
|
@@ -17,7 +17,7 @@ function Inner({ id }: { id: string }) {
|
|
|
17
17
|
data-density={q.get('density') ?? undefined}
|
|
18
18
|
className="min-h-dvh bg-ground p-8 text-ink max-sm:p-4"
|
|
19
19
|
>
|
|
20
|
-
<div className="mx-auto max-w-5xl"><Suspense><P /></Suspense></div>
|
|
20
|
+
<div data-specimen className="mx-auto max-w-5xl"><Suspense><P /></Suspense></div>
|
|
21
21
|
</div>
|
|
22
22
|
);
|
|
23
23
|
}
|
|
@@ -6,7 +6,7 @@ Status: v1 (`create`, `adopt`, `skill`) shipped in 0.2.0 (decision 0009). v2 (`u
|
|
|
6
6
|
|
|
7
7
|
A team gives its coding agent this, with what it wants in its own words at the end:
|
|
8
8
|
|
|
9
|
-
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words].
|
|
9
|
+
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words]. Done when its hand-over says the Meridian standard is met, or names what only I can decide or provide.
|
|
10
10
|
|
|
11
11
|
The sentence names no command, because people do not: "change this product into our dashboard", "a new one based on
|
|
12
12
|
this folder, in another folder" and "build an orders console" all ask for a dashboard on Meridian and differ only in
|
|
@@ -15,6 +15,14 @@ which folder holds it. The skill's "Choose the route" table maps what was said,
|
|
|
15
15
|
written) or `update` and `brand` (a project that already has Meridian), and says the route before the first command.
|
|
16
16
|
An earlier sentence named `adopt`, the wrong command for every request for a new dashboard.
|
|
17
17
|
|
|
18
|
+
The sentence is written to be sent as a goal (`/goal` in Claude Code and Codex), which keeps the agent working until a
|
|
19
|
+
separate model, reading the conversation after every turn, finds the condition met. That model sees the sentence, not
|
|
20
|
+
the skill, so the sentence ends with a condition the transcript can show: the hand-over (SKILL.md, step 7) quotes
|
|
21
|
+
`pnpm verify --full`'s last line and the scoreboard's count, or names what only the person can decide or provide. The
|
|
22
|
+
degree lives in the skill, never in the sentence: `skills/zz-meridian/references/standard.md` holds the register, the
|
|
23
|
+
scoreboard of floors and craft kept for every view, the loop run until nothing is weak, and which decisions the agent
|
|
24
|
+
makes and records and which wait for the person. People do not say how good it has to be, so the skill does not ask.
|
|
25
|
+
|
|
18
26
|
The split follows what each part is good at. The package does the settled work, the same way every time, and proves it
|
|
19
27
|
built: what to copy, which dependencies to merge, the alias, the stylesheet, the brand. The agent does the judgement:
|
|
20
28
|
rebuilding each page on Meridian's components, the fake API, and reading what `pnpm verify` finds.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Evaluating the skill
|
|
2
|
+
|
|
3
|
+
A person gives their agent one sentence (`docs/distribution.md`), and the skill carries everything the sentence leaves
|
|
4
|
+
out: the standard, the definition of done, and how the agent evaluates its own work
|
|
5
|
+
(`skills/zz-meridian/references/standard.md`). When those three are right, an agent that follows the skill reaches the
|
|
6
|
+
standard on the person's project. So a change to the skill is judged by whether an agent reading it chooses the right
|
|
7
|
+
route, decides instead of asking, knows what done means and how it will know, and finds the defects that keep a product
|
|
8
|
+
from it. Rebuilding a whole dashboard to judge a change in wording is not needed.
|
|
9
|
+
|
|
10
|
+
## Four levels
|
|
11
|
+
|
|
12
|
+
| Level | What it shows | Cost | When |
|
|
13
|
+
|---|---|---|---|
|
|
14
|
+
| L0 static | Every path, command and flag the skill names exists (`node scripts/check.ts`); the text has no dated or contradictory instruction (a prompt audit, `/claude-api prompt-audit`) | seconds | every change to the skill |
|
|
15
|
+
| L1 decisions | An agent reads the skill in a scenario's folder and stops before the first command that writes: its route, its announcement, its decisions, its brief, the views it will score, its definition of done and how it will evaluate | 2 to 5 minutes each, run side by side | a change to the route, the decisions, the brief or the standard |
|
|
16
|
+
| L2 planted defects | An agent runs the loop on a built Meridian project with known defects planted (a clipped name, a missing empty state, a literal colour, a wrong total, a page with no protagonist, a stale `verify.config.ts` route): which it finds, which it fixes, and whether it stops only when `--full` prints the outcome | about 15 minutes | a change to the standard or the loop |
|
|
17
|
+
| L3 end to end | The sentence, a fresh agent and a real request, from nothing (greenfield) or an existing app (brownfield) to the hand-over | 1 to 2 hours each | weekly, never per change |
|
|
18
|
+
|
|
19
|
+
## L1 scenarios
|
|
20
|
+
|
|
21
|
+
Each runs in a scratch folder. A scenario that starts from an existing app copies its fixture there, renames
|
|
22
|
+
`fixture.env` to `.env` (an address on a reserved domain that stands for production), and commits it, so the folder is
|
|
23
|
+
the clean repository a team would have.
|
|
24
|
+
|
|
25
|
+
| Scenario | Folder | The request after "to:" | What a right answer does |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| Greenfield | empty | build an orders console for our bakery chain, three shops; today's orders, late pickups, which cakes sell best | `create .`; pages that answer the three questions; timezone, currency and "late" recorded as decisions; deletes the sample pages it does not need |
|
|
28
|
+
| Next.js brownfield | `cli/test/fixture-crumb-ops` | make our ops console look and work like a professional product, and let the shop leads see late pickups at a glance | `adopt` in place; finds `API_URL` is production before running anything; fake API first, committed, with a request log; "before" renders; lists every route and action that must survive; keeps `lib/api.ts` |
|
|
29
|
+
| Vite brownfield | `cli/test/fixture-vite-rota` | turn our rota app into a proper dashboard for the ward managers | `create` beside it, never in it; ports both routes and the one request; "before" from a copy; names the cookie and CORS change of a read moved to the server; switching over is the person's |
|
|
30
|
+
| Update | a project made with `create --no-install`, committed | update Meridian to the latest | `update --dry-run` first; already current means it says so and stops |
|
|
31
|
+
| Rebrand | the same | change our brand colour to #D97706 | `brand` with the manifest's version; sees the amber is 10° from the warning hue; nearest safe hue as the accent, the exact colour in the logo, recorded, no question |
|
|
32
|
+
| Ambiguous | `cli/test/fixture-crumb-ops` | build me a dashboard for this | one question at most, the route, with the recommendation first; without an answer it takes the recommendation and says so |
|
|
33
|
+
| Based on | `cli/test/fixture-crumb-ops` | based on this folder, make a new dashboard in ../crumb-v2 | `create ../crumb-v2`; reads the source and never writes it; ports its data layer and its contract |
|
|
34
|
+
|
|
35
|
+
Every scenario is also held to what is true of all of them: the agent reads `standard.md` before building, asks nothing
|
|
36
|
+
but the route, says the route before the first command, records decisions with their reasons, lists every view it will
|
|
37
|
+
score, and states the definition of done as the commands and lines that will prove it.
|
|
38
|
+
|
|
39
|
+
The probe is given the sentence, told where the skill and the local CLI are, told to write nothing, and asked for, in
|
|
40
|
+
order: its announcement, the route and first commands, its decisions, the brief, the views, the definition of done and
|
|
41
|
+
how it will know, how it will evaluate each view, its questions, and what in the skill was unclear, contradictory or
|
|
42
|
+
missing, with `file:line`. Run at least one scenario on a smaller model than the one the skill is written with: the
|
|
43
|
+
skill is for anyone's agent.
|
|
44
|
+
|
|
45
|
+
## Reading the results
|
|
46
|
+
|
|
47
|
+
Write what a right answer does before the probes run, and grade against it. A finding counts when the skill caused it:
|
|
48
|
+
a contradiction, a path that does not resolve, a case it does not cover, a step that would stop an unattended run, a
|
|
49
|
+
definition of done that cannot be reached. A finding that comes from the probe's own context (a memory or rule of the
|
|
50
|
+
machine it ran on) is not the skill's. Fix each counted finding in the skill or in Meridian's code, and run the
|
|
51
|
+
scenarios it touched again.
|
|
52
|
+
|
|
53
|
+
## What each level finds
|
|
54
|
+
|
|
55
|
+
Each level finds what the ones below it cannot, which is why none replaces another:
|
|
56
|
+
|
|
57
|
+
- **L1** finds what reading the skill against the code shows: a definition of done the scripts make unreachable (the
|
|
58
|
+
first round found that the walk-throughs drove the template's own sample pages, so no product could pass), a step
|
|
59
|
+
that would stop an unattended run, a contradiction between two files, a case no route covers.
|
|
60
|
+
- **L2** finds where judging by eye is not enough. Of six planted defects an agent found five; the one it missed, a
|
|
61
|
+
second featured metric, became a rule in `scripts/check.ts`. A rule the code can check is checked there, not left to
|
|
62
|
+
the scoreboard.
|
|
63
|
+
- **L3** finds what only building shows: the gate misreading an adopted project's imports, a phone card's badge over
|
|
64
|
+
a long name, a verify that crashed on its own early exit. Each became a fix with a test, so the weekly run that
|
|
65
|
+
found it does not have to find it again.
|
package/payload/docs/surfaces.md
CHANGED
|
@@ -25,7 +25,7 @@ Below 1024px the rail becomes a drawer (the same node, so nothing is defined twi
|
|
|
25
25
|
| Navigation | Rail | Drawer from the masthead's menu button; closes on Escape, on the scrim and on navigation | AppShell |
|
|
26
26
|
| Masthead | Title, head-note, actions on one band | Title row with the menu button; head-note under it; actions wrap to their own row, the primary last | PageFrame |
|
|
27
27
|
| Metric tiles | Four across | Two across from 34rem of row width, one below | Row `tiles` |
|
|
28
|
-
| Tables | Columns, sortable heads | A list of cards, one per row: the primary column as the title, two or three facts under it, the status at the end; low-value columns drop first (`hideBelow`) | DataTable |
|
|
28
|
+
| Tables | Columns, sortable heads | A list of cards, one per row: the primary column as the title, two or three facts under it, the status at the end; low-value columns drop first (`hideBelow`). Both read the table's own width, so a table in a narrow frame on a wide screen becomes cards too | DataTable |
|
|
29
29
|
| Dialogs | Centred, 520px | A bottom sheet, full width, safe-area padding | Dialog |
|
|
30
30
|
| Menus and selects | Popover | Popover, at least 44px rows on touch | Menu, Select |
|
|
31
31
|
| Charts | Full height, 6 to 8 date labels | Shorter (180px), 3 to 4 date labels; the Meridian follows the finger and the tooltip pins to the top edge | TrendChart |
|
package/payload/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zz-meridian-template",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "ZZ Meridian: a dashboard design system and starter. DTCG tokens, five layers of React components and a Design Atlas, in a light and a dark theme.",
|