'use strict'; /** * F9-F11 offseason hub + E1 movement strip — the laws, not the pixels. * * What these protect is that the surface cannot show a number it does not have. * The design file is full of sample values (Wembanyama +420 → +330, Nabers * cleared at 11:42 AM); those are a SPEC for what a live feed renders, and * copying them into the component would be fabrication carrying a designer's * authority. */ const fs = require('fs'); const path = require('path'); const ROOT = path.join(__dirname, '..', '..'); const read = (r) => fs.readFileSync(path.join(ROOT, r), 'utf8'); /** * Strip comments before matching. My first version of these assertions matched * my own doc blocks -- the ordering check found "WHAT CHANGED TODAY" in the * header comment, and the no-curves check caught the word "curve" in the * sentence explaining why curves are wrong. A guard that reads its own * explanation is not reading the render. */ const stripComments = (s) => s.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, ''); const HUB_RAW = read('web/src/components/vyndr/OffseasonHub.tsx'); const STRIP_RAW = read('web/src/components/vyndr/MovementStrip.tsx'); const HUB = stripComments(HUB_RAW); const STRIP = stripComments(STRIP_RAW); describe('the hub cannot ship the design file\'s sample data', () => { it('contains none of the spec\'s sample subjects or prices', () => { for (const sample of ['Wembanyama', 'Nabers', 'Dybantsa', 'Boozer', 'Kincaid', '+420', '+330']) { expect(HUB).not.toContain(sample); } }); it('renders the QUIET WIRE empty state verbatim, not a generic blank', () => { expect(HUB).toMatch(/QUIET WIRE/); expect(HUB).toMatch(/We don't manufacture movement\./); }); it('carries the spec\'s load-bearing subhead', () => { // An offseason number is not a game line; saying so is the difference // between a read and a bet. expect(HUB).toMatch(/OUTLOOKS REPRICE ON NEWS · NOT GAME ODDS/); }); it('leads with what changed today — the countdown is ambient, not the hero', () => { // In the RENDER the countdown sits in the header block above; the hero // section is WHAT CHANGED TODAY. Both must be present and ordered. const iCountdown = HUB.indexOf('DAYS TO'); const iHero = HUB.indexOf('WHAT CHANGED TODAY'); expect(iCountdown).toBeGreaterThan(-1); expect(iHero).toBeGreaterThan(iCountdown); expect(HUB_RAW).toMatch(/never the hero/); // the law, stated in the source }); it('every OUTLOOK-ONLY row carries NOT GRADED', () => { // The block exists in order to say it. expect(HUB).toMatch(/NOT GRADED/); }); it('empty board says nothing rather than showing placeholders', () => { expect(HUB).toMatch(/Nothing shown rather than a board of placeholders/); }); }); describe('E1 movement strip obeys its spec laws', () => { it('does NOT reimplement the colour law — it consumes gradeShift', () => { // Forking the toward/against rule is how two surfaces drift apart. expect(STRIP).toMatch(/buildGradeTimeline/); expect(STRIP).not.toMatch(/isUnder\s*\(/); }); it('draws STEPS, not curves', () => { // H then V — a hold, then a jump. No smoothing, which would invent prices // that never traded. expect(STRIP).toMatch(/H\$\{x1\} V\$\{y1\}/); // No SVG curve commands in the emitted path -- C, S, Q or T. expect(STRIP).not.toMatch(/[CSQT]\s*\$\{/); }); it('renders FLAT as a hairline plus the day count', () => { expect(STRIP).toMatch(/FLAT\{typeof days === 'number'/); }); it('is never blank — too little history says so', () => { expect(STRIP).toMatch(/NO MOVEMENT HISTORY/); }); it('green is reserved for a move that FAVOURS the read', () => { expect(STRIP).toMatch(/dir === 'toward' \? TOWARD/); }); }); describe('the archetype doctrine is recorded', () => { it('the 83-taxonomy doctrine exists and forbids decoration-as-data', () => { const d = read('specs/ARCHETYPE-TAXONOMY-DOCTRINE.md'); expect(d).toMatch(/Decoration-as-data is forbidden/); expect(d).toMatch(/A glyph renders ONLY where its archetype is modeled and proven/); expect(d).toMatch(/DUAL THREAT/); }); });