From 6d022d23783ccbab30bc968335449b12f56a4982 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:11:56 -0700 Subject: [PATCH 01/24] Define distributed textbook chapter sources --- src/_data/textbook_sources.json | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/_data/textbook_sources.json diff --git a/src/_data/textbook_sources.json b/src/_data/textbook_sources.json new file mode 100644 index 0000000..d48e29d --- /dev/null +++ b/src/_data/textbook_sources.json @@ -0,0 +1,90 @@ +[ + { + "number": 0, + "display_number": "Zero", + "slug": "chapter-zero", + "title": "Meta Energy Theory — Axioms, Postulates, and Theorems", + "repository": "The-Interdependency/metapat", + "path": "CHAPTER_ZERO.md", + "branch": "main", + "status": "root ontology and theory", + "summary": "The invariant vocabulary of distinction, boundary, simplex, tensor, energy-state, registration, and question." + }, + { + "number": 1, + "display_number": "One", + "slug": "chapter-one", + "title": "The Subtractive Foundations of the Unit Carrier", + "repository": "The-Interdependency/ucns", + "path": "docs/chapter-1.md", + "branch": "main", + "status": "carrier foundations", + "summary": "The directed 720° carrier, Structural Null, separated zeros, valuation triad, pairing, typed dispatch, and retained memory." + }, + { + "number": 2, + "display_number": "Two", + "slug": "chapter-two", + "title": "Measurement Without Transfer", + "repository": "The-Interdependency/edcm", + "path": "docs/chapter-2.md", + "branch": "main", + "status": "measurement discipline", + "summary": "Typed absence, frozen canon, evidence compartments, proof-transfer firewalls, identity epochs, and an honest measurement frontier." + }, + { + "number": 3, + "display_number": "Three", + "slug": "chapter-three", + "title": "Modules That Speak for Themselves", + "repository": "The-Interdependency/skill-lib", + "path": "docs/chapter-3.md", + "branch": "main", + "status": "self-declaration method", + "summary": "Module Self-Declared Metadata in Markdown: declarations beside implementation, machine reconciliation, and drift-resistant evidence." + }, + { + "number": 4, + "display_number": "Four", + "slug": "chapter-four", + "title": "Canon Without Inversion", + "repository": "The-Interdependency/interdependent-lib", + "path": "docs/chapter-4.md", + "branch": "main", + "status": "cross-repository canon placement", + "summary": "How a meta-package carries family-level canon without inverting runtime dependencies or duplicating authority." + }, + { + "number": 5, + "display_number": "Five", + "slug": "chapter-five", + "title": "One Architecture, Four Layers", + "repository": "The-Interdependency/ptcna", + "path": "docs/chapter-5.md", + "branch": "main", + "status": "architecture", + "summary": "The Prime Tensor Circled Neural Architecture as one package with neural, circle, seed, and core layers." + }, + { + "number": 6, + "display_number": "Six", + "slug": "chapter-six", + "title": "The Instrument", + "repository": "The-Interdependency/a0", + "path": "docs/chapter-6.md", + "branch": "main", + "status": "research instrument", + "summary": "a0 as the codebase, a0p as the public instrument, and persistent agent structure distinct from interchangeable model providers." + }, + { + "number": 7, + "display_number": "Seven", + "slug": "chapter-seven", + "title": "The Echo", + "repository": "The-Interdependency/zfae", + "path": "docs/chapter-7.md", + "branch": "main", + "status": "theory under development", + "summary": "Zeta Function Alpha Echo as an emergent event claim, explicitly bounded as theory with a falsifiable prediction." + } +] From 839a5c24d9dbb31e099d31608b567f173a74e709 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:12:54 -0700 Subject: [PATCH 02/24] Fetch distributed textbook chapters --- scripts/fetch-textbook.mjs | 173 +++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 scripts/fetch-textbook.mjs diff --git a/scripts/fetch-textbook.mjs b/scripts/fetch-textbook.mjs new file mode 100644 index 0000000..c1659a7 --- /dev/null +++ b/scripts/fetch-textbook.mjs @@ -0,0 +1,173 @@ +import { createHash } from 'node:crypto'; +import { execFileSync } from 'node:child_process'; +import { mkdir, readFile, writeFile } from 'node:fs/promises'; + +// === MODULE_BUILD === +// id: distributed_textbook_fetch +// module_name: fetch-textbook +// module_kind: service +// summary: Resolves chapters zero through seven from their owning repositories and emits one provenance-bearing reading dataset. +// owner: Erin Spencer +// public_surface: npm run refresh:textbook, generated.textbook +// internal_surface: allowlisted GitHub API and raw-file retrieval, chapter-source validation, snapshot fallback +// auth_boundary: optional read-only GITHUB_TOKEN +// storage_boundary: writes generated textbook data and a last-known-good snapshot +// network_boundary: allowlisted read-only HTTPS to api.github.com and raw.githubusercontent.com +// user_data_boundary: none +// admin_only: false +// tests: tests/textbook-integrity.test.mjs, tests/generated-site.test.mjs, tests/site.spec.mjs +// rollout: required by refresh:data before validation and Eleventy generation +// rollback: remove refresh:textbook and the generated chapter routes; source repositories remain unchanged +// === END MODULE_BUILD === +// Usage: run `npm run refresh:textbook`; set OFFLINE=1 to use a retained snapshot or metadata-only hmmm records. +// Limits: displays exact source Markdown but does not transfer license, theorem, proof, empirical, or canonical status between repositories. + +// === BOUNDARIES === +// id: distributed_textbook_network_boundary +// summary: Reads only the eight declared chapter files from allowlisted GitHub endpoints. +// auth_boundary: optional GitHub read token +// storage_boundary: write beneath src/_data/generated and src/_data/snapshots +// network_boundary: external read-only +// user_data_boundary: none +// admin_only: false +// pii: none +// secrets: GITHUB_TOKEN is passed only as an HTTPS authorization header and never written +// side_effects: generated dataset and snapshot writes +// owner: Erin Spencer +// === END BOUNDARIES === + +const apiOrigin = 'https://api.github.com'; +const rawOrigin = 'https://raw.githubusercontent.com'; +const allowedOrigins = new Set([apiOrigin, rawOrigin]); +const manifest = JSON.parse(await readFile('src/_data/textbook_sources.json', 'utf8')); +const snapshotPath = 'src/_data/snapshots/textbook.last-known-good.json'; +const generatedPath = 'src/_data/generated/textbook.json'; +const githubHeaders = ['-H', 'Accept: application/vnd.github+json', '-H', 'X-GitHub-Api-Version: 2022-11-28']; +if (process.env.GITHUB_TOKEN) githubHeaders.push('-H', `Authorization: Bearer ${process.env.GITHUB_TOKEN}`); + +function curlText(target, extraHeaders = []) { + const url = target instanceof URL ? target : new URL(target); + if (url.protocol !== 'https:' || !allowedOrigins.has(url.origin)) throw new Error(`refusing non-allowlisted textbook target: ${url.origin}`); + return execFileSync('curl', ['-fsSL', '--retry', '2', '--max-time', '30', ...extraHeaders, url.href], { + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'] + }); +} + +function getJson(target) { + return JSON.parse(curlText(target, githubHeaders)); +} + +function apiUrl(pathname, search = {}) { + const url = new URL(pathname, apiOrigin); + for (const [key, value] of Object.entries(search)) url.searchParams.set(key, String(value)); + return url; +} + +function encodedRepository(repository) { + const [owner, repo] = repository.split('/'); + if (!owner || !repo) throw new Error(`invalid chapter repository ${repository}`); + return { owner: encodeURIComponent(owner), repo: encodeURIComponent(repo) }; +} + +function encodedPath(path) { + return path.split('/').map(segment => encodeURIComponent(segment)).join('/'); +} + +function validateManifest() { + if (!Array.isArray(manifest) || manifest.length !== 8) throw new Error('textbook source manifest must contain chapters zero through seven'); + const numbers = manifest.map(source => source.number); + if (numbers.some((number, index) => number !== index)) throw new Error('textbook source manifest must be ordered 0 through 7'); + if (new Set(manifest.map(source => source.slug)).size !== 8) throw new Error('textbook chapter slugs must be unique'); + if (new Set(manifest.map(source => `${source.repository}:${source.path}`)).size !== 8) throw new Error('textbook chapter source locations must be unique'); +} + +function metadataOnly(source, error) { + return { + ...source, + content: null, + contentSha256: null, + commit: null, + blob: null, + resolvedUrl: null, + sourceUrl: `https://github.com/${source.repository}/blob/${source.branch}/${source.path}`, + retrievedAt: null, + fallback: true, + retrievalError: error + }; +} + +function fetchOne(source) { + const { owner, repo } = encodedRepository(source.repository); + const path = encodedPath(source.path); + const base = `/repos/${owner}/${repo}`; + const commitInfo = getJson(apiUrl(`${base}/commits/${encodeURIComponent(source.branch)}`)); + const commit = commitInfo.sha; + if (!/^[a-f0-9]{40}$/i.test(commit)) throw new Error(`${source.repository} branch did not resolve to a commit SHA`); + const fileInfo = getJson(apiUrl(`${base}/contents/${path}`, { ref: commit })); + if (fileInfo.type !== 'file' || !fileInfo.sha) throw new Error(`${source.repository}/${source.path} did not resolve to a file blob`); + const resolvedUrl = new URL(`/${owner}/${repo}/${commit}/${path}`, rawOrigin); + const content = curlText(resolvedUrl); + if (!content.trim()) throw new Error(`${source.repository}/${source.path} is empty`); + if (!content.includes(source.title)) throw new Error(`${source.repository}/${source.path} no longer contains expected title: ${source.title}`); + const chapterHeading = source.number === 0 ? '# Chapter Zero' : `# Chapter ${source.number}:`; + if (!content.includes(chapterHeading)) throw new Error(`${source.repository}/${source.path} no longer declares ${chapterHeading}`); + return { + ...source, + content, + contentSha256: createHash('sha256').update(content).digest('hex'), + commit, + blob: fileInfo.sha, + resolvedUrl: resolvedUrl.href, + sourceUrl: `https://github.com/${source.repository}/blob/${commit}/${source.path}`, + retrievedAt: new Date().toISOString(), + fallback: false, + retrievalError: null + }; +} + +async function readSnapshot() { + try { + const snapshot = JSON.parse(await readFile(snapshotPath, 'utf8')); + return Array.isArray(snapshot?.chapters) ? snapshot : null; + } catch { + return null; + } +} + +validateManifest(); +await mkdir('src/_data/generated', { recursive: true }); +await mkdir('src/_data/snapshots', { recursive: true }); +const previous = await readSnapshot(); +const previousByNumber = new Map((previous?.chapters || []).map(chapter => [chapter.number, chapter])); +const offline = process.env.OFFLINE === '1'; +const chapters = []; + +for (const source of manifest) { + if (offline) { + const retained = previousByNumber.get(source.number); + chapters.push(retained ? { ...retained, ...source, fallback: true, retrievalError: 'offline requested; retained last-known-good chapter content' } : metadataOnly(source, 'offline requested; no retained chapter snapshot')); + continue; + } + try { + chapters.push(fetchOne(source)); + } catch (error) { + const retained = previousByNumber.get(source.number); + const message = String(error?.message || error); + chapters.push(retained ? { ...retained, ...source, fallback: true, retrievalError: message } : metadataOnly(source, message)); + } +} + +const dataset = { + schema: 'interdependency.distributed-textbook/1.0.0', + title: 'The Interdependency — Chapters Zero Through Seven', + generatedAt: new Date().toISOString(), + fallback: chapters.some(chapter => chapter.fallback), + complete: chapters.every(chapter => Boolean(chapter.content)), + chapterCount: chapters.length, + chapters +}; + +await writeFile(generatedPath, JSON.stringify(dataset, null, 2)); +if (!offline && chapters.every(chapter => !chapter.fallback && chapter.content)) await writeFile(snapshotPath, JSON.stringify(dataset, null, 2)); +console.log(`textbook chapters=${chapters.length} complete=${dataset.complete} fallback=${dataset.fallback}`); From 111335c906042325f8e471f90689cd8facf99e45 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:13:11 -0700 Subject: [PATCH 03/24] Wire textbook refresh and tests --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 73ebae8..cd33b09 100644 --- a/package.json +++ b/package.json @@ -5,16 +5,17 @@ "type": "module", "scripts": { "dev": "npm run refresh:data && eleventy --serve", - "refresh:data": "npm run refresh:canon && npm run refresh:github", + "refresh:data": "npm run refresh:canon && npm run refresh:github && npm run refresh:textbook", "refresh:canon": "node scripts/fetch-canon.mjs && node scripts/parse-canon.mjs", "refresh:github": "node scripts/fetch-github-org.mjs", + "refresh:textbook": "node scripts/fetch-textbook.mjs", "research:enrich": "node scripts/enrich-citations.mjs", "audit:workflows": "node scripts/audit-workflows.mjs", "prevalidate": "npm run refresh:data", "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/offline-project-snapshot.test.mjs tests/repo-coverage.test.mjs tests/research-ledger.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/offline-project-snapshot.test.mjs tests/repo-coverage.test.mjs tests/research-ledger.test.mjs tests/site-contract.test.mjs", "test:generated": "node --test tests/generated-site.test.mjs && node tests/links.test.mjs", "test:browser": "playwright test", "test:e2e": "playwright test tests/site.spec.mjs", From 5e8b7f46116386d777c809f6e2ebb9b219381941 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:13:22 -0700 Subject: [PATCH 04/24] Prepare textbook data for offline tests --- scripts/prepare-tests.mjs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/prepare-tests.mjs b/scripts/prepare-tests.mjs index f55694a..25faf86 100644 --- a/scripts/prepare-tests.mjs +++ b/scripts/prepare-tests.mjs @@ -2,9 +2,9 @@ import { execFileSync } from 'node:child_process'; // === MODULE_BUILD === // id: offline_test_data_preparation -// purpose: Regenerate canon and project data deterministically before npm test without requiring network access or a full site build. +// purpose: Regenerate canon, project, and distributed-textbook data deterministically before npm test without requiring network access or a full site build. // entrypoint: npm test via the pretest lifecycle -// tests: tests/canon-integrity.test.mjs, tests/repo-coverage.test.mjs +// tests: tests/canon-integrity.test.mjs, tests/textbook-integrity.test.mjs, tests/repo-coverage.test.mjs // === END MODULE_BUILD === // === BOUNDARIES === // id: offline_test_preparation @@ -17,7 +17,8 @@ const env = { ...process.env, OFFLINE: '1', GITHUB_TOKEN: '' }; for (const script of [ 'scripts/fetch-canon.mjs', 'scripts/parse-canon.mjs', - 'scripts/fetch-github-org.mjs' + 'scripts/fetch-github-org.mjs', + 'scripts/fetch-textbook.mjs' ]) { execFileSync(process.execPath, [script], { env, stdio: 'inherit' }); } From d1a22b67dd99f9377422e5dfd19a260b9beb1cbc Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:13:30 -0700 Subject: [PATCH 05/24] Ignore generated textbook dataset --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ba3421c..8d3e13d 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ _site/ # Build-time generated data /src/_data/generated/canon.json +/src/_data/generated/textbook.json # Python __pycache__/ From f42aa950b165b4e59569b1145ab4bd40baca2378 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:13:42 -0700 Subject: [PATCH 06/24] Render distributed textbook Markdown --- .eleventy.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.eleventy.js b/.eleventy.js index e0446bb..b9bcf6d 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -2,9 +2,9 @@ import markdownIt from 'markdown-it'; // === MODULE_BUILD === // id: eleventy_site_configuration -// purpose: Build the static-first public knowledge system and copy deliberate fallback artifacts. +// purpose: Build the static-first public knowledge system, render exact distributed-textbook Markdown, and copy deliberate fallback artifacts. // entrypoint: npm run build -// tests: tests/site-contract.test.mjs +// tests: tests/site-contract.test.mjs, tests/generated-site.test.mjs // === END MODULE_BUILD === export default function configureEleventy(eleventyConfig) { @@ -20,6 +20,7 @@ export default function configureEleventy(eleventyConfig) { eleventyConfig.addFilter('dateOnly', value => value ? String(value).slice(0, 10) : 'hmmm'); eleventyConfig.addFilter('where', (items, key, value) => (items || []).filter(item => item?.[key] === value)); eleventyConfig.addFilter('statusClass', value => `status-${String(value || 'hmmm').toLowerCase().replace(/[^a-z0-9]+/g, '-')}`); + eleventyConfig.addFilter('markdown', value => md.render(String(value || ''))); return { dir: { input: 'src', output: '_site', includes: '_includes', data: '_data' }, From 714b2f1ccc97f1355673a1814e8d54fc7ba2ceff Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:14:19 -0700 Subject: [PATCH 07/24] Validate distributed textbook coverage --- scripts/validate-content.mjs | 37 +++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/scripts/validate-content.mjs b/scripts/validate-content.mjs index fc796bd..bcd85fe 100644 --- a/scripts/validate-content.mjs +++ b/scripts/validate-content.mjs @@ -5,18 +5,18 @@ import { access, readFile } from 'node:fs/promises'; // id: generated_content_gate // module_name: validate-content // module_kind: instrument -// summary: Refuses deployment when canon identity, heading hierarchy, snapshot integrity, generated route coverage, or recovery artifacts drift. +// summary: Refuses deployment when canon identity, heading hierarchy, textbook coverage, snapshot integrity, generated route coverage, or recovery artifacts drift. // owner: Erin Spencer // public_surface: npm run validate -// internal_surface: canon snapshot digest, heading hierarchy, and repository-route assertions +// internal_surface: canon snapshot digest, heading hierarchy, distributed-textbook provenance, and repository-route assertions // auth_boundary: none // storage_boundary: read // network_boundary: none // user_data_boundary: none // admin_only: false -// tests: tests/canon-parser.test.mjs, tests/canon-integrity.test.mjs, tests/repo-coverage.test.mjs, tests/site-contract.test.mjs +// tests: tests/canon-parser.test.mjs, tests/canon-integrity.test.mjs, tests/textbook-integrity.test.mjs, tests/repo-coverage.test.mjs, tests/site-contract.test.mjs // rollout: required by npm run build and npm run check -// rollback: remove the gate only with an explicit replacement preserving provenance, hierarchy, and route checks +// rollback: remove the gate only with an explicit replacement preserving provenance, hierarchy, textbook, and route checks // === END MODULE_BUILD === // Usage: run `npm run validate`; it refreshes data first and exits nonzero on any integrity mismatch. // Limits: validates repository artifacts, not GitHub Pages settings or public DNS. @@ -37,6 +37,8 @@ import { access, readFile } from 'node:fs/promises'; const canon = JSON.parse(await readFile('src/_data/generated/canon.json', 'utf8')); const repos = JSON.parse(await readFile('src/_data/generated/repos.json', 'utf8')); +const textbook = JSON.parse(await readFile('src/_data/generated/textbook.json', 'utf8')); +const textbookSources = JSON.parse(await readFile('src/_data/textbook_sources.json', 'utf8')); const snapshotRaw = await readFile('src/_data/snapshots/canon.last-known-good.md', 'utf8'); const snapshotText = snapshotRaw.replace(/^---\n[\s\S]*?\n---\n/, ''); const snapshotHash = createHash('sha256').update(snapshotText).digest('hex'); @@ -60,8 +62,29 @@ if (preamble.level !== 2 || preamble.section !== 'preamble') throw new Error('Pr if (!canon.source.fallback) { const interdefinablesIndex = canon.sections.findIndex(section => section.title === 'The Interdefinables'); const preambleIndex = canon.sections.findIndex(section => section.title === 'Preamble'); - if (interdefinablesIndex < 0 || preambleIndex !== interdefinablesIndex + 1) { - throw new Error('Preamble must be the next major section after The Interdefinables'); + if (interdefinablesIndex < 0 || preambleIndex !== interdefinablesIndex + 1) throw new Error('Preamble must be the next major section after The Interdefinables'); +} + +if (textbook.schema !== 'interdependency.distributed-textbook/1.0.0') throw new Error(`unexpected textbook schema: ${textbook.schema}`); +if (!Array.isArray(textbookSources) || textbookSources.length !== 8) throw new Error('textbook source manifest must contain exactly eight chapters'); +if (!Array.isArray(textbook.chapters) || textbook.chapters.length !== 8 || textbook.chapterCount !== 8) throw new Error('generated textbook must contain chapters zero through seven'); +for (let number = 0; number < 8; number += 1) { + const source = textbookSources[number]; + const chapter = textbook.chapters[number]; + if (source.number !== number || chapter.number !== number) throw new Error(`textbook chapter order drift at ${number}`); + for (const key of ['slug', 'title', 'repository', 'path', 'branch']) { + if (chapter[key] !== source[key]) throw new Error(`textbook chapter ${number} ${key} drift`); + } +} +if (new Set(textbook.chapters.map(chapter => chapter.slug)).size !== 8) throw new Error('duplicate textbook chapter slug'); +if (new Set(textbook.chapters.map(chapter => `${chapter.repository}:${chapter.path}`)).size !== 8) throw new Error('duplicate textbook source location'); +if (process.env.OFFLINE !== '1') { + if (!textbook.complete || textbook.fallback) throw new Error('production textbook refresh is incomplete or using fallback content'); + for (const chapter of textbook.chapters) { + if (!chapter.content?.trim()) throw new Error(`chapter ${chapter.number} content missing`); + if (!/^[a-f0-9]{64}$/.test(chapter.contentSha256 || '')) throw new Error(`chapter ${chapter.number} digest missing`); + if (!/^[a-f0-9]{40}$/.test(chapter.commit || '') || !/^[a-f0-9]{40}$/.test(chapter.blob || '')) throw new Error(`chapter ${chapter.number} source identity missing`); + if (!chapter.sourceUrl?.startsWith(`https://github.com/${chapter.repository}/blob/${chapter.commit}/`)) throw new Error(`chapter ${chapter.number} exact source URL missing`); } } @@ -69,4 +92,4 @@ if (repos.publicRepoCount !== repos.generatedRouteCount) throw new Error('repo r if (new Set(repos.repositories.map(repo => repo.slug)).size !== repos.repositories.length) throw new Error('duplicate project slug'); await access('fallback/index.html'); await access('artifacts/four-cuts-1.html'); -console.log(`validated ${canon.units.length} canon units, ${canon.notes.length} notes, canonical heading hierarchy, and ${repos.publicRepoCount} repositories`); +console.log(`validated ${canon.units.length} canon units, ${canon.notes.length} notes, ${textbook.chapterCount} textbook chapters, canonical hierarchy, and ${repos.publicRepoCount} repositories`); From 4cb3cf4b4188b3ce92d149c63d0d4b3468a2e7f2 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:14:37 -0700 Subject: [PATCH 08/24] Add distributed textbook index --- src/chapters/index.njk | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/chapters/index.njk diff --git a/src/chapters/index.njk b/src/chapters/index.njk new file mode 100644 index 0000000..eaa8d92 --- /dev/null +++ b/src/chapters/index.njk @@ -0,0 +1,43 @@ +--- +layout: layouts/base.njk +title: The Interdependency Textbook +description: Chapters zero through seven of the distributed Interdependency textbook, displayed together with exact repository provenance and status boundaries. +permalink: /chapters/ +--- +
+

