Skip to content

Commit a45185a

Browse files
committed
feat: add readiness promotion criteria matrix
1 parent 9796311 commit a45185a

15 files changed

Lines changed: 312 additions & 31 deletions

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ This document re-baselines current mainline truth on 2026-04-19, records what ch
209209
- current mainline blockers are `graph_backend_not_independent` and `vector_backend_not_independent`
210210
- missing query/vector boundary cases now return distinct blocker ids instead of only prose recommendations
211211
- overall status still remains `in_progress` / `no-go`.
212+
- The next bounded execution slice after that makes prerequisite coverage machine-readable:
213+
- readiness now reports `promotionCriteria`
214+
- readiness now reports `promotionCriteriaPassed`
215+
- readiness now reports `promotionCriteriaTotal`
216+
- current mainline criteria coverage is `5/7`, with graph/vector independence still unsatisfied
217+
- overall status still remains `in_progress` / `no-go`.
212218
- Current expected outcome on `main` remains:
213219
- status `in_progress`
214220
- decision `no-go`

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

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -297,25 +297,28 @@ Execution anchor:
297297
- decision stays `no-go`,
298298
- file snapshots still do not qualify as independent graph backend readiness.
299299

300-
## Latest Mainline Increment (2026-04-20 M8.11 Foundation Promotion-Blocker Evidence)
301-
302-
- Added machine-readable readiness blockers so operator tooling no longer has to parse prose recommendations:
303-
- `FoundationReadinessReport.promotionBlockers`
304-
- typed blocker ids now distinguish graph, query, vector, docs, store, and verifier failures.
305-
- Current mainline blocker set is now explicit:
300+
## Latest Mainline Increment (2026-04-20 M8.12 Foundation Promotion-Criteria Matrix)
301+
302+
- Added a machine-readable promotion-criteria matrix so operator tooling and CI can see both coverage and blockers without inferring from prose:
303+
- `FoundationReadinessReport.promotionCriteria`
304+
- `FoundationReadinessReport.promotionCriteriaPassed`
305+
- `FoundationReadinessReport.promotionCriteriaTotal`
306+
- Current mainline readiness coverage is now explicit:
307+
- satisfied: `store_backend_evidence_present`, `query_backend_boundary_present`, `vector_backend_present`, `docs_aligned`, `readiness_verifier_present`
308+
- unsatisfied: `graph_backend_independent`, `vector_backend_independent`
309+
- current count: `5/7`
310+
- Blocker evidence remains machine-readable and aligned with the criteria matrix:
306311
- `graph_backend_not_independent`
307312
- `vector_backend_not_independent`
308-
- Missing-boundary fixtures are also distinguishable now:
309-
- `query_backend_boundary_missing`
310-
- `vector_backend_missing`
313+
- missing-boundary fixtures still distinguish `query_backend_boundary_missing` and `vector_backend_missing`
311314
- Runtime/operator visibility stayed aligned:
312-
- `scripts/verify-foundation-readiness.js` prints promotion blockers,
313-
- markdown readiness reports include a dedicated `Promotion Blockers` section,
314-
- `src/frontend/agent_workspace_runtime.js` persists blocker ids in `lastFoundationReadiness` and surfaces them in the toolbar summary.
315+
- `scripts/verify-foundation-readiness.js` now prints promotion criteria counts and per-criterion summaries,
316+
- markdown readiness reports include a dedicated `Promotion Criteria` section,
317+
- `src/frontend/agent_workspace_runtime.js` persists `promotionCriteriaPassed` / `promotionCriteriaTotal` in `lastFoundationReadiness` and surfaces `criteria 5/7` in the toolbar summary.
315318
- Guardrail remains unchanged on `main`:
316319
- status stays `in_progress`,
317320
- decision stays `no-go`,
318-
- blockers are now explicit evidence, not a status change.
321+
- criteria improve inspectability only; they do not relax the anti-overclaim boundary.
319322

