Skip to content

Commit da4f44b

Browse files
committed
feat: expose readiness provenance evidence
1 parent a45185a commit da4f44b

16 files changed

Lines changed: 173 additions & 15 deletions

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ This document re-baselines current mainline truth on 2026-04-19, records what ch
215215
- readiness now reports `promotionCriteriaTotal`
216216
- current mainline criteria coverage is `5/7`, with graph/vector independence still unsatisfied
217217
- overall status still remains `in_progress` / `no-go`.
218+
- The next bounded execution slice after that makes repo-evidence fallback machine-readable:
219+
- readiness now reports `provenance.repoRootSource`
220+
- readiness now reports `provenance.runtimeProjectRootAligned`
221+
- hermetic runtime/API paths can now prove they are reading real repo evidence instead of silently implying local runtime-root alignment
222+
- overall status still remains `in_progress` / `no-go`.
218223
- Current expected outcome on `main` remains:
219224
- status `in_progress`
220225
- decision `no-go`

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,23 @@ 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.13 Foundation Readiness Provenance Evidence)
301+
302+
- Added machine-readable provenance so operator tooling can tell whether readiness is reading the runtime project root or falling back to real repo evidence:
303+
- `FoundationReadinessReport.provenance.repoRootSource`
304+
- `FoundationReadinessReport.provenance.runtimeProjectRootAligned`
305+
- Current mainline behavior is now explicit under hermetic runtime/test roots:
306+
- direct utility/report usage resolves with aligned provenance,
307+
- hermetic runtime/API paths can report `runtimeProjectRootAligned = false` while still preserving the same repo-truth readiness result.
308+
- Runtime/operator visibility stayed aligned:
309+
- `scripts/verify-foundation-readiness.js` now prints provenance lines,
310+
- markdown readiness reports include a dedicated `Provenance` section,
311+
- `src/frontend/agent_workspace_runtime.js` persists provenance in `lastFoundationReadiness` and surfaces `repo-source ... aligned ...` in the toolbar summary.
312+
- Guardrail remains unchanged on `main`:
313+
- status stays `in_progress`,
314+
- decision stays `no-go`,
315+
- provenance improves auditability only; it does not relax the anti-overclaim boundary.
316+
300317
## Latest Mainline Increment (2026-04-20 M8.12 Foundation Promotion-Criteria Matrix)
301318

302319
- Added a machine-readable promotion-criteria matrix so operator tooling and CI can see both coverage and blockers without inferring from prose:

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ 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+
- `provenance.repoRootSource`
61+
- `provenance.runtimeProjectRootAligned`
6062
- `promotionCriteria`
6163
- `promotionCriteriaPassed`
6264
- `promotionCriteriaTotal`
@@ -81,6 +83,9 @@ Bundle note:
8183
- passed `5/7`
8284
- satisfied: `store_backend_evidence_present`, `query_backend_boundary_present`, `vector_backend_present`, `docs_aligned`, `readiness_verifier_present`
8385
- unsatisfied: `graph_backend_independent`, `vector_backend_independent`
86+
- Current expected provenance behavior is:
87+
- direct verifier/utility usage reports `runtimeProjectRootAligned = true`
88+
- hermetic runtime/API usage may report `runtimeProjectRootAligned = false` while preserving the same repo-truth readiness payload
8489
- Current expected signal semantics on `main` are:
8590
- `queryBackendScoreSignals = [keyword_matches, title_match_bonus, vector_prefilter_content_bonus, relation_bonus]`
8691
- `vectorAdapterSignalKind = lexical_token_overlap`

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

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