Zero through Seven · eight repositories · one reading sequence

+

The Interdependency Textbook

+

The textbook is distributed by design. Each chapter lives with the repository whose subject it teaches, while this surface restores the complete reading order. The source repository retains its own license, status vocabulary, and authority; citation does not transfer theorem, proof, empirical, or canonical status between chapters.

+
+
+

Reading boundary

+

This textbook is distinct from the canonical text of The Interdependent Way, which remains in wayseer00/main:canon/INTERDEPENDENT_WAY.txt. These chapters explain the wider Interdependency technical architecture and preserve their repository-local claims.

+
+
+

Complete sequence

+

Chapters Zero through Seven

+
    + {% for chapter in generated.textbook.chapters %} +
  1. + + {{ chapter.display_number }} + {{ chapter.status }} +

    {{ chapter.title }}

    +

    {{ chapter.summary }}

    + {{ chapter.repository }} · {{ chapter.path }} +
    +
  2. + {% endfor %} +
+
+
+

Source state

+
+
Schema
{{ generated.textbook.schema }}
+
Generated
{{ generated.textbook.generatedAt }}
+
Chapter count
{{ generated.textbook.chapterCount }}
+
Complete
{{ generated.textbook.complete }}
+
Fallback used
{{ generated.textbook.fallback }}
+
+
+

