You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/scripts/arts-check.ts

192 lines
6.4 KiB

/**
* arts-check — guard for the `src/arts/` ecosystem invariants (arts docs
* reconciliation, batch A0). Ships the net that batches A1–A3 / B3 land
* against, so the drift-fix and language passes cannot silently regress the
* structural promises the arts corpus makes.
*
* The canon these invariants encode is `src/arts/README.md` §"naming
* conventions" + the "Map" index:
*
* A-readme (error) — every `src/arts/{name}/` has a README.md. A missing
docs(arts): ethereal README + A1 drift sweep (orca/cache/adom) + honest guard Ethereal (was undocumented — the miss that prompted this pass): - new src/arts/ethereal/README.md, API drawn from the code (computePosition, the 7 middleware, autoUpdate, selectPositioningStrategy, dual JS/CSS-anchor engine, +1-frame read-phase model) - wired into src/arts/README.md Map + aliases + cross-deps; $ethereal added to the CLAUDE.md alias table; the also-missing bus/orca/prefs aliases + Map rows completed against vite.config.ts A1 drift (every fix verified against the cited code symbol, not the plan): - orca: ~13 phantom identifiers across 7 sections (priority, execution / ORCA_EXEC_*, tokenTimeoutMs, onFatal / ORCA_ON_FATAL_*, onTimeout, the whole multi-level timeout model, the transaction-port model + ORCA_TX_*, OrcaMaybePromise, OrcaCompensationContext) reconciled to the real API (parallel waves, actionTimeoutMs-only, transaction:string tag + compensate, fatal via returning OrcaFatal); added the real missing fields fanIn / parallel / compensate; glossary OrcaRun -> OrcaRunResult - cache: residual createActiveApp({cache}) -> services:{cache:defineActiveCache()}; documented the ActiveEngine contract surface (loading / lastError / disposed / snapshot / clearError / onChange / dispose); dangling demo URL -> /active/get-started/ecosystem - adom: added prefersReducedMotion / writeProperty / removeProperty; listen 1 -> 4 typed overloads; documented 12 undocumented standalone rune helpers; /test/adom -> /active/docs/adom Guard (scripts/arts-check.ts): removed the ethereal README exemption (set empty) and promoted A-index from warn to error — the net no longer passes green with a real gap. arts:check: 0 errors, 0 warnings, 22 arts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
* README is a hole in the corpus. README_PENDING is a self-cleaning
* exemption set (empty now — every art is documented, ethereal included):
* if an exempted art later gains a README the guard demands it be removed
* from the set, so the exemption can never outlive the gap it covers.
* A-naming (error) — the `Engine*` / `Active*` split holds:
* · No `Engine*` root is DECLARED in a `.svelte.ts` file. Engines are
* pure factories over private/no state (README §7-9) — they never own
* `$state`, so they never need the runes extension. (A `.svelte.ts`
* that merely *wraps* an engine is fine; only a declaration trips it.)
* · Every reactive `class Active*` root lives in a `.svelte.ts` file
* (README §12) — a plain `.ts` cannot own module `$state`. Error
* classes (`Active…Error`) are not reactive roots and are exempt.
docs(arts): ethereal README + A1 drift sweep (orca/cache/adom) + honest guard Ethereal (was undocumented — the miss that prompted this pass): - new src/arts/ethereal/README.md, API drawn from the code (computePosition, the 7 middleware, autoUpdate, selectPositioningStrategy, dual JS/CSS-anchor engine, +1-frame read-phase model) - wired into src/arts/README.md Map + aliases + cross-deps; $ethereal added to the CLAUDE.md alias table; the also-missing bus/orca/prefs aliases + Map rows completed against vite.config.ts A1 drift (every fix verified against the cited code symbol, not the plan): - orca: ~13 phantom identifiers across 7 sections (priority, execution / ORCA_EXEC_*, tokenTimeoutMs, onFatal / ORCA_ON_FATAL_*, onTimeout, the whole multi-level timeout model, the transaction-port model + ORCA_TX_*, OrcaMaybePromise, OrcaCompensationContext) reconciled to the real API (parallel waves, actionTimeoutMs-only, transaction:string tag + compensate, fatal via returning OrcaFatal); added the real missing fields fanIn / parallel / compensate; glossary OrcaRun -> OrcaRunResult - cache: residual createActiveApp({cache}) -> services:{cache:defineActiveCache()}; documented the ActiveEngine contract surface (loading / lastError / disposed / snapshot / clearError / onChange / dispose); dangling demo URL -> /active/get-started/ecosystem - adom: added prefersReducedMotion / writeProperty / removeProperty; listen 1 -> 4 typed overloads; documented 12 undocumented standalone rune helpers; /test/adom -> /active/docs/adom Guard (scripts/arts-check.ts): removed the ethereal README exemption (set empty) and promoted A-index from warn to error — the net no longer passes green with a real gap. arts:check: 0 errors, 0 warnings, 22 arts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
* A-index (error) — the `src/arts/README.md` Map lists every art. An art
* that never reaches the index is invisible to readers (ethereal was: a
* full positioning engine absent from the Map, the aliases and the deps).
*
* Mirrors scripts/docs-check.ts (textual invariants, no Svelte-graph imports).
* Exit code 1 when any error-level finding exists.
*/
import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
import { join, resolve, relative, sep } from 'node:path';
const REPO = resolve(import.meta.dirname, '..');
const ARTS = join(REPO, 'src', 'arts');
interface Finding {
severity: 'error' | 'warn';
invariant: string;
file: string;
line: number;
message: string;
}
const findings: Finding[] = [];
const notes: string[] = [];
function report(
severity: 'error' | 'warn',
invariant: string,
file: string,
line: number,
message: string
): void {
findings.push({
severity,
invariant,
file: relative(REPO, file).split(sep).join('/'),
line,
message
});
}
function read(file: string): string {
return readFileSync(file, 'utf-8');
}
/** The arts = the immediate subdirectories of `src/arts/`. */
const arts = readdirSync(ARTS)
.filter((entry) => statSync(join(ARTS, entry)).isDirectory())
.sort();
/** Collect `.ts` sources under an art, excluding tests. */
function walkTs(dir: string, out: string[] = []): string[] {
for (const entry of readdirSync(dir)) {
const full = join(dir, entry);
if (statSync(full).isDirectory()) {
if (entry !== 'node_modules') walkTs(full, out);
} else if (/\.ts$/.test(entry) && !/\.(test|spec)\./.test(entry)) {
out.push(full);
}
}
return out;
}
const tsFiles = walkTs(ARTS);
// ── Invariant A-readme — every art has a README ─────────────────────────────
docs(arts): ethereal README + A1 drift sweep (orca/cache/adom) + honest guard Ethereal (was undocumented — the miss that prompted this pass): - new src/arts/ethereal/README.md, API drawn from the code (computePosition, the 7 middleware, autoUpdate, selectPositioningStrategy, dual JS/CSS-anchor engine, +1-frame read-phase model) - wired into src/arts/README.md Map + aliases + cross-deps; $ethereal added to the CLAUDE.md alias table; the also-missing bus/orca/prefs aliases + Map rows completed against vite.config.ts A1 drift (every fix verified against the cited code symbol, not the plan): - orca: ~13 phantom identifiers across 7 sections (priority, execution / ORCA_EXEC_*, tokenTimeoutMs, onFatal / ORCA_ON_FATAL_*, onTimeout, the whole multi-level timeout model, the transaction-port model + ORCA_TX_*, OrcaMaybePromise, OrcaCompensationContext) reconciled to the real API (parallel waves, actionTimeoutMs-only, transaction:string tag + compensate, fatal via returning OrcaFatal); added the real missing fields fanIn / parallel / compensate; glossary OrcaRun -> OrcaRunResult - cache: residual createActiveApp({cache}) -> services:{cache:defineActiveCache()}; documented the ActiveEngine contract surface (loading / lastError / disposed / snapshot / clearError / onChange / dispose); dangling demo URL -> /active/get-started/ecosystem - adom: added prefersReducedMotion / writeProperty / removeProperty; listen 1 -> 4 typed overloads; documented 12 undocumented standalone rune helpers; /test/adom -> /active/docs/adom Guard (scripts/arts-check.ts): removed the ethereal README exemption (set empty) and promoted A-index from warn to error — the net no longer passes green with a real gap. arts:check: 0 errors, 0 warnings, 22 arts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
/** Self-cleaning exemption for arts whose README is not authored yet. Empty:
* every art is documented (ethereal's README landed with its Map/alias wiring). */
const README_PENDING = new Set<string>();
for (const art of arts) {
const readme = join(ARTS, art, 'README.md');
const exists = existsSync(readme);
if (!exists) {
if (README_PENDING.has(art)) {
notes.push(`A-readme: '${art}/README.md' absent — exempt pending batch A3`);
} else {
report('error', 'A-readme', readme, 1, `art '${art}' has no README.md`);
}
} else if (README_PENDING.has(art)) {
// Self-cleaning: the exemption must not outlive the gap it covers.
report(
'error',
'A-readme',
readme,
1,
`art '${art}' now has a README — remove '${art}' from README_PENDING in scripts/arts-check.ts`
);
}
}
// ── Invariant A-naming — the Engine*/Active* split holds ────────────────────
/** An EXPORTED declaration of an `Engine*` root (class or create/define factory). */
const ENGINE_DECL =
/^\s*export\s+(?:async\s+)?(?:abstract\s+)?(?:class\s+Engine\w+|function\s+(?:create|define)Engine\w+|const\s+(?:create|define)Engine\w+\s*=)/;
/** An EXPORTED reactive `class Active*` root (not an `Active…Error`). */
const ACTIVE_CLASS = /^\s*export\s+(?:abstract\s+)?class\s+(Active\w+)/;
for (const file of tsFiles) {
const isSvelte = file.endsWith('.svelte.ts');
const lines = read(file).split('\n');
lines.forEach((line, i) => {
if (isSvelte && ENGINE_DECL.test(line)) {
report(
'error',
'A-naming',
file,
i + 1,
'an Engine* root is declared in a .svelte.ts file — engines are stateless (arts/README §naming); reactive roots are Active* only'
);
}
if (!isSvelte) {
const m = line.match(ACTIVE_CLASS);
if (m && !/Error$/.test(m[1])) {
report(
'error',
'A-naming',
file,
i + 1,
`reactive root class ${m[1]} is declared in a plain .ts — Active* roots own $state and must live in a .svelte.ts (arts/README §naming)`
);
}
}
});
}
// ── Invariant A-index — the arts index Map lists every art (WARN) ───────────
const indexSrc = read(join(ARTS, 'README.md'));
const indexed = new Set([...indexSrc.matchAll(/\.\/([a-z][\w-]*)\/README\.md/g)].map((m) => m[1]));
for (const art of arts) {
if (!indexed.has(art)) {
report(
docs(arts): ethereal README + A1 drift sweep (orca/cache/adom) + honest guard Ethereal (was undocumented — the miss that prompted this pass): - new src/arts/ethereal/README.md, API drawn from the code (computePosition, the 7 middleware, autoUpdate, selectPositioningStrategy, dual JS/CSS-anchor engine, +1-frame read-phase model) - wired into src/arts/README.md Map + aliases + cross-deps; $ethereal added to the CLAUDE.md alias table; the also-missing bus/orca/prefs aliases + Map rows completed against vite.config.ts A1 drift (every fix verified against the cited code symbol, not the plan): - orca: ~13 phantom identifiers across 7 sections (priority, execution / ORCA_EXEC_*, tokenTimeoutMs, onFatal / ORCA_ON_FATAL_*, onTimeout, the whole multi-level timeout model, the transaction-port model + ORCA_TX_*, OrcaMaybePromise, OrcaCompensationContext) reconciled to the real API (parallel waves, actionTimeoutMs-only, transaction:string tag + compensate, fatal via returning OrcaFatal); added the real missing fields fanIn / parallel / compensate; glossary OrcaRun -> OrcaRunResult - cache: residual createActiveApp({cache}) -> services:{cache:defineActiveCache()}; documented the ActiveEngine contract surface (loading / lastError / disposed / snapshot / clearError / onChange / dispose); dangling demo URL -> /active/get-started/ecosystem - adom: added prefersReducedMotion / writeProperty / removeProperty; listen 1 -> 4 typed overloads; documented 12 undocumented standalone rune helpers; /test/adom -> /active/docs/adom Guard (scripts/arts-check.ts): removed the ethereal README exemption (set empty) and promoted A-index from warn to error — the net no longer passes green with a real gap. arts:check: 0 errors, 0 warnings, 22 arts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
'error',
'A-index',
join(ARTS, 'README.md'),
1,
docs(arts): ethereal README + A1 drift sweep (orca/cache/adom) + honest guard Ethereal (was undocumented — the miss that prompted this pass): - new src/arts/ethereal/README.md, API drawn from the code (computePosition, the 7 middleware, autoUpdate, selectPositioningStrategy, dual JS/CSS-anchor engine, +1-frame read-phase model) - wired into src/arts/README.md Map + aliases + cross-deps; $ethereal added to the CLAUDE.md alias table; the also-missing bus/orca/prefs aliases + Map rows completed against vite.config.ts A1 drift (every fix verified against the cited code symbol, not the plan): - orca: ~13 phantom identifiers across 7 sections (priority, execution / ORCA_EXEC_*, tokenTimeoutMs, onFatal / ORCA_ON_FATAL_*, onTimeout, the whole multi-level timeout model, the transaction-port model + ORCA_TX_*, OrcaMaybePromise, OrcaCompensationContext) reconciled to the real API (parallel waves, actionTimeoutMs-only, transaction:string tag + compensate, fatal via returning OrcaFatal); added the real missing fields fanIn / parallel / compensate; glossary OrcaRun -> OrcaRunResult - cache: residual createActiveApp({cache}) -> services:{cache:defineActiveCache()}; documented the ActiveEngine contract surface (loading / lastError / disposed / snapshot / clearError / onChange / dispose); dangling demo URL -> /active/get-started/ecosystem - adom: added prefersReducedMotion / writeProperty / removeProperty; listen 1 -> 4 typed overloads; documented 12 undocumented standalone rune helpers; /test/adom -> /active/docs/adom Guard (scripts/arts-check.ts): removed the ethereal README exemption (set empty) and promoted A-index from warn to error — the net no longer passes green with a real gap. arts:check: 0 errors, 0 warnings, 22 arts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
`art '${art}' is not listed in the arts index Map table (src/arts/README.md)`
);
}
}
// ── Report ──────────────────────────────────────────────────────────────────
findings.sort(
(a, b) =>
a.invariant.localeCompare(b.invariant) || a.file.localeCompare(b.file) || a.line - b.line
);
const errors = findings.filter((f) => f.severity === 'error');
const warns = findings.filter((f) => f.severity === 'warn');
for (const f of findings) {
console.log(
`${f.severity.toUpperCase().padEnd(5)} [${f.invariant}] ${f.file}:${f.line} — ${f.message}`
);
}
for (const n of notes) console.log(`NOTE ${n}`);
console.log(
`\narts-check: ${errors.length} error(s), ${warns.length} warning(s) across ${arts.length} arts`
);
process.exit(errors.length > 0 ? 1 : 0);

Powered by TurnKey Linux.