diff --git a/.eleventy.js b/.eleventy.js index b9553ec..70d7c99 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -5,7 +5,7 @@ import { installMathRenderer } from './scripts/markdown-math.mjs'; // id: eleventy_site_configuration // purpose: Build the static-first public knowledge system, render exact distributed-textbook Markdown and LaTeX as static MathML, and copy deliberate fallback artifacts. // entrypoint: npm run build -// tests: tests/site-contract.test.mjs, tests/math-rendering.test.mjs, tests/generated-site.test.mjs +// tests: tests/site-contract.test.mjs, tests/math-rendering.test.mjs, tests/narratives.test.mjs, tests/generated-site.test.mjs // === END MODULE_BUILD === export default function configureEleventy(eleventyConfig) { diff --git a/The-Interdependency.github.io_msdmd.ts b/The-Interdependency.github.io_msdmd.ts index 584c30d..2507eb2 100644 --- a/The-Interdependency.github.io_msdmd.ts +++ b/The-Interdependency.github.io_msdmd.ts @@ -7,7 +7,7 @@ export default defineMsdmdCollection({ "fields": { "entrypoint": "npm run build", "purpose": "Build the static-first public knowledge system, render exact distributed-textbook Markdown and LaTeX as static MathML, and copy deliberate fallback artifacts.", - "tests": "tests/site-contract.test.mjs, tests/math-rendering.test.mjs, tests/generated-site.test.mjs" + "tests": "tests/site-contract.test.mjs, tests/math-rendering.test.mjs, tests/narratives.test.mjs, tests/generated-site.test.mjs" }, "file": ".eleventy.js", "id": "eleventy_site_configuration" diff --git a/package.json b/package.json index 0680a92..addb1e4 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "validate": "node scripts/validate-content.mjs && node scripts/verify-generated-routes.mjs && node scripts/verify-article-canon.mjs", "build": "npm run validate && eleventy && pagefind --site _site && node scripts/write-build-info.mjs", "pretest": "node scripts/prepare-tests.mjs", - "test": "node --test tests/canon-parser.test.mjs tests/canon-integrity.test.mjs tests/textbook-integrity.test.mjs tests/math-rendering.test.mjs tests/offline-project-snapshot.test.mjs tests/repo-coverage.test.mjs tests/research-ledger.test.mjs tests/works-registry.test.mjs tests/site-contract.test.mjs", + "test": "node --test tests/canon-parser.test.mjs tests/canon-integrity.test.mjs tests/textbook-integrity.test.mjs tests/math-rendering.test.mjs tests/narratives.test.mjs tests/offline-project-snapshot.test.mjs tests/repo-coverage.test.mjs tests/research-ledger.test.mjs tests/works-registry.test.mjs tests/site-contract.test.mjs", "test:generated": "node --test tests/generated-site.test.mjs tests/textbook-generated.test.mjs tests/math-generated.test.mjs && node tests/links.test.mjs", "test:browser": "playwright test", "test:e2e": "playwright test tests/site.spec.mjs", diff --git a/src/_data/jack_and_diane.json b/src/_data/jack_and_diane.json new file mode 100644 index 0000000..faecbbb --- /dev/null +++ b/src/_data/jack_and_diane.json @@ -0,0 +1,221 @@ +{ + "schema": "interdependency.living-narrative/1.0.0", + "id": "jack-and-diane", + "title": "Jack & Diane: The Longhand Threshold", + "subtitle": "Two fictional American kids keep an alternating record of what happens after the copying is finished and the demonstrating begins.", + "status": "fictional interpretation", + "relationship": "Friends and study partners; no romantic relationship is presumed.", + "canonContact": { + "unit": "Rights and Definitions of The Way — Article Five", + "source": "wayseer00/main:canon/INTERDEPENDENT_WAY.txt", + "boundary": "The canon supplies the adulthood criteria. The characters, events, voices, and judgments in this serial are fiction and cannot amend, complete, or speak for the canon." + }, + "editorialBoundary": { + "threshold": "Completing a handwritten transcription demonstrates sustained attention; by itself, it does not establish adulthood or political adulthood.", + "civil": "Jack and Diane remain minors under applicable civil law. Nothing in this fiction removes child-protection, education, care, or guardian responsibilities.", + "incompletion": "The serial does not decide whether either character has reached physical maturity. Their claim remains unfinished until every required capacity can be demonstrated honestly." + }, + "characters": [ + { + "id": "jack", + "name": "Jack", + "age": 14, + "voice": "Fast to act, impatient with ceremony, and learning that asking for help can be evidence of competence rather than its opposite." + }, + { + "id": "diane", + "name": "Diane", + "age": 13, + "voice": "Careful with language, alert to hidden assumptions, and learning that a plan becomes real only when it risks honest failure." + } + ], + "criteria": [ + { + "name": "Handwritten Articles", + "status": "complete", + "note": "Both have completed their own longhand transcription." + }, + { + "name": "Original personal Preamble", + "status": "in progress", + "note": "Each must describe the political reality they actually perceive, not repeat the source." + }, + { + "name": "Survival and social competencies", + "status": "in progress", + "note": "Cooking, first aid, communication, sanitation, skill acquisition, and shelter maintenance must be demonstrated." + }, + { + "name": "Lineaged skill portfolio", + "status": "in progress", + "note": "Claims need witnesses appropriate to the craft or domain." + }, + { + "name": "Schedule of intended actions", + "status": "drafting", + "note": "The schedule must contain real commitments and visible points of failure." + }, + { + "name": "Self-sufficient interdependency", + "status": "not yet claimed", + "note": "Neither isolation nor dependence disguised as cooperation satisfies the standard." + }, + { + "name": "Political Circle", + "status": "not formed", + "note": "Two people are not a Circle of Twelve." + } + ], + "entries": [ + { + "sequence": 1, + "when": "Day 1", + "author": "jack", + "authorLabel": "Jack", + "title": "The last page was not a finish line", + "body": [ + "My hand cramped before I signed the last page. I expected something to happen when I put the pen down. Nothing did. The room stayed the room, and I was still fourteen.", + "Diane said that was probably the first honest result. We completed the copy. We did not complete ourselves. I wrote COMPLETE beside transcription and then crossed out COMPLETE beside adulthood. The ink looked like an argument I had lost to my own handwriting." + ], + "evidence": [ + "Longhand transcription completed", + "No adulthood claim made" + ] + }, + { + "sequence": 2, + "when": "Day 2", + "author": "diane", + "authorLabel": "Diane", + "title": "A Preamble cannot be borrowed", + "body": [ + "Jack tried to start his Preamble with a sentence from the Way. I told him that would prove he could copy twice. He told me my first paragraph sounded like a school report. We were both right, which was annoying.", + "I started again with what I can actually see: adults make decisions children must live inside, but age does not make every decision competent. Children also make choices other people must survive. A fair system has to notice both facts without pretending they are the same fact." + ], + "evidence": [ + "First Preamble draft rejected by its author", + "Current political reality named in original language" + ] + }, + { + "sequence": 3, + "when": "Week 1", + "author": "jack", + "authorLabel": "Jack", + "title": "Competence is not never burning dinner", + "body": [ + "I burned the rice because I was fixing the loose cabinet hinge while the pot was on. My first thought was that I had failed cooking. Diane asked whether I could explain why it burned, make the next batch safely, and clean up without somebody taking over.", + "The second batch worked. I wrote that competence might include catching your own failure before it becomes somebody else's permanent job. I still need three meals I can make from whatever is already available, not only when the kitchen is stocked for my plan." + ], + "evidence": [ + "Prepared one complete meal after correcting a failed attempt", + "Cabinet hinge repaired and checked by an adult witness", + "Flexible meal planning remains open" + ] + }, + { + "sequence": 4, + "when": "Week 2", + "author": "diane", + "authorLabel": "Diane", + "title": "Help that waits for consent", + "body": [ + "We practiced first aid from the community-center course. Jack kept reaching for the bandage before I finished describing the pretend injury. I made him stop. Correct help at the wrong moment can still replace the person being helped.", + "Then I missed a sanitation step and he caught it without grabbing anything out of my hands. He asked, ‘Do you want the observation now or after the run?’ I wanted it now. That question was more useful than being rescued." + ], + "evidence": [ + "First-aid practice completed under instruction", + "Missed sanitation step recorded rather than hidden", + "Consent check added to the practice routine" + ] + }, + { + "sequence": 5, + "when": "Week 3", + "author": "jack", + "authorLabel": "Jack", + "title": "Communication after the clever sentence", + "body": [ + "I made a joke while Diane was explaining why our checklist was unfair to somebody with one working hand. Everybody laughed except her. I said she knew I did not mean harm. She said intent was information about me, not repair for what happened to her point.", + "I restated her objection before defending mine. The checklist changed. We now record what a skill accomplishes and allow more than one way to demonstrate it. My joke is not in the portfolio. The correction is." + ], + "evidence": [ + "Accessibility objection restated accurately", + "Checklist revised to test function rather than one performance method", + "Repair accepted without erasing the harm" + ] + }, + { + "sequence": 6, + "when": "Month 1", + "author": "diane", + "authorLabel": "Diane", + "title": "A witness is not a fan", + "body": [ + "I wanted Jack to sign my bicycle-repair page because he watched me patch a tube. He refused. He said watching one repair made him a witness to one repair, not someone qualified to lineage the skill. I was angry because the repair held.", + "The bicycle-shop mentor later watched me diagnose two different leaks, choose patches, explain the cure time, and inspect the tire. She signed only what she observed. The smaller claim feels heavier because it is true." + ], + "evidence": [ + "Bicycle puncture diagnosis and repair witnessed by a domain mentor", + "Portfolio scope narrowed to observed competence", + "Additional maintenance skills remain unclaimed" + ] + }, + { + "sequence": 7, + "when": "Month 2", + "author": "jack", + "authorLabel": "Jack", + "title": "Put failure on the calendar", + "body": [ + "Our first schedule said we would ‘help the neighborhood.’ That sentence could never fail because it did not promise anything. We replaced it with one Saturday pantry shelf at the community center: inventory by Thursday, permissions by Friday, setup by ten, cleanup by two, and a public count of what was taken and what was wasted.", + "The first Saturday failed. We had food and volunteers but no approved storage bins. We wrote FAILED beside setup. Nobody died from the word. The next schedule names who confirms the bins and by when." + ], + "evidence": [ + "Vague intention replaced by a bounded public commitment", + "First attempt failed visibly", + "Second schedule assigns verification responsibility" + ] + }, + { + "sequence": 8, + "when": "Month 3", + "author": "diane", + "authorLabel": "Diane", + "title": "Two is not Twelve", + "body": [ + "Jack said we should find ten more people and form a Circle. I asked whether we wanted ten signatures or ten adults able to tell us no. We made a rule for ourselves: we will not recruit anyone to complete our picture.", + "For now we meet with people who are testing their own competencies. Nobody owes us a Circle. If Twelve eventually stand together, it should be because each has a claim the others can question and evidence the others can inspect." + ], + "evidence": [ + "Circle formation remains explicitly incomplete", + "Recruitment pressure rejected", + "Mutual inspection proposed as a condition of association" + ] + }, + { + "sequence": 9, + "when": "Current page", + "author": "jack", + "authorLabel": "Jack", + "title": "The line we have not crossed", + "body": [ + "We have more evidence than we had three months ago. That is not the same as enough evidence. We are still American kids under the laws and duties that protect kids. The Way does not make those disappear because we filled notebooks.", + "I used to think adulthood meant nobody could tell me what to do. Now I think it might mean I can show what I can carry, name what I cannot, choose who I rely on, and remain responsible for what happens when my plan meets reality. I am not writing CLAIMED yet." + ], + "evidence": [ + "Progress distinguished from completion", + "Civil protections and responsibilities preserved", + "Adulthood claim remains open" + ] + } + ], + "continuationPrompts": [ + "What happens when Jack and Diane disagree about whether a competency has been demonstrated?", + "Which forms of dependence increase agency, and which quietly transfer responsibility?", + "How does each revise the personal Preamble after encountering a political fact they had ignored?", + "Who may witness a skill, and what makes that witness competent for the claim?", + "What failure would force either character to delay or withdraw an adulthood claim?", + "Can they contribute to a Circle without treating the Circle as proof of themselves?" + ] +} diff --git a/src/_includes/layouts/base.njk b/src/_includes/layouts/base.njk index 5746cfe..2c1a34f 100644 --- a/src/_includes/layouts/base.njk +++ b/src/_includes/layouts/base.njk @@ -27,6 +27,7 @@ The Way Textbook Article Lab + Narratives Projects Artifacts Works diff --git a/src/assets/css/site.css b/src/assets/css/site.css index d9995be..d023c65 100644 --- a/src/assets/css/site.css +++ b/src/assets/css/site.css @@ -72,6 +72,29 @@ h3 { font-size: clamp(1.2rem, 2vw, 1.55rem); } .panel, .provenance, .hmmm, .reading, details { padding: 1.2rem; background: rgba(16, 24, 42, .88); border: 1px solid var(--line); border-radius: var(--radius); } .hmmm { border-left: .35rem solid var(--amber); } .hmmm > :first-child { margin-top: 0; color: var(--amber); } +.narrative-boundary { border-left: .35rem solid var(--violet); } +.narrative-boundary > :first-child { margin-top: 0; } +.character-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.character-card { position: relative; overflow: hidden; } +.character-card::after { content: ""; position: absolute; inset: auto -3rem -4rem auto; width: 9rem; aspect-ratio: 1; border: 1px solid var(--line); border-radius: 50%; opacity: .6; } +.character-card[data-character="jack"] { border-top: .25rem solid var(--cyan); } +.character-card[data-character="diane"] { border-top: .25rem solid var(--violet); } +.criteria-list { display: grid; gap: .7rem; margin: 1.5rem 0 3rem; } +.criterion { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 1rem; align-items: center; padding: 1rem 1.15rem; border: 1px solid var(--line); border-radius: .75rem; background: rgba(16, 24, 42, .78); } +.criterion h3 { margin: 0 0 .25rem; } +.criterion p { margin: 0; color: var(--silver); } +.journal-list { display: grid; gap: 1.2rem; padding: 0; list-style: none; } +.journal-entry { max-width: 58rem; padding: clamp(1.15rem, 4vw, 2.2rem); border: 1px solid var(--line); border-radius: var(--radius); background: linear-gradient(145deg, rgba(16, 24, 42, .96), rgba(9, 13, 24, .94)); box-shadow: var(--shadow); } +.journal-list li:nth-child(even) .journal-entry { margin-left: auto; } +.journal-entry[data-author="jack"] { border-left: .35rem solid var(--cyan); } +.journal-entry[data-author="diane"] { border-left: .35rem solid var(--violet); } +.journal-entry h3 { margin: .3rem 0 1rem; font-size: clamp(1.45rem, 3vw, 2.15rem); } +.journal-entry > p:not(.eyebrow) { max-width: 68ch; } +.journal-meta { display: flex; justify-content: space-between; gap: 1rem; padding-bottom: .75rem; border-bottom: 1px solid var(--line); color: var(--silver); font: 700 .75rem/1.4 ui-monospace, monospace; text-transform: uppercase; letter-spacing: .06em; } +.journal-entry details { margin-top: 1.25rem; padding: .85rem 1rem; background: rgba(9, 13, 24, .72); } +.journal-entry summary { cursor: pointer; color: var(--cyan); font-weight: 700; } +.continuation-list { columns: 2 20rem; column-gap: 2rem; } +.continuation-list li { break-inside: avoid; margin-bottom: .85rem; } .breadcrumb { margin-bottom: 2rem; color: var(--silver); font-size: .9rem; } .breadcrumb a { color: var(--silver); } .page-head { max-width: 62rem; margin-bottom: 3rem; } @@ -134,6 +157,11 @@ summary { cursor: pointer; font-weight: 800; } .canon-outline .unit-level-4 { margin-left: 1.3rem; } .textbook-chapter { padding: 1rem; } .chapter-pagination .button { flex: 1 1 100%; } + .character-grid { grid-template-columns: 1fr; } + .criterion { grid-template-columns: 1fr; } + .criterion .status { justify-self: start; } + .journal-list li:nth-child(even) .journal-entry { margin-left: 0; } + .continuation-list { columns: 1; } .site-footer { grid-template-columns: 1fr; } .hmmm-boundary { grid-column: auto; grid-template-columns: 1fr; } } diff --git a/src/home/index.njk b/src/home/index.njk index 1b40b49..43edeba 100644 --- a/src/home/index.njk +++ b/src/home/index.njk @@ -25,6 +25,12 @@ permalink: /home/

