Skip to content

Commit ff9143a

Browse files
committed
feat(knowledge): expose foundation readiness api
1 parent de0e54e commit ff9143a

15 files changed

Lines changed: 385 additions & 1 deletion

docs/brainstorms/2026-04-19-mainline-progress-reconciliation-and-post-m7-direction-requirements.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,17 @@ This document re-baselines current mainline truth on 2026-04-19, records what ch
162162
- `npm test -- src/learning/KnowledgeLearningPlatform.persistence.test.ts --runInBand`
163163
- The current working branch remains a reference source for future lanes, not a justification for direct wide merge.
164164

165-
## Execution Note (2026-04-20 M8.1)
165+
## Execution Note (2026-04-20 M8.1-M8.2)
166166

167167
- The smallest executed post-M7 slice is now an evidence bundle, not an adapter claim:
168168
- `npm run verify:foundation:readiness`
169169
- The bundle writes machine-readable baseline reports:
170170
- `build/foundation-readiness/foundation-readiness-latest.json`
171171
- `build/foundation-readiness/foundation-readiness-latest.md`
172+
- The next bounded execution slice exposes the same baseline through typed runtime/API surfaces:
173+
- `FoundationReadinessReport` / `FoundationReadinessAPI`
174+
- `GET /api/knowledge/foundation/readiness`
175+
- The readiness route is required to preserve honest repo-truth even under hermetic runtime/test roots.
172176
- Current expected outcome on `main` remains:
173177
- status `in_progress`
174178
- decision `no-go`

docs/diataxis/en/explanation/development-progress-dashboard.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,25 @@ Execution anchor:
639639
- `npm run docs:diataxis:check`
640640
- `npm run docs:site:build`
641641

642+
## Latest Mainline Increment (2026-04-20 M8.2 Foundation Readiness API Surface)
643+
644+
- Added a typed foundation-readiness contract surface on mainline:
645+
- `FoundationReadinessReport` in `src/learning/types.ts`
646+
- `FoundationReadinessAPI` in `src/learning/api.ts`
647+
- `getFoundationReadiness()` in `src/learning/KnowledgeLearningPlatform.ts`
648+
- Added operator/frontend-readable route wiring:
649+
- `GET /api/knowledge/foundation/readiness` in `src/server.ts`
650+
- Kept the scope evidence-first:
651+
- the route exposes current `in_progress` / `no-go` readiness state,
652+
- it does not claim graph/vector adapter integration that is still absent on `main`.
653+
- Hardened repo-root resolution so readiness truth remains correct in hermetic runtime/test project roots:
654+
- explicit runtime roots are accepted when valid,
655+
- fallback resolution still locates the real repo evidence bundle when temp runtime roots do not contain docs/package metadata.
656+
- Expanded regression coverage for the new API surface:
657+
- `src/knowledge.api.contract.test.ts`
658+
- `src/learning/KnowledgeLearningPlatform.test.ts`
659+
- `src/server.migration.test.ts`
660+
642661
## Latest Mainline Increment (2026-04-20 M8.1 Foundation Readiness Evidence Bundle)
643662

644663
- Added a dedicated readiness verifier for the post-M7 foundation lane:

docs/diataxis/en/explanation/foundation-reentry-readiness-checklist.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ Bundle note:
4646
- It packages current mainline truth into:
4747
- `build/foundation-readiness/foundation-readiness-latest.json`
4848
- `build/foundation-readiness/foundation-readiness-latest.md`
49+
- The same bounded readiness payload is also exposed through:
50+
- `GET /api/knowledge/foundation/readiness`
4951
- Current expected result on `main` is:
5052
- status `In Progress`
5153
- decision `No-Go`

docs/diataxis/zh/explanation/development-progress-dashboard.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,25 @@
642642
- `npm run docs:diataxis:check`
643643
- `npm run docs:site:build`
644644