300+
## 主线最新增量(2026-04-20 M8.13 Foundation Readiness 来源证据)
301+
302+
- 已新增 machine-readable provenance,执行侧现在可以直接知道 readiness 是读取 runtime project root,还是回退到真实 repo 证据:
303+
- `FoundationReadinessReport.provenance.repoRootSource`
304+
- `FoundationReadinessReport.provenance.runtimeProjectRootAligned`
305+
- 当前主线在 hermetic runtime/test root 下的行为现在是显式的:
306+
- 直接 utility/report 调用会得到对齐状态,
307+
- hermetic runtime/API 路径可以显式报告 `runtimeProjectRootAligned = false`,同时仍保持同一份 repo-truth readiness 结论。
308+
- 运行时/执行侧可见性保持对齐:
309+
- `scripts/verify-foundation-readiness.js` 现在会输出 provenance 行,
310+
- readiness markdown 报告新增独立 `Provenance` 小节,
311+
- `src/frontend/agent_workspace_runtime.js` 会在 `lastFoundationReadiness` 中保留 provenance,并在工具栏摘要中显示 `repo-source ... aligned ...`
312+
- `main` 上的护栏结论保持不变:
313+
- 状态仍为 `in_progress`
314+
- 决策仍为 `no-go`
315+
- provenance 只提升可审计性,不会放松 anti-overclaim 边界。
316+
300317
## 主线最新增量(2026-04-20 M8.12 Foundation 晋级条件矩阵)
301318

302319
- 已新增 machine-readable promotion-criteria matrix,执行侧与 CI 现在可以同时看到覆盖面与 blocker,而不必再从 prose 反推:

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
- 决策 `No-Go`
5858
- 原因:主线 persistence 仍是 `file_snapshot_only`,query-backend 与 vector 边界虽已进入主线,但 graph backend 独立性仍缺失,且 vector adapter 仍只是 `prefilter_only`,因此独立 graph/ANN 证据仍未进入主线。
5959
- readiness 载荷现在也显式区分这层语义:
60+
- `provenance.repoRootSource`
61+
- `provenance.runtimeProjectRootAligned`
6062
- `promotionCriteria`
6163
- `promotionCriteriaPassed`
6264
- `promotionCriteriaTotal`
@@ -81,6 +83,9 @@
8183
- 通过 `5/7`
8284
- 已满足:`store_backend_evidence_present``query_backend_boundary_present``vector_backend_present``docs_aligned``readiness_verifier_present`
8385
- 未满足:`graph_backend_independent``vector_backend_independent`
86+
- 当前预期 provenance 行为为:
87+
- 直接 verifier/utility 调用会报告 `runtimeProjectRootAligned = true`
88+
- hermetic runtime/API 调用可能报告 `runtimeProjectRootAligned = false`,但 readiness 载荷仍必须保持同一份 repo-truth 结论
8489
- 当前 `main` 的预期信号语义为:
8590
- `queryBackendScoreSignals = [keyword_matches, title_match_bonus, vector_prefilter_content_bonus, relation_bonus]`
8691
- `vectorAdapterSignalKind = lexical_token_overlap`