All eight Rights articles now have a canon-bounded path through exact excerpt, note conversation, reductio ad absurdum, worst and best practices, applications across eleven domains, and a study-only research field with explicit coverage gaps.

Open the Article LabRead publication drafts
+
+

Living narratives · fiction under constraint

+

What happens after the copying is finished?

+

Jack and Diane begin an alternating journal after completing handwritten copies of the Way. Their fictional record tests adulthood, competence, consent, failure, and interdependence without becoming canon or research evidence.

+
Read Jack & DianeEnter Living Narratives
+

Current field snapshot

{{ generated.repos.publicRepoCount }} public repositories · {{ generated.canon.units.length }} canonical units · {{ generated.textbook.chapterCount }} textbook chapters

diff --git a/src/narratives/index.njk b/src/narratives/index.njk new file mode 100644 index 0000000..9ae3799 --- /dev/null +++ b/src/narratives/index.njk @@ -0,0 +1,26 @@ +--- +layout: layouts/base.njk +title: Living Narratives +description: Clearly labeled fiction that tests The Interdependent Way against ordinary lives without becoming canon, evidence, or instruction. +permalink: /narratives/ +--- + +
+

Fiction · interpretation under constraint

+

Living Narratives

+

Stories make principles encounter time, error, unequal capacity, consent, repair, and consequence. They may illuminate the Way. They do not amend it and they do not count as research evidence.

