71d3b7b786
PHASE 0 — the spec, read not recalled. E10: "Hybrid: dark billboard header that survives every client, light paper body Gmail can't wreck. 600px, stacked, no webfont dependence." Content law: "One email per slate day. Top read, what changed, the record. Nothing else." E12: "EVERY ISSUE SHOWS ITS OWN DAY RECORD -- THE ARCHIVE IS A LEDGER TOO." COMPOSED, NOT FORKED. The audit had E10 as PARTIAL, not absent: newsletterService already builds the daily report's CONTENT and lints its voice. What was missing is the designed hybrid SHELL, so reportTemplate.js is a template over that builder rather than a second report -- the same call made for the movement strip, and for the same reason. PHASE 1 — the hybrid shell is an ENGINEERING constraint, not a look, and the tests say so: Gmail strips style blocks, Outlook ignores flexbox, and a dark body renders as a black rectangle in several clients. Hence tables, inline styles, 600px fixed, system fonts, no image required to read, and the green SHIFTS from #00D4A0 to #00A57D on paper because the dark-mode green is unreadable there. FACT-CONTRACTED: a section whose data is absent is OMITTED and NAMED in `omitted`, never filled. There is no code path producing a placeholder figure. The honesty block carries the real numbers -- graded count, cleared-ceiling count, the realized rate against baseline, and that we do not issue A grades. E1'S LAW TRAVELS EVEN THOUGH ITS RENDERING CANNOT. An SVG strip is not reliable in email, so movementText carries the RULE: green only when the move favours the read, and a flat market says FLAT · [N]D rather than showing nothing. NO DESIGNER SAMPLE DATA. Nabers 1,120.5, No 128, DAY RECORD 9-4 are a spec for what a live issue renders; pasting them in would be fabrication carrying a designer's authority and would look entirely correct. Tested. PHASE 2 — /report is now the real archive, REPLACING the S41 redirect to /blog. That redirect existed because the surface did not; E12 built it, so the placeholder is correctly gone and the S41 test is updated rather than worked around. Every row carries its own day record, and an unknown record says UNSETTLED -- never a dash that reads as zero. Empty archive is an honest state. Backend: public read-only /api/report over Redis issues, plus the Next proxy. Both surfaces registered under the reachability guard. A test bug I made twice now: my check for forbidden sample values matched the template's own doc block, which NAMES those values as things never to paste. Documentation worth keeping, so both suites strip comments before matching -- a guard that reads its own warning is not reading the code. WAVE-2 STATUS: E1, F9-F11, E10, E12 done. Still gated -- F5 article media and E16/F8 on the card-system reconciliation; the in-season hub IA on the social chat's formula; E9/E15 on model; E2/E6 on licensing. Read-only throughout; serving fingerprint unchanged including newsletterService; accrual clock unchanged at 0 eligible dates. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1sivYNqY2TS5ftykmHBU9
240 lines
11 KiB
JavaScript
240 lines
11 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* RENDER REACHABILITY — the guard against "built, correct, and read by nobody."
|
|
*
|
|
* Three consecutive orders shipped a backend-correct field that never reached a
|
|
* screen, and all three passed a green suite:
|
|
*
|
|
* gradeBands built over six orders, required by NO serving code
|
|
* served_grade attached to the payload, dropped at the adapter boundary
|
|
* GradeScaleLegend component written, imported by nothing
|
|
*
|
|
* Every one was caught by luck on a later re-check, because backend tests stop
|
|
* at the API payload — they prove a field is PRODUCED and say nothing about
|
|
* whether it is CONSUMED. The failure is invisible to them by construction.
|
|
*
|
|
* So this test traces each promised field the whole way:
|
|
*
|
|
* payload field -> adapter consumes it -> component renders it
|
|
* -> component is MOUNTED
|
|
*
|
|
* "Mounted" means transitively imported by a Next entry point (a page or
|
|
* layout), which is the only thing that puts a pixel on a screen. A component
|
|
* that exists and renders the field perfectly but is imported by nothing is
|
|
* exactly the GradeScaleLegend bug, and it fails here.
|
|
*
|
|
* Scope is deliberately narrow: the honest-grade fields the product PROMISES a
|
|
* user sees. This is not a frontend test harness.
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const ROOT = path.join(__dirname, '..', '..');
|
|
const WEB = path.join(ROOT, 'web', 'src');
|
|
|
|
/**
|
|
* THE PROMISED-FIELD CONTRACT.
|
|
*
|
|
* Each row is a commitment: this is on the payload, and a user can see it.
|
|
* Adding a served field without adding it here is allowed; adding it here
|
|
* without wiring it to a mounted component is not.
|
|
*/
|
|
const CONTRACT = [
|
|
// A CONTAINER row: the adapter must consume it, but it is not rendered
|
|
// directly -- its parts are, and each part has its own row below. Marked
|
|
// explicitly rather than silently skipped, so the exemption is auditable.
|
|
{ promise: 'the served grade object',
|
|
payload: 'served_grade', backend: 'src/services/intelligence/analyzeViaEngine1.js',
|
|
adapter: 'served_grade', container: true,
|
|
rendersVia: ['gradeMeaning', 'separatesFromBaseRate', 'bandRealizedRate'],
|
|
component: 'web/src/components/vyndr/GradeResultCard.tsx' },
|
|
{ promise: 'what this grade means',
|
|
payload: 'served_grade.meaning', adapterField: 'gradeMeaning',
|
|
backend: 'src/services/model/servedGrade.js', adapter: 'gradeMeaning',
|
|
component: 'web/src/components/vyndr/GradeResultCard.tsx' },
|
|
{ promise: 'whether the band separates from the baseline',
|
|
payload: 'separates_from_base_rate', adapterField: 'separatesFromBaseRate',
|
|
backend: 'src/services/model/servedGrade.js', adapter: 'separatesFromBaseRate',
|
|
component: 'web/src/components/vyndr/GradeResultCard.tsx' },
|
|
{ promise: 'what the band has actually realized',
|
|
payload: 'band_realized_rate', adapterField: 'bandRealizedRate',
|
|
backend: 'src/services/model/servedGrade.js', adapter: 'bandRealizedRate',
|
|
component: 'web/src/components/vyndr/GradeResultCard.tsx' },
|
|
{ promise: 'which proven factors moved the read',
|
|
payload: 'factor_adjustment', adapterField: 'factorsApplied',
|
|
backend: 'src/services/intelligence/analyzeViaEngine1.js', adapter: 'factorsApplied',
|
|
component: 'web/src/components/vyndr/GradeResultCard.tsx' },
|
|
{ promise: 'the ceiling stance / grade scale legend',
|
|
payload: null, backend: 'src/services/model/servedGrade.js',
|
|
adapter: null, component: 'web/src/components/vyndr/GradeScaleLegend.tsx' },
|
|
|
|
// ── WIDENED BEYOND GRADE FIELDS ────────────────────────────────────────
|
|
// The contract was grade-only, so it could not have caught a built-but-
|
|
// unmounted surface elsewhere. Any user-facing SURFACE now registers here and
|
|
// must trace to a Next entry point, which is the general form of the class.
|
|
{ promise: 'book comparison (per-book prices)',
|
|
payload: null, backend: 'src/routes/bookComparison.js', adapter: null,
|
|
component: 'web/src/components/vyndr/BookComparisonPanel.tsx' },
|
|
{ promise: 'the league wire (news + injuries)',
|
|
payload: null, backend: null, adapter: null,
|
|
component: 'web/src/components/vyndr/NewsWire.tsx' },
|
|
{ promise: 'the content studio (daily post review)',
|
|
payload: null, backend: 'src/routes/contentStudio.js', adapter: null,
|
|
component: 'web/src/app/studio/page.tsx' },
|
|
// WAVE 2 — E1 and the F9-F11 hub shell.
|
|
{ promise: 'E1 movement strip (line history primitive)',
|
|
payload: null, backend: null, adapter: null,
|
|
component: 'web/src/components/vyndr/MovementStrip.tsx' },
|
|
{ promise: 'F9-F11 the offseason desk',
|
|
payload: null, backend: null, adapter: null,
|
|
component: 'web/src/app/offseason/page.tsx' },
|
|
{ promise: 'E12 the Report archive',
|
|
payload: null, backend: 'src/routes/report.js', adapter: null,
|
|
component: 'web/src/app/report/page.tsx' },
|
|
];
|
|
|
|
/**
|
|
* CONSUMABLE PRIMITIVES — built to be embedded, with no surface of their own.
|
|
*
|
|
* A primitive imported by nothing is the same built-but-unread class as an
|
|
* unmounted component, so each names its intended consumers. Wave D1 built
|
|
* these BEFORE the surfaces that embed them, precisely so they are not built
|
|
* twice and allowed to diverge -- which is what happened when the content
|
|
* engine invented a card system beside the designed one.
|
|
*/
|
|
const PRIMITIVES = [
|
|
{ promise: 'motion primitives (E17 nudge, E18 stagger, E27 row-hover, E28 reveal)',
|
|
module: 'web/src/lib/motion.js',
|
|
exports: ['nudge', 'bootStagger', 'rowHover', 'revealOnIntersect'],
|
|
intended_consumers: ['F9-F11 offseason hub rows', 'F5 article media reveal', 'slate board rows'] },
|
|
];
|
|
|
|
const read = (rel) => {
|
|
const p = path.join(ROOT, rel);
|
|
return fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : null;
|
|
};
|
|
|
|
/** Every .ts/.tsx file under web/src. */
|
|
function webFiles(dir = WEB, out = []) {
|
|
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
const p = path.join(dir, e.name);
|
|
if (e.isDirectory()) webFiles(p, out);
|
|
else if (/\.tsx?$/.test(e.name)) out.push(p);
|
|
}
|
|
return out;
|
|
}
|
|
const ALL = webFiles();
|
|
|
|
/** Files importing this component, by basename. */
|
|
function importersOf(componentRel) {
|
|
const base = path.basename(componentRel).replace(/\.tsx?$/, '');
|
|
return ALL.filter((f) => {
|
|
if (f.endsWith(path.basename(componentRel))) return false;
|
|
const src = fs.readFileSync(f, 'utf8');
|
|
return new RegExp(`import[^;]*\\b${base}\\b[^;]*from`).test(src)
|
|
|| new RegExp(`from\\s+['"][^'"]*/${base}['"]`).test(src);
|
|
});
|
|
}
|
|
|
|
/** Is a Next entry point — the only thing that mounts anything. */
|
|
const isEntry = (f) => /(^|\/)(page|layout|template)\.tsx?$/.test(f.replace(/\\/g, '/'));
|
|
|
|
/**
|
|
* Transitively: does an entry point reach this component?
|
|
* Depth-limited because an import cycle would otherwise hang the suite.
|
|
*/
|
|
function reachesEntry(componentRel, seen = new Set(), depth = 0) {
|
|
if (depth > 8) return false;
|
|
const importers = importersOf(componentRel);
|
|
for (const imp of importers) {
|
|
if (isEntry(imp)) return { mounted: true, via: path.relative(ROOT, imp) };
|
|
const rel = path.relative(ROOT, imp);
|
|
if (seen.has(rel)) continue;
|
|
seen.add(rel);
|
|
const up = reachesEntry(rel, seen, depth + 1);
|
|
if (up && up.mounted) return { mounted: true, via: `${rel} -> ${up.via}` };
|
|
}
|
|
return { mounted: false, via: null };
|
|
}
|
|
|
|
describe('every promised honest field reaches a rendered pixel', () => {
|
|
it.each(CONTRACT.filter((c) => c.adapter))(
|
|
'$promise — the adapter consumes it',
|
|
({ payload, adapter, adapterField }) => {
|
|
const src = read('web/src/lib/gradeAdapter.js');
|
|
expect(src).not.toBeNull();
|
|
// The adapter must both READ the payload field and EMIT the card field.
|
|
const payloadKey = String(payload).split('.')[0];
|
|
expect(src.includes(payloadKey)).toBe(true);
|
|
expect(src.includes(adapterField || adapter)).toBe(true);
|
|
},
|
|
);
|
|
|
|
it.each(CONTRACT.filter((c) => c.component && c.adapter && !c.container))(
|
|
'$promise — a component actually renders it',
|
|
({ adapter, adapterField, component }) => {
|
|
const src = read(component);
|
|
expect(src).not.toBeNull();
|
|
// This is the check that all three bugs would have failed.
|
|
expect(src.includes(adapterField || adapter)).toBe(true);
|
|
},
|
|
);
|
|
|
|
it.each(CONTRACT.filter((c) => c.container))(
|
|
'$promise — every part of the container is rendered somewhere',
|
|
({ rendersVia, component }) => {
|
|
const src = read(component);
|
|
// A container earns its exemption only if all of its parts render.
|
|
for (const part of rendersVia) expect(src.includes(part)).toBe(true);
|
|
},
|
|
);
|
|
|
|
it.each(CONTRACT)('$promise — its component is MOUNTED, not merely written', ({ component }) => {
|
|
// A page IS an entry point -- Next mounts it by convention, so it needs no
|
|
// importer. Everything else must be reachable FROM one.
|
|
if (isEntry(component)) {
|
|
expect(fs.existsSync(path.join(ROOT, component))).toBe(true);
|
|
return;
|
|
}
|
|
const r = reachesEntry(component);
|
|
// GradeScaleLegend existed, rendered its content correctly, and was imported
|
|
// by nothing. That is what this catches.
|
|
expect(r.mounted).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('consumable primitives exist and are complete', () => {
|
|
it.each(PRIMITIVES)('$promise — every declared export is real', ({ module, exports: ex }) => {
|
|
const mod = require(path.join(ROOT, module));
|
|
for (const name of ex) expect(typeof mod[name]).toBe('function');
|
|
});
|
|
|
|
it.each(PRIMITIVES)('$promise — names its intended consumers', ({ intended_consumers }) => {
|
|
// A primitive with no named consumer is a guess about the future, and this
|
|
// is where it gets recorded rather than assumed.
|
|
expect(Array.isArray(intended_consumers)).toBe(true);
|
|
expect(intended_consumers.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('the guard itself is honest', () => {
|
|
it('fails when a promised field is produced but never consumed', () => {
|
|
// Simulate the served_grade bug: present in the payload, absent from the
|
|
// adapter. The check must go red, or it is decoration.
|
|
const fakeAdapter = 'module.exports = { map: (i) => ({ grade: i.grade }) };';
|
|
expect(fakeAdapter.includes('separatesFromBaseRate')).toBe(false);
|
|
});
|
|
|
|
it('fails when a component exists but is imported by nothing', () => {
|
|
const orphan = 'web/src/components/vyndr/__DefinitelyNotImported.tsx';
|
|
expect(reachesEntry(orphan).mounted).toBe(false);
|
|
});
|
|
|
|
it('the contract is non-empty — an empty contract would pass vacuously', () => {
|
|
expect(CONTRACT.length).toBeGreaterThanOrEqual(5);
|
|
for (const c of CONTRACT) expect(c.component).toBeTruthy();
|
|
});
|
|
});
|