@@ -4,6 +4,7 @@ type AgentRuntimeModule = {
44 createAgentWorkspaceRuntime : ( options ?: Record < string , unknown > ) => {
55 init : ( ) => void ;
66 sendConversation : ( ) => Promise < void > ;
7+ loadFoundationReadiness : ( ) => Promise < void > ;
78 openLearningPathDock : ( preferredAtomId ?: string ) => void ;
89 hidePathDock : ( ) => void ;
910 togglePathFullscreen : ( ) => void ;
@@ -20,6 +21,7 @@ type AgentRuntimeModule = {
2021 capabilityEvents : Array < Record < string , unknown > > ;
2122 lastCapabilityEvent : Record < string , unknown > | null ;
2223 lastConversation : Record < string , unknown > | null ;
24+ lastFoundationReadiness : Record < string , unknown > | null ;
2325 lastFailure : Record < string , unknown > | null ;
2426 pathState : {
2527 visible : boolean ;
@@ -68,6 +70,7 @@ function createShellHtml(): string {
6870 <button id="agent-workspace-open-learning-path" type="button">Learning Path</button>
6971 <button id="agent-workspace-close-learning-path" type="button">Close Path</button>
7072 <button id="agent-workspace-path-fullscreen" type="button">Path Fullscreen</button>
73+ <button id="agent-workspace-open-foundation-readiness" type="button">Foundation Readiness</button>
7174 <div id="agent-workspace-knowledge-list"></div>
7275 </aside>
7376 </body>
@@ -1528,6 +1531,7 @@ describe('agent workspace runtime behavior', () => {
15281531 'agentWorkspace.placeholders.input' : 'Ask in English' ,
15291532 'agentWorkspace.actions.pathFullscreen' : 'Path Fullscreen EN' ,
15301533 'agentWorkspace.actions.exitPathFullscreen' : 'Exit Path Fullscreen EN' ,
1534+ 'agentWorkspace.actions.openFoundationReadiness' : 'Foundation Readiness EN' ,
15311535 'agentWorkspace.messages.clickPointToFocus' : 'Click to focus EN' ,
15321536 'agentWorkspace.labels.score' : 'Score EN' ,
15331537 'agentWorkspace.actions.openLearningPath' : 'Open Learning Path EN' ,
@@ -1536,6 +1540,7 @@ describe('agent workspace runtime behavior', () => {
15361540 'agentWorkspace.placeholders.input' : '请用中文提问' ,
15371541 'agentWorkspace.actions.pathFullscreen' : '路径全屏 ZH' ,
15381542 'agentWorkspace.actions.exitPathFullscreen' : '退出路径全屏 ZH' ,
1543+ 'agentWorkspace.actions.openFoundationReadiness' : '基础就绪性 ZH' ,
15391544 'agentWorkspace.messages.clickPointToFocus' : '点击进入专注 ZH' ,
15401545 'agentWorkspace.labels.score' : '分数 ZH' ,
15411546 'agentWorkspace.actions.openLearningPath' : '打开学习路径 ZH' ,
@@ -1612,8 +1617,10 @@ describe('agent workspace runtime behavior', () => {
16121617 await flushAsync ( ) ;
16131618
16141619 const pathFullscreenButton = document . getElementById ( 'agent-workspace-path-fullscreen' ) as HTMLButtonElement ;
1620+ const readinessButton = document . getElementById ( 'agent-workspace-open-foundation-readiness' ) as HTMLButtonElement ;
16151621 expect ( input . placeholder ) . toBe ( 'Ask in English' ) ;
16161622 expect ( pathFullscreenButton . textContent ) . toBe ( 'Path Fullscreen EN' ) ;
1623+ expect ( readinessButton . textContent ) . toBe ( 'Foundation Readiness EN' ) ;
16171624 runtime . togglePathFullscreen ( ) ;
16181625 expect ( pathFullscreenButton . textContent ) . toBe ( 'Exit Path Fullscreen EN' ) ;
16191626
@@ -1633,6 +1640,7 @@ describe('agent workspace runtime behavior', () => {
16331640 const actionButtonZh = document . querySelector ( '.agent-workspace-action-button' ) as HTMLButtonElement ;
16341641 expect ( input . placeholder ) . toBe ( '请用中文提问' ) ;
16351642 expect ( pathFullscreenButton . textContent ) . toBe ( '退出路径全屏 ZH' ) ;
1643+ expect ( readinessButton . textContent ) . toBe ( '基础就绪性 ZH' ) ;
16361644 expect ( pointCardZh . title ) . toBe ( '点击进入专注 ZH' ) ;
16371645 expect ( pointMetaZh . textContent || '' ) . toContain ( '分数 ZH: 0.905' ) ;
16381646 expect ( actionButtonZh . textContent ) . toBe ( '打开学习路径 ZH' ) ;
@@ -1641,6 +1649,78 @@ describe('agent workspace runtime behavior', () => {
16411649 expect ( pathFullscreenButton . textContent ) . toBe ( '路径全屏 ZH' ) ;
16421650 } ) ;
16431651
1652+ test ( 'loads foundation readiness from toolbar and records diagnostics snapshot' , async ( ) => {
1653+ const fetchMock = jest . fn ( ) . mockResolvedValue ( {
1654+ ok : true ,
1655+ status : 200 ,
1656+ json : async ( ) => ( {
1657+ success : true ,
1658+ readiness : {
1659+ evaluatedAt : '2026-04-20T05:00:00.000Z' ,
1660+ status : 'in_progress' ,
1661+ decision : 'no-go' ,
1662+ baseline : {
1663+ storeType : 'file' ,
1664+ exists : true ,
1665+ loaded : true ,
1666+ fileBackedStore : true ,
1667+ graphAdapterModulePresent : true ,
1668+ vectorAdapterModulePresent : true ,
1669+ vectorAdapterStatus : 'prefilter_only' ,
1670+ vectorAdapterIndependent : false ,
1671+ } ,
1672+ documents : {
1673+ checklistPagesPresent : true ,
1674+ dashboardReferencesPresent : true ,
1675+ } ,
1676+ packageScripts : {
1677+ readinessVerifierPresent : true ,
1678+ } ,
1679+ mandatoryChecks : [
1680+ {
1681+ gateId : 'contract' ,
1682+ command : 'npm test -- src/knowledge.api.contract.test.ts --runInBand' ,
1683+ } ,
1684+ ] ,
1685+ recommendations : [
1686+ 'Keep foundation re-entry at no-go while the vector adapter remains a local prefilter boundary without independent ANN evidence on mainline.' ,
1687+ ] ,
1688+ } ,
1689+ } ) ,
1690+ } ) ;
1691+ ( global as unknown as Record < string , unknown > ) . fetch = fetchMock ;
1692+
1693+ const runtime = runtimeModule . createAgentWorkspaceRuntime ( { defaultUserId : 'agent_user_default' } ) ;
1694+ runtime . init ( ) ;
1695+
1696+ const readinessButton = document . getElementById ( 'agent-workspace-open-foundation-readiness' ) as HTMLButtonElement ;
1697+ readinessButton . click ( ) ;
1698+ await flushAsync ( ) ;
1699+
1700+ expect ( fetchMock ) . toHaveBeenCalledWith (
1701+ '/api/knowledge/foundation/readiness' ,
1702+ expect . objectContaining ( {
1703+ method : 'GET' ,
1704+ } )
1705+ ) ;
1706+
1707+ const messages = document . getElementById ( 'agent-workspace-messages' ) as HTMLElement ;
1708+ expect ( messages . textContent || '' ) . toContain ( 'Foundation readiness' ) ;
1709+ expect ( messages . textContent || '' ) . toContain ( 'prefilter_only' ) ;
1710+
1711+ const snapshot = runtime . getDiagnosticsSnapshot ( ) ;
1712+ expect ( snapshot . lastFoundationReadiness ) . toEqual (
1713+ expect . objectContaining ( {
1714+ status : 'in_progress' ,
1715+ decision : 'no-go' ,
1716+ storeType : 'file' ,
1717+ vectorAdapterStatus : 'prefilter_only' ,
1718+ vectorAdapterIndependent : false ,
1719+ recommendationsCount : 1 ,
1720+ } )
1721+ ) ;
1722+ } ) ;
1723+
16441724 test ( 'records replay candidates and capability execution diagnostics snapshot' , async ( ) => {
16451725 const fetchMock = jest
16461726 . fn ( )
0 commit comments