+
+
+ + fictional serial +

{{ jack_and_diane.title }}

+

{{ jack_and_diane.subtitle }}

+ {{ jack_and_diane.entries.length }} opening journal entries · designed for continuation +
+
+
+

Authority boundary

+

What belongs here

+

Narrative can test whether an interpretation survives ordinary life. Canon remains in wayseer00; scientific claims remain in the study-only Research ledger; these stories remain fiction.

+
+

hmmm

One serial opens the space. Additional narratives should earn their place by exposing a different lived constraint, not by multiplying agreeable examples.

diff --git a/src/narratives/jack-and-diane.njk b/src/narratives/jack-and-diane.njk new file mode 100644 index 0000000..283d597 --- /dev/null +++ b/src/narratives/jack-and-diane.njk @@ -0,0 +1,82 @@ +--- +layout: layouts/base.njk +title: "Jack & Diane: The Longhand Threshold" +description: A fictional alternating journal about two young people testing what adulthood and interdependence require after completing handwritten copies of The Interdependent Way. +permalink: /narratives/jack-and-diane/ +--- + +
+

{{ jack_and_diane.status }} · continuing serial

+

{{ jack_and_diane.title }}

+

{{ jack_and_diane.subtitle }}

+
fictionnot canonclaim unfinished
+
+ +
+