hmmm

The chapters now share a public reading surface, not a merged authority. Corrections still belong first in the repository that owns the chapter; this site should then refresh and display the new exact source identity.

From 19f2769403521c8b62cc3e4ed97db8263930fc18 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:14:55 -0700 Subject: [PATCH 09/24] Add distributed textbook chapter reader --- src/chapters/chapter.njk | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/chapters/chapter.njk diff --git a/src/chapters/chapter.njk b/src/chapters/chapter.njk new file mode 100644 index 0000000..d022a59 --- /dev/null +++ b/src/chapters/chapter.njk @@ -0,0 +1,44 @@ +--- +layout: layouts/base.njk +pagination: + data: generated.textbook.chapters + size: 1 + alias: chapter +permalink: "/chapters/{{ chapter.slug }}/" +title: "Chapter {{ chapter.display_number }} · {{ chapter.title }}" +--- + +
+

Distributed textbook · Chapter {{ chapter.display_number }}

+
+ exact repository source + {{ chapter.status }} + {% if chapter.fallback %}fallback{% endif %} +
+

This chapter is displayed from {{ chapter.repository }}:{{ chapter.path }}. Its repository retains its license, status vocabulary, and claim authority; this reader does not transfer those statuses to any other chapter or to The Interdependent Way canon.

