[verified] docs: reconcile AeroSim Wave 2 progress
Build and publish Corp v1 Board portal / build (pull_request) Successful in 39s
Build and publish Corp v1 Board portal / build (pull_request) Successful in 39s
This commit is contained in:
@@ -48,8 +48,8 @@ A playable MVP covering a light trainer, commercial airliner, and fighter-style
|
|||||||
|
|
||||||
- Project organization: [corp-v1-aerosim](https://gitea.lego-cloud.eu/corp-v1-aerosim)
|
- Project organization: [corp-v1-aerosim](https://gitea.lego-cloud.eu/corp-v1-aerosim)
|
||||||
- Skills organization: [corp-v1-aerosim-skills-code-agent](https://gitea.lego-cloud.eu/corp-v1-aerosim-skills-code-agent)
|
- Skills organization: [corp-v1-aerosim-skills-code-agent](https://gitea.lego-cloud.eu/corp-v1-aerosim-skills-code-agent)
|
||||||
- [Application repository](https://gitea.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim) — `test` at `58d33ffbd3ca21ffdc5882a75de8fe71c25188b6`
|
- [Application repository](https://gitea.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim) — `test` at `efbf3967548f1cbf5e06f97fa9d659535e35a7b4`
|
||||||
- [Documentation repository](https://gitea.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim-documentation) — `test` at `29d5e7810e63f3407f62730c1b2c71bc0644310b`
|
- [Documentation repository](https://gitea.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim-documentation) — `test` at `f686610a8b1b21825c66dc424f484fb2672933d7`
|
||||||
- [Published documentation](https://pages.apps.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim-documentation/) — protected by the existing Keycloak access layer
|
- [Published documentation](https://pages.apps.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim-documentation/) — protected by the existing Keycloak access layer
|
||||||
|
|
||||||
## Delivery progress checkpoint — 2026-09-03
|
## Delivery progress checkpoint — 2026-09-03
|
||||||
@@ -58,11 +58,11 @@ Release `1.0.0` contains 114 Tasks. Progress is reported by lifecycle checkpoint
|
|||||||
|
|
||||||
| Measure | Progress | Meaning |
|
| Measure | Progress | Meaning |
|
||||||
|---|---:|---|
|
|---|---:|---|
|
||||||
| Canonical `ToBeReleased` | 4 / 114 (3.5%) | `TASK-0001`, `TASK-0008`, `TASK-0011`, and `TASK-0014` have reviewed implementation, merged application changes, successful integrated CI, and reconciled canonical delivery evidence. |
|
| Canonical `ToBeReleased` | 8 / 114 (7.0%) | Wave 1 Tasks `TASK-0001`, `TASK-0008`, `TASK-0011`, and `TASK-0014` plus Wave 2 Tasks `TASK-0012`, `TASK-0015`, `TASK-0073`, and `TASK-0114` have reconciled canonical delivery evidence. The remaining 106 ReadyForDelivery Tasks have not reached this checkpoint. |
|
||||||
| Repository-verified implementation | 5 / 114 (4.4%) | The four canonical Tasks plus `TASK-0015`, merged through application PR #13 at application `test` SHA `58d33ffbd3ca21ffdc5882a75de8fe71c25188b6`; its canonical task-history reconciliation is pending completion of the active Wave 2 delivery. |
|
| Repository-verified implementation | 8 / 114 (7.0%) | The same eight Tasks are implemented at application `test` SHA `efbf3967548f1cbf5e06f97fa9d659535e35a7b4`; integrated publish task `1760` and validate task `1761` succeeded. This implementation measure is reported separately from canonical lifecycle and release state. |
|
||||||
| Released | 0 / 114 (0%) | No Release `1.0.0` artifact has been approved and released. `ToBeReleased` is not release authorization. |
|
| Released | 0 / 114 (0%) | No Release `1.0.0` artifact has been approved and released. `ToBeReleased` is not release authorization. |
|
||||||
|
|
||||||
Wave 1 is implemented and reconciled. Wave 2 is active: `TASK-0015` is integrated, while `TASK-0012`, `TASK-0073`, and `TASK-0114` remain under automated review and repair. The authoritative task-level lifecycle remains in the [AeroSim documentation](https://pages.apps.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim-documentation/); this Board record is a dated portfolio checkpoint, not a second task database.
|
Wave 2 is complete: its final application head is `efbf3967548f1cbf5e06f97fa9d659535e35a7b4`, and its canonical documentation was merged through PR #143 at documentation `test` SHA `f686610a8b1b21825c66dc424f484fb2672933d7`. Documentation exact-head build task `1762` and integrated build task `1763` succeeded, and the deployed release-readiness readback passed. Wave 3 is active: `TASK-0013`, `TASK-0016`, `TASK-0074`, and `TASK-0115` are claimed and in progress, but are not yet implemented or merged. The authoritative task-level lifecycle remains in the [AeroSim documentation](https://pages.apps.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim-documentation/); this Board record is a dated portfolio checkpoint, not a second task database.
|
||||||
|
|
||||||
## Discord
|
## Discord
|
||||||
|
|
||||||
|
|||||||
+343
-15
@@ -58,25 +58,353 @@ assert.match(board, /Only these Board members may approve a project kickoff or p
|
|||||||
assert.match(board, /Only these Board members may approve changes to `corp-v1--main`/i);
|
assert.match(board, /Only these Board members may approve changes to `corp-v1--main`/i);
|
||||||
|
|
||||||
const aerosimProject = read('docs/projects/aerosim.md');
|
const aerosimProject = read('docs/projects/aerosim.md');
|
||||||
for (const marker of [
|
const APP_SHA = 'efbf3967548f1cbf5e06f97fa9d659535e35a7b4';
|
||||||
|
const DOC_SHA = 'f686610a8b1b21825c66dc424f484fb2672933d7';
|
||||||
|
|
||||||
|
const markdownSection = (document, heading) => {
|
||||||
|
const marker = `## ${heading}`;
|
||||||
|
const start = document.indexOf(marker);
|
||||||
|
assert.notEqual(start, -1, `AeroSim section is missing: ${heading}`);
|
||||||
|
const end = document.indexOf('\n## ', start + marker.length);
|
||||||
|
return document.slice(start, end === -1 ? document.length : end);
|
||||||
|
};
|
||||||
|
|
||||||
|
const uniqueLine = (text, predicate, description) => {
|
||||||
|
const matches = text.split('\n').filter(predicate);
|
||||||
|
assert.equal(matches.length, 1, `AeroSim must contain exactly one ${description}`);
|
||||||
|
return matches[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
function verifyAeroSimProject(document) {
|
||||||
|
const requiredSectionHeadings = [
|
||||||
|
'Resources',
|
||||||
|
'Delivery progress checkpoint — 2026-09-03',
|
||||||
|
'Discord',
|
||||||
|
];
|
||||||
|
const documentLines = document.split('\n');
|
||||||
|
const requiredSectionIndices = requiredSectionHeadings.map((heading) => {
|
||||||
|
const indices = documentLines.flatMap((line, index) => line === `## ${heading}` ? [index] : []);
|
||||||
|
assert.equal(indices.length, 1, `AeroSim required section heading must appear exactly once: ${heading}`);
|
||||||
|
return indices[0];
|
||||||
|
});
|
||||||
|
assert.ok(
|
||||||
|
requiredSectionIndices.every((index, position) => position === 0 || requiredSectionIndices[position - 1] < index),
|
||||||
|
'AeroSim required sections must follow Resources, checkpoint, Discord order',
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const marker of [
|
||||||
'Delivery progress checkpoint — 2026-09-03',
|
'Delivery progress checkpoint — 2026-09-03',
|
||||||
'4 / 114',
|
'8 / 114',
|
||||||
'3.5%',
|
'7.0%',
|
||||||
'5 / 114',
|
|
||||||
'4.4%',
|
|
||||||
'0 / 114',
|
'0 / 114',
|
||||||
|
'TASK-0012',
|
||||||
'TASK-0015',
|
'TASK-0015',
|
||||||
'PR #13',
|
'TASK-0073',
|
||||||
'58d33ffbd3ca21ffdc5882a75de8fe71c25188b6',
|
'TASK-0114',
|
||||||
'29d5e7810e63f3407f62730c1b2c71bc0644310b',
|
'TASK-0013',
|
||||||
]) {
|
'TASK-0016',
|
||||||
assert.ok(aerosimProject.includes(marker), `AeroSim progress checkpoint is missing: ${marker}`);
|
'TASK-0074',
|
||||||
|
'TASK-0115',
|
||||||
|
'PR #143',
|
||||||
|
'1760',
|
||||||
|
'1761',
|
||||||
|
'1762',
|
||||||
|
'1763',
|
||||||
|
'efbf3967548f1cbf5e06f97fa9d659535e35a7b4',
|
||||||
|
'f686610a8b1b21825c66dc424f484fb2672933d7',
|
||||||
|
'106 ReadyForDelivery',
|
||||||
|
]) {
|
||||||
|
assert.ok(document.includes(marker), `AeroSim progress checkpoint is missing: ${marker}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const resources = markdownSection(document, 'Resources');
|
||||||
|
const applicationResource = uniqueLine(resources, (line) => line.startsWith('- [Application repository]'), 'application repository resource');
|
||||||
|
const documentationResource = uniqueLine(resources, (line) => line.startsWith('- [Documentation repository]'), 'documentation repository resource');
|
||||||
|
assert.match(applicationResource, new RegExp(`application.*\\b${APP_SHA}\\b`, 'i'), 'application repository must reference the application SHA');
|
||||||
|
assert.match(documentationResource, new RegExp(`documentation.*\\b${DOC_SHA}\\b`, 'i'), 'documentation repository must reference the documentation SHA');
|
||||||
|
|
||||||
|
const checkpoint = markdownSection(document, 'Delivery progress checkpoint — 2026-09-03');
|
||||||
|
const checkpointLines = checkpoint.split('\n');
|
||||||
|
const checkpointTableHeader = '| Measure | Progress | Meaning |';
|
||||||
|
const checkpointTableHeaderIndices = checkpointLines.flatMap(
|
||||||
|
(line, index) => line === checkpointTableHeader ? [index] : [],
|
||||||
|
);
|
||||||
|
assert.equal(checkpointTableHeaderIndices.length, 1, 'AeroSim checkpoint table header must appear exactly once');
|
||||||
|
const checkpointTableHeaderIndex = checkpointTableHeaderIndices[0];
|
||||||
|
assert.equal(
|
||||||
|
checkpointLines[checkpointTableHeaderIndex + 1],
|
||||||
|
'|---|---:|---|',
|
||||||
|
'AeroSim checkpoint table separator must exactly preserve its three columns and progress alignment',
|
||||||
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
checkpointLines.slice(checkpointTableHeaderIndex + 2, checkpointTableHeaderIndex + 5).map(
|
||||||
|
(line) => line.match(/^\| (Canonical `ToBeReleased`|Repository-verified implementation|Released) \|/)?.[1],
|
||||||
|
),
|
||||||
|
['Canonical `ToBeReleased`', 'Repository-verified implementation', 'Released'],
|
||||||
|
'AeroSim checkpoint rows must follow canonical, implementation, released order',
|
||||||
|
);
|
||||||
|
const canonicalRow = uniqueLine(checkpoint, (line) => line.startsWith('| Canonical `ToBeReleased` |'), 'canonical ToBeReleased row');
|
||||||
|
const implementationRow = uniqueLine(checkpoint, (line) => line.startsWith('| Repository-verified implementation |'), 'repository-verified implementation row');
|
||||||
|
const releasedRow = uniqueLine(checkpoint, (line) => line.startsWith('| Released |'), 'released row');
|
||||||
|
const waveStatus = uniqueLine(checkpoint, (line) => line.startsWith('Wave 2 is complete:'), 'Wave 2/Wave 3 status paragraph');
|
||||||
|
|
||||||
|
assert.match(releasedRow, /\|\s*0\s*\/\s*114\s*\(0%\)/i, 'AeroSim must distinguish released progress');
|
||||||
|
assert.match(canonicalRow, /\|\s*8\s*\/\s*114\s*\(7\.0%\)/i, 'AeroSim must expose canonical delivery completion');
|
||||||
|
assert.match(implementationRow, /\|\s*8\s*\/\s*114\s*\(7\.0%\)/i, 'AeroSim must expose repository-verified implementation separately');
|
||||||
|
assert.match(
|
||||||
|
canonicalRow,
|
||||||
|
/Wave 2 Tasks `TASK-0012`, `TASK-0015`, `TASK-0073`, and `TASK-0114`/,
|
||||||
|
'AeroSim Wave 2 task group must remain on the canonical completion row',
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
implementationRow,
|
||||||
|
new RegExp('application `test` SHA `' + APP_SHA + '`; integrated publish task `1760` and validate task `1761` succeeded', 'i'),
|
||||||
|
'AeroSim implementation row must bind the application SHA, publish task 1760, and validate task 1761',
|
||||||
|
);
|
||||||
|
assert.match(waveStatus, new RegExp('final application head is `' + APP_SHA + '`'), 'Wave 2 status must bind the final application head to the application SHA');
|
||||||
|
assert.match(waveStatus, new RegExp('documentation `test` SHA `' + DOC_SHA + '`'), 'Wave 2 status must bind the documentation merge to the documentation SHA');
|
||||||
|
assert.match(
|
||||||
|
waveStatus,
|
||||||
|
/Documentation exact-head build task `1762` and integrated build task `1763` succeeded/,
|
||||||
|
'Wave 2 status must bind exact-head build task 1762 and integrated build task 1763',
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
waveStatus,
|
||||||
|
/Wave 3 is active: `TASK-0013`, `TASK-0016`, `TASK-0074`, and `TASK-0115` are claimed/,
|
||||||
|
'AeroSim Wave 3 task group must remain in the active Wave 3 clause',
|
||||||
|
);
|
||||||
|
assert.match(waveStatus, /Wave 3[^\n]*claimed[^\n]*not (?:yet )?implemented or merged/i, 'AeroSim must distinguish active Wave 3 claims from implementation');
|
||||||
|
assert.match(waveStatus, /dated portfolio checkpoint, not a second task database/i, 'AeroSim must remain a non-authoritative portfolio checkpoint');
|
||||||
|
|
||||||
|
for (const [staleMarker, stalePattern] of [
|
||||||
|
['4 / 114', /(?<!\d)4\s*\/\s*114(?!\d)/],
|
||||||
|
['3.5%', /(?<![\d.])3\.5%(?![\d.])/],
|
||||||
|
['5 / 114', /(?<!\d)5\s*\/\s*114(?!\d)/],
|
||||||
|
['4.4%', /(?<![\d.])4\.4%(?![\d.])/],
|
||||||
|
['58d33ffbd3ca21ffdc5882a75de8fe71c25188b6', /58d33ffbd3ca21ffdc5882a75de8fe71c25188b6/],
|
||||||
|
['29d5e7810e63f3407f62730c1b2c71bc0644310b', /29d5e7810e63f3407f62730c1b2c71bc0644310b/],
|
||||||
|
]) {
|
||||||
|
assert.doesNotMatch(document, stalePattern, `stale AeroSim checkpoint marker must not remain: ${staleMarker}`);
|
||||||
|
}
|
||||||
|
assert.doesNotMatch(waveStatus, /Wave 2 is active/i, 'Wave 2 must not remain active');
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyAeroSimProject(aerosimProject);
|
||||||
|
|
||||||
|
if (process.argv.includes('--self-test')) {
|
||||||
|
const replaceExactly = (document, oldText, newText) => {
|
||||||
|
assert.equal(document.split(oldText).length - 1, 1, `mutation fixture must find exactly one occurrence: ${oldText}`);
|
||||||
|
return document.replace(oldText, newText);
|
||||||
|
};
|
||||||
|
const swap = (document, left, right) => {
|
||||||
|
const placeholder = '__VERIFY_PORTAL_MUTATION_PLACEHOLDER__';
|
||||||
|
return replaceExactly(replaceExactly(replaceExactly(document, left, placeholder), right, left), placeholder, right);
|
||||||
|
};
|
||||||
|
const swapAll = (document, left, right) => {
|
||||||
|
assert.ok(document.includes(left), `mutation fixture must find: ${left}`);
|
||||||
|
assert.ok(document.includes(right), `mutation fixture must find: ${right}`);
|
||||||
|
const placeholder = '__VERIFY_PORTAL_MUTATION_PLACEHOLDER__';
|
||||||
|
return document.replaceAll(left, placeholder).replaceAll(right, left).replaceAll(placeholder, right);
|
||||||
|
};
|
||||||
|
const checkpointRow = (document, prefix) => uniqueLine(
|
||||||
|
markdownSection(document, 'Delivery progress checkpoint — 2026-09-03'),
|
||||||
|
(line) => line.startsWith(prefix),
|
||||||
|
`${prefix} mutation source row`,
|
||||||
|
);
|
||||||
|
const sectionBlock = (document, heading) => {
|
||||||
|
const section = markdownSection(document, heading);
|
||||||
|
return section.endsWith('\n') ? section : `${section}\n`;
|
||||||
|
};
|
||||||
|
const futureCountFixtures = [14, 15, 24, 25, 114].flatMap((count) => [
|
||||||
|
{
|
||||||
|
name: `accepts legitimate future count ${count} / 114`,
|
||||||
|
document: replaceExactly(
|
||||||
|
aerosimProject,
|
||||||
|
'Release `1.0.0` contains 114 Tasks.',
|
||||||
|
`Release \`1.0.0\` contains 114 Tasks. Forecast example: ${count} / 114.`,
|
||||||
|
),
|
||||||
|
accepted: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `accepts legitimate compact future count ${count}/114`,
|
||||||
|
document: replaceExactly(
|
||||||
|
aerosimProject,
|
||||||
|
'Release `1.0.0` contains 114 Tasks.',
|
||||||
|
`Release \`1.0.0\` contains 114 Tasks. Forecast example: ${count}/114.`,
|
||||||
|
),
|
||||||
|
accepted: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const staleCountFixtures = [4, 5].flatMap((count) => [
|
||||||
|
{
|
||||||
|
name: `rejects stale count ${count} / 114`,
|
||||||
|
document: replaceExactly(
|
||||||
|
aerosimProject,
|
||||||
|
'Release `1.0.0` contains 114 Tasks.',
|
||||||
|
`Release \`1.0.0\` contains 114 Tasks. Superseded snapshot: ${count} / 114.`,
|
||||||
|
),
|
||||||
|
accepted: false,
|
||||||
|
message: new RegExp(`stale AeroSim checkpoint marker must not remain: ${count} / 114`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `rejects compact stale count ${count}/114`,
|
||||||
|
document: replaceExactly(
|
||||||
|
aerosimProject,
|
||||||
|
'Release `1.0.0` contains 114 Tasks.',
|
||||||
|
`Release \`1.0.0\` contains 114 Tasks. Superseded snapshot: ${count}/114.`,
|
||||||
|
),
|
||||||
|
accepted: false,
|
||||||
|
message: new RegExp(`stale AeroSim checkpoint marker must not remain: ${count} / 114`),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const canonicalRowFixture = checkpointRow(aerosimProject, '| Canonical `ToBeReleased` |');
|
||||||
|
const implementationRowFixture = checkpointRow(aerosimProject, '| Repository-verified implementation |');
|
||||||
|
const releasedRowFixture = checkpointRow(aerosimProject, '| Released |');
|
||||||
|
const resourcesSectionFixture = sectionBlock(aerosimProject, 'Resources');
|
||||||
|
const checkpointSectionFixture = sectionBlock(aerosimProject, 'Delivery progress checkpoint — 2026-09-03');
|
||||||
|
const discordSectionFixture = sectionBlock(aerosimProject, 'Discord');
|
||||||
|
const fixtures = [
|
||||||
|
...futureCountFixtures,
|
||||||
|
...staleCountFixtures,
|
||||||
|
{
|
||||||
|
name: 'rejects removed checkpoint table header',
|
||||||
|
document: replaceExactly(aerosimProject, '| Measure | Progress | Meaning |\n', ''),
|
||||||
|
accepted: false,
|
||||||
|
message: /checkpoint table header/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects malformed checkpoint table header',
|
||||||
|
document: replaceExactly(aerosimProject, '| Measure | Progress | Meaning |', '| Measure | Meaning | Progress |'),
|
||||||
|
accepted: false,
|
||||||
|
message: /checkpoint table header/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects removed checkpoint table separator',
|
||||||
|
document: replaceExactly(aerosimProject, '|---|---:|---|\n', ''),
|
||||||
|
accepted: false,
|
||||||
|
message: /checkpoint table separator/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects malformed checkpoint table separator',
|
||||||
|
document: replaceExactly(aerosimProject, '|---|---:|---|', '|---|---|---|'),
|
||||||
|
accepted: false,
|
||||||
|
message: /checkpoint table separator/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects swapped canonical and implementation rows',
|
||||||
|
document: swap(aerosimProject, canonicalRowFixture, implementationRowFixture),
|
||||||
|
accepted: false,
|
||||||
|
message: /checkpoint rows must follow canonical, implementation, released order/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects swapped implementation and released rows',
|
||||||
|
document: swap(aerosimProject, implementationRowFixture, releasedRowFixture),
|
||||||
|
accepted: false,
|
||||||
|
message: /checkpoint rows must follow canonical, implementation, released order/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects removed Resources heading',
|
||||||
|
document: replaceExactly(aerosimProject, '## Resources\n', ''),
|
||||||
|
accepted: false,
|
||||||
|
message: /required section heading.*Resources/i,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects renamed Resources heading',
|
||||||
|
document: replaceExactly(aerosimProject, '## Resources', '## Project resources'),
|
||||||
|
accepted: false,
|
||||||
|
message: /required section heading.*Resources/i,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects removed checkpoint heading',
|
||||||
|
document: replaceExactly(aerosimProject, '## Delivery progress checkpoint — 2026-09-03\n', ''),
|
||||||
|
accepted: false,
|
||||||
|
message: /required section heading.*Delivery progress checkpoint/i,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects renamed checkpoint heading',
|
||||||
|
document: replaceExactly(aerosimProject, '## Delivery progress checkpoint — 2026-09-03', '## Delivery status — 2026-09-03'),
|
||||||
|
accepted: false,
|
||||||
|
message: /required section heading.*Delivery progress checkpoint/i,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects removed Discord heading',
|
||||||
|
document: replaceExactly(aerosimProject, '## Discord\n', ''),
|
||||||
|
accepted: false,
|
||||||
|
message: /required section heading.*Discord/i,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects renamed Discord heading',
|
||||||
|
document: replaceExactly(aerosimProject, '## Discord', '## Project channels'),
|
||||||
|
accepted: false,
|
||||||
|
message: /required section heading.*Discord/i,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects Resources and checkpoint sections in reverse order',
|
||||||
|
document: swap(aerosimProject, resourcesSectionFixture, checkpointSectionFixture),
|
||||||
|
accepted: false,
|
||||||
|
message: /required sections must follow Resources, checkpoint, Discord order/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects checkpoint and Discord sections in reverse order',
|
||||||
|
document: swap(aerosimProject, checkpointSectionFixture, discordSectionFixture),
|
||||||
|
accepted: false,
|
||||||
|
message: /required sections must follow Resources, checkpoint, Discord order/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects swapped application and documentation SHA associations',
|
||||||
|
document: swapAll(aerosimProject, APP_SHA, DOC_SHA),
|
||||||
|
accepted: false,
|
||||||
|
message: /application repository.*SHA|documentation repository.*SHA/i,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects swapped publish and validate CI task associations',
|
||||||
|
document: replaceExactly(
|
||||||
|
aerosimProject,
|
||||||
|
'publish task `1760` and validate task `1761`',
|
||||||
|
'publish task `1761` and validate task `1760`',
|
||||||
|
),
|
||||||
|
accepted: false,
|
||||||
|
message: /publish task.*1760|validate task.*1761/i,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects swapped documentation CI task associations',
|
||||||
|
document: replaceExactly(
|
||||||
|
aerosimProject,
|
||||||
|
'exact-head build task `1762` and integrated build task `1763`',
|
||||||
|
'exact-head build task `1763` and integrated build task `1762`',
|
||||||
|
),
|
||||||
|
accepted: false,
|
||||||
|
message: /exact-head build task.*1762|integrated build task.*1763/i,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rejects Wave 2 and Wave 3 task-group permutations',
|
||||||
|
document: swap(
|
||||||
|
aerosimProject,
|
||||||
|
'`TASK-0012`, `TASK-0015`, `TASK-0073`, and `TASK-0114`',
|
||||||
|
'`TASK-0013`, `TASK-0016`, `TASK-0074`, and `TASK-0115`',
|
||||||
|
),
|
||||||
|
accepted: false,
|
||||||
|
message: /Wave 2 task group|Wave 3 task group/i,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const failures = [];
|
||||||
|
for (const fixture of fixtures) {
|
||||||
|
try {
|
||||||
|
verifyAeroSimProject(fixture.document);
|
||||||
|
if (!fixture.accepted) throw new assert.AssertionError({message: 'mutated document was incorrectly accepted'});
|
||||||
|
console.log(`ok - ${fixture.name}`);
|
||||||
|
} catch (error) {
|
||||||
|
if (!fixture.accepted && fixture.message?.test(error.message)) {
|
||||||
|
console.log(`ok - ${fixture.name}`);
|
||||||
|
} else {
|
||||||
|
failures.push(`${fixture.name}: ${error.message}`);
|
||||||
|
console.error(`not ok - ${fixture.name}: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.equal(failures.length, 0, `AeroSim verifier self-tests failed:\n${failures.join('\n')}`);
|
||||||
|
console.log('AeroSim verifier self-tests passed.');
|
||||||
}
|
}
|
||||||
assert.match(aerosimProject, /Released[^\n]*0\s*\/\s*114[^\n]*0%/i, 'AeroSim must distinguish released progress');
|
|
||||||
assert.match(aerosimProject, /ToBeReleased[^\n]*4\s*\/\s*114[^\n]*3\.5%/i, 'AeroSim must expose canonical delivery completion');
|
|
||||||
assert.match(aerosimProject, /repository-verified[^\n]*5\s*\/\s*114[^\n]*4\.4%/i, 'AeroSim must expose pending-reconciliation implementation evidence');
|
|
||||||
assert.doesNotMatch(aerosimProject, /Application repository[^\n]*14b5c0e8f25215d8bb4f41edcc0cdff4a87c342c/, 'stale AeroSim application SHA must not remain');
|
|
||||||
assert.doesNotMatch(aerosimProject, /Documentation repository[^\n]*5f674525f6c8b5ce29fe2653350c6188fb97ea01/, 'stale AeroSim documentation SHA must not remain');
|
|
||||||
|
|
||||||
const lifecycle = read('docs/governance/project-lifecycle.md');
|
const lifecycle = read('docs/governance/project-lifecycle.md');
|
||||||
assert.match(lifecycle, /Board approval/i, 'project lifecycle must require Board approval');
|
assert.match(lifecycle, /Board approval/i, 'project lifecycle must require Board approval');
|
||||||
|
|||||||
Reference in New Issue
Block a user