Read before entering

+

The story cannot bestow adulthood

+

{{ jack_and_diane.editorialBoundary.threshold }}

+

{{ jack_and_diane.editorialBoundary.civil }}

+

{{ jack_and_diane.editorialBoundary.incompletion }}

+

Canon contact: {{ jack_and_diane.canonContact.unit }} · {{ jack_and_diane.canonContact.source }}. {{ jack_and_diane.canonContact.boundary }}

+
+ +
+

The journal keepers

+

Two voices, no shared mind

+

{{ jack_and_diane.relationship }}

+
+ {% for character in jack_and_diane.characters %} +
+

Age {{ character.age }}

+

{{ character.name }}

+

{{ character.voice }}

+
+ {% endfor %} +
+
+ +
+

Opening ledger

+

What the notebooks do—and do not—show

+
+ {% for item in jack_and_diane.criteria %} +
+

{{ item.name }}

{{ item.note }}

+ {{ item.status }} +
+ {% endfor %} +
+
+ +
+

Alternating record

+

The Longhand Journal

+
    + {% for entry in jack_and_diane.entries %} +
  1. +
    +
    + {{ entry.when }} + Entry {{ entry.sequence }} +
    +

    Journal of {{ entry.authorLabel }}

    +

    {{ entry.title }}

    + {% for paragraph in entry.body %}

    {{ paragraph }}

    {% endfor %} +
    + Evidence entered beside this page +
      {% for item in entry.evidence %}
    • {{ item }}
    • {% endfor %}
    +
    +
    +
  2. + {% endfor %} +