+
+
+

Source evidence

+
+
Repository
{{ chapter.repository }}
+
Path
{{ chapter.path }}
+
Commit
{% if chapter.commit %}{{ chapter.commit }}{% else %}hmmm{% endif %}
+
Blob
{% if chapter.blob %}{{ chapter.blob }}{% else %}hmmm{% endif %}
+
Digest
{% if chapter.contentSha256 %}{{ chapter.contentSha256 }}{% else %}hmmm{% endif %}
+
Retrieved
{{ chapter.retrievedAt or "hmmm" }}
+
+ +
+{% if chapter.content %} +
+ {{ chapter.content | markdown | safe }} +
+{% else %} +

Chapter {{ chapter.display_number }} source unavailable

The offline build has no retained content snapshot for this chapter. Its declared source remains available through the repository link above; no substitute text has been invented.

{{ chapter.retrievalError }}

+{% endif %} + +

hmmm

Questions, corrections, and status changes belong to {{ chapter.repository }}. This page will follow the source on the next verified build.

From f2f224982dbc5189509449cd571fc1a3d90cd51d Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:15:22 -0700 Subject: [PATCH 10/24] Add textbook to primary navigation --- src/_includes/layouts/base.njk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/_includes/layouts/base.njk b/src/_includes/layouts/base.njk index 3b4125b..7a306e0 100644 --- a/src/_includes/layouts/base.njk +++ b/src/_includes/layouts/base.njk @@ -24,6 +24,7 @@ Start Preamble The Way + Textbook Article Lab Projects Artifacts @@ -36,12 +37,13 @@
The Interdependent Way -

Canon, interpretation, research, implementation, and frontier claims are kept visibly distinct.

+

Canon, distributed textbook, interpretation, research, implementation, and frontier claims are kept visibly distinct.

