Skip to content

Commit 321a6eb

Browse files
committed
feat: preserve readiness action details in runtime
1 parent 241e699 commit 321a6eb

9 files changed

Lines changed: 99 additions & 3 deletions

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ This document re-baselines current mainline truth on 2026-04-19, records what ch
233233
- agent-workspace diagnostics snapshots now persist `mandatoryCheckIds`
234234
- toolbar summaries now render the same gate ids exposed by `mandatoryChecks`
235235
- overall status still remains `in_progress` / `no-go`.
236+
- The next bounded execution slice after that makes runtime actionable-detail parity explicit:
237+
- agent-workspace diagnostics snapshots now persist full `mandatoryChecks`, `promotionBlockers`, and `recommendations`
238+
- toolbar summaries now expose recommendation counts alongside the existing gate/blocker ids
239+
- overall status still remains `in_progress` / `no-go`.
236240
- Current expected outcome on `main` remains:
237241
- status `in_progress`
238242
- decision `no-go`

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,20 @@ Execution anchor:
340340
- decision stays `no-go`,
341341
- gate parity improves inspectability only; it does not weaken the promotion contract.
342342

343+
## Latest Mainline Increment (2026-04-20 M8.17 Foundation Runtime Actionable-Detail Parity)
344+
345+
- Closed the next operator-runtime parity gap for actionable readiness detail arrays already present in the typed payload:
346+
- `lastFoundationReadiness.mandatoryChecks`
347+
- `lastFoundationReadiness.promotionBlockers`
348+
- `lastFoundationReadiness.recommendations`
349+
- Runtime/operator visibility now keeps the same actionable detail used by exported diagnostics:
350+
- toolbar summaries expose `recommendations 2` alongside existing gate/blocker ids,
351+
- diagnostics snapshots preserve full gate commands, blocker summaries, and recommendation strings for downstream report consumers.
352+
- Guardrail remains unchanged on `main`:
353+
- status stays `in_progress`,
354+
- decision stays `no-go`,
355+
- actionable-detail parity improves inspectability only; it does not relax the no-go contract.
356+
343357
## Latest Mainline Increment (2026-04-20 M8.13 Foundation Readiness Provenance Evidence)
344358

345359
- Added machine-readable provenance so operator tooling can tell whether readiness is reading the runtime project root or falling back to real repo evidence:

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Bundle note:
5454
- runbook link `foundation-reentry-readiness-checklist`
5555
- runtime snapshots now preserve both `promotionCriteriaSatisfiedIds` and `promotionCriteriaUnsatisfiedIds`
5656
- runtime snapshots now preserve `mandatoryCheckIds` for the active gate contract
57+
- runtime snapshots now preserve full `mandatoryChecks`, `promotionBlockers`, and `recommendations`
5758
- Current expected result on `main` is:
5859
- status `In Progress`
5960
- decision `No-Go`
@@ -90,6 +91,7 @@ Bundle note:
9091
- `promotionCriteriaUnsatisfiedIds = [graph_backend_independent, vector_backend_independent]`
9192
- Current expected runtime/operator summary phrasing on `main` is:
9293
- `gates contract, core_behavior, persistence_safety, interaction_non_regression, documentation`
94+
- `recommendations 2`
9395
- `satisfied store_backend_evidence_present, query_backend_boundary_present, vector_backend_present, docs_aligned, readiness_verifier_present`
9496
- `unmet graph_backend_independent, vector_backend_independent`
9597
- Current expected provenance behavior is:

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,20 @@
340340
- 决策仍为 `no-go`
341341
- gate 对齐只提升可检查性,不会削弱 promotion contract。
342342

343+
## 主线最新增量(2026-04-20 M8.17 Foundation 运行时可执行细节对齐)
344+
345+
- 已补齐 typed readiness payload 中可执行细节数组在运行时中的下一处对齐缺口:
346+
- `lastFoundationReadiness.mandatoryChecks`
347+
- `lastFoundationReadiness.promotionBlockers`
348+
- `lastFoundationReadiness.recommendations`
349+
- 运行时/执行侧现在会保留导出诊断所需的同一组 actionable detail:
350+
- 工具栏摘要会在既有 gate/blocker ids 之外显示 `recommendations 2`
351+
- diagnostics snapshot 会保留 gate command、blocker summary、recommendation string,便于后续报告消费。
352+
- `main` 上的护栏结论保持不变:
353+
- 状态仍为 `in_progress`
354+
- 决策仍为 `no-go`
355+
- 可执行细节对齐只提升可检查性,不会放松 no-go contract。
356+
343357
## 主线最新增量(2026-04-20 M8.13 Foundation Readiness 来源证据)
344358

