section-source-cli-spec.test.mjs
131 lines 5.7 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * SectionSource Phase 1E local CLI implementation tests.
3 *
4 * Phase 1E adds the local CLI command, and later phases may add body-free
5 * self-hosted MCP only. It must not add hosted MCP, Hub, search, persistence,
6 * Scooling runtime behavior, section bodies, snippets, summaries, PageIndex,
7 * OCR, LLM calls, or provider routing.
8 */
9 import { describe, it } from 'node:test';
10 import assert from 'node:assert/strict';
11 import fs from 'fs';
12 import path from 'path';
13 import { fileURLToPath } from 'url';
14
15 import { readSectionSource } from '../lib/section-source-note.mjs';
16
17 const __dirname = path.dirname(fileURLToPath(import.meta.url));
18 const repoRoot = path.dirname(__dirname);
19 const fixtureVault = path.join(__dirname, 'fixtures', 'vault-fs');
20 const specPath = path.join(repoRoot, 'docs', 'SECTION-SOURCE-CLI-IMPLEMENTATION-SPEC.md');
21
22 function readRepoFile(relativePath) {
23 return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8');
24 }
25
26 describe('SectionSource Phase 1E local CLI implementation', () => {
27 it('unit: spec covers the required local CLI implementation areas', () => {
28 const spec = fs.readFileSync(specPath, 'utf8');
29 const requiredSections = [
30 '## Proposed Command',
31 '## Accepted Output',
32 '## Explicitly Excluded Output',
33 '## Error Behavior',
34 '## Authorization And Path Safety',
35 '## Transport Boundaries',
36 '## Seven-Tier Test Requirements',
37 '## Stop Conditions',
38 '## Acceptance Criteria',
39 ];
40
41 for (const section of requiredSections) {
42 assert.equal(spec.includes(section), true, `${section} is documented`);
43 }
44 assert.match(spec, /knowtation get-section-source <path> --json/);
45 assert.match(spec, /This phase adds the local CLI command only/);
46 });
47
48 it('integration: current SectionSource local integration remains the expected CLI target', () => {
49 const source = readSectionSource(fixtureVault, 'inbox/one.md');
50 const serialized = JSON.stringify(source);
51
52 assert.equal(source.schema, 'knowtation.section_source/v0');
53 assert.equal(source.path, 'inbox/one.md');
54 assert.equal(source.sections.every((section) => section.body_returned === false), true);
55 assert.equal(source.sections.every((section) => section.snippet_returned === false), true);
56 assert.equal(Object.hasOwn(source, 'body'), false);
57 assert.equal(Object.hasOwn(source, 'frontmatter'), false);
58 assert.equal(Object.hasOwn(source, 'snippet'), false);
59 assert.equal(serialized.includes('Body of inbox one'), false);
60 });
61
62 it('end-to-end: local CLI, self-hosted MCP, and hosted MCP are registered without Hub wiring', () => {
63 const cliSource = readRepoFile('cli/index.mjs');
64 const selfHostedMcp = readRepoFile('mcp/create-server.mjs');
65 const hostedMcp = readRepoFile('hub/gateway/mcp-hosted-server.mjs');
66 const hostedAcl = readRepoFile('hub/gateway/mcp-tool-acl.mjs');
67 const hubServer = readRepoFile('hub/gateway/server.mjs');
68
69 assert.equal(cliSource.includes('get-section-source'), true);
70 assert.equal(cliSource.includes('readSectionSource'), true);
71 assert.equal(selfHostedMcp.includes('get_section_source'), true);
72 assert.equal(selfHostedMcp.includes('readSectionSource'), true);
73 assert.equal(hostedMcp.includes('get_section_source'), true);
74 assert.equal(hostedMcp.includes('buildSectionSource'), true);
75 assert.equal(hostedAcl.includes('get_section_source'), true);
76 assert.equal(hostedMcp.includes('readSectionSource'), false);
77 assert.equal(hubServer.includes('get-section-source'), false);
78 assert.equal(hubServer.includes('get_section_source'), false);
79 assert.equal(hubServer.includes('section_source/v0'), false);
80 });
81
82 it('stress: CLI spec checks remain bounded to contract files', () => {
83 const started = Date.now();
84 const files = [
85 'docs/SECTION-SOURCE-CLI-IMPLEMENTATION-SPEC.md',
86 'docs/SECTION-SOURCE-TRANSPORT-PLAN.md',
87 'docs/SECTION-SOURCE-V0-SPEC.md',
88 'lib/section-source-note.mjs',
89 ].map((relativePath) => readRepoFile(relativePath));
90 const elapsedMs = Date.now() - started;
91
92 assert.equal(files.length, 4);
93 assert.ok(elapsedMs < 200, `expected bounded CLI spec check under 200ms, got ${elapsedMs}ms`);
94 });
95
96 it('data-integrity: local CLI adds no writes, sidecars, indexes, vectors, or summaries', () => {
97 const implementation = [
98 readRepoFile('lib/section-source.mjs'),
99 readRepoFile('lib/section-source-note.mjs'),
100 ].join('\n');
101
102 assert.doesNotMatch(implementation, /\bwriteFile(Sync)?\s*\(/);
103 assert.doesNotMatch(implementation, /\bappendFile(Sync)?\s*\(/);
104 assert.doesNotMatch(implementation, /\bsidecar[A-Za-z0-9_]*\s*=/);
105 assert.doesNotMatch(implementation, /\bvector[A-Za-z0-9_]*\s*=/);
106 assert.doesNotMatch(implementation, /\bsummary[A-Za-z0-9_]*\s*=/);
107 });
108
109 it('performance: spec requires one-note reads and no external providers', () => {
110 const spec = fs.readFileSync(specPath, 'utf8');
111
112 assert.match(spec, /The command reads one note only/);
113 assert.match(spec, /The command does not scan the whole vault/);
114 assert.match(spec, /The command does not call external providers/);
115 });
116
117 it('security: spec blocks body, snippet, hosted, search, persistence, and Scooling exposure', () => {
118 const spec = fs.readFileSync(specPath, 'utf8');
119 const blockedPhrases = [
120 'No note body text appears in output.',
121 'No section body text appears in output.',
122 'No snippets appear in output.',
123 'No full frontmatter appears in output.',
124 'Hosted, Scooling, classroom, search, and persistence exposure remain blocked.',
125 ];
126
127 for (const phrase of blockedPhrases) {
128 assert.equal(spec.includes(phrase), true, `${phrase} is documented`);
129 }
130 });
131 });
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago