diff --git a/.agents/rules/blog-system.md b/.agents/rules/blog-system.md index 1e87418..5e64605 100644 --- a/.agents/rules/blog-system.md +++ b/.agents/rules/blog-system.md @@ -74,14 +74,17 @@ --- ## 6. Test-Driven Development (TDD) & Adversarial Verification -1. **Red-Green-Refactor Lifecycle:** - - Write tests in `test/*.test.js` using Node's native test runner (`node:test`, `node:assert/strict`). - - Test inputs before implementing filters, data loaders, or template macros. -2. **Adversarial Test Coverage Required:** - - **Data & Configuration:** Test that missing required environment variables (e.g. `SITE_DOMAIN`) throw fatal errors. - - **Filters:** Test edge cases: empty strings, undefined values, single-word inputs, massive word counts, non-date objects. - - **Content Schemas:** Validate all Markdown files in `src/posts/` against frontmatter schemas. - - **Design Spec Compliance:** Automate regex/AST assertions on `src/assets/css/` ensuring zero violations of the "Do Not Use" list (`backdrop-filter`, `box-shadow`, `text-shadow`, gradients, floaty transitions). - - **Link & Anchor Integrity:** Verify that every compiled page has zero broken internal links and that all Table of Contents anchor links resolve to valid heading IDs. -3. **Execution Invariant:** - - Always run `npm test` before committing. All tests must pass cleanly with 0 failures. +1. **Strict Pre-Implementation Testing (Tests Before Functional Code):** + - Test cases MUST ALWAYS be written in `test/*.test.js` before writing or modifying any functional code (filters, templates, server routes, ingestion pipeline, data loaders, scripts). + - Never implement or modify functional or production code prior to writing and establishing corresponding automated tests. +2. **Mandatory Adversarial Test Coverage:** + - Standard behavior for any functional change MUST ALWAYS include adversarial testing specifically designed to stress assumptions and break the system: + - **Data & Configuration:** Test that missing required environment variables (e.g. `SITE_DOMAIN`) throw fatal errors. + - **Filters & Logic:** Test edge cases: empty strings, undefined/null values, unexpected types, single-word inputs, massive word counts, non-date objects. + - **Security & Integrity:** Test path traversals, malformed JSON, unauthorized tokens, malicious payloads. + - **Content Schemas:** Validate all Markdown files in `src/posts/` against frontmatter schemas. + - **Design Spec Compliance:** Automate regex/AST assertions on `src/assets/css/` ensuring zero violations of the "Do Not Use" list (`backdrop-filter`, `box-shadow`, `text-shadow`, gradients, floaty transitions). + - **Link & Anchor Integrity:** Verify that every compiled page has zero broken internal links and that all Table of Contents anchor links resolve to valid heading IDs. +3. **Pre-Presentation Verification Gate:** + - Before presenting the final output to the user, run `npm test`. + - All test cases must pass before presenting the final output. Presenting unverified output or code with failing tests is strictly prohibited. diff --git a/.agents/skills/eleventy-tiling-blog/SKILL.md b/.agents/skills/eleventy-tiling-blog/SKILL.md index 61e2499..568c8c9 100644 --- a/.agents/skills/eleventy-tiling-blog/SKILL.md +++ b/.agents/skills/eleventy-tiling-blog/SKILL.md @@ -98,9 +98,14 @@ When writing or modifying Eleventy files: --- ## 4. Validation & Verification + +Always follow the project TDD standard: write automated tests (including adversarial edge cases) in `test/` before modifying functional templates, filters, or configuration. Ensure all test cases pass before presenting the final output. -Run these commands to test Eleventy builds: +Run these commands to test and verify builds: ```bash +# Run complete test suite (unit tests, filters, server, design rules, build integrity) +npm test + # Validate Eleventy configuration and build static output npx @11ty/eleventy --dryrun @@ -110,3 +115,4 @@ npx @11ty/eleventy # Launch local dev server with auto-refresh npx @11ty/eleventy --serve ``` + diff --git a/.agents/skills/obsidian-sync/SKILL.md b/.agents/skills/obsidian-sync/SKILL.md index f0afe10..783ca4a 100644 --- a/.agents/skills/obsidian-sync/SKILL.md +++ b/.agents/skills/obsidian-sync/SKILL.md @@ -100,3 +100,13 @@ The Obsidian plugin runs inside Obsidian desktop/mobile and interacts with the O If using CouchDB-based self-hosted LiveSync: - A local watcher or CouchDB change listener daemon can be configured to detect updates to notes marked with `published: true` or in a dedicated `Blog/` folder. - When an update event fires, the daemon pulls the latest revision from the CouchDB database, runs the normalization pipeline, and saves it to `src/posts/`. + +--- + +## 6. Validation & Verification + +Always write automated test cases in `test/ingestion-api.test.js` before modifying or adding any functional synchronization or endpoint code: +- **Mandatory Adversarial Testing:** Include adversarial tests covering unauthorized tokens, invalid/missing frontmatter schemas, path traversals in slugs, and malformed base64 asset payloads. +- **Pre-Presentation Verification:** Run `npm test` and ensure all test cases pass before presenting the final output. + + diff --git a/AGENTS.md b/AGENTS.md index f1dbb09..465f71d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,14 +51,19 @@ Every component, style, and layout change must strictly adhere to [`sample-desig - **Typography:** IBM Plex Mono / JetBrains Mono for UI elements and code blocks; Inter for body prose. ### 2.4 Strict Test-Driven Development (TDD) & Adversarial Verification Mandate -- **Test-First Development:** For all new features, custom filters, template helpers, frontmatter schemas, or configuration changes, write automated tests asserting expected behaviors and edge cases *before* or alongside implementing the code. -- **Adversarial Mindset:** Actively design tests to break assumptions: - - Missing environment variables (e.g. unset `SITE_DOMAIN` must throw). - - Malformed frontmatter (missing titles, invalid dates, empty tags). - - Edge-case inputs to filters (empty strings, giant numbers, special characters). - - Design rule violations (asserting 0 instances of `backdrop-filter`, `box-shadow`, gradients, or floaty animations). - - Broken internal links and missing anchor tags in generated HTML. -- **Verification Gate:** Every code change must be verified by running `npm test`. No feature or commit is considered complete unless 100% of the test suite passes. +- **Strict Test-First Invariant (Tests Before Code):** + - Test cases MUST ALWAYS be written and established *before writing or modifying any functional code* (filters, templates, server routes, ingestion logic, build scripts). + - Never write or modify functional or production code before the corresponding automated tests are created. +- **Mandatory Adversarial Testing:** + - Standard behavior for any functional change MUST ALWAYS include adversarial testing specifically designed to falsify assumptions and break the implementation: + - Missing or malformed environment variables (e.g., unset `SITE_DOMAIN` must throw). + - Malformed frontmatter (missing required keys, invalid dates, malformed tags, extra/empty fields). + - Edge-case and malicious inputs to filters and functions (empty strings, undefined/null values, unexpected types, HTML injections, path traversals, giant payloads). + - Design rule violations (asserting 0 instances of `backdrop-filter`, `box-shadow`, gradients, or floaty animations). + - Broken internal links, missing assets, and broken TOC anchor tags. +- **Pre-Presentation Verification Gate:** + - Before presenting the final output to the user, the agent MUST run the full test suite (`npm test`). + - All test cases must pass before presenting the final output. Never deliver, present, or claim completion of work if any test case is failing or unverified. --- diff --git a/README.md b/README.md index 6902975..0c70087 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,12 @@ docker compose logs -f docker compose down ``` +### 2.3 Development Standards: Strict TDD & Adversarial Verification +This project enforces a strict test-first development lifecycle and verification standard: +1. **Tests Written Before Functional Code:** Automated test cases in `test/` must always be written before writing or modifying any functional code, filters, templates, server endpoints, or scripts. +2. **Mandatory Adversarial Testing:** Standard behavior for any functional change must always include adversarial test cases (boundary values, malformed/null inputs, unauthorized requests, path traversals, corrupt frontmatter, and design spec violations). +3. **Pre-Presentation Verification Gate:** Every change must be verified by running `npm test`. All test cases must pass before presenting the final output or committing code. + --- ## 3. Push & Update Cycles diff --git a/test/development-standards.test.js b/test/development-standards.test.js new file mode 100644 index 0000000..ef61e17 --- /dev/null +++ b/test/development-standards.test.js @@ -0,0 +1,112 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; + +const agentsMdPath = path.resolve("AGENTS.md"); +const rulesMdPath = path.resolve(".agents/rules/blog-system.md"); + +test("Development Standards: AGENTS.md enforces test-first, adversarial testing, and verification gates", () => { + assert.ok(fs.existsSync(agentsMdPath), "AGENTS.md must exist in root"); + const content = fs.readFileSync(agentsMdPath, "utf-8"); + + // 1. Must enforce writing tests BEFORE modifying functional/production code + assert.match( + content, + /before\s+(?:writing\s+or\s+)?modifying\s+(?:any\s+)?(?:functional|production)\s+code/i, + "AGENTS.md must explicitly mandate that tests are written before modifying functional/production code" + ); + + // 2. Must mandate adversarial testing + assert.match( + content, + /adversarial\s+test(?:ing|s)/i, + "AGENTS.md must mandate adversarial testing" + ); + + // 3. Must mandate that all tests pass before presenting final output + assert.match( + content, + /pass\s+before\s+presenting\s+(?:the\s+)?final\s+output/i, + "AGENTS.md must mandate that test cases pass before presenting final output" + ); +}); + +test("Development Standards: .agents/rules/blog-system.md enforces test-first, adversarial testing, and verification gates", () => { + assert.ok(fs.existsSync(rulesMdPath), ".agents/rules/blog-system.md must exist"); + const content = fs.readFileSync(rulesMdPath, "utf-8"); + + // 1. Must enforce writing tests BEFORE modifying functional/production code + assert.match( + content, + /before\s+(?:writing\s+or\s+)?modifying\s+(?:any\s+)?(?:functional|production)\s+code/i, + "blog-system.md must explicitly mandate that tests are written before modifying functional/production code" + ); + + // 2. Must mandate adversarial testing + assert.match( + content, + /adversarial\s+test(?:ing|s)/i, + "blog-system.md must mandate adversarial testing" + ); + + // 3. Must mandate that all tests pass before presenting final output + assert.match( + content, + /pass\s+before\s+presenting\s+(?:the\s+)?final\s+output/i, + "blog-system.md must mandate that test cases pass before presenting final output" + ); +}); + +test("Development Standards: Adversarial checks against vague or permissive testing language", () => { + const files = [agentsMdPath, rulesMdPath]; + for (const filePath of files) { + const content = fs.readFileSync(filePath, "utf-8"); + const relPath = path.relative(process.cwd(), filePath); + + // Adversarial: ensure no permissive "or alongside implementing" loophole exists + assert.doesNotMatch( + content, + /or\s+alongside\s+implementing/i, + `Violation in ${relPath}: Permissive loophole "or alongside implementing" must not exist; tests must strictly precede functional code` + ); + } +}); + +test("Development Standards: README.md and skills reference TDD, adversarial testing, and verification", () => { + const readmePath = path.resolve("README.md"); + assert.ok(fs.existsSync(readmePath), "README.md must exist"); + const readmeContent = fs.readFileSync(readmePath, "utf-8"); + + assert.match( + readmeContent, + /written\s+before\s+(?:writing\s+or\s+)?modifying\s+(?:any\s+)?functional\s+code/i, + "README.md must document writing tests before modifying functional code" + ); + assert.match( + readmeContent, + /adversarial\s+test(?:ing|s)/i, + "README.md must document mandatory adversarial testing" + ); + assert.match( + readmeContent, + /pass\s+before\s+presenting\s+(?:the\s+)?final\s+output/i, + "README.md must document that tests must pass before presenting final output" + ); + + // Check eleventy-tiling-blog skill + const eleventySkillPath = path.resolve(".agents/skills/eleventy-tiling-blog/SKILL.md"); + assert.ok(fs.existsSync(eleventySkillPath), "eleventy-tiling-blog SKILL.md must exist"); + const eleventySkill = fs.readFileSync(eleventySkillPath, "utf-8"); + assert.match(eleventySkill, /adversarial/i, "eleventy-tiling-blog SKILL.md must mention adversarial testing"); + assert.match(eleventySkill, /before\s+modifying\s+functional/i, "eleventy-tiling-blog SKILL.md must mandate tests before modifying functional code"); + + // Check obsidian-sync skill + const obsidianSkillPath = path.resolve(".agents/skills/obsidian-sync/SKILL.md"); + assert.ok(fs.existsSync(obsidianSkillPath), "obsidian-sync SKILL.md must exist"); + const obsidianSkill = fs.readFileSync(obsidianSkillPath, "utf-8"); + assert.match(obsidianSkill, /adversarial/i, "obsidian-sync SKILL.md must mention adversarial testing"); + assert.match(obsidianSkill, /before[*\s`_]+modifying/i, "obsidian-sync SKILL.md must mandate tests before modifying functional code"); +}); + +