320323
## Latest Mainline Increment (2026-04-16 M7.2 Runtime Evidence Deepening Lane)
321324

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ Bundle note:
5757
- decision `No-Go`
5858
- rationale: mainline persistence is still `file_snapshot_only`, query-backend and vector-boundary modules are present, but graph-backend independence is absent and the vector adapter is still only `prefilter_only`, so independent graph/ANN evidence is still absent.
5959
- The readiness payload now makes that distinction explicit:
60+
- `promotionCriteria`
61+
- `promotionCriteriaPassed`
62+
- `promotionCriteriaTotal`
6063
- `promotionBlockers`
6164
- `graphBackendStatus`
6265
- `graphBackendSignalKind`
@@ -74,6 +77,10 @@ Bundle note:
7477
- Current expected promotion blockers on `main` are:
7578
- `graph_backend_not_independent`
7679
- `vector_backend_not_independent`
80+
- Current expected promotion criteria on `main` are:
81+
- passed `5/7`
82+
- satisfied: `store_backend_evidence_present`, `query_backend_boundary_present`, `vector_backend_present`, `docs_aligned`, `readiness_verifier_present`
83+
- unsatisfied: `graph_backend_independent`, `vector_backend_independent`
7784
- Current expected signal semantics on `main` are:
7885
- `queryBackendScoreSignals = [keyword_matches, title_match_bonus, vector_prefilter_content_bonus, relation_bonus]`
7986
- `vectorAdapterSignalKind = lexical_token_overlap`

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

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -297,25 +297,28 @@
297297
- 决策仍为 `no-go`
298298
- file snapshot 仍不构成独立 graph backend readiness。
299299

300-
## 主线最新增量(2026-04-20 M8.11 Foundation 晋级阻塞项证据)
301-
302-
- 已新增 machine-readable readiness blockers,执行侧不再需要解析自由文本 recommendation 才能知道 `no-go` 原因:
303-
- `FoundationReadinessReport.promotionBlockers`
304-
- typed blocker id 现在可区分 graph、query、vector、docs、store、verifier 类失败。
305-
- 当前主线阻塞集合现在是显式事实:
300+
## 主线最新增量(2026-04-20 M8.12 Foundation 晋级条件矩阵)
301+
302+
- 已新增 machine-readable promotion-criteria matrix,执行侧与 CI 现在可以同时看到覆盖面与 blocker,而不必再从 prose 反推:
303+
- `FoundationReadinessReport.promotionCriteria`
304+
- `FoundationReadinessReport.promotionCriteriaPassed`
305+
- `FoundationReadinessReport.promotionCriteriaTotal`
306+
- 当前主线 readiness 覆盖率现在是显式事实:
307+
- 已满足:`store_backend_evidence_present``query_backend_boundary_present``vector_backend_present``docs_aligned``readiness_verifier_present`
308+
- 未满足:`graph_backend_independent``vector_backend_independent`
309+
- 当前计数:`5/7`
310+
- blocker 证据仍保持 machine-readable,并与 criteria matrix 对齐:
306311
- `graph_backend_not_independent`
307312
- `vector_backend_not_independent`
308-
- 缺失边界的 fixture 现在也能被准确区分:
309-
- `query_backend_boundary_missing`
310-
- `vector_backend_missing`
313+
- 缺失边界 fixture 仍可区分 `query_backend_boundary_missing``vector_backend_missing`
311314
- 运行时/执行侧可见性保持对齐:
312-
- `scripts/verify-foundation-readiness.js` 现在输出 promotion blockers
313-
- readiness markdown 报告新增独立 `Promotion Blockers` 小节,
314-
- `src/frontend/agent_workspace_runtime.js` 会在 `lastFoundationReadiness` 中保留 blocker ids,并在工具栏摘要里显示。
315+
- `scripts/verify-foundation-readiness.js` 现在会输出 promotion criteria 计数与逐项摘要
316+
- readiness markdown 报告新增独立 `Promotion Criteria` 小节,
317+
- `src/frontend/agent_workspace_runtime.js` 会在 `lastFoundationReadiness` 中保留 `promotionCriteriaPassed` / `promotionCriteriaTotal`,并在工具栏摘要里显示 `criteria 5/7`
315318
- `main` 上的护栏结论保持不变:
316319
- 状态仍为 `in_progress`
317320
- 决策仍为 `no-go`
318-
- blocker 只是把阻塞证据显式化,不构成状态升级
321+
- criteria 只是提升可观测性,不会放松 anti-overclaim 边界
319322

320323
## 主线最新增量(2026-04-16 M7.2 运行时证据加深链路)
321324

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
- 决策 `No-Go`
5858
- 原因:主线 persistence 仍是 `file_snapshot_only`,query-backend 与 vector 边界虽已进入主线,但 graph backend 独立性仍缺失,且 vector adapter 仍只是 `prefilter_only`,因此独立 graph/ANN 证据仍未进入主线。
5959
- readiness 载荷现在也显式区分这层语义:
60+
- `promotionCriteria`
61+
- `promotionCriteriaPassed`
62+
- `promotionCriteriaTotal`
6063
- `promotionBlockers`
6164
- `graphBackendStatus`
6265
- `graphBackendSignalKind`
@@ -74,6 +77,10 @@
7477
- 当前 `main` 的预期晋级阻塞项为:
7578
- `graph_backend_not_independent`
7679
- `vector_backend_not_independent`
80+
- 当前 `main` 的预期晋级条件矩阵为:
81+
- 通过 `5/7`
82+
- 已满足:`store_backend_evidence_present``query_backend_boundary_present``vector_backend_present``docs_aligned``readiness_verifier_present`
83+
- 未满足:`graph_backend_independent``vector_backend_independent`
7784
- 当前 `main` 的预期信号语义为:
7885
- `queryBackendScoreSignals = [keyword_matches, title_match_bonus, vector_prefilter_content_bonus, relation_bonus]`
7986
- `vectorAdapterSignalKind = lexical_token_overlap`