+
+ +
+

Continuation hooks

+

Questions for the next pages

+ +
+ +

hmmm

Jack and Diane have completed the copying and begun the evidence. Neither adulthood, interdependence, physical maturity, nor a Political Circle has been declared complete. The next true entry begins where a plan fails without somebody hiding the failure.

diff --git a/tests/accessibility.spec.mjs b/tests/accessibility.spec.mjs index 2f94d05..a9e7e23 100644 --- a/tests/accessibility.spec.mjs +++ b/tests/accessibility.spec.mjs @@ -13,7 +13,7 @@ if (!firstLabUnit) throw new Error(`missing Lab canon unit ${articleLab[0].unit_ for (const route of [ '/', '/home/', '/preamble/', '/chapters/', '/chapters/chapter-zero/', '/chapters/chapter-seven/', - '/articles/', '/articles/article-two/', '/way/', '/lab/', `/lab/${firstLabUnit.routeSlug}/`, '/projects/', + '/articles/', '/articles/article-two/', '/narratives/', '/narratives/jack-and-diane/', '/way/', '/lab/', `/lab/${firstLabUnit.routeSlug}/`, '/projects/', '/research/method/' ]) { test(`${route} has no serious or critical automated accessibility violations`, async ({ page }) => { diff --git a/tests/generated-site.test.mjs b/tests/generated-site.test.mjs index 585bb62..7cf3b15 100644 --- a/tests/generated-site.test.mjs +++ b/tests/generated-site.test.mjs @@ -6,7 +6,7 @@ import { readFile } from 'node:fs/promises'; // Usage: run only after Eleventy has generated _site, normally through npm run test:generated or npm run check. test('generated deployment artifact contains the unified routes', async () => { - const [splash, home, preamble, chapters, artifacts, fourCuts, fallback, articles] = await Promise.all([ + const [splash, home, preamble, chapters, artifacts, fourCuts, fallback, articles, narratives, jackAndDiane] = await Promise.all([ readFile('_site/index.html', 'utf8'), readFile('_site/home/index.html', 'utf8'), readFile('_site/preamble/index.html', 'utf8'), @@ -14,7 +14,9 @@ test('generated deployment artifact contains the unified routes', async () => { readFile('_site/artifacts/index.html', 'utf8'), readFile('_site/artifacts/four-cuts/index.html', 'utf8'), readFile('_site/fallback/index.html', 'utf8'), - readFile('_site/articles/index.html', 'utf8') + readFile('_site/articles/index.html', 'utf8'), + readFile('_site/narratives/index.html', 'utf8'), + readFile('_site/narratives/jack-and-diane/index.html', 'utf8') ]); assert.match(splash, /class="awakening-splash"/); @@ -38,6 +40,13 @@ test('generated deployment artifact contains the unified routes', async () => { assert.match(fourCuts, /Wealth and tax/); assert.match(fallback, /Emergency static edition/); assert.match(articles, /Publication drafts/); + assert.match(narratives, /Living Narratives/); + assert.match(narratives, /Jack & Diane: The Longhand Threshold/); + assert.match(jackAndDiane, /The story cannot bestow adulthood/); + assert.match(jackAndDiane, /Jack and Diane remain minors/); + assert.match(jackAndDiane, /status-risk">not canon/); + assert.match(jackAndDiane, /The Longhand Journal/); + assert.match(jackAndDiane, /The line we have not crossed/); for (const title of [ 'Article One: Contribution without contempt', 'Article Two: Freedom without abandonment', diff --git a/tests/narratives.test.mjs b/tests/narratives.test.mjs new file mode 100644 index 0000000..ee2ca21 --- /dev/null +++ b/tests/narratives.test.mjs @@ -0,0 +1,50 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; + +const narrative = JSON.parse(await readFile('src/_data/jack_and_diane.json', 'utf8')); + +test('Jack and Diane narrative is structured, fictional, and canon-bounded', () => { + assert.equal(narrative.schema, 'interdependency.living-narrative/1.0.0'); + assert.equal(narrative.id, 'jack-and-diane'); + assert.equal(narrative.status, 'fictional interpretation'); + assert.equal(narrative.canonContact.source, 'wayseer00/main:canon/INTERDEPENDENT_WAY.txt'); + assert.match(narrative.canonContact.boundary, /fiction/i); + assert.match(narrative.editorialBoundary.threshold, /does not establish adulthood/i); + assert.match(narrative.editorialBoundary.civil, /remain minors/i); + assert.match(narrative.editorialBoundary.incompletion, /physical maturity/i); +}); + +test('the two journal keepers and every entry preserve identity and order', () => { + assert.deepEqual(narrative.characters.map(({ id, age }) => [id, age]), [['jack', 14], ['diane', 13]]); + const characterIds = new Set(narrative.characters.map(character => character.id)); + assert.ok(narrative.entries.length >= 8); + assert.deepEqual(narrative.entries.map(entry => entry.sequence), narrative.entries.map((_, index) => index + 1)); + for (const entry of narrative.entries) { + assert.ok(characterIds.has(entry.author), `unknown author ${entry.author}`); + assert.ok(entry.title?.trim()); + assert.ok(entry.body.length >= 2); + assert.ok(entry.evidence.length >= 2); + } +}); + +test('the opening ledger leaves every unearned threshold visibly incomplete', () => { + const criteria = new Map(narrative.criteria.map(item => [item.name, item.status])); + assert.equal(criteria.get('Handwritten Articles'), 'complete'); + assert.equal(criteria.get('Original personal Preamble'), 'in progress'); + assert.equal(criteria.get('Self-sufficient interdependency'), 'not yet claimed'); + assert.equal(criteria.get('Political Circle'), 'not formed'); + assert.ok(narrative.continuationPrompts.length >= 5); +}); + +test('narrative templates expose fiction, civil, canon, and hmmm boundaries', async () => { + const [index, story] = await Promise.all([ + readFile('src/narratives/index.njk', 'utf8'), + readFile('src/narratives/jack-and-diane.njk', 'utf8') + ]); + assert.match(index, /do not count as research evidence/i); + assert.match(story, /status-risk">not canon/); + assert.match(story, /editorialBoundary\.civil/); + assert.match(story, /canonContact\.source/); + assert.match(story, /
/); +}); diff --git a/tests/site-contract.test.mjs b/tests/site-contract.test.mjs index f8a7b68..763ab5f 100644 --- a/tests/site-contract.test.mjs +++ b/tests/site-contract.test.mjs @@ -10,11 +10,12 @@ test('one static-first build owns public routes and exact Markdown rendering', a assert.match(config, /html: false/); }); -test('base layout remains readable without javascript and exposes the textbook', async () => { +test('base layout remains readable without javascript and exposes the textbook and narratives', async () => { const layout = await readFile('src/_includes/layouts/base.njk', 'utf8'); assert.match(layout, /