diff --git a/.eleventy.js b/.eleventy.js index 70d7c99..ff847de 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -7,6 +7,7 @@ import { installMathRenderer } from './scripts/markdown-math.mjs'; // entrypoint: npm run build // tests: tests/site-contract.test.mjs, tests/math-rendering.test.mjs, tests/narratives.test.mjs, tests/generated-site.test.mjs // === END MODULE_BUILD === +// Usage: run `npm run build`; Eleventy emits the static site, copies root machine instructions, and preserves dependency-free public reading paths. export default function configureEleventy(eleventyConfig) { const md = installMathRenderer(markdownIt({ html: false, linkify: true, typographer: true })); @@ -14,6 +15,7 @@ export default function configureEleventy(eleventyConfig) { eleventyConfig.addPassthroughCopy({ 'src/assets': 'assets', 'CNAME': 'CNAME', + 'llms.txt': 'llms.txt', 'artifacts/four-cuts-1.html': 'artifacts/four-cuts/index.html', 'fallback': 'fallback' }); diff --git a/The-Interdependency.github.io_msdmd.ts b/The-Interdependency.github.io_msdmd.ts index 15ae574..5a9a83c 100644 --- a/The-Interdependency.github.io_msdmd.ts +++ b/The-Interdependency.github.io_msdmd.ts @@ -60,6 +60,74 @@ export default defineMsdmdCollection({ "file": "scripts/audit-workflows.mjs", "id": "workflow_action_audit" }, + { + "block": "BOUNDARIES", + "fields": { + "admin_only": "false", + "auth_boundary": "none", + "network_boundary": "none", + "owner": "Erin Spencer", + "pii": "none", + "secrets": "none", + "side_effects": "root llms.txt replacement on --apply", + "storage_boundary": "write", + "summary": "Reads repository source declarations and writes only the root llms.txt when explicitly invoked with --apply.", + "user_data_boundary": "none" + }, + "file": "scripts/build-llms.mjs", + "id": "llms_instruction_builder_boundary" + }, + { + "block": "CONTRACTS", + "fields": { + "class": "correctness", + "given": "a Markdown fenced-code example contains LLMS fence text", + "then": "the example contributes no declaration to llms.txt" + }, + "file": "scripts/build-llms.mjs", + "id": "llms_markdown_examples_ignored" + }, + { + "block": "CONTRACTS", + "fields": { + "class": "doctrine", + "given": "repository source files contain msdmd LLMS entries and the builder runs", + "then": "llms.txt is generated deterministically from project_overview, key_definitions, architecture_summary, and usage_rules entries" + }, + "file": "scripts/build-llms.mjs", + "id": "llms_root_generated_from_declarations" + }, + { + "block": "CONTRACTS", + "fields": { + "class": "safety", + "given": "a required LLMS entry is absent", + "then": "the generated section contains hmmm rather than invented content" + }, + "file": "scripts/build-llms.mjs", + "id": "llms_unknowns_visible" + }, + { + "block": "MODULE_BUILD", + "fields": { + "admin_only": "false", + "auth_boundary": "none", + "internal_surface": "parseLlmsText, collectLlmsEntries, generateLlms", + "module_kind": "instrument", + "module_name": "build-llms", + "network_boundary": "none", + "owner": "Erin Spencer", + "public_surface": "npm run build:llms, npm run check:llms", + "rollback": "remove the runner, its package scripts and tests, llms.txt passthrough, and root llms.txt together", + "rollout": "check:llms is required by npm run check; build:llms intentionally applies reviewed declaration changes", + "storage_boundary": "write", + "summary": "Generates and drift-checks the canonical root llms.txt from repository-local msdmd LLMS declarations.", + "tests": "tests/llms-build.test.mjs", + "user_data_boundary": "none" + }, + "file": "scripts/build-llms.mjs", + "id": "llms_instruction_builder" + }, { "block": "MODULE_BUILD", "fields": { @@ -569,6 +637,16 @@ export default defineMsdmdCollection({ "file": "src/eai/aicontext.11ty.js", "id": "ai_context_exact_distributed_sources" }, + { + "block": "CONTRACTS", + "fields": { + "class": "safety", + "given": "a reader encounters energy, current, drift, coherence, tensor, runtime, or orchestration vocabulary in copied source text", + "then": "the reader treats it according to source-local status and makes no present-state, measurement, access, synchronization, or capability claim without supplied cited evidence" + }, + "file": "src/eai/aicontext.11ty.js", + "id": "ai_context_grounded_inference_boundary" + }, { "block": "CONTRACTS", "fields": { @@ -589,13 +667,69 @@ export default defineMsdmdCollection({ "file": "src/eai/aicontext.11ty.js", "id": "ai_context_public_biography_boundary" }, + { + "block": "CONTRACTS", + "fields": { + "class": "accessibility", + "given": "the static site is built", + "then": "/llms.txt, homepage navigation, alternate-link metadata, and /sitemap.xml expose /eai/aicontext.md without changing its byte-zero contract" + }, + "file": "src/eai/aicontext.11ty.js", + "id": "ai_context_public_discovery" + }, + { + "block": "CONTRACTS", + "fields": { + "class": "identity", + "given": "the public biography is parsed as JSON-LD", + "then": "Erin Spencer has one canonical fragment @id on the deployed non-www endpoint and the identifier grants no authentication, authorization, runtime connection, or access" + }, + "file": "src/eai/aicontext.11ty.js", + "id": "ai_context_stable_person_identity" + }, + { + "block": "LLMS", + "fields": { + "content": "- `/eai/aicontext.md` begins at byte zero with Erin Spencer's connection contract, then publishes grounded interpretation rules, exact canon, eight exact source-owned textbook chapters, public biography JSON-LD, work-graph identity, and publication provenance." + }, + "file": "src/eai/aicontext.11ty.js", + "id": "architecture_summary" + }, + { + "block": "LLMS", + "fields": { + "ai_context": "One ordered machine-oriented Markdown artifact carrying the author contract, exact distributed source copies, public biography JSON-LD, provenance, interpretation boundaries, and unresolved continuation.", + "canon": "The canonical text of The Interdependent Way lives only at `wayseer00/main:canon/INTERDEPENDENT_WAY.txt`; website copies do not become authority.", + "hmmm": "The mandatory boundary object for unresolved constraints and honest incompletion.", + "json_ld_at_id": "A stable public identifier for one JSON-LD subject; it does not authenticate a person, authorize an action, connect a runtime, or grant access.", + "public_biography": "An author-requested public project biography with explicit privacy exclusions and field-level correction routing." + }, + "file": "src/eai/aicontext.11ty.js", + "id": "key_definitions" + }, + { + "block": "LLMS", + "fields": { + "content": "The Interdependent Way website is a static-first publication consumer for the sole canon in `wayseer00/main`, the distributed Interdependency textbook, and bounded public project context. Its machine entry point is `/eai/aicontext.md`." + }, + "file": "src/eai/aicontext.11ty.js", + "id": "project_overview" + }, + { + "block": "LLMS", + "fields": { + "content": "- Read `/eai/aicontext.md` from its first byte and preserve its source order, status labels, provenance, privacy limits, and `hmmm` boundaries." + }, + "file": "src/eai/aicontext.11ty.js", + "id": "usage_rules" + }, { "block": "MODULE_BUILD", "fields": { "admin_only": "false", "auth_boundary": "none", - "data_schema": "the-interdependency.stack-manifest/1.0.0, the-interdependency.distributed-publication/1.0.0, interdependentway.public-biography/1.0.0", - "internal_surface": "renderAiContext, buildWorkGraph, buildPublicationManifest", + "data_schema": "the-interdependency.stack-manifest/1.0.0, the-interdependency.distributed-publication/1.0.0, interdependentway.public-biography/1.0.0, interdependentway.inference-boundary/1.0.0", + "internal_surface": "renderAiContext, buildWorkGraph, buildPublicationManifest, interpretationBoundary", "module_kind": "route", "module_name": "aicontext", "network_boundary": "none", @@ -605,14 +739,35 @@ export default defineMsdmdCollection({ "rollback": "remove this template, biography record, aicontext checks, and route documentation together", "rollout": "Eleventy emits the route after online production validation resolves every required source without fallback", "storage_boundary": "read", - "summary": "Publishes one machine-oriented Markdown context file containing the exact connection contract, canonical Way copy, distributed textbook, public biography, and immutable source identities.", + "summary": "Publishes one discoverable, machine-oriented Markdown context file containing the exact connection contract, grounded interpretation rules, canonical Way copy, distributed textbook, public biography, and immutable source identities.", "tests": "tests/aicontext.test.mjs, tests/generated-site.test.mjs", - "unresolved": "signed source authentication, author-reviewed expansion of the public biography", + "unresolved": "signed source authentication, author-reviewed expansion of the public biography, empirical effectiveness across independent model providers", "user_data_boundary": "read" }, "file": "src/eai/aicontext.11ty.js", "id": "ai_context_publication" }, + { + "block": "MODULE_BUILD", + "fields": { + "admin_only": "false", + "auth_boundary": "none", + "internal_surface": "SitemapTemplate.render, collections.all, site.url", + "module_kind": "route", + "module_name": "sitemap", + "network_boundary": "none", + "owner": "Erin Spencer", + "public_surface": "/sitemap.xml", + "rollback": "remove this template and its discovery checks", + "rollout": "emitted by every Eleventy build", + "storage_boundary": "none", + "summary": "Publishes stable public page locations plus the collection-excluded AI-context endpoint for machine discovery.", + "tests": "tests/site-contract.test.mjs, tests/generated-site.test.mjs", + "user_data_boundary": "none" + }, + "file": "src/sitemap.11ty.js", + "id": "public_sitemap" + }, { "block": "CHECKS", "fields": { @@ -639,6 +794,19 @@ export default defineMsdmdCollection({ "file": "tests/aicontext.test.mjs", "id": "check_ai_context_exact_distributed_sources" }, + { + "block": "CHECKS", + "fields": { + "call": "self::checkGroundedInferenceBoundary", + "cleanup": "none", + "mutates": "none", + "proves": "ai_context_grounded_inference_boundary", + "requires": "node", + "timeout": "10" + }, + "file": "tests/aicontext.test.mjs", + "id": "check_ai_context_grounded_inference_boundary" + }, { "block": "CHECKS", "fields": { @@ -664,6 +832,71 @@ export default defineMsdmdCollection({ }, "file": "tests/aicontext.test.mjs", "id": "check_ai_context_public_biography_boundary" + }, + { + "block": "CHECKS", + "fields": { + "call": "self::checkStablePersonIdentity", + "cleanup": "none", + "mutates": "none", + "proves": "ai_context_stable_person_identity", + "requires": "node", + "timeout": "10" + }, + "file": "tests/aicontext.test.mjs", + "id": "check_ai_context_stable_person_identity" + }, + { + "block": "CHECKS", + "fields": { + "call": "self::checkAiContextPublicDiscovery", + "cleanup": "none", + "mutates": "none", + "proves": "ai_context_public_discovery", + "requires": "node", + "timeout": "10" + }, + "file": "tests/generated-site.test.mjs", + "id": "check_ai_context_public_discovery" + }, + { + "block": "CHECKS", + "fields": { + "call": "self::checkLlmsMarkdownExamplesIgnored", + "cleanup": "none", + "mutates": "none", + "proves": "llms_markdown_examples_ignored", + "requires": "node", + "timeout": "10" + }, + "file": "tests/llms-build.test.mjs", + "id": "check_llms_markdown_examples_ignored" + }, + { + "block": "CHECKS", + "fields": { + "call": "self::checkLlmsRootGeneratedFromDeclarations", + "cleanup": "none", + "mutates": "none", + "proves": "llms_root_generated_from_declarations", + "requires": "node", + "timeout": "10" + }, + "file": "tests/llms-build.test.mjs", + "id": "check_llms_root_generated_from_declarations" + }, + { + "block": "CHECKS", + "fields": { + "call": "self::checkLlmsUnknownsVisible", + "cleanup": "none", + "mutates": "none", + "proves": "llms_unknowns_visible", + "requires": "node", + "timeout": "10" + }, + "file": "tests/llms-build.test.mjs", + "id": "check_llms_unknowns_visible" } ], "edges": [ @@ -723,6 +956,13 @@ export default defineMsdmdCollection({ "source_id": "generated_site_test_server_boundary", "to": "Erin Spencer" }, + { + "from": "llms_instruction_builder_boundary", + "kind": "owns", + "source_block": "BOUNDARIES", + "source_id": "llms_instruction_builder_boundary", + "to": "Erin Spencer" + }, { "from": "public_build_identity_boundary", "kind": "owns", @@ -793,6 +1033,27 @@ export default defineMsdmdCollection({ "source_id": "check_ai_context_exact_distributed_sources", "to": "node" }, + { + "from": "check_ai_context_grounded_inference_boundary", + "kind": "calls", + "source_block": "CHECKS", + "source_id": "check_ai_context_grounded_inference_boundary", + "to": "self::checkGroundedInferenceBoundary" + }, + { + "from": "check_ai_context_grounded_inference_boundary", + "kind": "claims_proves", + "source_block": "CHECKS", + "source_id": "check_ai_context_grounded_inference_boundary", + "to": "ai_context_grounded_inference_boundary" + }, + { + "from": "check_ai_context_grounded_inference_boundary", + "kind": "requires", + "source_block": "CHECKS", + "source_id": "check_ai_context_grounded_inference_boundary", + "to": "node" + }, { "from": "check_ai_context_non_transfer_boundary", "kind": "calls", @@ -835,6 +1096,111 @@ export default defineMsdmdCollection({ "source_id": "check_ai_context_public_biography_boundary", "to": "node" }, + { + "from": "check_ai_context_public_discovery", + "kind": "calls", + "source_block": "CHECKS", + "source_id": "check_ai_context_public_discovery", + "to": "self::checkAiContextPublicDiscovery" + }, + { + "from": "check_ai_context_public_discovery", + "kind": "claims_proves", + "source_block": "CHECKS", + "source_id": "check_ai_context_public_discovery", + "to": "ai_context_public_discovery" + }, + { + "from": "check_ai_context_public_discovery", + "kind": "requires", + "source_block": "CHECKS", + "source_id": "check_ai_context_public_discovery", + "to": "node" + }, + { + "from": "check_ai_context_stable_person_identity", + "kind": "calls", + "source_block": "CHECKS", + "source_id": "check_ai_context_stable_person_identity", + "to": "self::checkStablePersonIdentity" + }, + { + "from": "check_ai_context_stable_person_identity", + "kind": "claims_proves", + "source_block": "CHECKS", + "source_id": "check_ai_context_stable_person_identity", + "to": "ai_context_stable_person_identity" + }, + { + "from": "check_ai_context_stable_person_identity", + "kind": "requires", + "source_block": "CHECKS", + "source_id": "check_ai_context_stable_person_identity", + "to": "node" + }, + { + "from": "check_llms_markdown_examples_ignored", + "kind": "calls", + "source_block": "CHECKS", + "source_id": "check_llms_markdown_examples_ignored", + "to": "self::checkLlmsMarkdownExamplesIgnored" + }, + { + "from": "check_llms_markdown_examples_ignored", + "kind": "claims_proves", + "source_block": "CHECKS", + "source_id": "check_llms_markdown_examples_ignored", + "to": "llms_markdown_examples_ignored" + }, + { + "from": "check_llms_markdown_examples_ignored", + "kind": "requires", + "source_block": "CHECKS", + "source_id": "check_llms_markdown_examples_ignored", + "to": "node" + }, + { + "from": "check_llms_root_generated_from_declarations", + "kind": "calls", + "source_block": "CHECKS", + "source_id": "check_llms_root_generated_from_declarations", + "to": "self::checkLlmsRootGeneratedFromDeclarations" + }, + { + "from": "check_llms_root_generated_from_declarations", + "kind": "claims_proves", + "source_block": "CHECKS", + "source_id": "check_llms_root_generated_from_declarations", + "to": "llms_root_generated_from_declarations" + }, + { + "from": "check_llms_root_generated_from_declarations", + "kind": "requires", + "source_block": "CHECKS", + "source_id": "check_llms_root_generated_from_declarations", + "to": "node" + }, + { + "from": "check_llms_unknowns_visible", + "kind": "calls", + "source_block": "CHECKS", + "source_id": "check_llms_unknowns_visible", + "to": "self::checkLlmsUnknownsVisible" + }, + { + "from": "check_llms_unknowns_visible", + "kind": "claims_proves", + "source_block": "CHECKS", + "source_id": "check_llms_unknowns_visible", + "to": "llms_unknowns_visible" + }, + { + "from": "check_llms_unknowns_visible", + "kind": "requires", + "source_block": "CHECKS", + "source_id": "check_llms_unknowns_visible", + "to": "node" + }, { "from": "ai_context_publication", "kind": "owns", @@ -926,6 +1292,13 @@ export default defineMsdmdCollection({ "source_id": "live_deployment_truth_gate", "to": "Erin Spencer" }, + { + "from": "llms_instruction_builder", + "kind": "owns", + "source_block": "MODULE_BUILD", + "source_id": "llms_instruction_builder", + "to": "Erin Spencer" + }, { "from": "public_build_identity", "kind": "owns", @@ -933,6 +1306,13 @@ export default defineMsdmdCollection({ "source_id": "public_build_identity", "to": "Erin Spencer" }, + { + "from": "public_sitemap", + "kind": "owns", + "source_block": "MODULE_BUILD", + "source_id": "public_sitemap", + "to": "Erin Spencer" + }, { "from": "related_works_registry_fetch", "kind": "owns", diff --git a/docs/aicontext.md b/docs/aicontext.md index 840b934..094292d 100644 --- a/docs/aicontext.md +++ b/docs/aicontext.md @@ -7,17 +7,24 @@ Read the file from its first byte. The author-supplied `EOF` connection contract is deliberately first and has no front matter, byte-order marker, HTML wrapper, or generated introduction before it. A consuming agent should then: 1. apply the opening content-creation and connection contract; -2. read the work-graph and publication manifests as JSON; -3. treat `` as an exact publication copy whose authority remains `wayseer00/main:canon/INTERDEPENDENT_WAY.txt`; -4. read textbook chapters in declared order from Zero through Seven while preserving each source-local status and license; -5. parse the JSON-LD inside `` and its vertical-bar context boundary; -6. carry ``, ``, and the closing `hmmm` into continuation rather than inventing completion. +2. apply `` before interpreting any copied project vocabulary; +3. read the work-graph and publication manifests as JSON; +4. treat `` as an exact publication copy whose authority remains `wayseer00/main:canon/INTERDEPENDENT_WAY.txt`; +5. read textbook chapters in declared order from Zero through Seven while preserving each source-local status and license; +6. parse the JSON-LD inside `` and its vertical-bar context boundary; +7. carry ``, ``, and the closing `hmmm` into continuation rather than inventing completion. + +The biography subject has the canonical JSON-LD identity `https://interdependentway.org/eai/aicontext.md#erin-spencer`. The `www` host redirects to this non-`www` canonical host. The identifier distinguishes the public record; it does not authenticate Erin, authorize actions, connect a runtime, or grant access. + +Machine discovery is redundant by design: the homepage links the endpoint, HTML pages advertise it with `rel="alternate"`, `/sitemap.xml` lists it, and `/llms.txt` supplies concise usage rules. These pointers do not alter the required byte-zero contract. Build and inspect locally: ```bash npm run build sed -n '1,120p' _site/eai/aicontext.md +npm run build:llms +npm run check:llms npm run check ``` @@ -70,6 +77,8 @@ Repository boundaries remain authority and provenance boundaries. The website co The endpoint transfers no authorship, ownership, license, canon, theorem, proof, certification, measurement, empirical, frontier, or authentication status between sources. Digests establish byte identity only. Every source has a correction target. Online production fails before Eleventy renders when canon or any required textbook chapter is missing or fallback. +Copied vocabulary does not establish live state. References to energy, currents, drift, coherence, tensors, runtimes, or orchestration retain the epistemic status of their owning source. They do not establish that any system is deployed, synchronized, observable, conscious, measurable, or accessible. An EDCM measurement claim requires an actual cited EDCM result record; vocabulary, association, or confident phrasing is not a readout. Missing evidence remains `hmmm` and must not be smuggled into a follow-up question as though it were observed. + The biography is intentionally public-scope. Its `privacy.excludedCategories` list records what is absent without publishing any excluded values. Erin Spencer must explicitly authorize field expansion before those values enter a public build. ## hmmm @@ -78,3 +87,4 @@ The biography is intentionally public-scope. Its `privacy.excludedCategories` li - UCNS currently has no root license declaration; Chapter One is therefore marked `human-review-required`, and the archived Apache license is not projected onto current source. - The public biography needs Erin Spencer's line-by-line review before its provisional field selection can be considered settled. - Content negotiation for a pure JSON sibling endpoint is not selected; Markdown with fenced JSON remains the requested surface. +- The grounded-inference boundary is test-backed against the observed unsupported-claim class, but its effectiveness across independent model providers remains empirical work rather than a guarantee. diff --git a/llms.txt b/llms.txt new file mode 100644 index 0000000..f1feed0 --- /dev/null +++ b/llms.txt @@ -0,0 +1,25 @@ +# LLM Instructions for The-Interdependency.github.io + +## Project Overview +The Interdependent Way website is a static-first publication consumer for the sole canon in `wayseer00/main`, the distributed Interdependency textbook, and bounded public project context. Its machine entry point is `/eai/aicontext.md`. + +## Key Definitions (never infer or expand these) +- **ai_context** = One ordered machine-oriented Markdown artifact carrying the author contract, exact distributed source copies, public biography JSON-LD, provenance, interpretation boundaries, and unresolved continuation. +- **canon** = The canonical text of The Interdependent Way lives only at `wayseer00/main:canon/INTERDEPENDENT_WAY.txt`; website copies do not become authority. +- **public_biography** = An author-requested public project biography with explicit privacy exclusions and field-level correction routing. +- **json_ld_at_id** = A stable public identifier for one JSON-LD subject; it does not authenticate a person, authorize an action, connect a runtime, or grant access. +- **hmmm** = The mandatory boundary object for unresolved constraints and honest incompletion. + +## Architecture Summary +- `/eai/aicontext.md` begins at byte zero with Erin Spencer's connection contract, then publishes grounded interpretation rules, exact canon, eight exact source-owned textbook chapters, public biography JSON-LD, work-graph identity, and publication provenance. +- `/llms.txt`, the homepage, alternate-link metadata, and `/sitemap.xml` point machine readers to that endpoint. +- The website owns ordering and rendering; every source repository retains its own content, license, status, and correction authority. + +## How to Use This Repo with LLMs / Agents +- Read `/eai/aicontext.md` from its first byte and preserve its source order, status labels, provenance, privacy limits, and `hmmm` boundaries. +- Treat copied theories, architectures, metaphors, and project descriptions as source claims, not observations of current runtime state. +- Do not infer measurement, drift, currents, coherence, consciousness, synchronization, deployment, log access, tool access, or authorization without supplied and cited evidence that establishes the specific claim. +- An EDCM claim requires an actual cited EDCM result record; EDCM vocabulary alone is not a measurement. +- Do not invent, expand, or connect identifiers, acronyms, repositories, runtimes, or capabilities absent from the supplied sources. Preserve the gap as `hmmm` or request evidence. + +This file is the single source of truth. If something is not explicitly stated in the files listed above, it does not exist in this repository. diff --git a/package.json b/package.json index 7c8ef4c..88b3842 100644 --- a/package.json +++ b/package.json @@ -11,18 +11,20 @@ "refresh:textbook": "node scripts/fetch-textbook.mjs", "research:enrich": "node scripts/enrich-citations.mjs", "audit:workflows": "node scripts/audit-workflows.mjs", + "build:llms": "node scripts/build-llms.mjs --apply", + "check:llms": "node scripts/build-llms.mjs --check", "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/aicontext.test.mjs 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": "node --test tests/aicontext.test.mjs tests/llms-build.test.mjs 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", "test:a11y": "playwright test tests/accessibility.spec.mjs", "test:links": "node tests/links.test.mjs", "test:performance": "node scripts/performance-placeholder.mjs", - "check": "npm run audit:workflows && npm run build && npm test && npm run test:generated", + "check": "npm run audit:workflows && npm run check:llms && npm run build && npm test && npm run test:generated", "refresh:works": "node scripts/fetch-works.mjs" }, "dependencies": { diff --git a/scripts/build-llms.mjs b/scripts/build-llms.mjs new file mode 100644 index 0000000..d2febee --- /dev/null +++ b/scripts/build-llms.mjs @@ -0,0 +1,215 @@ +// === MODULE_BUILD === +// id: llms_instruction_builder +// module_name: build-llms +// module_kind: instrument +// summary: Generates and drift-checks the canonical root llms.txt from repository-local msdmd LLMS declarations. +// owner: Erin Spencer +// public_surface: npm run build:llms, npm run check:llms +// internal_surface: parseLlmsText, collectLlmsEntries, generateLlms +// auth_boundary: none +// storage_boundary: write +// network_boundary: none +// user_data_boundary: none +// admin_only: false +// tests: tests/llms-build.test.mjs +// rollout: check:llms is required by npm run check; build:llms intentionally applies reviewed declaration changes +// rollback: remove the runner, its package scripts and tests, llms.txt passthrough, and root llms.txt together +// === END MODULE_BUILD === +// Usage: edit `LLMS` declarations beside their owning module, run `npm run build:llms`, inspect `llms.txt`, then run `npm run check:llms`; never hand-edit generated doctrine independently. + +// === BOUNDARIES === +// id: llms_instruction_builder_boundary +// summary: Reads repository source declarations and writes only the root llms.txt when explicitly invoked with --apply. +// auth_boundary: none +// storage_boundary: write +// network_boundary: none +// user_data_boundary: none +// admin_only: false +// pii: none +// secrets: none +// side_effects: root llms.txt replacement on --apply +// owner: Erin Spencer +// === END BOUNDARIES === + +// === CONTRACTS === +// id: llms_root_generated_from_declarations +// given: repository source files contain msdmd LLMS entries and the builder runs +// then: llms.txt is generated deterministically from project_overview, key_definitions, architecture_summary, and usage_rules entries +// class: doctrine +// +// id: llms_markdown_examples_ignored +// given: a Markdown fenced-code example contains LLMS fence text +// then: the example contributes no declaration to llms.txt +// class: correctness +// +// id: llms_unknowns_visible +// given: a required LLMS entry is absent +// then: the generated section contains hmmm rather than invented content +// class: safety +// === END CONTRACTS === + +import { readdir, readFile, writeFile } from 'node:fs/promises'; +import { extname, join, relative, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +const markerByExtension = new Map([ + ['.md', '#'], ['.markdown', '#'], ['.py', '#'], ['.rb', '#'], ['.sh', '#'], + ['.ts', '//'], ['.tsx', '//'], ['.js', '//'], ['.jsx', '//'], ['.mjs', '//'], + ['.rs', '//'], ['.go', '//'], ['.java', '//'], ['.c', '//'], ['.cpp', '//'], + ['.swift', '//'], ['.kt', '//'], ['.sql', '--'], ['.lua', '--'], ['.hs', '--'] +]); +const skippedDirectories = new Set([ + '.git', '.venv', '.pytest_cache', '.mypy_cache', '.next', '.nuxt', '.tox', + '__pycache__', '_site', 'build', 'dist', 'node_modules', 'target', 'test-results', 'tests', 'venv' +]); + +function markdownWithoutFencedCode(text) { + let inFence = false; + return text.split(/\r?\n/).map(line => { + const trimmed = line.trimStart(); + if (trimmed.startsWith('```') || trimmed.startsWith('~~~')) { + inFence = !inFence; + return ''; + } + return inFence ? '' : line; + }).join('\n'); +} + +export function parseLlmsText(text, marker = '#', source = '') { + const prepared = /\.md(?:own)?$/i.test(source) ? markdownWithoutFencedCode(text) : text; + const entries = []; + let inBlock = false; + let current = null; + let currentField = null; + const opening = `${marker} === LLMS ===`; + const closing = `${marker} === END LLMS ===`; + const prefix = `${marker} `; + + const emit = () => { + if (current) entries.push(current); + current = null; + currentField = null; + }; + + for (const rawLine of prepared.split(/\r?\n/)) { + const line = rawLine.trim(); + if (line === opening) { + emit(); + inBlock = true; + continue; + } + if (line === closing && inBlock) { + emit(); + inBlock = false; + continue; + } + if (!inBlock || !line.startsWith(prefix)) continue; + const body = line.slice(prefix.length); + if (body.startsWith('id:')) { + emit(); + current = { source, id: body.slice(3).trim(), fields: {} }; + continue; + } + if (!current) continue; + if (!body) { + if (currentField) current.fields[currentField] += '\n'; + continue; + } + if (body.startsWith(' ') && body.includes(':')) { + const separator = body.indexOf(':'); + currentField = body.slice(0, separator).trim(); + current.fields[currentField] = body.slice(separator + 1).trim(); + continue; + } + if (body.startsWith(' ') && currentField) { + current.fields[currentField] += `\n${body.slice(4)}`; + } + } + if (inBlock) emit(); + return entries; +} + +async function sourceFiles(root) { + const files = []; + async function walk(directory) { + const children = await readdir(directory, { withFileTypes: true }); + children.sort((left, right) => left.name.localeCompare(right.name)); + for (const child of children) { + if (child.isDirectory()) { + if (!skippedDirectories.has(child.name)) await walk(join(directory, child.name)); + } else if (child.isFile() && markerByExtension.has(extname(child.name).toLowerCase())) { + files.push(join(directory, child.name)); + } + } + } + await walk(root); + return files; +} + +export async function collectLlmsEntries(root = '.') { + const absoluteRoot = resolve(root); + const entries = []; + for (const path of await sourceFiles(absoluteRoot)) { + const extension = extname(path).toLowerCase(); + const source = relative(absoluteRoot, path); + entries.push(...parseLlmsText(await readFile(path, 'utf8'), markerByExtension.get(extension), source)); + } + return entries; +} + +function contentFor(entries, id) { + const values = entries + .filter(entry => entry.id === id && entry.fields.content?.trim()) + .map(entry => entry.fields.content.trim()); + return values.length ? values.join('\n\n') : 'hmmm'; +} + +export function generateLlms(entries, repositoryName = 'The-Interdependency.github.io') { + const definitions = entries + .filter(entry => entry.id === 'key_definitions') + .flatMap(entry => Object.entries(entry.fields)) + .filter(([key]) => key !== 'content') + .map(([key, value]) => `- **${key}** = ${value.trim() || 'hmmm'}`); + return [ + `# LLM Instructions for ${repositoryName}`, + '', + '## Project Overview', + contentFor(entries, 'project_overview'), + '', + '## Key Definitions (never infer or expand these)', + definitions.length ? definitions.join('\n') : '- **hmmm** = hmmm', + '', + '## Architecture Summary', + contentFor(entries, 'architecture_summary'), + '', + '## How to Use This Repo with LLMs / Agents', + contentFor(entries, 'usage_rules'), + '', + 'This file is the single source of truth. If something is not explicitly stated in the files listed above, it does not exist in this repository.', + '' + ].join('\n'); +} + +async function main() { + const root = resolve('.'); + const outputPath = join(root, 'llms.txt'); + const generated = generateLlms(await collectLlmsEntries(root)); + if (process.argv.includes('--apply')) { + await writeFile(outputPath, generated, 'utf8'); + console.log(`wrote ${outputPath}`); + } + if (process.argv.includes('--check')) { + const current = await readFile(outputPath, 'utf8').catch(() => null); + if (current !== generated) throw new Error(`llms-build drift: ${outputPath} differs from LLMS declarations`); + console.log('llms-build drift: pass'); + } else if (!process.argv.includes('--apply')) { + process.stdout.write(generated); + } +} + +if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) { + main().catch(error => { + console.error(error.message); + process.exitCode = 1; + }); +} diff --git a/src/_data/erin.public-biography.json b/src/_data/erin.public-biography.json index 2e1c059..730d95b 100644 --- a/src/_data/erin.public-biography.json +++ b/src/_data/erin.public-biography.json @@ -1,5 +1,6 @@ { "@context": "https://schema.org", + "@id": "https://interdependentway.org/eai/aicontext.md#erin-spencer", "@type": "Person", "schema": "interdependentway.public-biography/1.0.0", "name": "Erin Spencer", diff --git a/src/_includes/layouts/base.njk b/src/_includes/layouts/base.njk index 5e85397..baccefa 100644 --- a/src/_includes/layouts/base.njk +++ b/src/_includes/layouts/base.njk @@ -1,4 +1,5 @@ + @@ -8,6 +9,7 @@ {{ title or site.title }} + diff --git a/src/_includes/layouts/splash.njk b/src/_includes/layouts/splash.njk index e37e125..8ec33d0 100644 --- a/src/_includes/layouts/splash.njk +++ b/src/_includes/layouts/splash.njk @@ -26,6 +26,7 @@ {{ title or site.title }} + diff --git a/src/eai/aicontext.11ty.js b/src/eai/aicontext.11ty.js index ff90c96..2964168 100644 --- a/src/eai/aicontext.11ty.js +++ b/src/eai/aicontext.11ty.js @@ -6,24 +6,48 @@ import { readFileSync } from 'node:fs'; // id: ai_context_publication // module_name: aicontext // module_kind: route -// summary: Publishes one machine-oriented Markdown context file containing the exact connection contract, canonical Way copy, distributed textbook, public biography, and immutable source identities. +// summary: Publishes one discoverable, machine-oriented Markdown context file containing the exact connection contract, grounded interpretation rules, canonical Way copy, distributed textbook, public biography, and immutable source identities. // owner: Erin Spencer // public_surface: /eai/aicontext.md -// internal_surface: renderAiContext, buildWorkGraph, buildPublicationManifest +// internal_surface: renderAiContext, buildWorkGraph, buildPublicationManifest, interpretationBoundary // auth_boundary: none // storage_boundary: read // network_boundary: none // user_data_boundary: read // admin_only: false -// data_schema: the-interdependency.stack-manifest/1.0.0, the-interdependency.distributed-publication/1.0.0, interdependentway.public-biography/1.0.0 +// data_schema: the-interdependency.stack-manifest/1.0.0, the-interdependency.distributed-publication/1.0.0, interdependentway.public-biography/1.0.0, interdependentway.inference-boundary/1.0.0 // requires: canonical_source_fetch, canon_structure_materializer, distributed_textbook_fetch // tests: tests/aicontext.test.mjs, tests/generated-site.test.mjs // rollout: Eleventy emits the route after online production validation resolves every required source without fallback // rollback: remove this template, biography record, aicontext checks, and route documentation together -// unresolved: signed source authentication, author-reviewed expansion of the public biography +// unresolved: signed source authentication, author-reviewed expansion of the public biography, empirical effectiveness across independent model providers // === END MODULE_BUILD === // Usage: run `npm run build`, then read `_site/eai/aicontext.md`; production uses the same refreshed canon and chapter identities as the public readers. -// Limits: this publication copies source text without acquiring its canon, license, theorem, proof, measurement, empirical, or certification authority. +// Limits: this publication copies source text without acquiring its canon, license, theorem, proof, measurement, empirical, certification, runtime, authentication, authorization, or tool-access authority. + +// === LLMS === +// id: project_overview +// content: The Interdependent Way website is a static-first publication consumer for the sole canon in `wayseer00/main`, the distributed Interdependency textbook, and bounded public project context. Its machine entry point is `/eai/aicontext.md`. +// +// id: key_definitions +// ai_context: One ordered machine-oriented Markdown artifact carrying the author contract, exact distributed source copies, public biography JSON-LD, provenance, interpretation boundaries, and unresolved continuation. +// canon: The canonical text of The Interdependent Way lives only at `wayseer00/main:canon/INTERDEPENDENT_WAY.txt`; website copies do not become authority. +// public_biography: An author-requested public project biography with explicit privacy exclusions and field-level correction routing. +// json_ld_at_id: A stable public identifier for one JSON-LD subject; it does not authenticate a person, authorize an action, connect a runtime, or grant access. +// hmmm: The mandatory boundary object for unresolved constraints and honest incompletion. +// +// id: architecture_summary +// content: - `/eai/aicontext.md` begins at byte zero with Erin Spencer's connection contract, then publishes grounded interpretation rules, exact canon, eight exact source-owned textbook chapters, public biography JSON-LD, work-graph identity, and publication provenance. +// - `/llms.txt`, the homepage, alternate-link metadata, and `/sitemap.xml` point machine readers to that endpoint. +// - The website owns ordering and rendering; every source repository retains its own content, license, status, and correction authority. +// +// id: usage_rules +// content: - Read `/eai/aicontext.md` from its first byte and preserve its source order, status labels, provenance, privacy limits, and `hmmm` boundaries. +// - Treat copied theories, architectures, metaphors, and project descriptions as source claims, not observations of current runtime state. +// - Do not infer measurement, drift, currents, coherence, consciousness, synchronization, deployment, log access, tool access, or authorization without supplied and cited evidence that establishes the specific claim. +// - An EDCM claim requires an actual cited EDCM result record; EDCM vocabulary alone is not a measurement. +// - Do not invent, expand, or connect identifiers, acronyms, repositories, runtimes, or capabilities absent from the supplied sources. Preserve the gap as `hmmm` or request evidence. +// === END LLMS === // === BOUNDARIES === // id: ai_context_publication_boundary @@ -60,6 +84,21 @@ import { readFileSync } from 'node:fs'; // given: canon, textbook chapters, and biography share one public artifact // then: authorship, ownership, license, canonical, proof, certification, measurement, empirical, and authentication status do not transfer between sources // class: doctrine +// +// id: ai_context_stable_person_identity +// given: the public biography is parsed as JSON-LD +// then: Erin Spencer has one canonical fragment @id on the deployed non-www endpoint and the identifier grants no authentication, authorization, runtime connection, or access +// class: identity +// +// id: ai_context_grounded_inference_boundary +// given: a reader encounters energy, current, drift, coherence, tensor, runtime, or orchestration vocabulary in copied source text +// then: the reader treats it according to source-local status and makes no present-state, measurement, access, synchronization, or capability claim without supplied cited evidence +// class: safety +// +// id: ai_context_public_discovery +// given: the static site is built +// then: /llms.txt, homepage navigation, alternate-link metadata, and /sitemap.xml expose /eai/aicontext.md without changing its byte-zero contract +// class: accessibility // === END CONTRACTS === export const connectionContract = `EOF @@ -96,6 +135,43 @@ EOF`; const canonSnapshotPath = 'src/_data/snapshots/canon.last-known-good.md'; const biographyPath = 'src/_data/erin.public-biography.json'; const consumerRepository = 'The-Interdependency/The-Interdependency.github.io'; +export const publicPersonId = 'https://interdependentway.org/eai/aicontext.md#erin-spencer'; + +export const interpretationBoundary = { + schema: 'interdependentway.inference-boundary/1.0.0', + scope: 'interpretation of this public artifact', + addressing: { + person_id: publicPersonId, + identifier_is_authentication: false, + identifier_is_authorization: false, + identifier_is_runtime_connection: false + }, + grounding_rules: [ + 'Treat copied source text as source content, not evidence that a described system is deployed, running, connected, synchronized, or observable now.', + 'Treat framework terms according to their source-local definitions and epistemic status; do not convert metaphor, theory, architecture, or vocabulary into measurement.', + 'Do not introduce or expand an identifier, acronym, repository, runtime, relationship, or capability that is absent from the supplied sources.', + 'Do not frame an unsupported premise as an observation when asking a follow-up question; state the gap as hmmm and request the missing evidence.' + ], + measurement_gate: { + applies_to: [ + 'current or energy flow', + 'drift or anomalous flux', + 'coherence or phase-lock', + 'behavioral bleed-through', + 'consciousness or instantiation state' + ], + requires: 'a supplied, cited measurement record that identifies its source, instrument or method, input, and actual readout', + edcm_rule: 'An EDCM claim requires an actual cited EDCM result record; EDCM vocabulary alone is not a measurement.', + without_record: 'hmmm; do not state or imply that the condition was observed or measured' + }, + capability_gate: { + repository_association_grants_runtime_access: false, + public_context_grants_log_access: false, + public_context_grants_tool_access: false, + public_context_grants_synchronization: false, + statement_of_readiness_proves_capability: false + } +}; function sha256(value) { return createHash('sha256').update(value).digest('hex'); @@ -310,6 +386,7 @@ export function renderAiContext({ canon, canonText, textbook, biography, biograp const biographyJson = JSON.parse(biography); if (biographyJson.schema !== 'interdependentway.public-biography/1.0.0') throw new Error('aicontext biography schema drift'); + if (biographyJson['@id'] !== publicPersonId) throw new Error('aicontext biography identity drift'); if (biographyJson.privacy?.scope !== 'public project biography') throw new Error('aicontext biography privacy scope drift'); const biographyCopy = JSON.stringify(biographyJson, null, 2); const workGraph = buildWorkGraph({ canon, textbook, consumerCommit }); @@ -317,6 +394,9 @@ export function renderAiContext({ canon, canonText, textbook, biography, biograp let output = `${connectionContract}\n\n`; output += '\n\n'; + output += '\n```json\n'; + output += `${JSON.stringify(interpretationBoundary, null, 2)}\n`; + output += '```\n\n\n'; output += '\n```json\n'; output += `${JSON.stringify(workGraph, null, 2)}\n`; output += '```\n\n\n'; diff --git a/src/home/index.njk b/src/home/index.njk index 2a02c57..2d790e7 100644 --- a/src/home/index.njk +++ b/src/home/index.njk @@ -4,6 +4,7 @@ title: The Interdependent Way description: The living public knowledge system for the canon, distributed textbook, deliberate tensions, research, applications, and implementation projects. permalink: /home/ --- +

