section-source-scooling-adapter-spec.test.mjs
154 lines 6.8 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * SectionSource Scooling adapter planning spec tests.
3 *
4 * Phase 1I accepts Scooling adapter planning only. It must not add Scooling
5 * runtime code, hosted get_section_source, Hub routes, search, persistence,
6 * write-back behavior, section bodies, snippets, summaries, PageIndex, OCR,
7 * 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-SCOOLING-ADAPTER-PLANNING-SPEC.md');
21
22 function readRepoFile(relativePath) {
23 return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8');
24 }
25
26 function hostedRuntimeSource() {
27 return [
28 readRepoFile('hub/gateway/mcp-hosted-server.mjs'),
29 readRepoFile('hub/gateway/mcp-tool-acl.mjs'),
30 readRepoFile('hub/gateway/server.mjs'),
31 ].join('\n');
32 }
33
34 function scoolingBoundarySource() {
35 return [
36 readRepoFile('hub/gateway/scooling-write-back-smoke.mjs'),
37 readRepoFile('hub/gateway/README.md'),
38 ].join('\n');
39 }
40
41 describe('SectionSource Scooling adapter planning spec', () => {
42 it('unit: spec covers required Scooling adapter decision areas', () => {
43 const spec = fs.readFileSync(specPath, 'utf8');
44 const requiredSections = [
45 '## Planning Decision',
46 '## Future Adapter Target',
47 '## Accepted Future Input Source',
48 '## Accepted Future Output',
49 '## Explicitly Excluded Output',
50 '## Authorization Boundary',
51 '## Fallback Behavior',
52 '## Prompt-Injection Handling',
53 '## Deletion, Export, And Staleness',
54 '## Write-Back Boundary',
55 '## Seven-Tier Test Requirements',
56 '## Stop Conditions',
57 '## Acceptance Criteria',
58 ];
59
60 for (const section of requiredSections) {
61 assert.equal(spec.includes(section), true, `${section} is documented`);
62 }
63 assert.match(spec, /Phase 1I accepts Scooling adapter planning only/);
64 assert.match(spec, /KnowtationVaultAdapter\.getSectionSource\(path\)/);
65 assert.match(spec, /Scooling remains a consumer/);
66 assert.match(spec, /Scooling adapter slice is complete in the Scooling repository at commit `ea5421e`/);
67 assert.match(readRepoFile('docs/SECTION-SOURCE-V0-SPEC.md'), /Phase 1J is implemented in the Scooling repository\s+at commit `ea5421e`/);
68 });
69
70 it('integration: current SectionSource output remains the only accepted body-free target', () => {
71 const source = readSectionSource(fixtureVault, 'inbox/one.md');
72 const serialized = JSON.stringify(source);
73
74 assert.equal(source.schema, 'knowtation.section_source/v0');
75 assert.equal(source.path, 'inbox/one.md');
76 assert.equal(source.sections.every((section) => section.body_returned === false), true);
77 assert.equal(source.sections.every((section) => section.snippet_returned === false), true);
78 assert.equal(Object.hasOwn(source, 'body'), false);
79 assert.equal(Object.hasOwn(source, 'frontmatter'), false);
80 assert.equal(Object.hasOwn(source, 'snippet'), false);
81 assert.equal(serialized.includes('Body of inbox one'), false);
82 });
83
84 it('end-to-end: hosted runtime is available while Scooling runtime exposure remains blocked', () => {
85 const hostedRuntime = hostedRuntimeSource();
86 const scoolingBoundary = scoolingBoundarySource();
87
88 assert.equal(hostedRuntime.includes('get_section_source'), true);
89 assert.equal(hostedRuntime.includes('buildSectionSource'), true);
90 assert.equal(hostedRuntime.includes('readSectionSource'), false);
91 assert.equal(scoolingBoundary.includes('get_section_source'), false);
92 assert.equal(scoolingBoundary.includes('section_source/v0'), false);
93 assert.equal(scoolingBoundary.includes('getSectionSource'), false);
94 assert.equal(scoolingBoundary.includes('SectionSource'), false);
95 });
96
97 it('stress: Scooling planning checks stay bounded to contract and smoke files', () => {
98 const started = Date.now();
99 const files = [
100 'docs/SECTION-SOURCE-SCOOLING-ADAPTER-PLANNING-SPEC.md',
101 'docs/SECTION-SOURCE-V0-SPEC.md',
102 'docs/SECTION-SOURCE-HOSTED-AUTHORIZATION-REVIEW-SPEC.md',
103 'hub/gateway/scooling-write-back-smoke.mjs',
104 'hub/gateway/README.md',
105 ].map((relativePath) => readRepoFile(relativePath));
106 const elapsedMs = Date.now() - started;
107
108 assert.equal(files.length, 5);
109 assert.ok(elapsedMs < 200, `expected bounded Scooling planning check under 200ms, got ${elapsedMs}ms`);
110 });
111
112 it('data-integrity: planning adds no writes, sidecars, indexes, vectors, summaries, or live write-back', () => {
113 const implementation = [
114 readRepoFile('lib/section-source.mjs'),
115 readRepoFile('lib/section-source-note.mjs'),
116 scoolingBoundarySource(),
117 ].join('\n');
118
119 assert.equal(scoolingBoundarySource().includes('allowLiveWrite !== false'), true);
120 assert.equal(scoolingBoundarySource().includes('performedLiveWrite: false'), true);
121 assert.doesNotMatch(implementation, /\bwriteFile(Sync)?\s*\(/);
122 assert.doesNotMatch(implementation, /\bappendFile(Sync)?\s*\(/);
123 assert.doesNotMatch(implementation, /\bsidecar[A-Za-z0-9_]*\s*=/);
124 assert.doesNotMatch(implementation, /\bvector[A-Za-z0-9_]*\s*=/);
125 assert.doesNotMatch(implementation, /\bsummary[A-Za-z0-9_]*\s*=/);
126 assert.doesNotMatch(implementation, /\bgetSectionSource\s*=/);
127 });
128
129 it('performance: spec requires one-note reads and no external providers', () => {
130 const spec = fs.readFileSync(specPath, 'utf8');
131
132 assert.match(spec, /The future adapter must request one note's SectionSource metadata at a time/);
133 assert.match(spec, /The future adapter must not scan the whole vault/);
134 assert.match(spec, /The future adapter must not call external providers/);
135 });
136
137 it('security: planning blocks body, snippet, hosted, search, persistence, write-back, and provider exposure', () => {
138 const spec = fs.readFileSync(specPath, 'utf8');
139 const blockedPhrases = [
140 'Scooling runtime exposure remains blocked in this phase.',
141 'No note body text appears in Scooling SectionSource output.',
142 'No section body text appears in Scooling SectionSource output.',
143 'No snippets appear in Scooling SectionSource output.',
144 'No full frontmatter appears in Scooling SectionSource output.',
145 'Hosted, classroom, search, persistence, write-back, and provider exposure remain blocked.',
146 ];
147
148 for (const phrase of blockedPhrases) {
149 assert.equal(spec.includes(phrase), true, `${phrase} is documented`);
150 }
151 assert.match(spec, /must not bypass Knowtation path, vault, hosted, or canister-user checks/);
152 assert.match(spec, /never parse Markdown as the canonical section source/);
153 });
154 });
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