hmmmHonest incompletion remains visible so the next action has somewhere true to begin.
From ff3726224ba81d1f54047e69e8e88381ee998203 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:15:48 -0700 Subject: [PATCH 11/24] Feature chapters zero through seven on home --- src/home/index.njk | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/home/index.njk b/src/home/index.njk index 45d77d3..7d528be 100644 --- a/src/home/index.njk +++ b/src/home/index.njk @@ -1,18 +1,24 @@ --- layout: layouts/base.njk title: The Interdependent Way -description: The living public knowledge system for the canon, its deliberate tensions, research, applications, and implementation projects. +description: The living public knowledge system for the canon, distributed textbook, deliberate tensions, research, applications, and implementation projects. permalink: /home/ ---
-

Canon · interpretation · research · implementation · frontier

+

Canon · textbook · interpretation · research · implementation · frontier

A way through complexity without pretending the tension is gone.

-

The Interdependent Way is a dense living text and a constellation of attempts to test, explain, implement, challenge, and preserve it. The Preamble is directly available here; deeper orientation and exact source remain available without hiding the entrance.

- +

The Interdependent Way is a dense living text and a constellation of attempts to test, explain, implement, challenge, and preserve it. The Preamble is directly available here; the distributed Interdependency textbook now restores chapters Zero through Seven into one reading sequence.

+
12 + 1
+
+

Distributed Interdependency textbook

+

Chapters Zero through Seven

+

Eight chapters now form one continuous technical reading path across metapat, ucns, edcm, skill-lib, interdependent-lib, ptcna, a0, and zfae. Each chapter remains bound to the license, status vocabulary, and authority of the repository that carries it.

+ +

Eight rights-article laboratories

From canon excerpt to public practice

@@ -26,6 +32,7 @@ permalink: /home/ Canon-derived

Return to Awakening

Re-enter the opening threshold and its reminder that you are not alone.

Canon-derived

Read the Preamble

Enter the opening civic claim directly through a stable route generated from the selected canon.

Canon-derived

Read the Way

Move through the preamble, articles, etiquette, addenda, and their internal structure without beginning at the raw wall of text.

+ Distributed textbook

Read Chapters Zero–Seven

Follow the technical architecture from root ontology through carrier, measurement, self-declaration, canon placement, architecture, instrument, and echo.

Interpretation

Enter the Article Lab

Test each Rights article through its notes, absurd limits, practice contrasts, domain applications, research support, dissent, and limits.

Publication

Read public articles

Follow selected canon units through companion readings, applications, handbook seeds, and script drafts without losing source boundaries.

Implementation

Map the Projects

Every public organization repository receives a generated space, grouped by function and refreshed at build time.

@@ -34,7 +41,7 @@ permalink: /home/

Current field snapshot

-

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

-

Project data was generated {{ generated.repos.snapshotAt | dateOnly }}{% if generated.repos.fallback %} from the last verified snapshot{% endif %}. Canon digest {{ generated.canon.source.contentSha256 }}.

+

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

+

Project data was generated {{ generated.repos.snapshotAt | dateOnly }}{% if generated.repos.fallback %} from the last verified snapshot{% endif %}. Canon digest {{ generated.canon.source.contentSha256 }}. Textbook complete: {{ generated.textbook.complete }}.

-

hmmm

Reviewed research now makes initial contact with all eight Rights articles, but coverage remains uneven and deliberately open to stronger dissent, replication, field studies, disability-led critique, and non-Western evidence.

+

hmmm

The textbook now has a complete public reading spine, while each chapter remains independently revisable in its source repository. The Article Lab research remains deliberately open to stronger dissent, replication, field studies, disability-led critique, and non-Western evidence.

From 5209c997c2b95ce2e006544c314e5eb88dc82111 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:18:02 -0700 Subject: [PATCH 12/24] Style distributed textbook reader --- src/assets/css/site.css | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/assets/css/site.css b/src/assets/css/site.css index 58b52ac..d9995be 100644 --- a/src/assets/css/site.css +++ b/src/assets/css/site.css @@ -84,6 +84,28 @@ h3 { font-size: clamp(1.2rem, 2vw, 1.55rem); } .canon-outline .unit-level-4 { margin-left: clamp(2rem, 6vw, 5rem); } .canon-outline .unit-level-3 a { border-left: .25rem solid var(--violet); } .canon-outline .unit-level-4 a { border-left: .25rem solid var(--cyan); background: rgba(9, 13, 24, .76); } +.chapter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); gap: 1rem; padding: 0; margin: 1.5rem 0 3rem; list-style: none; } +.chapter-grid li { min-width: 0; } +.chapter-card { height: 100%; } +.chapter-number { display: block; margin-bottom: .4rem; color: rgba(174, 187, 210, .42); font: 800 clamp(2.8rem, 7vw, 5rem)/1 Georgia, "Times New Roman", serif; letter-spacing: -.04em; } +.chapter-card small { display: block; margin-top: 1rem; color: var(--silver); overflow-wrap: anywhere; } +.chapter-head { margin-bottom: 1.5rem; } +.chapter-provenance { margin: 0 0 2rem; } +.textbook-chapter { max-width: 55rem; margin: 3rem auto; padding: clamp(1.1rem, 4vw, 3.2rem); border: 1px solid var(--line); border-radius: var(--radius); background: linear-gradient(180deg, rgba(16,24,42,.96), rgba(7,10,18,.96)); box-shadow: var(--shadow); } +.textbook-chapter > :first-child { margin-top: 0; } +.textbook-chapter h1 { font-size: clamp(2.2rem, 5vw, 4.6rem); } +.textbook-chapter h1 + h1 { margin-top: .6rem; color: var(--cyan); font-size: clamp(1.55rem, 3.5vw, 2.9rem); letter-spacing: -.025em; } +.textbook-chapter h2 { margin-top: 3.5rem; padding-top: 1rem; border-top: 1px solid var(--line); } +.textbook-chapter h3 { margin-top: 2.2rem; } +.textbook-chapter p, .textbook-chapter li { max-width: 76ch; } +.textbook-chapter blockquote { margin: 1.5rem 0; padding: .2rem 1.2rem; border-left: .3rem solid var(--violet); color: var(--silver); } +.textbook-chapter pre { max-width: 100%; padding: 1rem; overflow: auto; border: 1px solid var(--line); border-radius: .7rem; background: #05070c; } +.textbook-chapter code { overflow-wrap: anywhere; } +.textbook-chapter table { display: block; width: 100%; overflow-x: auto; border-collapse: collapse; } +.textbook-chapter th, .textbook-chapter td { padding: .65rem .8rem; border: 1px solid var(--line); text-align: left; vertical-align: top; } +.textbook-chapter th { background: var(--night-soft); } +.textbook-chapter hr { margin: 3rem 0; border: 0; border-top: 1px solid var(--line); } +.chapter-pagination { display: flex; align-items: center; justify-content: space-between; gap: .75rem; flex-wrap: wrap; margin: 3rem 0; } .source-block { white-space: pre-wrap; overflow-wrap: anywhere; padding: 1rem; border: 1px solid var(--line); border-radius: .8rem; background: #070a12; color: #dce6fa; font: .92rem/1.6 ui-monospace, SFMono-Regular, Consolas, monospace; } dl.meta { display: grid; grid-template-columns: minmax(9rem, .35fr) 1fr; gap: .45rem 1rem; } dl.meta dt { color: var(--silver); } @@ -110,8 +132,10 @@ summary { cursor: pointer; font-weight: 800; } .index-list a { grid-template-columns: 1fr; gap: .15rem; } .canon-outline .unit-level-3 { margin-left: .65rem; } .canon-outline .unit-level-4 { margin-left: 1.3rem; } + .textbook-chapter { padding: 1rem; } + .chapter-pagination .button { flex: 1 1 100%; } .site-footer { grid-template-columns: 1fr; } .hmmm-boundary { grid-column: auto; grid-template-columns: 1fr; } } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { scroll-behavior: auto !important; transition: none !important; } } -@media print { body { background: white; color: black; } body::before, .site-header, .actions, .noscript { display: none; } .site-main { max-width: none; padding: 0; } .card, .panel, .provenance, .hmmm, details { background: white; color: black; box-shadow: none; } a { color: black; } } +@media print { body { background: white; color: black; } body::before, .site-header, .actions, .noscript { display: none; } .site-main { max-width: none; padding: 0; } .card, .panel, .provenance, .hmmm, details, .textbook-chapter { background: white; color: black; box-shadow: none; } a { color: black; } } From 9587b54ad64106ba1b7a8ceb6ebbef8f2133344d Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:18:27 -0700 Subject: [PATCH 13/24] Test distributed textbook source integrity --- tests/textbook-integrity.test.mjs | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/textbook-integrity.test.mjs diff --git a/tests/textbook-integrity.test.mjs b/tests/textbook-integrity.test.mjs new file mode 100644 index 0000000..7b8f5ca --- /dev/null +++ b/tests/textbook-integrity.test.mjs @@ -0,0 +1,61 @@ +// Usage: run through `npm test`; OFFLINE=1 may produce metadata-only hmmm records when no retained snapshot exists. +// Evidence boundary: verifies source identity, order, hashes, and status labels; it does not validate each chapter's substantive claims. +import { createHash } from 'node:crypto'; +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; + +const expected = [ + [0, 'chapter-zero', 'Meta Energy Theory — Axioms, Postulates, and Theorems', 'The-Interdependency/metapat', 'CHAPTER_ZERO.md'], + [1, 'chapter-one', 'The Subtractive Foundations of the Unit Carrier', 'The-Interdependency/ucns', 'docs/chapter-1.md'], + [2, 'chapter-two', 'Measurement Without Transfer', 'The-Interdependency/edcm', 'docs/chapter-2.md'], + [3, 'chapter-three', 'Modules That Speak for Themselves', 'The-Interdependency/skill-lib', 'docs/chapter-3.md'], + [4, 'chapter-four', 'Canon Without Inversion', 'The-Interdependency/interdependent-lib', 'docs/chapter-4.md'], + [5, 'chapter-five', 'One Architecture, Four Layers', 'The-Interdependency/ptcna', 'docs/chapter-5.md'], + [6, 'chapter-six', 'The Instrument', 'The-Interdependency/a0', 'docs/chapter-6.md'], + [7, 'chapter-seven', 'The Echo', 'The-Interdependency/zfae', 'docs/chapter-7.md'] +]; + +test('distributed textbook manifest and generated data preserve chapters zero through seven', async () => { + const manifest = JSON.parse(await readFile('src/_data/textbook_sources.json', 'utf8')); + const textbook = JSON.parse(await readFile('src/_data/generated/textbook.json', 'utf8')); + + assert.equal(textbook.schema, 'interdependency.distributed-textbook/1.0.0'); + assert.equal(textbook.chapterCount, 8); + assert.equal(manifest.length, 8); + assert.equal(textbook.chapters.length, 8); + assert.equal(new Set(manifest.map(chapter => chapter.slug)).size, 8); + assert.equal(new Set(manifest.map(chapter => `${chapter.repository}:${chapter.path}`)).size, 8); + + for (const [number, slug, title, repository, path] of expected) { + const source = manifest[number]; + const chapter = textbook.chapters[number]; + assert.deepEqual( + [source.number, source.slug, source.title, source.repository, source.path], + [number, slug, title, repository, path] + ); + assert.deepEqual( + [chapter.number, chapter.slug, chapter.title, chapter.repository, chapter.path], + [number, slug, title, repository, path] + ); + assert.equal(chapter.branch, 'main'); + assert.ok(chapter.summary); + assert.ok(chapter.status); + assert.ok(chapter.sourceUrl?.startsWith(`https://github.com/${repository}/blob/`)); + + if (chapter.content) { + assert.ok(chapter.content.includes(title)); + assert.equal(createHash('sha256').update(chapter.content).digest('hex'), chapter.contentSha256); + assert.match(chapter.contentSha256, /^[a-f0-9]{64}$/); + if (!chapter.fallback) { + assert.match(chapter.commit, /^[a-f0-9]{40}$/); + assert.match(chapter.blob, /^[a-f0-9]{40}$/); + } + } else { + assert.equal(chapter.fallback, true); + assert.ok(chapter.retrievalError); + } + } + + assert.equal(textbook.chapters[7].status, 'theory under development'); +}); From 799408d83619999691944d135e84129944503e23 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:19:01 -0700 Subject: [PATCH 14/24] Verify all distributed textbook chapter routes --- tests/generated-site.test.mjs | 36 ++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/generated-site.test.mjs b/tests/generated-site.test.mjs index 7aef9f0..92a4e2f 100644 --- a/tests/generated-site.test.mjs +++ b/tests/generated-site.test.mjs @@ -6,10 +6,11 @@ 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, artifacts, fourCuts, fallback, articles] = await Promise.all([ + const [splash, home, preamble, chapters, artifacts, fourCuts, fallback, articles] = await Promise.all([ readFile('_site/index.html', 'utf8'), readFile('_site/home/index.html', 'utf8'), readFile('_site/preamble/index.html', 'utf8'), + readFile('_site/chapters/index.html', 'utf8'), readFile('_site/artifacts/index.html', 'utf8'), readFile('_site/artifacts/four-cuts/index.html', 'utf8'), readFile('_site/fallback/index.html', 'utf8'), @@ -25,11 +26,15 @@ test('generated deployment artifact contains the unified routes', async () => { assert.doesNotMatch(splash, /primary-nav/); assert.match(home, /A way through complexity/); assert.match(home, /href="\/preamble\/"[^>]*>Read the Preamble/); + assert.match(home, /href="\/chapters\/"/); + assert.match(home, /Chapters Zero through Seven/); assert.match(home, /href="\/"/); assert.match(home, /Return to Awakening/); assert.match(preamble, /One-click canon entrance/); assert.match(preamble, /Humanity faces extinction/); assert.match(preamble, /Canonical repository/); + assert.match(chapters, /The Interdependency Textbook/); + assert.match(chapters, /Chapters Zero through Seven/); assert.match(artifacts, /Artifacts/); assert.match(fourCuts, /Wealth and tax/); assert.match(fallback, /Emergency static edition/); @@ -46,6 +51,35 @@ test('generated deployment artifact contains the unified routes', async () => { ]) assert.match(articles, new RegExp(title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); }); +test('distributed textbook displays all eight exact chapter sources', async () => { + const textbook = JSON.parse(await readFile('src/_data/generated/textbook.json', 'utf8')); + const index = await readFile('_site/chapters/index.html', 'utf8'); + const contact = [ + /Zero is not nothing/, + /directed twofold branched angular cover/, + /NA != 0/, + /Modules That Speak for Themselves/, + /meta-package/, + /Prime Tensor Circled Neural Architecture/, + /research instrument, not a product/, + /theory under development/ + ]; + + assert.equal(textbook.chapters.length, 8); + for (const chapter of textbook.chapters) { + assert.match(index, new RegExp(`href="/chapters/${chapter.slug}/"`)); + assert.match(index, new RegExp(chapter.title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); + const html = await readFile(`_site/chapters/${chapter.slug}/index.html`, 'utf8'); + assert.match(html, /class="textbook-chapter"/); + assert.match(html, new RegExp(chapter.repository.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); + assert.match(html, new RegExp(chapter.path.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); + assert.match(html, /Open exact source in GitHub/); + assert.match(html, /Source evidence/); + assert.match(html, contact[chapter.number]); + } + assert.match(await readFile('_site/chapters/chapter-seven/index.html', 'utf8'), /theory under development/); +}); + test('Way map renders Human consciousness beneath Interdefinables and before Preamble', async () => { const way = await readFile('_site/way/index.html', 'utf8'); const interdefinablesSection = way.indexOf('

The Interdefinables

'); From 00c25d66a37f427c28f973746fd6dd8755ee1623 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:19:30 -0700 Subject: [PATCH 15/24] Test distributed textbook navigation --- tests/site.spec.mjs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/site.spec.mjs b/tests/site.spec.mjs index 0c5e3c7..cd7c703 100644 --- a/tests/site.spec.mjs +++ b/tests/site.spec.mjs @@ -4,6 +4,7 @@ import { readFileSync } from 'node:fs'; import { test, expect } from '@playwright/test'; const canon = JSON.parse(readFileSync('src/_data/generated/canon.json', 'utf8')); +const textbook = JSON.parse(readFileSync('src/_data/generated/textbook.json', 'utf8')); const articleLab = JSON.parse(readFileSync('src/_data/article_lab.json', 'utf8')); const labRoutes = articleLab.map(record => { const unit = canon.units.find(candidate => candidate.id === record.unit_id); @@ -15,6 +16,9 @@ const routes = [ ['/', /You are not alone/], ['/home/', /A way through complexity/], ['/preamble/', /Humanity faces extinction/], + ['/chapters/', /The Interdependency Textbook/], + ['/chapters/chapter-zero/', /Zero is not nothing/], + ['/chapters/chapter-seven/', /theory under development/], ['/articles/', /Publication drafts/], ['/articles/article-two/', /Freedom without abandonment/], ['/way/', /The Way/], @@ -51,11 +55,30 @@ test('Awakening is the public splash and preserves one-click continuation', asyn await expect(page.locator('.source-block')).toContainText('Humanity faces extinction'); }); -test('the knowledge-system home links back through Awakening and keeps Preamble in primary navigation', async ({ page }) => { +test('the knowledge-system home links to Awakening, Preamble, and the distributed textbook', async ({ page }) => { await page.goto('/home/'); await expect(page.locator('a.brand')).toHaveAttribute('href', '/home/'); await expect(page.locator('nav[aria-label="Primary navigation"] a[href="/"]', { hasText: 'Awakening' })).toBeVisible(); await expect(page.locator('nav[aria-label="Primary navigation"] a[href="/preamble/"]', { hasText: 'Preamble' })).toBeVisible(); + await expect(page.locator('nav[aria-label="Primary navigation"] a[href="/chapters/"]', { hasText: 'Textbook' })).toBeVisible(); + await expect(page.locator('main a[href="/chapters/"]').first()).toBeVisible(); +}); + +test('chapters zero through seven are indexed, source-bound, and sequentially navigable', async ({ page }) => { + await page.goto('/chapters/'); + for (const chapter of textbook.chapters) { + await expect(page.locator(`a[href="/chapters/${chapter.slug}/"]`)).toBeVisible(); + } + + await page.goto('/chapters/chapter-zero/'); + await expect(page.locator('.textbook-chapter')).toContainText('Zero is not nothing'); + await expect(page.locator('.chapter-provenance')).toContainText('The-Interdependency/metapat'); + await expect(page.locator('.chapter-pagination a', { hasText: 'Next chapter' })).toBeVisible(); + + await page.goto('/chapters/chapter-seven/'); + await expect(page.locator('.textbook-chapter')).toContainText('theory under development'); + await expect(page.locator('.chapter-provenance')).toContainText('The-Interdependency/zfae'); + await expect(page.locator('.status-frontier')).toContainText('theory under development'); }); test('all eight rights articles are reachable from the article index', async ({ page }) => { From 0c90fbc2b56d92a068d664bd700b1fba96192462 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:19:48 -0700 Subject: [PATCH 16/24] Audit textbook routes for accessibility --- tests/accessibility.spec.mjs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/accessibility.spec.mjs b/tests/accessibility.spec.mjs index e648fdd..2704b8a 100644 --- a/tests/accessibility.spec.mjs +++ b/tests/accessibility.spec.mjs @@ -1,5 +1,5 @@ // Usage: run `npm run test:a11y` after `npm run build`; serious and critical axe findings fail. -// Evidence boundary: automated axe checks do not replace manual keyboard, screen-reader, or cognitive-access review. +// Evidence boundary: automated axe checks do not replace manual keyboard, screen-reader, mathematical-notation, or cognitive-access review. import { readFileSync } from 'node:fs'; import { createRequire } from 'node:module'; import { test, expect } from '@playwright/test'; @@ -11,7 +11,10 @@ const articleLab = JSON.parse(readFileSync('src/_data/article_lab.json', 'utf8') const firstLabUnit = canon.units.find(unit => unit.id === articleLab[0].unit_id); if (!firstLabUnit) throw new Error(`missing Lab canon unit ${articleLab[0].unit_id}`); -for (const route of ['/', '/home/', '/preamble/', '/articles/', '/articles/article-two/', '/way/', '/lab/', `/lab/${firstLabUnit.routeSlug}/`, '/projects/']) { +for (const route of [ + '/', '/home/', '/preamble/', '/chapters/', '/chapters/chapter-zero/', '/chapters/chapter-seven/', + '/articles/', '/articles/article-two/', '/way/', '/lab/', `/lab/${firstLabUnit.routeSlug}/`, '/projects/' +]) { test(`${route} has no serious or critical automated accessibility violations`, async ({ page }) => { await page.goto(route); await page.addScriptTag({ path: axePath }); From 97c94c09df9bb1978aae88c76747c6d0d7e80bdb Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:20:23 -0700 Subject: [PATCH 17/24] Document distributed textbook routes and provenance --- README.md | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 97fdc61..d03dcc3 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,36 @@ # The Interdependent Way public knowledge system -This repository builds `interdependentway.org`: a static-first, progressively layered entrance to The Interdependent Way, its deliberate tensions, surrounding research, public artifacts, and the repositories attempting implementation. +This repository builds `interdependentway.org`: a static-first, progressively layered entrance to The Interdependent Way, its deliberate tensions, the distributed Interdependency textbook, surrounding research, public artifacts, and the repositories attempting implementation. ## What is authoritative -The canonical text lives in `wayseer00/main:canon/INTERDEPENDENT_WAY.txt`, and nowhere in this repository supersedes it. The repository copy at `canon/the_interdependent_way.md` is a recovery mirror only. Build output records whether the remote source or recovery mirror supplied the current snapshot, together with SHA-256 provenance; successful remote retrieval also records the resolved source commit and blob SHA. +The canonical text of **The Interdependent Way** lives in `wayseer00/main:canon/INTERDEPENDENT_WAY.txt`, and nowhere in this repository supersedes it. The repository copy at `canon/the_interdependent_way.md` is a recovery mirror only. Build output records whether the remote source or recovery mirror supplied the current snapshot, together with SHA-256 provenance; successful remote retrieval also records the resolved source commit and blob SHA. + +The **distributed Interdependency textbook** is a separate technical reading sequence. Chapters Zero through Seven remain owned by their source repositories: + +| Chapter | Title | Source | +|---:|---|---| +| 0 | Meta Energy Theory — Axioms, Postulates, and Theorems | `The-Interdependency/metapat:CHAPTER_ZERO.md` | +| 1 | The Subtractive Foundations of the Unit Carrier | `The-Interdependency/ucns:docs/chapter-1.md` | +| 2 | Measurement Without Transfer | `The-Interdependency/edcm:docs/chapter-2.md` | +| 3 | Modules That Speak for Themselves | `The-Interdependency/skill-lib:docs/chapter-3.md` | +| 4 | Canon Without Inversion | `The-Interdependency/interdependent-lib:docs/chapter-4.md` | +| 5 | One Architecture, Four Layers | `The-Interdependency/ptcna:docs/chapter-5.md` | +| 6 | The Instrument | `The-Interdependency/a0:docs/chapter-6.md` | +| 7 | The Echo | `The-Interdependency/zfae:docs/chapter-7.md` | + +This site displays exact, provenance-bearing chapter snapshots. It does not merge licenses or transfer theorem, proof, empirical, frontier, or canonical status between repositories. ## Architecture - `/` is the canon-derived **Awakening** splash page and public threshold. - `/home/` is the complete living knowledge-system entrance. - `/preamble/` remains one click from Awakening and from the primary navigation. +- `/chapters/` is the unified index for the eight-repository textbook. +- `/chapters/chapter-zero/` through `/chapters/chapter-seven/` render exact source Markdown with commit, blob, digest, and repository links. - Eleventy generates complete HTML into `_site`. - Pagefind supplies static search. -- GitHub organization and canon data are retrieved at build time, never in a visitor’s browser. +- GitHub organization, canon, and textbook source data are retrieved at build time, never in a visitor’s browser. - Every public organization repository receives a generated project page. - `.interdependency/project.yml` supplies reviewed project purpose, maturity, relationships, and links. - `fallback/` is a dependency-free emergency edition. @@ -28,18 +45,30 @@ npm run dev npm run check ``` -Use the recovery snapshots without network access: +Refresh only the textbook source set: + +```bash +npm run refresh:textbook +``` + +Use recovery snapshots without network access: ```bash OFFLINE=1 npm run build ``` +An offline build uses the retained last-known-good textbook snapshot when one exists. If a clean checkout has no retained chapter content, it renders metadata-only `hmmm` records rather than inventing or silently copying text. + Route checks after a build: ```text -/ Awakening threshold -/home/ knowledge-system entrance -/preamble/ direct canonical Preamble +/ Awakening threshold +/home/ knowledge-system entrance +/preamble/ direct canonical Preamble +/chapters/ textbook index +/chapters/chapter-zero/ Chapter Zero +... +/chapters/chapter-seven/ Chapter Seven ``` Add reviewed project metadata to a repository: @@ -60,6 +89,7 @@ Place that file at `.interdependency/project.yml`. Until it exists, the public p ## Status language - **canon** — exact or mechanically derived from the canonical source +- **distributed textbook** — exact source material whose status remains local to its owning repository - **interpretation** — explanatory material subject to review - **research** — externally sourced support, dissent, or context - **implemented** — a working public surface exists @@ -68,6 +98,6 @@ Place that file at `.interdependency/project.yml`. Until it exists, the public p ## Release discipline -GitHub Actions runs the workflow action audit, provenance refresh, article-to-canon exactness gate, build, validation, tests, static search generation, browser checks, accessibility checks, deployment, and live build-identity verification. The workflow audit requires full-length commit SHA pins and rejects tag refs, short SHAs, stale SHAs, or unapproved pins for the GitHub-owned actions used by this site. Failed builds do not replace the last successful Pages artifact. Emergency fallback deployment is explicit rather than automatic. +GitHub Actions runs the workflow action audit, canon and textbook provenance refresh, article-to-canon exactness gate, build, validation, tests, static search generation, browser checks, accessibility checks, deployment, and live build-identity verification. The textbook gate requires all eight current source files during an online production build and rejects missing content, reordered chapters, changed source locations, missing source identities, or silent fallback. The workflow action audit requires full-length commit SHA pins and rejects tag refs, short SHAs, stale SHAs, or unapproved pins for the GitHub-owned actions used by this site. Failed builds do not replace the last successful Pages artifact. Emergency fallback deployment is explicit rather than automatic. Repository source cannot configure the Pages source, custom domain, DNS, HTTPS, or branch protection. The required administrative settings and the release-truth contract are documented in [`docs/pages-release.md`](docs/pages-release.md). From bc260a36ca4779d646f0d52c740d0d5e6294a9c2 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Tue, 21 Jul 2026 10:20:49 -0700 Subject: [PATCH 18/24] Assert static textbook architecture --- tests/site-contract.test.mjs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/tests/site-contract.test.mjs b/tests/site-contract.test.mjs index 1850a89..836ba87 100644 --- a/tests/site-contract.test.mjs +++ b/tests/site-contract.test.mjs @@ -2,16 +2,19 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; -test('one static-first build owns public routes', async () => { +test('one static-first build owns public routes and exact Markdown rendering', async () => { const config = await readFile('.eleventy.js', 'utf8'); assert.match(config, /artifacts\/four-cuts-1\.html.*artifacts\/four-cuts\/index\.html/s); assert.match(config, /fallback/); + assert.match(config, /addFilter\('markdown'/); + assert.match(config, /html: false/); }); -test('base layout remains readable without javascript', async () => { +test('base layout remains readable without javascript and exposes the textbook', async () => { const layout = await readFile('src/_includes/layouts/base.njk', 'utf8'); assert.match(layout, /