645+
## 主线最新增量(2026-04-20 M8.2 Foundation Readiness API 面)
646+
647+
- 已在主线补齐 typed foundation-readiness 合同面:
648+
- `src/learning/types.ts` 中新增 `FoundationReadinessReport`
649+
- `src/learning/api.ts` 中新增 `FoundationReadinessAPI`
650+
- `src/learning/KnowledgeLearningPlatform.ts` 中新增 `getFoundationReadiness()`
651+
- 已增加可供运维/前端读取的路由接线:
652+
- `src/server.ts` 中新增 `GET /api/knowledge/foundation/readiness`
653+
- 仍保持 evidence-first 边界:
654+
- 该路由暴露当前 `in_progress` / `no-go` 状态,
655+
- 不会把主线尚不存在的 graph/vector adapter 说成已集成。
656+
- 已加固 repo-root 解析,避免 hermetic runtime/test project root 造成 readiness 误判:
657+
- 显式 runtime root 合法时优先使用,
658+
- temp runtime root 不含 docs/package 元数据时,会回退到真实仓库证据根。
659+
- 已补新 API 面的回归覆盖:
660+
- `src/knowledge.api.contract.test.ts`
661+
- `src/learning/KnowledgeLearningPlatform.test.ts`
662+
- `src/server.migration.test.ts`
663+
645664
## 主线最新增量(2026-04-20 M8.1 Foundation Readiness 证据打包)
646665

647666
- 已为 post-M7 foundation lane 增加独立就绪性验证命令:

docs/diataxis/zh/explanation/foundation-reentry-readiness-checklist.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
- 它会把当前主线事实写入:
4747
- `build/foundation-readiness/foundation-readiness-latest.json`
4848
- `build/foundation-readiness/foundation-readiness-latest.md`
49+
- 同一份受限 readiness 载荷现在也通过下列路由暴露:
50+
- `GET /api/knowledge/foundation/readiness`
4951
- 当前主线的预期结果是:
5052
- 状态 `In Progress`
5153
- 决策 `No-Go`

