Skip to content

Commit 40a32e9

Browse files
V46 promotion: repair canonical posture rewrite
Adds V46-specific promotion rewrites for source-of-truth, notes, delta, and parity posture so promoted-mode validation removes stale V45/V46 draft language. Regenerates the V46 promotion-readiness digest for the corrected promotion script and adds a regression test that runs promotion preparation on a temporary V46 spec family before promoted validation.
1 parent ff8d9a5 commit 40a32e9

3 files changed

Lines changed: 160 additions & 2 deletions

File tree

.bitcode/v46-promotion-readiness-report.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@
171171
{
172172
"relativePath": "scripts/prepare-bitcode-spec-family-promotion.mjs",
173173
"present": true,
174-
"digest": "sha256:5cda7fced9684ab4d85e594a0528bbc282e43d5387ee6034d6257381e10adc86",
174+
"digest": "sha256:73948c223c7a0d2587ee213145b35f5e9c605dfee8700044b360f3acbd3a46c8",
175175
"requiredTokens": [
176176
{
177177
"token": "if (version === 'V46')",

packages/protocol/test/spec-family-promotion-posture.test.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import assert from 'node:assert/strict';
2+
import { execFileSync } from 'node:child_process';
23
import { copyFileSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
34
import { tmpdir } from 'node:os';
45
import path from 'node:path';
@@ -28,6 +29,16 @@ const V45_SPEC_FAMILY_FILES = [
2829
'BITCODE_SPEC_V45_PARITY_MATRIX.md',
2930
];
3031

32+
const V46_SPEC_FAMILY_FILES = [
33+
'BITCODE_SPEC.txt',
34+
'BITCODE_SPECIFYING.md',
35+
'BITCODE_SPEC_TEMPLATEGUIDE.md',
36+
'BITCODE_SPEC_V46.md',
37+
'BITCODE_SPEC_V46_DELTA.md',
38+
'BITCODE_SPEC_V46_NOTES.md',
39+
'BITCODE_SPEC_V46_PARITY_MATRIX.md',
40+
];
41+
3142
test('promoted spec-family validation rejects stale draft source-of-truth prose', async () => {
3243
const protocol = await import('../src/index.js');
3344
const tempDir = mkdtempSync(path.join(tmpdir(), 'bitcode-promoted-spec-posture-'));
@@ -73,6 +84,52 @@ test('promoted spec-family validation rejects stale draft source-of-truth prose'
7384
}
7485
});
7586

87+
test('V46 promotion preparation rewrites draft posture before promoted validation', async () => {
88+
const protocol = await import('../src/index.js');
89+
const tempDir = mkdtempSync(path.join(tmpdir(), 'bitcode-promoted-spec-posture-'));
90+
91+
try {
92+
for (const relativePath of V46_SPEC_FAMILY_FILES) {
93+
copyFileSync(path.join(repoRoot, relativePath), path.join(tempDir, relativePath));
94+
}
95+
96+
writeFileSync(path.join(tempDir, 'BITCODE_SPEC.txt'), 'V46\n');
97+
98+
execFileSync(
99+
process.execPath,
100+
[
101+
path.join(repoRoot, 'scripts/prepare-bitcode-spec-family-promotion.mjs'),
102+
'--version',
103+
'V46',
104+
'--commit',
105+
'0123456789abcdef0123456789abcdef01234567',
106+
'--repo-root',
107+
tempDir,
108+
],
109+
{ stdio: 'pipe' }
110+
);
111+
112+
const report = protocol.buildV21SpecFamilyReport({
113+
repoRoot: tempDir,
114+
version: 'V46',
115+
mode: 'promoted',
116+
currentTarget: 'V46',
117+
});
118+
119+
assert.equal(report.passed, true, report.failures.join('; '));
120+
assert.match(
121+
readFileSync(path.join(tempDir, 'BITCODE_SPEC_V46.md'), 'utf8'),
122+
/`BITCODE_SPEC\.txt` points to `V46`; V46 is the active promoted Bitcode canon\./u
123+
);
124+
assert.match(
125+
readFileSync(path.join(tempDir, 'BITCODE_SPEC_V46_NOTES.md'), 'utf8'),
126+
/Canonical pointer: `BITCODE_SPEC\.txt` -> `V46`/u
127+
);
128+
} finally {
129+
rmSync(tempDir, { recursive: true, force: true });
130+
}
131+
});
132+
76133
test('promoted spec-family validation rejects stale draft posture outside source-of-truth prose', async () => {
77134
const protocol = await import('../src/index.js');
78135
const tempDir = mkdtempSync(path.join(tmpdir(), 'bitcode-promoted-spec-posture-'));

scripts/prepare-bitcode-spec-family-promotion.mjs

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,101 @@ function rewriteV45PromotedParityMatrix(content, version) {
199199
.replaceAll('| spec closed; source gap |', '| closed |');
200200
}
201201

202+
/**
203+
* @param {string} content
204+
* @param {string} version
205+
*/
206+
function rewriteV46PromotedSourceOfTruthHierarchy(content, version) {
207+
if (version !== 'V46') return content;
208+
return content.replace(
209+
[
210+
'`BITCODE_SPEC.txt` points to `V45`; V45 is the active promoted Bitcode canon.',
211+
'`BITCODE_SPEC_V46.md`, `BITCODE_SPEC_V46_DELTA.md`,',
212+
'`BITCODE_SPEC_V46_NOTES.md`, and `BITCODE_SPEC_V46_PARITY_MATRIX.md` are draft',
213+
'target material only. They do not authorize implementation behavior until a',
214+
'gate-specific V46 parity or implementation gate accepts the relevant scope.'
215+
].join('\n'),
216+
[
217+
'`BITCODE_SPEC.txt` points to `V46`; V46 is the active promoted Bitcode canon.',
218+
'`BITCODE_SPEC_V46.md`, `BITCODE_SPEC_V46_DELTA.md`,',
219+
'`BITCODE_SPEC_V46_NOTES.md`, and `BITCODE_SPEC_V46_PARITY_MATRIX.md` are the',
220+
'promoted V46 specification-family material. The V46 formal specification family',
221+
'is active canon and authorizes implementation behavior only through the',
222+
'source-safe, proof-backed comprehension, interface, and operator-readback',
223+
'boundaries it states.'
224+
].join('\n')
225+
);
226+
}
227+
228+
/**
229+
* @param {string} content
230+
* @param {string} version
231+
*/
232+
function rewriteV46PromotedDraftPosture(content, version) {
233+
if (version !== 'V46') return content;
234+
return content
235+
.replace(
236+
'V46 does not replace V45 as active canon until promotion workflow validation.\nIt is the draft target for external protocol comprehension, public/operator\ndocs, route copy, interface contract readback, and launch-facing proof\nexplainability.',
237+
'V46 replaces V45 as active canon after promotion workflow validation. It is\nthe promoted target for external protocol comprehension, public/operator docs,\nroute copy, interface contract readback, and launch-facing proof explainability.'
238+
)
239+
.replaceAll('V46 draft work', 'V46 promoted canon work')
240+
.replaceAll('V46 formal draft', 'V46 formal canon')
241+
.replaceAll('V46 remains draft', 'V46 is active canon')
242+
.replaceAll('until V46 promotion', 'through V46 promotion')
243+
.replaceAll('before V46 can be promoted', 'before V46 promotion closure')
244+
.replaceAll('does not promote V46', 'records V46 promotion')
245+
.replaceAll('draft `BITCODE_SPEC_V46_PROVEN.md`', 'promoted `BITCODE_SPEC_V46_PROVEN.md`')
246+
.replaceAll('V45 remains active canon while V46 is drafted.', 'V46 is active canon after promotion workflow validation.')
247+
.replaceAll(
248+
'V46 does not replace V45 until a later promotion workflow validates and\n advances `BITCODE_SPEC.txt`.',
249+
'V46 replaces V45 after the maintained promotion workflow validates and\n advances `BITCODE_SPEC.txt`.'
250+
)
251+
.replaceAll('V45 active / V46 draft', 'pre-promotion V45-to-V46 draft')
252+
.replaceAll('V45 active / draft V46', 'pre-promotion draft V46')
253+
.replaceAll('Canonical pointer: `BITCODE_SPEC.txt` -> `V45`', 'Canonical pointer: `BITCODE_SPEC.txt` -> `V46`')
254+
.replaceAll('Active canonical anchor: `BITCODE_SPEC_V45.md`', 'Active canonical anchor: `BITCODE_SPEC_V46.md`')
255+
.replaceAll('Active generated proof appendix: `BITCODE_SPEC_V45_PROVEN.md`', 'Active generated proof appendix: `BITCODE_SPEC_V46_PROVEN.md`')
256+
.replaceAll(
257+
'Until then, V45 remains the active\npointer truth through `BITCODE_SPEC.txt`.',
258+
'V46 now holds the active pointer truth through `BITCODE_SPEC.txt`.'
259+
)
260+
.replaceAll(
261+
'These notes are not implementation authority above the active V45\nspecification family. They preserve draft notes-level atoms that must later be\nconsolidated into formal V46 specification text before parity or\nimplementation gates rely on them.',
262+
'These notes are implementation authority only through the promoted V46\nspecification family. They preserve accepted notes-level atoms that have been\nconsolidated into formal V46 specification text, parity evidence, proof\nreadback, and promotion receipts.'
263+
)
264+
.replaceAll('This matrix opens V46 parity work. It is intentionally draft-only: it records', 'This matrix records promoted V46 parity work. It records')
265+
.replaceAll('current authority remains V45.', 'current authority is V46.')
266+
.replaceAll('V45 is active canon; V46 is draft target only.', 'V46 is active canon; V45 is the prior promoted anchor.')
267+
.replaceAll('`BITCODE_SPEC.txt` remains V45 during V46 promoted canon work', '`BITCODE_SPEC.txt` points to V46 after promotion')
268+
.replaceAll('Gate 1 preserves active V45 / draft V46 posture.', 'Gate 1 preserved pre-promotion posture; promotion now records active V46 posture.')
269+
.replaceAll('V45 is active canon while V46 is draft target.', 'V46 is active canon after promotion workflow validation.')
270+
.replaceAll(
271+
'validate active V45 plus draft V46, prepare V46 active / draft V47 posture',
272+
'validated pre-promotion V46 draft posture, prepare V46 active / draft V47 posture'
273+
)
274+
.replaceAll(
275+
'validate active V45 plus draft V46 and the gate branch is committed',
276+
'validated pre-promotion V46 draft posture and the gate branch is committed'
277+
);
278+
}
279+
280+
/**
281+
* @param {string} content
282+
* @param {string} version
283+
*/
284+
function rewriteV46PromotedParityMatrix(content, version) {
285+
if (version !== 'V46') return content;
286+
return content
287+
.replace(
288+
'V46 parity truth, generated comprehension artifacts, local interface rehearsal, gate closure, and promotion automation are aligned',
289+
'V46 promoted parity truth, generated comprehension artifacts, local interface rehearsal, gate closure, and promotion automation are aligned'
290+
)
291+
.replaceAll('| draft-required |', '| closed |')
292+
.replaceAll('| implemented prerequisite |', '| closed |')
293+
.replaceAll('| accepted boundary |', '| closed |')
294+
.replaceAll('| pending |', '| closed |');
295+
}
296+
202297
/**
203298
* @param {string} version
204299
* @param {string} commit
@@ -756,7 +851,13 @@ function rewritePromotionStatus(version, commit, content, kind) {
756851
'V46 source-side protocol comprehension object model, public/operator claim boundaries, route readback, interface claim contracts, proof readback, local rehearsal, workflow, and promotion surfaces are canonicalized in the promoted V46 file family',
757852
'V46 state': stateByKind[kind]
758853
});
759-
return kind === 'parity' ? rewritePromotedParityJudgments(rewritten, version) : rewritten;
854+
const promotedPosture = rewriteV46PromotedDraftPosture(
855+
rewriteV46PromotedSourceOfTruthHierarchy(rewritten, version),
856+
version
857+
);
858+
return kind === 'parity'
859+
? rewriteV46PromotedParityMatrix(rewritePromotedParityJudgments(promotedPosture, version), version)
860+
: promotedPosture;
760861
}
761862

762863
if (!['V21', 'V22', 'V23', 'V24', 'V25'].includes(version)) {

0 commit comments

Comments
 (0)