From 61aa7d6454301bab9c7a34d0b0911646ad0df1d6 Mon Sep 17 00:00:00 2001 From: jarvis-at-skic Date: Mon, 7 Sep 2026 04:40:52 +0000 Subject: [PATCH] [verified] docs: update AeroSim Wave 15 roll-up --- docs/projects/aerosim.md | 16 +-- package.json | 6 ++ pnpm-lock.yaml | 32 +++--- scripts/verify-portal.mjs | 135 ++++++++++--------------- tests/aerosim-delivery-rollup.test.mjs | 39 +++++++ 5 files changed, 124 insertions(+), 104 deletions(-) create mode 100644 tests/aerosim-delivery-rollup.test.mjs diff --git a/docs/projects/aerosim.md b/docs/projects/aerosim.md index 0106dab..300edb8 100644 --- a/docs/projects/aerosim.md +++ b/docs/projects/aerosim.md @@ -48,21 +48,23 @@ 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) - 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 `efbf3967548f1cbf5e06f97fa9d659535e35a7b4` -- [Documentation repository](https://gitea.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim-documentation) — `test` at `f686610a8b1b21825c66dc424f484fb2672933d7` +- [Application repository](https://gitea.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim) — `test` at `09628fbb828380fbe159be7530da26f4bbf02129` +- [Documentation repository](https://gitea.lego-cloud.eu/corp-v1-aerosim/corp-v1-aerosim-documentation) — `test` at `d8a45594c33efc3acbd1523955d4f235facc9a1f` - [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-07 Release `1.0.0` contains 114 Tasks. Progress is reported by lifecycle checkpoint rather than collapsing implementation and release into one percentage. | Measure | Progress | Meaning | |---|---:|---| -| 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 | 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. | +| Canonical `ToBeReleased` | 49 / 114 (43.0%) | Canonical records place the Tasks in Waves 1–8 and 12–14 at the release-handoff state. This is not a release. | +| Repository-verified implementation pending reconciliation | 6 / 114 (5.3%) | `TASK-0048`, `TASK-0061`, `TASK-0065`, `TASK-0077`, `TASK-0083`, and `TASK-0111` are merged into the validated current application integration head, while their canonical records remain `InProgress`. This repository checkpoint does not replace canonical reconciliation. | +| Canonical `InProgress` | 7 / 114 (6.1%) | Wave 15 Tasks are claimed as one Delivery ownership unit and remain under implementation. | +| Canonical `ReadyForDelivery` | 58 / 114 (50.9%) | Unfinished Tasks in Waves 9–11 and 16–30 remain ready but unclaimed while Wave 15 is active. | +| Released | 0 / 114 (0.0%) | No Release `1.0.0` artifact has been approved and released. `ToBeReleased` is not release authorization. | -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. +Wave 15 is active, and 6 of its 7 Tasks are repository-verified through merged application PRs #85, #89, #90, #95, #96, and #97. The current application integration head is `09628fbb828380fbe159be7530da26f4bbf02129`; its integrated tasks `2718`–`2720` succeeded. `TASK-0078` remains canonical `InProgress`, and its implementation PR #92 is closed without merge, so Wave 16 remains unclaimed. The canonical Wave 15 claim remains at documentation `test` SHA `d8a45594c33efc3acbd1523955d4f235facc9a1f`, verified by PR #155 exact-head build task `2581` and integrated build task `2582`. 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 diff --git a/package.json b/package.json index e222e32..9835845 100644 --- a/package.json +++ b/package.json @@ -50,5 +50,11 @@ }, "engines": { "node": ">=20.0" + }, + "pnpm": { + "overrides": { + "fast-uri": "3.1.6", + "serialize-javascript": "7.0.3" + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0dd60de..d048618 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,10 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + fast-uri: 3.1.6 + serialize-javascript: 7.0.3 + importers: .: @@ -3061,8 +3065,8 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - fast-uri@3.1.5: - resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} + fast-uri@3.1.6: + resolution: {integrity: sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==} fast-xml-builder@1.3.1: resolution: {integrity: sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==} @@ -4763,9 +4767,6 @@ packages: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - range-parser@1.2.0: resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} engines: {node: '>= 0.6'} @@ -5035,8 +5036,9 @@ packages: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@7.0.3: + resolution: {integrity: sha512-h+cZ/XXarqDgCjo+YSyQU/ulDEESGGf8AMK9pPNmhNSl/FzPl6L8pMp1leca5z6NuG6tvV/auC8/43tmovowww==} + engines: {node: '>=20.0.0'} serve-handler@6.1.7: resolution: {integrity: sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==} @@ -8904,7 +8906,7 @@ snapshots: ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.5 + fast-uri: 3.1.6 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -9337,7 +9339,7 @@ snapshots: globby: 13.2.2 normalize-path: 3.0.0 schema-utils: 4.3.3 - serialize-javascript: 6.0.2 + serialize-javascript: 7.0.3 webpack: 5.109.2(@swc/core@1.15.47)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.26))(html-minifier-terser@7.2.0)(postcss@8.5.26) core-js-compat@3.50.0: @@ -9404,7 +9406,7 @@ snapshots: jest-worker: 29.7.0 postcss: 8.5.26 schema-utils: 4.3.3 - serialize-javascript: 6.0.2 + serialize-javascript: 7.0.3 webpack: 5.109.2(@swc/core@1.15.47)(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.26))(html-minifier-terser@7.2.0)(postcss@8.5.26) optionalDependencies: clean-css: 5.3.3 @@ -9847,7 +9849,7 @@ snapshots: fast-json-stable-stringify@2.1.0: {} - fast-uri@3.1.5: {} + fast-uri@3.1.6: {} fast-xml-builder@1.3.1: dependencies: @@ -11890,10 +11892,6 @@ snapshots: quick-lru@5.1.1: {} - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - range-parser@1.2.0: {} range-parser@1.2.1: {} @@ -12247,9 +12245,7 @@ snapshots: transitivePeerDependencies: - supports-color - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 + serialize-javascript@7.0.3: {} serve-handler@6.1.7: dependencies: diff --git a/scripts/verify-portal.mjs b/scripts/verify-portal.mjs index afc52b0..f7eb04d 100644 --- a/scripts/verify-portal.mjs +++ b/scripts/verify-portal.mjs @@ -85,8 +85,9 @@ for (const marker of ['corp-v1-dpvp', 'dpvp-maintainers', 'dpvp-skill-maintainer } const aerosimProject = read('docs/projects/aerosim.md'); -const APP_SHA = 'efbf3967548f1cbf5e06f97fa9d659535e35a7b4'; -const DOC_SHA = 'f686610a8b1b21825c66dc424f484fb2672933d7'; +const APP_SHA = '09628fbb828380fbe159be7530da26f4bbf02129'; +const DOC_SHA = 'd8a45594c33efc3acbd1523955d4f235facc9a1f'; +const AEROSIM_CHECKPOINT_HEADING = 'Delivery progress checkpoint — 2026-09-07'; const markdownSection = (document, heading) => { const marker = `## ${heading}`; @@ -103,11 +104,7 @@ const uniqueLine = (text, predicate, description) => { }; function verifyAeroSimProject(document) { - const requiredSectionHeadings = [ - 'Resources', - 'Delivery progress checkpoint — 2026-09-03', - 'Discord', - ]; + const requiredSectionHeadings = ['Resources', AEROSIM_CHECKPOINT_HEADING, 'Discord']; const documentLines = document.split('\n'); const requiredSectionIndices = requiredSectionHeadings.map((heading) => { const indices = documentLines.flatMap((line, index) => line === `## ${heading}` ? [index] : []); @@ -119,28 +116,27 @@ function verifyAeroSimProject(document) { 'AeroSim required sections must follow Resources, checkpoint, Discord order', ); - for (const marker of [ - 'Delivery progress checkpoint — 2026-09-03', - '8 / 114', - '7.0%', - '0 / 114', - 'TASK-0012', - 'TASK-0015', - 'TASK-0073', - 'TASK-0114', - 'TASK-0013', - 'TASK-0016', - 'TASK-0074', - 'TASK-0115', - 'PR #143', - '1760', - '1761', - '1762', - '1763', - 'efbf3967548f1cbf5e06f97fa9d659535e35a7b4', - 'f686610a8b1b21825c66dc424f484fb2672933d7', - '106 ReadyForDelivery', - ]) { + const requiredMarkers = [ + AEROSIM_CHECKPOINT_HEADING, + '49 / 114', + '43.0%', + '6 / 114 (5.3%)', + '7 / 114 (6.1%)', + '58 / 114 (50.9%)', + 'PR #155', + '2581', + '2582', + APP_SHA, + DOC_SHA, + 'Wave 15 is active', + '6 of its 7 Tasks are repository-verified', + 'PRs #85, #89, #90, #95, #96, and #97', + 'integrated tasks `2718`–`2720`', + '`TASK-0078` remains canonical `InProgress`', + 'PR #92 is closed without merge', + 'Wave 16 remains unclaimed', + ]; + for (const marker of requiredMarkers) { assert.ok(document.includes(marker), `AeroSim progress checkpoint is missing: ${marker}`); } @@ -150,7 +146,7 @@ function verifyAeroSimProject(document) { 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 checkpoint = markdownSection(document, AEROSIM_CHECKPOINT_HEADING); const checkpointLines = checkpoint.split('\n'); const checkpointTableHeader = '| Measure | Progress | Meaning |'; const checkpointTableHeaderIndices = checkpointLines.flatMap( @@ -158,62 +154,43 @@ function verifyAeroSimProject(document) { ); 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.equal(checkpointLines[checkpointTableHeaderIndex + 1], '|---|---:|---|', 'AeroSim checkpoint table separator must exactly preserve its three columns and progress alignment'); + const expectedRows = [ + 'Canonical `ToBeReleased`', + 'Repository-verified implementation pending reconciliation', + 'Canonical `InProgress`', + 'Canonical `ReadyForDelivery`', + 'Released', + ]; assert.deepEqual( - checkpointLines.slice(checkpointTableHeaderIndex + 2, checkpointTableHeaderIndex + 5).map( - (line) => line.match(/^\| (Canonical `ToBeReleased`|Repository-verified implementation|Released) \|/)?.[1], + checkpointLines.slice(checkpointTableHeaderIndex + 2, checkpointTableHeaderIndex + 7).map( + (line) => line.match(/^\| ([^|]+?) \|/)?.[1], ), - ['Canonical `ToBeReleased`', 'Repository-verified implementation', 'Released'], - 'AeroSim checkpoint rows must follow canonical, implementation, released order', + expectedRows, + 'AeroSim checkpoint rows must preserve canonical, reconciliation, active, ready, and 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 implementationRow = uniqueLine(checkpoint, (line) => line.startsWith('| Repository-verified implementation pending reconciliation |'), 'repository-verified pending-reconciliation row'); + const inProgressRow = uniqueLine(checkpoint, (line) => line.startsWith('| Canonical `InProgress` |'), 'canonical InProgress row'); + const readyRow = uniqueLine(checkpoint, (line) => line.startsWith('| Canonical `ReadyForDelivery` |'), 'canonical ReadyForDelivery 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'); + const waveStatus = uniqueLine(checkpoint, (line) => line.startsWith('Wave 15 is active'), 'Wave 15 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(canonicalRow, /\|\s*49\s*\/\s*114\s*\(43\.0%\)/i, 'AeroSim must expose canonical ToBeReleased progress'); + assert.match(implementationRow, /\|\s*6\s*\/\s*114\s*\(5\.3%\)/i, 'AeroSim must expose repository-verified pending reconciliation separately'); + assert.match(inProgressRow, /\|\s*7\s*\/\s*114\s*\(6\.1%\)/i, 'AeroSim must expose canonical InProgress progress'); + assert.match(readyRow, /\|\s*58\s*\/\s*114\s*\(50\.9%\)/i, 'AeroSim must expose canonical ReadyForDelivery progress'); + assert.match(releasedRow, /\|\s*0\s*\/\s*114\s*\(0\.0%\)/i, 'AeroSim must distinguish released progress'); + assert.match(waveStatus, new RegExp('documentation `test` SHA `' + DOC_SHA + '`[^\\n]*PR #155 exact-head build task'), 'Wave 15 status must bind PR #155 to the documentation SHA'); + assert.match(waveStatus, /exact-head build task `2581`[^\n]*integrated build task `2582`/i, 'Wave 15 status must bind exact-head and integrated documentation tasks'); + assert.match(waveStatus, new RegExp('application integration head is `' + APP_SHA + '`'), 'Wave 15 status must bind the current application SHA'); + assert.match(waveStatus, /6 of its 7 Tasks are repository-verified[^\n]*PRs #85, #89, #90, #95, #96, and #97/i, 'Wave 15 status must enumerate repository-verified integration evidence'); + assert.match(waveStatus, /`TASK-0078` remains canonical `InProgress`[^\n]*PR #92 is closed without merge/i, 'Wave 15 status must preserve the unmerged Task state'); + assert.match(readyRow, /Waves 9–11 and 16–30 remain ready but unclaimed/i, 'ReadyForDelivery must identify both earlier and later unclaimed waves'); 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', /(? { + assert.match(project, /## Delivery progress checkpoint — 2026-09-07/); + assert.match(project, /Canonical `ToBeReleased` \| 49 \/ 114 \(43\.0%\)/); + assert.match(project, /Repository-verified implementation pending reconciliation \| 6 \/ 114 \(5\.3%\)/); + assert.match(project, /Canonical `InProgress` \| 7 \/ 114 \(6\.1%\)/); + assert.match(project, /Canonical `ReadyForDelivery` \| 58 \/ 114 \(50\.9%\)/); + assert.match(project, /Released \| 0 \/ 114 \(0\.0%\)/); + assert.match(project, /Wave 15 is active/); + assert.match(project, /6 of its 7 Tasks are repository-verified/); + assert.match(project, /`TASK-0048`, `TASK-0061`, `TASK-0065`, `TASK-0077`, `TASK-0083`, and `TASK-0111`/); + assert.match(project, /`TASK-0078` remains canonical `InProgress`[^\n]*PR #92 is closed without merge/); + assert.match(project, /`09628fbb828380fbe159be7530da26f4bbf02129`/); + assert.match(project, /`d8a45594c33efc3acbd1523955d4f235facc9a1f`/); + assert.match(project, /PRs #85, #89, #90, #95, #96, and #97/); + assert.match(project, /integrated tasks `2718`–`2720`/); + assert.match(project, /Waves 9–11 and 16–30 remain ready but unclaimed/); + assert.doesNotMatch(project, /Repository-verified implementation pending reconciliation \| 0 \/ 114/); + assert.doesNotMatch(project, /`7f26eca79eadef3171564fc60035e9866c2c848e`/); + assert.doesNotMatch(project, /Wave 3 is active/); +}); + +test('portal pins patched audit dependencies without downgrading consumers', () => { + assert.deepEqual(packageJson.pnpm?.overrides, { + 'fast-uri': '3.1.6', + 'serialize-javascript': '7.0.3', + }); + assert.match(lockfile, /fast-uri@3\.1\.6:/); + assert.match(lockfile, /serialize-javascript@7\.0\.3:/); + assert.doesNotMatch(lockfile, /fast-uri@3\.1\.5:/); + assert.doesNotMatch(lockfile, /serialize-javascript@6\.0\.2:/); +});