import { describe, it, expect } from 'vitest' import { readFileSync } from 'node:fs' import { join } from 'node:path' const skill = () => readFileSync(join(__dirname, '../../skills/data-portal/SKILL.md'), 'utf8') // resolveSiteDir (platform/ui/server/routes/storage-broker.ts) resolves // //sites/ and refuses anything else with // invalid-site. A tree assembled where the skill used to say could not be // deployed at all. describe('data-portal SKILL.md names paths the broker accepts', () => { it('assembles into sites/, not pages/', () => { expect(skill()).toMatch(/\/sites\/\//) expect(skill()).not.toMatch(/assembled tree.*\bpages\/\//) expect(skill()).not.toMatch(/Copy `template\/` to [^\n]*pages\//) }) it('never tells the assembler to copy a public/ level', () => { expect(skill()).not.toMatch(/template\/public/) }) // site-deploy's canonical-tree section names pages// and instructs // reconciling stray trees into it. An assembler that follows it after // assembling at sites/ moves the tree somewhere the broker refuses, so the // skill has to say not to, for as long as the two disagree. it('warns against relocating the tree to site-deploy canonical path', () => { expect(skill()).toMatch(/Leave the tree where you assembled it/) expect(skill()).toMatch(/invalid-site/) }) }) describe('data-portal SKILL.md', () => { it('opens with frontmatter carrying name and description', () => { // Without these the skill is invisible to the available-skills reminder and // to skill-search. The defect is silent: no error, no log line. const text = skill() expect(text.startsWith('---\n')).toBe(true) const fm = text.slice(4, text.indexOf('\n---', 4)) expect(fm).toMatch(/^name:\s*data-portal\s*$/m) expect(fm).toMatch(/^description:\s*\S/m) }) it('declares the plugin-read convention (check-plugin-references.mjs)', () => { expect(skill()).toMatch(/plugin-read/) }) it('records the two-session provisioning sequence', () => { // The load-bearing sequencing decision: the broker registers a bucket to // whoever creates it, ON CREATE and never reassigned, so the client // account must create its own or its ingestion sweep is denied forever. const text = skill() expect(text).toMatch(/storage-r2-bucket-create/) expect(text).toMatch(/client|sub-account/i) }) it('names the passcode discipline', () => { expect(skill()).toMatch(/once/i) expect(skill()).toMatch(/never.*plaintext|plaintext.*never/i) }) it('routes store naming through cf-store-name.sh rather than hand-building', () => { // The script is already tested (bin/__tests__/cf-store-name.test.sh). What // is untested is that this skill defers to it — a hand-built name would // break the "name identifies owner and purpose" contract silently. expect(skill()).toMatch(/cf-store-name\.sh/) }) it('leaves no unfilled placeholder marker in its own prose', () => { expect(skill()).not.toMatch(/\bTBD\b|\bTODO\b/) }) })