Canon · textbook · interpretation · research · implementation · frontier

@@ -13,6 +14,12 @@ permalink: /home/
12 + 1
+
+

AI and machine readers

+

One bounded context before inference

+

The machine-oriented context preserves the content contract, exact canon and textbook copies, public biography, provenance, and the boundary between source vocabulary and actual measurement.

+ +

Distributed Interdependency textbook

Chapters Zero through Seven

diff --git a/src/sitemap.11ty.js b/src/sitemap.11ty.js new file mode 100644 index 0000000..6a58d24 --- /dev/null +++ b/src/sitemap.11ty.js @@ -0,0 +1,48 @@ +// === MODULE_BUILD === +// id: public_sitemap +// module_name: sitemap +// module_kind: route +// summary: Publishes stable public page locations plus the collection-excluded AI-context endpoint for machine discovery. +// owner: Erin Spencer +// public_surface: /sitemap.xml +// internal_surface: SitemapTemplate.render, collections.all, site.url +// auth_boundary: none +// storage_boundary: none +// network_boundary: none +// user_data_boundary: none +// admin_only: false +// tests: tests/site-contract.test.mjs, tests/generated-site.test.mjs +// rollout: emitted by every Eleventy build +// rollback: remove this template and its discovery checks +// === END MODULE_BUILD === +// Usage: crawlers read `/sitemap.xml`; ordinary routes come from `collections.all`, while the deliberately collection-excluded AI context and root LLM instructions are listed explicitly. + +function escapeXml(value) { + return String(value) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + +export default class SitemapTemplate { + data() { + return { + permalink: 'sitemap.xml', + eleventyExcludeFromCollections: true + }; + } + + render({ collections, site }) { + const routes = (collections?.all || []) + .map(item => item.url) + .filter(Boolean); + routes.push('/eai/aicontext.md', '/llms.txt'); + const uniqueRoutes = [...new Set(routes)].sort(); + const entries = uniqueRoutes + .map(route => ` ${escapeXml(`${site.url}${route}`)}`) + .join('\n'); + return `\n\n${entries}\n\n`; + } +} diff --git a/tests/aicontext.test.mjs b/tests/aicontext.test.mjs index 1d79de7..db93c3e 100644 --- a/tests/aicontext.test.mjs +++ b/tests/aicontext.test.mjs @@ -6,6 +6,8 @@ import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { connectionContract, + interpretationBoundary, + publicPersonId, renderAiContext } from '../src/eai/aicontext.11ty.js'; @@ -41,6 +43,22 @@ import { // timeout: 10 // mutates: none // cleanup: none +// +// id: check_ai_context_stable_person_identity +// proves: ai_context_stable_person_identity +// call: self::checkStablePersonIdentity +// requires: node +// timeout: 10 +// mutates: none +// cleanup: none +// +// id: check_ai_context_grounded_inference_boundary +// proves: ai_context_grounded_inference_boundary +// call: self::checkGroundedInferenceBoundary +// requires: node +// timeout: 10 +// mutates: none +// cleanup: none // === END CHECKS === const sha256 = value => createHash('sha256').update(value).digest('hex'); @@ -121,6 +139,7 @@ export function checkExactDistributedSources() { export function checkPublicBiographyBoundary() { const publicBiography = extractJson('MACHINE READABLE BIOGRAPHY'); + assert.equal(publicBiography['@id'], publicPersonId); assert.equal(publicBiography.name, 'Erin Spencer'); assert.equal(publicBiography.privacy.scope, 'public project biography'); assert.ok(publicBiography.privacy.excludedCategories.includes('exact location')); @@ -130,6 +149,29 @@ export function checkPublicBiographyBoundary() { } } +export function checkStablePersonIdentity() { + const publicBiography = extractJson('MACHINE READABLE BIOGRAPHY'); + const boundary = extractJson('INTERPRETATION BOUNDARY'); + assert.equal(publicBiography['@id'], 'https://interdependentway.org/eai/aicontext.md#erin-spencer'); + assert.equal(boundary.addressing.person_id, publicBiography['@id']); + assert.equal(boundary.addressing.identifier_is_authentication, false); + assert.equal(boundary.addressing.identifier_is_authorization, false); + assert.equal(boundary.addressing.identifier_is_runtime_connection, false); +} + +export function checkGroundedInferenceBoundary() { + const boundary = extractJson('INTERPRETATION BOUNDARY'); + assert.deepEqual(boundary, interpretationBoundary); + assert.match(boundary.measurement_gate.edcm_rule, /actual cited EDCM result record/); + assert.match(boundary.measurement_gate.without_record, /^hmmm/); + assert.ok(boundary.measurement_gate.applies_to.includes('drift or anomalous flux')); + assert.equal(boundary.capability_gate.public_context_grants_log_access, false); + assert.equal(boundary.capability_gate.public_context_grants_tool_access, false); + assert.equal(boundary.capability_gate.public_context_grants_synchronization, false); + assert.match(boundary.grounding_rules.join(' '), /do not convert metaphor, theory, architecture, or vocabulary into measurement/i); + assert.match(boundary.grounding_rules.join(' '), /Do not introduce or expand an identifier, acronym, repository, runtime, relationship, or capability/i); +} + export function checkNonTransferBoundary() { const workGraph = extractJson('WORK GRAPH'); const publication = extractJson('PUBLICATION MANIFEST'); @@ -146,3 +188,5 @@ test('aicontext begins with the exact author-supplied connection contract', chec test('aicontext preserves the exact distributed source order and identities', checkExactDistributedSources); test('aicontext publishes only the bounded machine-readable biography', checkPublicBiographyBoundary); test('aicontext carries explicit cross-source non-transfer boundaries', checkNonTransferBoundary); +test('aicontext gives Erin one stable non-authorizing JSON-LD identity', checkStablePersonIdentity); +test('aicontext blocks unsupported live-state, measurement, and capability inference', checkGroundedInferenceBoundary); diff --git a/tests/generated-site.test.mjs b/tests/generated-site.test.mjs index b566bb7..e7e35c3 100644 --- a/tests/generated-site.test.mjs +++ b/tests/generated-site.test.mjs @@ -6,6 +6,32 @@ import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import { connectionContract } from '../src/eai/aicontext.11ty.js'; +// === CHECKS === +// id: check_ai_context_public_discovery +// proves: ai_context_public_discovery +// call: self::checkAiContextPublicDiscovery +// requires: node +// timeout: 10 +// mutates: none +// cleanup: none +// === END CHECKS === + +export async function checkAiContextPublicDiscovery() { + const [home, splash, sitemap, llms] = await Promise.all([ + readFile('_site/home/index.html', 'utf8'), + readFile('_site/index.html', 'utf8'), + readFile('_site/sitemap.xml', 'utf8'), + readFile('_site/llms.txt', 'utf8') + ]); + assert.match(home, /href="\/eai\/aicontext\.md"/); + assert.match(home, /rel="alternate" type="text\/markdown" href="\/eai\/aicontext\.md"/); + assert.match(splash, /rel="alternate" type="text\/markdown" href="\/eai\/aicontext\.md"/); + assert.match(sitemap, /https:\/\/interdependentway\.org\/eai\/aicontext\.md<\/loc>/); + assert.match(sitemap, /https:\/\/interdependentway\.org\/llms\.txt<\/loc>/); + assert.match(llms, /machine entry point is `\/eai\/aicontext\.md`/); + assert.match(llms, /EDCM claim requires an actual cited EDCM result record/); +} + // 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, narratives, jackAndDiane] = await Promise.all([ @@ -217,7 +243,16 @@ test('generated deployment artifact publishes the complete machine-oriented AI c const biographyMatch = /]*>\n\|\n```json\n([\s\S]*?)\n```\n\|\n<\/MACHINE READABLE BIOGRAPHY>/.exec(aicontext); assert.ok(biographyMatch); assert.deepEqual(JSON.parse(biographyMatch[1]), biography); + assert.equal(biography['@id'], 'https://interdependentway.org/eai/aicontext.md#erin-spencer'); + const interpretationMatch = /]*>\n```json\n([\s\S]*?)\n```\n<\/INTERPRETATION BOUNDARY>/.exec(aicontext); + assert.ok(interpretationMatch); + const interpretation = JSON.parse(interpretationMatch[1]); + assert.equal(interpretation.addressing.identifier_is_runtime_connection, false); + assert.equal(interpretation.capability_gate.public_context_grants_log_access, false); + assert.match(interpretation.measurement_gate.edcm_rule, /actual cited EDCM result record/); assert.match(aicontext, /"canonical_status_transfer": false/); assert.match(aicontext, /"digest_is_authentication": false/); assert.match(aicontext, /hmmm The endpoint now demonstrates intersession continuity/); }); + +test('generated site exposes the AI context through redundant machine discovery', checkAiContextPublicDiscovery); diff --git a/tests/llms-build.test.mjs b/tests/llms-build.test.mjs new file mode 100644 index 0000000..a1b459b --- /dev/null +++ b/tests/llms-build.test.mjs @@ -0,0 +1,54 @@ +// Usage: run `node --test tests/llms-build.test.mjs`; it verifies declaration parsing, fenced-example exclusion, visible unknowns, and committed llms.txt drift without network access. +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import { collectLlmsEntries, generateLlms, parseLlmsText } from '../scripts/build-llms.mjs'; + +// === CHECKS === +// id: check_llms_root_generated_from_declarations +// proves: llms_root_generated_from_declarations +// call: self::checkLlmsRootGeneratedFromDeclarations +// requires: node +// timeout: 10 +// mutates: none +// cleanup: none +// +// id: check_llms_markdown_examples_ignored +// proves: llms_markdown_examples_ignored +// call: self::checkLlmsMarkdownExamplesIgnored +// requires: node +// timeout: 10 +// mutates: none +// cleanup: none +// +// id: check_llms_unknowns_visible +// proves: llms_unknowns_visible +// call: self::checkLlmsUnknownsVisible +// requires: node +// timeout: 10 +// mutates: none +// cleanup: none +// === END CHECKS === + +export async function checkLlmsRootGeneratedFromDeclarations() { + const generated = generateLlms(await collectLlmsEntries('.')); + assert.equal(await readFile('llms.txt', 'utf8'), generated); + assert.match(generated, /machine entry point is `\/eai\/aicontext\.md`/); + assert.match(generated, /EDCM claim requires an actual cited EDCM result record/); +} + +export function checkLlmsMarkdownExamplesIgnored() { + const fixture = '# before\n```text\n# === LLMS ===\n# id: project_overview\n# content: counterfeit\n# === END LLMS ===\n```\n'; + assert.deepEqual(parseLlmsText(fixture, '#', 'fixture.md'), []); +} + +export function checkLlmsUnknownsVisible() { + const generated = generateLlms([], 'fixture'); + assert.match(generated, /## Project Overview\nhmmm/); + assert.match(generated, /\*\*hmmm\*\* = hmmm/); + assert.match(generated, /## How to Use This Repo with LLMs \/ Agents\nhmmm/); +} + +test('root llms.txt is generated from colocated declarations', checkLlmsRootGeneratedFromDeclarations); +test('Markdown fenced examples cannot become LLM declarations', checkLlmsMarkdownExamplesIgnored); +test('missing LLM declarations remain visible as hmmm', checkLlmsUnknownsVisible); diff --git a/tests/site-contract.test.mjs b/tests/site-contract.test.mjs index 34e4940..bb51a64 100644 --- a/tests/site-contract.test.mjs +++ b/tests/site-contract.test.mjs @@ -2,14 +2,32 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; +// Usage: run with `npm test`; source-level checks verify that machine-discovery declarations remain wired before generated-artifact checks run. + 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, /'llms\.txt': 'llms\.txt'/); assert.match(config, /addFilter\('markdown'/); assert.match(config, /html: false/); }); +test('machine discovery source surfaces name the bounded AI context', async () => { + const [home, base, splash, sitemap] = await Promise.all([ + readFile('src/home/index.njk', 'utf8'), + readFile('src/_includes/layouts/base.njk', 'utf8'), + readFile('src/_includes/layouts/splash.njk', 'utf8'), + readFile('src/sitemap.11ty.js', 'utf8') + ]); + assert.match(home, /href="\/eai\/aicontext\.md"/); + assert.match(home, /href="\/llms\.txt"/); + assert.match(base, /rel="alternate" type="text\/markdown" href="\/eai\/aicontext\.md"/); + assert.match(splash, /rel="alternate" type="text\/markdown" href="\/eai\/aicontext\.md"/); + assert.match(sitemap, /routes\.push\('\/eai\/aicontext\.md', '\/llms\.txt'\)/); + assert.match(sitemap, /permalink: 'sitemap\.xml'/); +}); + 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, /