scripts/foundation-readiness-utils.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ function evaluateFoundationReadiness(options = {}) {
6969
const storeSource = readTextIfExists(storePath);
7070
const enDashboard = readTextIfExists(enDashboardPath);
7171
const zhDashboard = readTextIfExists(zhDashboardPath);
72+
const storeModulePresent = fileExists(storePath);
7273

7374
const fileBackedStore =
7475
storeSource.includes('createFileBackedKnowledgeGraphStore')
@@ -159,6 +160,9 @@ function evaluateFoundationReadiness(options = {}) {
159160
status,
160161
decision,
161162
baseline: {
163+
storeType: fileBackedStore ? 'file' : 'none',
164+
exists: storeModulePresent,
165+
loaded: storeModulePresent && storeSource.includes('loadSnapshot'),
162166
fileBackedStore,
163167
graphAdapterModulePresent,
164168
vectorAdapterModulePresent,
@@ -185,6 +189,9 @@ function formatFoundationReadinessMarkdown(result, reportPaths) {
185189
'',
186190
'## Baseline',
187191
'',
192+
`- Store type: ${result.baseline.storeType}`,
193+
`- Store evidence present: ${result.baseline.exists ? 'yes' : 'no'}`,
194+
`- Store load capability present: ${result.baseline.loaded ? 'yes' : 'no'}`,
188195
`- File-backed store evidence: ${result.baseline.fileBackedStore ? 'yes' : 'no'}`,
189196
`- Dedicated graph adapter module present: ${result.baseline.graphAdapterModulePresent ? 'yes' : 'no'}`,
190197
`- Dedicated vector adapter module present: ${result.baseline.vectorAdapterModulePresent ? 'yes' : 'no'}`,

scripts/verify-foundation-readiness.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ const DEFAULT_MARKDOWN_REPORT_NAME = 'foundation-readiness-latest.md';
1111
function printHumanReport(result, reportPaths) {
1212
console.log(`[Foundation Readiness] Status: ${result.status}`);
1313
console.log(`[Foundation Readiness] Decision: ${result.decision}`);
14+
console.log(`[Foundation Readiness] Store type: ${result.baseline.storeType}`);
15+
console.log(`[Foundation Readiness] Store evidence present: ${result.baseline.exists ? 'yes' : 'no'}`);
16+
console.log(`[Foundation Readiness] Store load capability present: ${result.baseline.loaded ? 'yes' : 'no'}`);
1417
console.log(
1518
`[Foundation Readiness] File-backed store evidence: ${result.baseline.fileBackedStore ? 'yes' : 'no'}`
1619
);

src/foundation.readiness.contract.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ type FoundationReadinessResult = {
1010
status: 'planned' | 'in_progress' | 'integrated';
1111
decision: 'go' | 'no-go';
1212
baseline: {
13+
storeType: 'none' | 'file';
14+
exists: boolean;
15+
loaded: boolean;
1316
fileBackedStore: boolean;
1417
graphAdapterModulePresent: boolean;
1518
vectorAdapterModulePresent: boolean;
@@ -98,6 +101,9 @@ describe('foundation readiness contract', () => {
98101

99102
expect(result.status).toBe('in_progress');
100103
expect(result.decision).toBe('no-go');
104+
expect(result.baseline.storeType).toBe('file');
105+
expect(result.baseline.exists).toBe(true);
106+
expect(result.baseline.loaded).toBe(true);
101107
expect(result.baseline.fileBackedStore).toBe(true);
102108
expect(result.baseline.graphAdapterModulePresent).toBe(false);
103109
expect(result.baseline.vectorAdapterModulePresent).toBe(false);
@@ -148,6 +154,9 @@ describe('foundation readiness contract', () => {
148154

149155
expect(result.status).toBe('integrated');
150156
expect(result.decision).toBe('go');
157+
expect(result.baseline.storeType).toBe('file');
158+
expect(result.baseline.exists).toBe(true);
159+
expect(result.baseline.loaded).toBe(false);
151160
expect(result.baseline.fileBackedStore).toBe(true);
152161
expect(result.baseline.graphAdapterModulePresent).toBe(true);
153162
expect(result.baseline.vectorAdapterModulePresent).toBe(true);

src/knowledge.api.contract.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ describe('Knowledge mastery API contract wiring', () => {
99
const endpoints = [
1010
'/api/knowledge/state',
1111
'/api/knowledge/store-diagnostics',
12+
'/api/knowledge/foundation/readiness',
1213
'/api/knowledge/operator/agent-workspace-diagnostics/index',
1314
'/api/knowledge/operator/agent-workspace-diagnostics/latest',
1415
'/api/knowledge/operator/agent-workspace-diagnostics/triage',
@@ -81,6 +82,7 @@ describe('Knowledge mastery API contract wiring', () => {
8182
'interface KnowledgeIngestAPI',
8283
'interface KnowledgeQueryAPI',
8384
'interface AgentConversationAPI',
85+
'interface FoundationReadinessAPI',
8486
'interface MasteryDiagnosticsAPI',
8587
'interface MasteryMisconceptionAPI',
8688
'interface LearningPathAPI',

src/learning/KnowledgeLearningPlatform.test.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
import * as fs from 'fs';
2+
import * as os from 'os';
3+
import * as path from 'path';
14
import { KnowledgeLearningPlatform } from './KnowledgeLearningPlatform';
5+
import { createFileBackedKnowledgeGraphStore } from './store';
26

37
describe('KnowledgeLearningPlatform', () => {
48
let nowIso: string;
@@ -1048,6 +1052,119 @@ describe('KnowledgeLearningPlatform', () => {
10481052
expect(state.sessionActionTelemetry.executionCount).toBeGreaterThanOrEqual(0);
10491053
});
10501054

1055+
test('foundation readiness resolves explicit repo roots without overclaiming missing adapters', async () => {
1056+
const tempRoot = fs.mkdtempSync(
1057+
path.join(fs.realpathSync(os.tmpdir()), 'noteconnection-foundation-platform-')
1058+
);
1059+
1060+
try {
1061+
const fakeRepoRoot = path.join(tempRoot, 'repo');
1062+
fs.mkdirSync(path.join(fakeRepoRoot, 'src', 'learning'), { recursive: true });
1063+
fs.mkdirSync(path.join(fakeRepoRoot, 'docs', 'diataxis', 'en', 'explanation'), { recursive: true });
1064+
fs.mkdirSync(path.join(fakeRepoRoot, 'docs', 'diataxis', 'zh', 'explanation'), { recursive: true });
1065+
1066+
fs.writeFileSync(
1067+
path.join(fakeRepoRoot, 'package.json'),
1068+
JSON.stringify(
1069+
{
1070+
scripts: {
1071+
'verify:foundation:readiness': 'node scripts/verify-foundation-readiness.js',
1072+
},
1073+
},
1074+
null,
1075+
2
1076+
),
1077+
'utf8'
1078+
);
1079+
fs.writeFileSync(
1080+
path.join(fakeRepoRoot, 'src', 'learning', 'store.ts'),
1081+
"export async function loadSnapshot() {}\nexport function createFileBackedKnowledgeGraphStore() {}\nexport const diagnostics = { storeType: 'file' };\n",
1082+
'utf8'
1083+
);
1084+
fs.writeFileSync(
1085+
path.join(
1086+
fakeRepoRoot,
1087+
'docs',
1088+
'diataxis',
1089+
'en',
1090+
'explanation',
1091+
'foundation-reentry-readiness-checklist.md'
1092+
),
1093+
'foundation checklist\n',
1094+
'utf8'
1095+
);
1096+
fs.writeFileSync(
1097+
path.join(
1098+
fakeRepoRoot,
1099+
'docs',
1100+
'diataxis',
1101+
'zh',
1102+
'explanation',
1103+
'foundation-reentry-readiness-checklist.md'
1104+
),
1105+
'foundation checklist\n',
1106+
'utf8'
1107+
);
1108+
fs.writeFileSync(
1109+
path.join(
1110+
fakeRepoRoot,
1111+
'docs',
1112+
'diataxis',
1113+
'en',
1114+
'explanation',
1115+
'development-progress-dashboard.md'
1116+
),
1117+
'foundation-reentry-readiness-checklist\n',
1118+
'utf8'
1119+
);
1120+
fs.writeFileSync(
1121+
path.join(
1122+
fakeRepoRoot,
1123+
'docs',
1124+
'diataxis',
1125+
'zh',
1126+
'explanation',
1127+
'development-progress-dashboard.md'
1128+
),
1129+
'foundation-reentry-readiness-checklist\n',
1130+
'utf8'
1131+
);
1132+
1133+
const readinessPlatform = new KnowledgeLearningPlatform({
1134+
nowProvider: () => new Date(nowIso),
1135+
projectRoot: fakeRepoRoot,
1136+
store: createFileBackedKnowledgeGraphStore({
1137+
filePath: path.join(tempRoot, 'runtime_data', 'knowledge_graph_store.v1.json'),
1138+
}),
1139+
});
1140+
1141+
const readiness = await readinessPlatform.getFoundationReadiness();
1142+
1143+
expect(readiness.status).toBe('in_progress');
1144+
expect(readiness.decision).toBe('no-go');
1145+
expect(readiness.baseline.storeType).toBe('file');
1146+
expect(readiness.baseline.exists).toBe(false);
1147+
expect(readiness.baseline.loaded).toBe(false);
1148+
expect(readiness.baseline.fileBackedStore).toBe(true);
1149+
expect(readiness.baseline.graphAdapterModulePresent).toBe(false);
1150+
expect(readiness.baseline.vectorAdapterModulePresent).toBe(false);
1151+
expect(readiness.documents.checklistPagesPresent).toBe(true);
1152+
expect(readiness.documents.dashboardReferencesPresent).toBe(true);
1153+
expect(readiness.packageScripts.readinessVerifierPresent).toBe(true);
1154+
expect(readiness.mandatoryChecks.map((entry) => entry.gateId)).toEqual(
1155+
expect.arrayContaining([
1156+
'contract',
1157+
'core_behavior',
1158+
'persistence_safety',
1159+
'interaction_non_regression',
1160+
'documentation',
1161+
])
1162+
);
1163+
} finally {
1164+
fs.rmSync(tempRoot, { recursive: true, force: true });
1165+
}
1166+
});
1167+
10511168
test('tutor action uses misconception context for targeted guidance', async () => {
10521169
const ingest = await platform.ingestKnowledge({
10531170
incremental: true,

0 commit comments

Comments
 (0)