scripts/foundation-readiness-utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ function resolveVectorAdapterSignalKind(vectorAdapterSource, vectorAdapterModule
159159

160160
function evaluateFoundationReadiness(options = {}) {
161161
const repoRoot = options.repoRoot || path.resolve(__dirname, '..');
162+
const provenance = options.provenance || {
163+
repoRootSource: options.repoRoot ? 'explicit' : 'module_root',
164+
runtimeProjectRootAligned: true,
165+
};
162166
const packageJson = readJsonIfExists(path.join(repoRoot, 'package.json'));
163167
const scripts = packageJson.scripts || {};
164168

@@ -472,6 +476,7 @@ function evaluateFoundationReadiness(options = {}) {
472476
packageScripts: {
473477
readinessVerifierPresent,
474478
},
479+
provenance,
475480
mandatoryChecks,
476481
promotionCriteriaPassed,
477482
promotionCriteriaTotal,
@@ -516,6 +521,11 @@ function formatFoundationReadinessMarkdown(result, reportPaths) {
516521
'',
517522
`- Readiness verifier present: ${result.packageScripts.readinessVerifierPresent ? 'yes' : 'no'}`,
518523
'',
524+
'## Provenance',
525+
'',
526+
`- Repo root source: ${result.provenance.repoRootSource}`,
527+
`- Runtime project root aligned: ${result.provenance.runtimeProjectRootAligned ? 'yes' : 'no'}`,
528+
'',
519529
'## Mandatory Checks',
520530
'',
521531
];

scripts/verify-foundation-readiness.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ function printHumanReport(result, reportPaths) {
4949
console.log(
5050
`[Foundation Readiness] Readiness verifier present: ${result.packageScripts.readinessVerifierPresent ? 'yes' : 'no'}`
5151
);
52+
console.log(`[Foundation Readiness] Repo root source: ${result.provenance.repoRootSource}`);
53+
console.log(
54+
`[Foundation Readiness] Runtime project root aligned: ${result.provenance.runtimeProjectRootAligned ? 'yes' : 'no'}`
55+
);
5256
console.log(
5357
`[Foundation Readiness] Promotion criteria: ${result.promotionCriteriaPassed}/${result.promotionCriteriaTotal}`
5458
);

src/agent_workspace.runtime.behavior.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,10 @@ describe('agent workspace runtime behavior', () => {
16881688
packageScripts: {
16891689
readinessVerifierPresent: true,
16901690
},
1691+
provenance: {
1692+
repoRootSource: 'cwd',
1693+
runtimeProjectRootAligned: false,
1694+
},
16911695
promotionCriteriaPassed: 5,
16921696
promotionCriteriaTotal: 7,
16931697
promotionCriteria: [
@@ -1773,6 +1777,8 @@ describe('agent workspace runtime behavior', () => {
17731777
expect(messages.textContent || '').toContain('prefilter_only');
17741778
expect(messages.textContent || '').toContain('local_hybrid');
17751779
expect(messages.textContent || '').toContain('lexical_token_overlap');
1780+
expect(messages.textContent || '').toContain('repo-source cwd');
1781+
expect(messages.textContent || '').toContain('aligned no');
17761782
expect(messages.textContent || '').toContain('graph_backend_not_independent');
17771783
expect(messages.textContent || '').toContain('vector_backend_not_independent');
17781784
expect(messages.textContent || '').toContain('criteria 5/7');
@@ -1797,6 +1803,8 @@ describe('agent workspace runtime behavior', () => {
17971803
vectorAdapterSignalKind: 'lexical_token_overlap',
17981804
vectorAdapterIndependent: false,
17991805
vectorAdapterLinkedIntoQueryBackend: true,
1806+
repoRootSource: 'cwd',
1807+
runtimeProjectRootAligned: false,
18001808
promotionBlockerIds: [
18011809
'graph_backend_not_independent',
18021810
'vector_backend_not_independent',

src/foundation.readiness.contract.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ type FoundationReadinessResult = {
3333
packageScripts: {
3434
readinessVerifierPresent: boolean;
3535
};
36+
provenance: {
37+
repoRootSource: 'explicit' | 'project_root_hint' | 'cwd' | 'module_root';
38+
runtimeProjectRootAligned: boolean;
39+
};
3640
promotionCriteriaPassed: number;
3741
promotionCriteriaTotal: number;
3842
promotionCriteria: Array<{
@@ -158,6 +162,10 @@ describe('foundation readiness contract', () => {
158162
expect(result.documents.checklistPagesPresent).toBe(true);
159163
expect(result.documents.dashboardReferencesPresent).toBe(true);
160164
expect(result.packageScripts.readinessVerifierPresent).toBe(true);
165+
expect(result.provenance).toEqual({
166+
repoRootSource: 'explicit',
167+
runtimeProjectRootAligned: true,
168+
});
161169
expect(result.promotionCriteriaPassed).toBe(5);
162170
expect(result.promotionCriteriaTotal).toBe(7);
163171
expect(result.promotionCriteria.map((entry) => entry.criterionId)).toEqual([
@@ -251,6 +259,10 @@ describe('foundation readiness contract', () => {
251259
expect(result.baseline.vectorAdapterLinkedIntoQueryBackend).toBe(false);
252260
expect(result.documents.checklistPagesPresent).toBe(true);
253261
expect(result.documents.dashboardReferencesPresent).toBe(true);
262+
expect(result.provenance).toEqual({
263+
repoRootSource: 'explicit',
264+
runtimeProjectRootAligned: true,
265+
});
254266
expect(result.promotionCriteriaPassed).toBe(6);
255267
expect(result.promotionCriteriaTotal).toBe(7);
256268
expect(
@@ -332,6 +344,10 @@ describe('foundation readiness contract', () => {
332344
expect(result.baseline.vectorAdapterLinkedIntoQueryBackend).toBe(false);
333345
expect(result.documents.checklistPagesPresent).toBe(true);
334346
expect(result.documents.dashboardReferencesPresent).toBe(true);
347+
expect(result.provenance).toEqual({
348+
repoRootSource: 'explicit',
349+
runtimeProjectRootAligned: true,
350+
});
335351
expect(result.promotionCriteriaPassed).toBe(7);
336352
expect(result.promotionCriteriaTotal).toBe(7);
337353
expect(result.promotionCriteria.every((entry) => entry.satisfied)).toBe(true);
@@ -379,6 +395,10 @@ describe('foundation readiness contract', () => {
379395
repoRoot: fakeRepo,
380396
});
381397

398+
expect(result.provenance).toEqual({
399+
repoRootSource: 'explicit',
400+
runtimeProjectRootAligned: true,
401+
});
382402
expect(result.promotionCriteriaPassed).toBe(3);
383403
expect(result.promotionCriteriaTotal).toBe(7);
384404
expect(

src/frontend/agent_workspace_runtime.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1442,6 +1442,8 @@
14421442
vectorAdapterSignalKind: '',
14431443
vectorAdapterIndependent: false,
14441444
vectorAdapterLinkedIntoQueryBackend: false,
1445+
repoRootSource: '',
1446+
runtimeProjectRootAligned: false,
14451447
promotionCriteriaPassed: 0,
14461448
promotionCriteriaTotal: 0,
14471449
promotionBlockerIds: [],
@@ -1464,6 +1466,9 @@
14641466
const recommendationsCount = Array.isArray(readiness && readiness.recommendations)
14651467
? readiness.recommendations.length
14661468
: 0;
1469+
const provenance = readiness && readiness.provenance && typeof readiness.provenance === 'object'
1470+
? readiness.provenance
1471+
: {};
14671472
const promotionBlockers = Array.isArray(readiness && readiness.promotionBlockers)
14681473
? readiness.promotionBlockers
14691474
.map((entry) => {
@@ -1512,6 +1517,8 @@
15121517
vectorAdapterSignalKind: trimString(baseline.vectorAdapterSignalKind),
15131518
vectorAdapterIndependent: Boolean(baseline.vectorAdapterIndependent),
15141519
vectorAdapterLinkedIntoQueryBackend: Boolean(baseline.vectorAdapterLinkedIntoQueryBackend),
1520+
repoRootSource: trimString(provenance.repoRootSource),
1521+
runtimeProjectRootAligned: Boolean(provenance.runtimeProjectRootAligned),
15151522
promotionCriteriaPassed,
15161523
promotionCriteriaTotal,
15171524
promotionBlockerIds,
@@ -1525,7 +1532,7 @@
15251532
'assistant',
15261533
getI18nText(
15271534
'agentWorkspace.messages.foundationReadinessLoaded',
1528-
`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'}, criteria ${promotionCriteriaPassed}/${promotionCriteriaTotal}, blockers ${promotionBlockerIds.join(', ') || 'none'}).`,
1535+
`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'}, criteria ${promotionCriteriaPassed}/${promotionCriteriaTotal}, blockers ${promotionBlockerIds.join(', ') || 'none'}).`,
15291536
{
15301537
status: trimString(readiness && readiness.status) || 'unknown',
15311538
decision: trimString(readiness && readiness.decision) || 'unknown',
@@ -1541,6 +1548,8 @@
15411548
vectorAdapterLinkedIntoQueryBackend: Boolean(baseline.vectorAdapterLinkedIntoQueryBackend)
15421549
? 'yes'
15431550
: 'no',
1551+
repoRootSource: trimString(provenance.repoRootSource) || 'n/a',
1552+
runtimeProjectRootAligned: Boolean(provenance.runtimeProjectRootAligned) ? 'yes' : 'no',
15441553
promotionCriteriaPassed,
15451554
promotionCriteriaTotal,
15461555
promotionBlockerIds: promotionBlockerIds.join(', ') || 'none',
@@ -1564,6 +1573,8 @@
15641573
vectorAdapterSignalKind: '',
15651574
vectorAdapterIndependent: false,
15661575
vectorAdapterLinkedIntoQueryBackend: false,
1576+
repoRootSource: '',
1577+
runtimeProjectRootAligned: false,
15671578
promotionCriteriaPassed: 0,
15681579
promotionCriteriaTotal: 0,
15691580
promotionBlockerIds: [],

0 commit comments

Comments
 (0)