scripts/foundation-readiness-utils.js

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ function createPromotionBlocker(blockerId, summary) {
2929
return { blockerId, summary };
3030
}
3131

32+
function createPromotionCriterion(criterionId, satisfied, summary) {
33+
return { criterionId, satisfied, summary };
34+
}
35+
3236
function resolveVectorAdapterStatus(vectorAdapterSource, vectorAdapterModulePresent) {
3337
if (!vectorAdapterModulePresent) {
3438
return 'absent';
@@ -228,10 +232,11 @@ function evaluateFoundationReadiness(options = {}) {
228232
const dashboardReferencesPresent =
229233
enDashboard.includes('foundation-reentry-readiness-checklist')
230234
&& zhDashboard.includes('foundation-reentry-readiness-checklist');
235+
const docsAligned = checklistPagesPresent && dashboardReferencesPresent;
231236
const readinessVerifierPresent =
232237
scripts['verify:foundation:readiness'] === 'node scripts/verify-foundation-readiness.js';
233238

234-
const baselineReady = storeModulePresent && checklistPagesPresent && dashboardReferencesPresent;
239+
const baselineReady = storeModulePresent && docsAligned;
235240

236241
let status = 'planned';
237242
let decision = 'no-go';
@@ -272,6 +277,62 @@ function evaluateFoundationReadiness(options = {}) {
272277
},
273278
];
274279

280+
const promotionCriteria = [
281+
createPromotionCriterion(
282+
'store_backend_evidence_present',
283+
storeModulePresent,
284+
storeModulePresent
285+
? 'Store backend evidence is present in the repository baseline.'
286+
: 'Store backend evidence is missing or unreadable.'
287+
),
288+
createPromotionCriterion(
289+
'graph_backend_independent',
290+
graphBackendIndependent,
291+
graphBackendIndependent
292+
? 'Graph backend resolves to independent graph semantics.'
293+
: 'Graph backend still resolves to file-backed snapshot semantics.'
294+
),
295+
createPromotionCriterion(
296+
'query_backend_boundary_present',
297+
graphAdapterModulePresent,
298+
graphAdapterModulePresent
299+
? 'Dedicated query backend boundary is present.'
300+
: 'Dedicated query backend boundary is absent.'
301+
),
302+
createPromotionCriterion(
303+
'vector_backend_present',
304+
vectorAdapterModulePresent,
305+
vectorAdapterModulePresent
306+
? 'Dedicated vector adapter boundary is present.'
307+
: 'Dedicated vector adapter boundary is absent.'
308+
),
309+
createPromotionCriterion(
310+
'vector_backend_independent',
311+
vectorAdapterIndependent,
312+
vectorAdapterIndependent
313+
? 'Vector backend resolves to independent ANN semantics.'
314+
: vectorAdapterModulePresent
315+
? 'Vector backend still resolves to lexical prefilter semantics.'
316+
: 'Vector backend cannot be independent because the adapter boundary is absent.'
317+
),
318+
createPromotionCriterion(
319+
'docs_aligned',
320+
docsAligned,
321+
docsAligned
322+
? 'EN/ZH checklist and dashboard references are aligned.'
323+
: 'EN/ZH checklist and dashboard references are not aligned.'
324+
),
325+
createPromotionCriterion(
326+
'readiness_verifier_present',
327+
readinessVerifierPresent,
328+
readinessVerifierPresent
329+
? 'Readiness verifier command is present in package scripts.'
330+
: 'Readiness verifier command is missing from package scripts.'
331+
),
332+
];
333+
const promotionCriteriaPassed = promotionCriteria.filter((entry) => entry.satisfied).length;
334+
const promotionCriteriaTotal = promotionCriteria.length;
335+
275336
const promotionBlockers = [];
276337
const recommendations = [];
277338

@@ -353,7 +414,7 @@ function evaluateFoundationReadiness(options = {}) {
353414
);
354415
}
355416

356-
if (!checklistPagesPresent || !dashboardReferencesPresent) {
417+
if (!docsAligned) {
357418
promotionBlockers.push(
358419
createPromotionBlocker(
359420
'docs_not_aligned',
@@ -412,6 +473,9 @@ function evaluateFoundationReadiness(options = {}) {
412473
readinessVerifierPresent,
413474
},
414475
mandatoryChecks,
476+
promotionCriteriaPassed,
477+
promotionCriteriaTotal,
478+
promotionCriteria,
415479
promotionBlockers,
416480
recommendations,
417481
};
@@ -469,6 +533,12 @@ function formatFoundationReadinessMarkdown(result, reportPaths) {
469533
});
470534
}
471535

536+
lines.push('', '## Promotion Criteria', '');
537+
lines.push(`- Passed: ${result.promotionCriteriaPassed}/${result.promotionCriteriaTotal}`);
538+
result.promotionCriteria.forEach((entry) => {
539+
lines.push(`- ${entry.criterionId}: ${entry.satisfied ? 'yes' : 'no'} (${entry.summary})`);
540+
});
541+
472542
lines.push('', '## Recommendations', '');
473543
result.recommendations.forEach((entry) => {
474544
lines.push(`- ${entry}`);

scripts/verify-foundation-readiness.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ function printHumanReport(result, reportPaths) {
4949
console.log(
5050
`[Foundation Readiness] Readiness verifier present: ${result.packageScripts.readinessVerifierPresent ? 'yes' : 'no'}`
5151
);
52+
console.log(
53+
`[Foundation Readiness] Promotion criteria: ${result.promotionCriteriaPassed}/${result.promotionCriteriaTotal}`
54+
);
55+
result.promotionCriteria.forEach((entry) => {
56+
console.log(
57+
` - ${entry.criterionId}: ${entry.satisfied ? 'yes' : 'no'} (${entry.summary})`
58+
);
59+
});
5260
console.log('[Foundation Readiness] Mandatory checks:');
5361
result.mandatoryChecks.forEach((entry) => {
5462
console.log(` - ${entry.gateId}: ${entry.command}`);

src/agent_workspace.runtime.behavior.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,45 @@ describe('agent workspace runtime behavior', () => {
16881688
packageScripts: {
16891689
readinessVerifierPresent: true,
16901690
},
1691+
promotionCriteriaPassed: 5,
1692+
promotionCriteriaTotal: 7,
1693+
promotionCriteria: [
1694+
{
1695+
criterionId: 'store_backend_evidence_present',
1696+
satisfied: true,
1697+
summary: 'Store backend evidence is present in the repository baseline.',
1698+
},
1699+
{
1700+
criterionId: 'graph_backend_independent',
1701+
satisfied: false,
1702+
summary: 'Graph backend still resolves to file-backed snapshot semantics.',
1703+
},
1704+
{
1705+
criterionId: 'query_backend_boundary_present',
1706+
satisfied: true,
1707+
summary: 'Dedicated query backend boundary is present.',
1708+
},
1709+
{
1710+
criterionId: 'vector_backend_present',
1711+
satisfied: true,
1712+
summary: 'Dedicated vector adapter boundary is present.',
1713+
},
1714+
{
1715+
criterionId: 'vector_backend_independent',
1716+
satisfied: false,
1717+
summary: 'Vector backend still resolves to lexical prefilter semantics.',
1718+
},
1719+
{
1720+
criterionId: 'docs_aligned',
1721+
satisfied: true,
1722+
summary: 'EN/ZH checklist and dashboard references are aligned.',
1723+
},
1724+
{
1725+
criterionId: 'readiness_verifier_present',
1726+
satisfied: true,
1727+
summary: 'Readiness verifier command is present in package scripts.',
1728+
},
1729+
],
16911730
mandatoryChecks: [
16921731
{
16931732
gateId: 'contract',
@@ -1736,6 +1775,7 @@ describe('agent workspace runtime behavior', () => {
17361775
expect(messages.textContent || '').toContain('lexical_token_overlap');
17371776
expect(messages.textContent || '').toContain('graph_backend_not_independent');
17381777
expect(messages.textContent || '').toContain('vector_backend_not_independent');
1778+
expect(messages.textContent || '').toContain('criteria 5/7');
17391779

17401780
const snapshot = runtime.getDiagnosticsSnapshot();
17411781
expect(snapshot.lastFoundationReadiness).toEqual(
@@ -1761,6 +1801,8 @@ describe('agent workspace runtime behavior', () => {
17611801
'graph_backend_not_independent',
17621802
'vector_backend_not_independent',
17631803
],
1804+
promotionCriteriaPassed: 5,
1805+
promotionCriteriaTotal: 7,
17641806
promotionBlockersCount: 2,
17651807
recommendationsCount: 2,
17661808
})

0 commit comments

Comments
 (0)