345359
- 已新增 machine-readable provenance,执行侧现在可以直接知道 readiness 是读取 runtime project root,还是回退到真实 repo 证据:

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
- runbook link `foundation-reentry-readiness-checklist`
5555
- runtime snapshot 现在会同时保留 `promotionCriteriaSatisfiedIds``promotionCriteriaUnsatisfiedIds`
5656
- runtime snapshot 现在也会保留当前 gate contract 的 `mandatoryCheckIds`
57+
- runtime snapshot 现在也会保留完整 `mandatoryChecks``promotionBlockers``recommendations`
5758
- 当前主线的预期结果是:
5859
- 状态 `In Progress`
5960
- 决策 `No-Go`
@@ -90,6 +91,7 @@
9091
- `promotionCriteriaUnsatisfiedIds = [graph_backend_independent, vector_backend_independent]`
9192
- 当前主线预期的运行时/执行侧摘要措辞为:
9293
- `gates contract, core_behavior, persistence_safety, interaction_non_regression, documentation`
94+
- `recommendations 2`
9395
- `satisfied store_backend_evidence_present, query_backend_boundary_present, vector_backend_present, docs_aligned, readiness_verifier_present`
9496
- `unmet graph_backend_independent, vector_backend_independent`
9597
- 当前预期 provenance 行为为:

src/agent_workspace.runtime.behavior.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,7 @@ describe('agent workspace runtime behavior', () => {
18091809
expect(messages.textContent || '').toContain(
18101810
'gates contract, core_behavior, persistence_safety, interaction_non_regression, documentation'
18111811
);
1812+
expect(messages.textContent || '').toContain('recommendations 2');
18121813
expect(messages.textContent || '').toContain(
18131814
'satisfied store_backend_evidence_present, query_backend_boundary_present, vector_backend_present, docs_aligned, readiness_verifier_present'
18141815
);
@@ -1846,6 +1847,28 @@ describe('agent workspace runtime behavior', () => {
18461847
'interaction_non_regression',
18471848
'documentation',
18481849
],
1850+
mandatoryChecks: [
1851+
{
1852+
gateId: 'contract',
1853+
command: 'npm test -- src/knowledge.api.contract.test.ts --runInBand',
1854+
},
1855+
{
1856+
gateId: 'core_behavior',
1857+
command: 'npm test -- src/learning/KnowledgeLearningPlatform.test.ts --runInBand',
1858+
},
1859+
{
1860+
gateId: 'persistence_safety',
1861+
command: 'npm test -- src/learning/KnowledgeLearningPlatform.persistence.test.ts --runInBand',
1862+
},
1863+
{
1864+
gateId: 'interaction_non_regression',
1865+
command: 'npm run test:agent-workspace:contracts',
1866+
},
1867+
{
1868+
gateId: 'documentation',
1869+
command: 'npm run docs:diataxis:check && npm run docs:site:build',
1870+
},
1871+
],
18491872
promotionCriteriaSatisfiedIds: [
18501873
'store_backend_evidence_present',
18511874
'query_backend_boundary_present',
@@ -1861,10 +1884,24 @@ describe('agent workspace runtime behavior', () => {
18611884
'graph_backend_not_independent',
18621885
'vector_backend_not_independent',
18631886
],
1887+
promotionBlockers: [
1888+
{
1889+
blockerId: 'graph_backend_not_independent',
1890+
summary: 'Graph backend still resolves to file-backed snapshot semantics.',
1891+
},
1892+
{
1893+
blockerId: 'vector_backend_not_independent',
1894+
summary: 'Vector backend still resolves to lexical prefilter semantics.',
1895+
},
1896+
],
18641897
promotionCriteriaPassed: 5,
18651898
promotionCriteriaTotal: 7,
18661899
mandatoryChecksCount: 5,
18671900
promotionBlockersCount: 2,
1901+
recommendations: [
1902+
'Keep foundation re-entry at no-go while graph persistence remains file-backed snapshot storage without independent graph backend semantics on mainline.',
1903+
'Keep foundation re-entry at no-go while the vector adapter remains a local prefilter boundary without independent ANN evidence on mainline.',
1904+
],
18681905
recommendationsCount: 2,
18691906
})
18701907
);

src/frontend/agent_workspace_runtime.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1445,13 +1445,16 @@
14451445
repoRootSource: '',
14461446
runtimeProjectRootAligned: false,
14471447
mandatoryCheckIds: [],
1448+
mandatoryChecks: [],
14481449
promotionCriteriaPassed: 0,
14491450
promotionCriteriaTotal: 0,
14501451
mandatoryChecksCount: 0,
14511452
promotionCriteriaSatisfiedIds: [],
14521453
promotionCriteriaUnsatisfiedIds: [],
14531454
promotionBlockerIds: [],
1455+
promotionBlockers: [],
14541456
promotionBlockersCount: 0,
1457+
recommendations: [],
14551458
recommendationsCount: 0,
14561459
};
14571460
setBusy(true);
@@ -1478,6 +1481,17 @@
14781481
})
14791482
.filter(Boolean)
14801483
: [];
1484+
const mandatoryChecks = Array.isArray(readiness && readiness.mandatoryChecks)
1485+
? readiness.mandatoryChecks
1486+
.map((entry) => {
1487+
const source = entry && typeof entry === 'object' ? entry : {};
1488+
return {
1489+
gateId: trimString(source.gateId),
1490+
command: trimString(source.command),
1491+
};
1492+
})
1493+
.filter((entry) => entry.gateId)
1494+
: [];
14811495
const provenance = readiness && readiness.provenance && typeof readiness.provenance === 'object'
14821496
? readiness.provenance
14831497
: {};
@@ -1538,13 +1552,18 @@
15381552
repoRootSource: trimString(provenance.repoRootSource),
15391553
runtimeProjectRootAligned: Boolean(provenance.runtimeProjectRootAligned),
15401554
mandatoryCheckIds,
1555+
mandatoryChecks,
15411556
promotionCriteriaPassed,
15421557
promotionCriteriaTotal,
15431558
mandatoryChecksCount: mandatoryCheckIds.length,
15441559
promotionCriteriaSatisfiedIds,
15451560
promotionCriteriaUnsatisfiedIds,
15461561
promotionBlockerIds,
1562+
promotionBlockers,
15471563
promotionBlockersCount: promotionBlockerIds.length,
1564+
recommendations: Array.isArray(readiness && readiness.recommendations)
1565+
? readiness.recommendations.map((entry) => trimString(entry)).filter(Boolean)
1566+
: [],
15481567
recommendationsCount,
15491568
};
15501569
const queryBackendScoreSignals = Array.isArray(baseline.queryBackendScoreSignals)
@@ -1554,7 +1573,7 @@
15541573
'assistant',
15551574
getI18nText(
15561575
'agentWorkspace.messages.foundationReadinessLoaded',
1557-
`Foundation readiness ${trimString(readiness && readiness.status) || 'unknown'} / ${trimString(readiness && readiness.decision) || 'unknown'} (store ${trimString(baseline.storeType) || 'n/a'}, graph ${trimString(baseline.graphBackendStatus) || 'n/a'}/${trimString(baseline.graphBackendSignalKind) || 'n/a'}, graph-independent ${Boolean(baseline.graphBackendIndependent) ? 'yes' : 'no'}, backend ${trimString(baseline.queryBackendDefaultMode) || 'n/a'}, signals ${queryBackendScoreSignals.join(', ') || 'none'}, vector ${trimString(baseline.vectorAdapterStatus) || 'n/a'}, signal-kind ${trimString(baseline.vectorAdapterSignalKind) || 'n/a'}, independent ${Boolean(baseline.vectorAdapterIndependent) ? 'yes' : 'no'}, linked ${Boolean(baseline.vectorAdapterLinkedIntoQueryBackend) ? 'yes' : 'no'}, repo-source ${trimString(provenance.repoRootSource) || 'n/a'}, aligned ${Boolean(provenance.runtimeProjectRootAligned) ? 'yes' : 'no'}, gates ${mandatoryCheckIds.join(', ') || 'none'}, criteria ${promotionCriteriaPassed}/${promotionCriteriaTotal}, satisfied ${promotionCriteriaSatisfiedIds.join(', ') || 'none'}, unmet ${promotionCriteriaUnsatisfiedIds.join(', ') || 'none'}, blockers ${promotionBlockerIds.join(', ') || 'none'}).`,
1576+
`Foundation readiness ${trimString(readiness && readiness.status) || 'unknown'} / ${trimString(readiness && readiness.decision) || 'unknown'} (store ${trimString(baseline.storeType) || 'n/a'}, graph ${trimString(baseline.graphBackendStatus) || 'n/a'}/${trimString(baseline.graphBackendSignalKind) || 'n/a'}, graph-independent ${Boolean(baseline.graphBackendIndependent) ? 'yes' : 'no'}, backend ${trimString(baseline.queryBackendDefaultMode) || 'n/a'}, signals ${queryBackendScoreSignals.join(', ') || 'none'}, vector ${trimString(baseline.vectorAdapterStatus) || 'n/a'}, signal-kind ${trimString(baseline.vectorAdapterSignalKind) || 'n/a'}, independent ${Boolean(baseline.vectorAdapterIndependent) ? 'yes' : 'no'}, linked ${Boolean(baseline.vectorAdapterLinkedIntoQueryBackend) ? 'yes' : 'no'}, repo-source ${trimString(provenance.repoRootSource) || 'n/a'}, aligned ${Boolean(provenance.runtimeProjectRootAligned) ? 'yes' : 'no'}, gates ${mandatoryCheckIds.join(', ') || 'none'}, criteria ${promotionCriteriaPassed}/${promotionCriteriaTotal}, satisfied ${promotionCriteriaSatisfiedIds.join(', ') || 'none'}, unmet ${promotionCriteriaUnsatisfiedIds.join(', ') || 'none'}, blockers ${promotionBlockerIds.join(', ') || 'none'}, recommendations ${recommendationsCount}).`,
15581577
{
15591578
status: trimString(readiness && readiness.status) || 'unknown',
15601579
decision: trimString(readiness && readiness.decision) || 'unknown',
@@ -1578,6 +1597,7 @@
15781597
promotionCriteriaSatisfiedIds: promotionCriteriaSatisfiedIds.join(', ') || 'none',
15791598
promotionCriteriaUnsatisfiedIds: promotionCriteriaUnsatisfiedIds.join(', ') || 'none',
15801599
promotionBlockerIds: promotionBlockerIds.join(', ') || 'none',
1600+
recommendationsCount,
15811601
}
15821602
)
15831603
);
@@ -1601,13 +1621,16 @@
16011621
repoRootSource: '',
16021622
runtimeProjectRootAligned: false,
16031623
mandatoryCheckIds: [],
1624+
mandatoryChecks: [],
16041625
promotionCriteriaPassed: 0,
16051626
promotionCriteriaTotal: 0,
16061627
mandatoryChecksCount: 0,
16071628
promotionCriteriaSatisfiedIds: [],
16081629
promotionCriteriaUnsatisfiedIds: [],
16091630
promotionBlockerIds: [],
1631+
promotionBlockers: [],
16101632
promotionBlockersCount: 0,
1633+
recommendations: [],
16111634
recommendationsCount: 0,
16121635
};
16131636
recordFailure('loadFoundationReadiness', errorMessage);

src/frontend/locales/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@
282282
"learningQualitySnapshotFailed": "Learning quality snapshot request failed.",
283283
"learningQualitySnapshotLoaded": "Learning quality snapshot loaded (retest {retestPassRatePct}%, recurrence {misconceptionRecurrenceRatePct}%).",
284284
"foundationReadinessFailed": "Foundation readiness request failed.",
285-
"foundationReadinessLoaded": "Foundation readiness {status} / {decision} (store {storeType}, graph {graphBackendStatus}/{graphBackendSignalKind}, graph-independent {graphBackendIndependent}, backend {queryBackendDefaultMode}, signals {queryBackendScoreSignals}, vector {vectorAdapterStatus}, signal-kind {vectorAdapterSignalKind}, independent {vectorAdapterIndependent}, linked {vectorAdapterLinkedIntoQueryBackend}, repo-source {repoRootSource}, aligned {runtimeProjectRootAligned}, gates {mandatoryCheckIds}, criteria {promotionCriteriaPassed}/{promotionCriteriaTotal}, satisfied {promotionCriteriaSatisfiedIds}, unmet {promotionCriteriaUnsatisfiedIds}, blockers {promotionBlockerIds}).",
285+
"foundationReadinessLoaded": "Foundation readiness {status} / {decision} (store {storeType}, graph {graphBackendStatus}/{graphBackendSignalKind}, graph-independent {graphBackendIndependent}, backend {queryBackendDefaultMode}, signals {queryBackendScoreSignals}, vector {vectorAdapterStatus}, signal-kind {vectorAdapterSignalKind}, independent {vectorAdapterIndependent}, linked {vectorAdapterLinkedIntoQueryBackend}, repo-source {repoRootSource}, aligned {runtimeProjectRootAligned}, gates {mandatoryCheckIds}, criteria {promotionCriteriaPassed}/{promotionCriteriaTotal}, satisfied {promotionCriteriaSatisfiedIds}, unmet {promotionCriteriaUnsatisfiedIds}, blockers {promotionBlockerIds}, recommendations {recommendationsCount}).",
286286
"memoryPolicyFailed": "Memory snapshot request failed.",
287287
"memoryPolicyLoaded": "Memory snapshot loaded ({layer}/{operation}): {entriesCount} entries, evicted {evictedCount}, totals session {sessionCount}, unit {unitCount}, long-term {longTermCount}, recommended {recommendedActionsCount} actions."
288288
}

