|
| 1 | +// Usage: run through `npm run test:generated` after a complete site build. |
| 2 | +// Evidence boundary: verifies generated artifact contracts, not the remote Pages environment. |
| 3 | +import { createHash } from 'node:crypto'; |
1 | 4 | import test from 'node:test'; |
2 | 5 | import assert from 'node:assert/strict'; |
3 | 6 | import { readFile } from 'node:fs/promises'; |
| 7 | +import { connectionContract } from '../src/eai/aicontext.11ty.js'; |
4 | 8 |
|
5 | | -// Usage: run with `npm run test:generated` after building `_site`. |
6 | | -// Evidence boundary: these checks verify generated publication structure, not source-repository freshness beyond the build artifacts already selected. |
| 9 | +// === CHECKS === |
| 10 | +// id: check_ai_context_public_discovery |
| 11 | +// proves: ai_context_public_discovery |
| 12 | +// call: self::checkAiContextPublicDiscovery |
| 13 | +// requires: node |
| 14 | +// timeout: 10 |
| 15 | +// mutates: none |
| 16 | +// cleanup: none |
| 17 | +// === END CHECKS === |
7 | 18 |
|
| 19 | +export async function checkAiContextPublicDiscovery() { |
| 20 | + const [home, splash, sitemap, llms] = await Promise.all([ |
| 21 | + readFile('_site/home/index.html', 'utf8'), |
| 22 | + readFile('_site/index.html', 'utf8'), |
| 23 | + readFile('_site/sitemap.xml', 'utf8'), |
| 24 | + readFile('_site/llms.txt', 'utf8') |
| 25 | + ]); |
| 26 | + assert.doesNotMatch(home, /<a[^>]+href="\/eai\/aicontext\.md"/); |
| 27 | + assert.match(home, /rel="alternate" type="text\/markdown" href="\/eai\/aicontext\.md"/); |
| 28 | + assert.match(splash, /rel="alternate" type="text\/markdown" href="\/eai\/aicontext\.md"/); |
| 29 | + assert.match(sitemap, /<loc>https:\/\/interdependentway\.org\/eai\/aicontext\.md<\/loc>/); |
| 30 | + assert.match(sitemap, /<loc>https:\/\/interdependentway\.org\/llms\.txt<\/loc>/); |
| 31 | + assert.match(llms, /machine entry point is `\/eai\/aicontext\.md`/); |
| 32 | + assert.match(llms, /EDCM claim requires an actual cited EDCM result record/); |
| 33 | +} |
| 34 | + |
| 35 | +// Usage: run only after Eleventy has generated _site, normally through npm run test:generated or npm run check. |
8 | 36 | test('generated deployment artifact contains the unified routes', async () => { |
9 | | - const sitemap = await readFile('_site/sitemap.xml', 'utf8'); |
10 | | - for (const route of ['/home/', '/way/', '/chapters/', '/narratives/', '/projects/', '/sitrep/', '/artifacts/', '/works/', '/research/method/', '/search/', '/eai/aicontext.md']) { |
11 | | - assert.match(sitemap, new RegExp(route.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); |
12 | | - } |
| 37 | + const [splash, home, preamble, chapters, artifacts, edcmMathematics, fourCuts, fallback, articles, narratives, jackAndDiane] = await Promise.all([ |
| 38 | + readFile('_site/index.html', 'utf8'), |
| 39 | + readFile('_site/home/index.html', 'utf8'), |
| 40 | + readFile('_site/preamble/index.html', 'utf8'), |
| 41 | + readFile('_site/chapters/index.html', 'utf8'), |
| 42 | + readFile('_site/artifacts/index.html', 'utf8'), |
| 43 | + readFile('_site/artifacts/edcm-mathematics/index.html', 'utf8'), |
| 44 | + readFile('_site/artifacts/four-cuts/index.html', 'utf8'), |
| 45 | + readFile('_site/fallback/index.html', 'utf8'), |
| 46 | + readFile('_site/articles/index.html', 'utf8'), |
| 47 | + readFile('_site/narratives/index.html', 'utf8'), |
| 48 | + readFile('_site/narratives/jack-and-diane/index.html', 'utf8') |
| 49 | + ]); |
| 50 | + |
| 51 | + assert.match(splash, /class="awakening-splash"/); |
| 52 | + assert.match(splash, /<h1>Awakening<\/h1>/); |
| 53 | + assert.match(splash, /5d explodes out of 4d/); |
| 54 | + assert.match(splash, /You are not alone/); |
| 55 | + assert.match(splash, /href="\/way\/"[^>]*>Enter The Way/); |
| 56 | + assert.doesNotMatch(splash, /href="\/preamble\/"[^>]*>Read the Preamble/); |
| 57 | + assert.doesNotMatch(splash, /href="\/home\/"[^>]*>Enter the living system/); |
| 58 | + assert.doesNotMatch(splash, /primary-nav/); |
| 59 | + assert.match(home, /Start with The Way/); |
| 60 | + assert.match(home, /href="\/way\/"/); |
| 61 | + assert.match(home, /href="\/chapters\/"/); |
| 62 | + assert.match(home, /Chapters Zero through Seven/); |
| 63 | + assert.doesNotMatch(home, /<a[^>]+href="\/eai\/aicontext\.md"/); |
| 64 | + assert.match(preamble, /One-click canon entrance/); |
| 65 | + assert.match(preamble, /Humanity faces extinction/); |
| 66 | + assert.match(preamble, /Canonical repository/); |
| 67 | + assert.match(chapters, /The Interdependency Textbook/); |
| 68 | + assert.match(chapters, /Chapters Zero through Seven/); |
| 69 | + assert.match(artifacts, /Artifacts/); |
| 70 | + assert.match(artifacts, /href="\/artifacts\/edcm-mathematics\/"/); |
| 71 | + assert.match(edcmMathematics, /EDCM mathematical reference/); |
| 72 | + assert.match(edcmMathematics, /Commit-pinned reproduction/); |
| 73 | + assert.match(edcmMathematics, /not a joint UCNS–EDCM canon selection/); |
| 74 | + assert.match(edcmMathematics, /2f09f9af10ef950ce68c765bcbed7dca83625c65/); |
| 75 | + assert.match(edcmMathematics, /c2e059de15c4ef2c5fa9368c63363b606e503206/); |
| 76 | + assert.match(edcmMathematics, /889336c7c723d6e013188e1b3f969f98aeca88e3075b8ce2e67bc87e897e724f/); |
| 77 | + assert.match(edcmMathematics, /Implemented v0\.3\.1 architecture layer/); |
| 78 | + assert.match(edcmMathematics, /<math\b/); |
| 79 | + assert.match(edcmMathematics, /<math tabindex="0"[^>]*display="block"/); |
| 80 | + assert.match(edcmMathematics, /<pre tabindex="0">/); |
| 81 | + assert.match(edcmMathematics, /NA/); |
| 82 | + assert.match(edcmMathematics, /hmmm/); |
| 83 | + assert.match(fourCuts, /Wealth and tax/); |
| 84 | + assert.match(fallback, /Emergency static edition/); |
| 85 | + assert.match(articles, /Publication drafts/); |
| 86 | + assert.match(narratives, /Living Narratives/); |
| 87 | + assert.match(narratives, /Jack & Diane: The Longhand Threshold/); |
| 88 | + assert.match(jackAndDiane, /The story cannot bestow adulthood/); |
| 89 | + assert.match(jackAndDiane, /Jack and Diane remain minors/); |
| 90 | + assert.match(jackAndDiane, /status-risk">not canon/); |
| 91 | + assert.match(jackAndDiane, /The Longhand Journal/); |
| 92 | + assert.match(jackAndDiane, /The line we have not crossed/); |
| 93 | + for (const title of [ |
| 94 | + 'Article One: Contribution without contempt', |
| 95 | + 'Article Two: Freedom without abandonment', |
| 96 | + 'Article Three: Speech as demonstrated consent', |
| 97 | + 'Article Four: Law as teachable duty', |
| 98 | + 'Article Five: Adulthood as demonstrated competence', |
| 99 | + 'Article Six: Authority as burden', |
| 100 | + 'Article Seven: Definitions before governance', |
| 101 | + 'Article Eight: Rights with living limits' |
| 102 | + ]) assert.match(articles, new RegExp(title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); |
13 | 103 | }); |
14 | 104 |
|
15 | 105 | test('distributed textbook displays all eight exact chapter sources', async () => { |
16 | | - const index = await readFile('_site/chapters/index.html', 'utf8'); |
17 | 106 | const textbook = JSON.parse(await readFile('src/_data/generated/textbook.json', 'utf8')); |
| 107 | + const index = await readFile('_site/chapters/index.html', 'utf8'); |
18 | 108 | const contact = [ |
19 | | - /serious trouble/, /automata|finite-state|formal language/i, /morpholog|agglutin|language/i, /quantum|interference|Born rule/i, |
20 | | - /selection|inherit|evolution/i, /brain|neural|cognitive/i, /measurement|operational|validity/i, /conscious|awareness|mind/i |
| 109 | + /Zero is not nothing/, |
| 110 | + /directed twofold branched angular cover/, |
| 111 | + /NA != 0/, |
| 112 | + /Modules That Speak for Themselves/, |
| 113 | + /meta-package/, |
| 114 | + /Prime Tensor Circled Neural Architecture/, |
| 115 | + /research[\s\S]*instrument, not a product/, |
| 116 | + /theory under development/ |
21 | 117 | ]; |
| 118 | + |
| 119 | + assert.equal(textbook.chapters.length, 8); |
22 | 120 | for (const chapter of textbook.chapters) { |
23 | 121 | assert.match(index, new RegExp(`href="/chapters/${chapter.slug}/"`)); |
24 | 122 | assert.match(index, new RegExp(chapter.title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); |
@@ -67,53 +165,116 @@ test('generated deployment artifact contains all rights article vertical slices |
67 | 165 | const pages = [ |
68 | 166 | ['article-one', /Contribution without contempt/, /From each as they will/], |
69 | 167 | ['article-two', /Freedom without abandonment/, /None shall be enslaved/], |
70 | | - ['article-three', /Reciprocity without retaliation/, /Your speech/], |
71 | | - ['article-four', /Law without obscurity/, /None shall be left ignorant/], |
72 | | - ['article-five', /Adulthood without caste/, /There are children/], |
73 | | - ['article-six', /Authority without worship/, /Violence is the ultimate Authority/], |
74 | | - ['article-seven', /Definition without closure/, /Where any would converse/], |
75 | | - ['article-eight', /Rights without abstraction/, /The whole of the law/] |
| 168 | + ['article-three', /Speech as demonstrated consent/, /Your speech/], |
| 169 | + ['article-four', /Law as teachable duty/, /None shall be left ignorant/], |
| 170 | + ['article-five', /Adulthood as demonstrated competence/, /Political Adulthood/], |
| 171 | + ['article-six', /Authority as burden/, /Violence is the ultimate Authority/], |
| 172 | + ['article-seven', /Definitions before governance/, /Where any would converse/], |
| 173 | + ['article-eight', /Rights with living limits/, /The whole of the law/] |
76 | 174 | ]; |
77 | | - for (const [slug, title, canon] of pages) { |
| 175 | + |
| 176 | + for (const [slug, titlePattern, canonPattern] of pages) { |
78 | 177 | const html = await readFile(`_site/articles/${slug}/index.html`, 'utf8'); |
79 | | - assert.match(html, title); |
80 | | - assert.match(html, canon); |
81 | | - assert.match(html, /Research/); |
82 | | - assert.match(html, /Source & provenance/); |
| 178 | + assert.match(html, titlePattern); |
| 179 | + assert.match(html, canonPattern); |
| 180 | + assert.match(html, /60–90 second script/); |
| 181 | + assert.match(html, /Study-only research attachment/); |
| 182 | + assert.match(html, /Inference boundary/); |
| 183 | + assert.match(html, /hmmm · study coverage/); |
| 184 | + assert.match(html, /hmmm/); |
83 | 185 | } |
84 | 186 | }); |
85 | 187 |
|
86 | 188 | test('every Rights Article Lab renders absurd-limit, practice, domain, and research sections', async () => { |
87 | | - const generated = JSON.parse(await readFile('src/_data/generated/canon.json', 'utf8')); |
88 | | - const rights = generated.units.filter(unit => unit.section === 'rights-and-definitions-of-the-way' && /^Article (One|Two|Three|Four|Five|Six|Seven|Eight)$/.test(unit.title)); |
89 | | - assert.equal(rights.length, 8); |
90 | | - for (const unit of rights) { |
| 189 | + const canon = JSON.parse(await readFile('src/_data/generated/canon.json', 'utf8')); |
| 190 | + const articleLab = JSON.parse(await readFile('src/_data/article_lab.json', 'utf8')); |
| 191 | + const requiredDomains = [ |
| 192 | + 'Medical', 'Construction', 'Engineering', 'Agriculture', 'Jurisprudence', |
| 193 | + 'Transportation and distribution', 'Child craft', 'Information systems', |
| 194 | + 'Emergency response', 'Hospitality and sanitation', 'Community governance' |
| 195 | + ]; |
| 196 | + |
| 197 | + for (const record of articleLab) { |
| 198 | + const unit = canon.units.find(candidate => candidate.id === record.unit_id); |
| 199 | + assert.ok(unit, `missing canon unit ${record.unit_id}`); |
91 | 200 | const html = await readFile(`_site/lab/${unit.routeSlug}/index.html`, 'utf8'); |
92 | | - assert.match(html, /Ad absurdum/); |
93 | | - assert.match(html, /Worst practice/); |
94 | | - assert.match(html, /Best practice/); |
95 | | - assert.match(html, /Domain applications/); |
96 | | - assert.match(html, /Research/); |
| 201 | + assert.match(html, /Reductio ad absurdum/); |
| 202 | + assert.match(html, /Worst practices and best practices/); |
| 203 | + assert.match(html, /Applications by domain/); |
| 204 | + assert.match(html, /Research field/); |
| 205 | + assert.match(html, /Inference boundary/); |
| 206 | + assert.match(html, /Only admitted research studies appear here|Research means an admitted primary study/); |
| 207 | + assert.match(html, /hmmm · study coverage/); |
| 208 | + assert.match(html, /href="https?:\/\//); |
| 209 | + for (const domain of requiredDomains) assert.match(html, new RegExp(domain.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); |
97 | 210 | } |
98 | 211 | }); |
99 | 212 |
|
100 | 213 | test('public Research pages exclude legislation, standards, guidelines, frameworks, and doctrine', async () => { |
101 | 214 | const method = await readFile('_site/research/method/index.html', 'utf8'); |
102 | | - for (const excluded of ['legislation', 'standards', 'guidelines', 'frameworks', 'doctrine']) { |
103 | | - assert.match(method, new RegExp(excluded, 'i')); |
104 | | - } |
105 | | - assert.match(method, /Research is study-only/i); |
| 215 | + const articlePages = await Promise.all([ |
| 216 | + 'article-one', 'article-two', 'article-three', 'article-four', |
| 217 | + 'article-five', 'article-six', 'article-seven', 'article-eight' |
| 218 | + ].map(slug => readFile(`_site/articles/${slug}/index.html`, 'utf8'))); |
| 219 | + const publicResearch = [method, ...articlePages].join('\n'); |
| 220 | + |
| 221 | + assert.match(method, /Legislation is not science/); |
| 222 | + assert.match(method, /19<\/strong> admitted studies/); |
| 223 | + assert.match(method, /20<\/strong> non-study records excluded/); |
| 224 | + for (const excludedTitle of [ |
| 225 | + 'Guidelines on sanitation and health', |
| 226 | + 'General comment No. 1', |
| 227 | + 'RFC 2119', |
| 228 | + 'National Incident Management System', |
| 229 | + 'The Belmont Report' |
| 230 | + ]) assert.doesNotMatch(publicResearch, new RegExp(excludedTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); |
106 | 231 | }); |
107 | 232 |
|
108 | 233 | test('generated deployment artifact publishes verifiable build identity', async () => { |
109 | | - const info = JSON.parse(await readFile('_site/assets/data/build-info.json', 'utf8')); |
110 | | - assert.match(info.commit, /^[a-f0-9]{40}$/); |
111 | | - assert.equal(info.textbook.chapter_count, 8); |
| 234 | + const build = JSON.parse(await readFile('_site/build.json', 'utf8')); |
| 235 | + assert.equal(build.repository, 'The-Interdependency/The-Interdependency.github.io'); |
| 236 | + assert.ok(build.commit); |
| 237 | + assert.match(build.generatedAt, /^\d{4}-\d{2}-\d{2}T/); |
| 238 | + assert.equal(build.canonicalSource.repository, 'wayseer00/main'); |
| 239 | + assert.equal(build.canonicalSource.path, 'canon/INTERDEPENDENT_WAY.txt'); |
| 240 | + assert.match(build.canonicalSource.contentSha256, /^[a-f0-9]{64}$/); |
112 | 241 | }); |
113 | 242 |
|
114 | 243 | test('generated deployment artifact publishes the complete machine-oriented AI context', async () => { |
115 | | - const context = await readFile('_site/eai/aicontext.md', 'utf8'); |
116 | | - assert.match(context, /Ownership is not authorship/); |
117 | | - assert.match(context, /hmmm doctrine/); |
118 | | - assert.match(context, /The Interdependent Way/); |
| 244 | + const [aicontext, textbookRaw, biographyRaw] = await Promise.all([ |
| 245 | + readFile('_site/eai/aicontext.md', 'utf8'), |
| 246 | + readFile('src/_data/generated/textbook.json', 'utf8'), |
| 247 | + readFile('src/_data/erin.public-biography.json', 'utf8') |
| 248 | + ]); |
| 249 | + const textbook = JSON.parse(textbookRaw); |
| 250 | + const biography = JSON.parse(biographyRaw); |
| 251 | + |
| 252 | + assert.equal(aicontext.slice(0, connectionContract.length), connectionContract); |
| 253 | + const canonMatch = /<CANON COPY>\n([\s\S]*?)<\/CANON COPY>/.exec(aicontext); |
| 254 | + const publicationMatch = /<PUBLICATION MANIFEST[^>]*>\n```json\n([\s\S]*?)\n```\n<\/PUBLICATION MANIFEST>/.exec(aicontext); |
| 255 | + assert.ok(canonMatch); |
| 256 | + assert.ok(publicationMatch); |
| 257 | + const publication = JSON.parse(publicationMatch[1]); |
| 258 | + assert.equal(createHash('sha256').update(canonMatch[1]).digest('hex'), publication.sources[0].content_sha256); |
| 259 | + let cursor = aicontext.indexOf('<TIW TEXTBOOK>'); |
| 260 | + for (const chapter of textbook.chapters) { |
| 261 | + const position = aicontext.indexOf(chapter.content, cursor); |
| 262 | + assert.ok(position > cursor, `aicontext chapter ${chapter.number} missing or out of order`); |
| 263 | + cursor = position; |
| 264 | + } |
| 265 | + const biographyMatch = /<MACHINE READABLE BIOGRAPHY[^>]*>\n\|\n```json\n([\s\S]*?)\n```\n\|\n<\/MACHINE READABLE BIOGRAPHY>/.exec(aicontext); |
| 266 | + assert.ok(biographyMatch); |
| 267 | + assert.deepEqual(JSON.parse(biographyMatch[1]), biography); |
| 268 | + assert.equal(biography['@id'], 'https://interdependentway.org/eai/aicontext.md#erin-spencer'); |
| 269 | + const interpretationMatch = /<INTERPRETATION BOUNDARY[^>]*>\n```json\n([\s\S]*?)\n```\n<\/INTERPRETATION BOUNDARY>/.exec(aicontext); |
| 270 | + assert.ok(interpretationMatch); |
| 271 | + const interpretation = JSON.parse(interpretationMatch[1]); |
| 272 | + assert.equal(interpretation.addressing.identifier_is_runtime_connection, false); |
| 273 | + assert.equal(interpretation.capability_gate.public_context_grants_log_access, false); |
| 274 | + assert.match(interpretation.measurement_gate.edcm_rule, /actual cited EDCM result record/); |
| 275 | + assert.match(aicontext, /"canonical_status_transfer": false/); |
| 276 | + assert.match(aicontext, /"digest_is_authentication": false/); |
| 277 | + assert.match(aicontext, /hmmm The endpoint now demonstrates intersession continuity/); |
119 | 278 | }); |
| 279 | + |
| 280 | +test('generated site exposes the AI context through redundant machine discovery', checkAiContextPublicDiscovery); |
0 commit comments