src/frontend/locales/zh.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@
282282
"learningQualitySnapshotFailed": "学习质量快照请求失败。",
283283
"learningQualitySnapshotLoaded": "学习质量快照已加载(复测通过率 {retestPassRatePct}% ,误解复发率 {misconceptionRecurrenceRatePct}%)。",
284284
"foundationReadinessFailed": "基础就绪性请求失败。",
285-
"foundationReadinessLoaded": "基础就绪性 {status} / {decision}(存储 {storeType},图后端 {graphBackendStatus}/{graphBackendSignalKind},图独立性 {graphBackendIndependent},后端 {queryBackendDefaultMode},打分信号 {queryBackendScoreSignals},向量阶段 {vectorAdapterStatus},信号类型 {vectorAdapterSignalKind},独立性 {vectorAdapterIndependent},接线 {vectorAdapterLinkedIntoQueryBackend},repo 来源 {repoRootSource},对齐 {runtimeProjectRootAligned},门禁 {mandatoryCheckIds},条件 {promotionCriteriaPassed}/{promotionCriteriaTotal},已满足 {promotionCriteriaSatisfiedIds},未满足 {promotionCriteriaUnsatisfiedIds},阻塞项 {promotionBlockerIds})。",
285+
"foundationReadinessLoaded": "基础就绪性 {status} / {decision}(存储 {storeType},图后端 {graphBackendStatus}/{graphBackendSignalKind},图独立性 {graphBackendIndependent},后端 {queryBackendDefaultMode},打分信号 {queryBackendScoreSignals},向量阶段 {vectorAdapterStatus},信号类型 {vectorAdapterSignalKind},独立性 {vectorAdapterIndependent},接线 {vectorAdapterLinkedIntoQueryBackend},repo 来源 {repoRootSource},对齐 {runtimeProjectRootAligned},门禁 {mandatoryCheckIds},条件 {promotionCriteriaPassed}/{promotionCriteriaTotal},已满足 {promotionCriteriaSatisfiedIds},未满足 {promotionCriteriaUnsatisfiedIds},阻塞项 {promotionBlockerIds},建议 {recommendationsCount} 条)。",
286286
"memoryPolicyFailed": "记忆快照请求失败。",
287287
"memoryPolicyLoaded": "记忆快照已加载({layer}/{operation}):{entriesCount} 条,清理 {evictedCount} 条,总量 session {sessionCount}、unit {unitCount}、long-term {longTermCount},推荐动作 {recommendedActionsCount} 个。"
288288
}

0 commit comments

Comments
 (0)