diff --git a/scripts/hwlab-g14-contract-test.ts b/scripts/hwlab-g14-contract-test.ts index b3956b93..56f3b7e0 100644 --- a/scripts/hwlab-g14-contract-test.ts +++ b/scripts/hwlab-g14-contract-test.ts @@ -231,7 +231,7 @@ const gitMirrorStatusRaw = [ 'lastSync={"ok":true}', "lastWrite=", "lastFlush=", - 'refs={"refs":{"localV02":"0cf79ecc9d8a784b7712b0b3a58d5e39025ba0dc","githubV02":"0cf79ecc9d8a784b7712b0b3a58d5e39025ba0dc","localG14":"1111111111111111111111111111111111111111","githubG14":"1111111111111111111111111111111111111111","localGitops":"2222222222222222222222222222222222222222","githubGitops":"3333333333333333333333333333333333333333"},"pendingFlush":true}', + 'refs={"refs":{"localV02":"0cf79ecc9d8a784b7712b0b3a58d5e39025ba0dc","githubV02":"0cf79ecc9d8a784b7712b0b3a58d5e39025ba0dc","localV03":"4444444444444444444444444444444444444444","githubV03":"4444444444444444444444444444444444444444","localV03Gitops":"5555555555555555555555555555555555555555","githubV03Gitops":"6666666666666666666666666666666666666666","localG14":"1111111111111111111111111111111111111111","githubG14":"1111111111111111111111111111111111111111","localGitops":"2222222222222222222222222222222222222222","githubGitops":"3333333333333333333333333333333333333333"},"pendingFlush":true}', ].join("\n"); const parsedGitMirrorRefs = parseGitMirrorStatusRefs(gitMirrorStatusRaw); assertCondition( @@ -245,6 +245,12 @@ assertCondition( "git mirror status parser must expose GitHub source branch staging ref", parsedGitMirrorRefs, ); +assertCondition( + parsedGitMirrorRefs.refs.localV03 === "4444444444444444444444444444444444444444" + && parsedGitMirrorRefs.refs.githubV03Gitops === "6666666666666666666666666666666666666666", + "git mirror status parser must expose v0.3 source and GitOps refs for lane expansion visibility", + parsedGitMirrorRefs, +); assertCondition( gitMirrorV02SyncRequirement("0cf79ecc9d8a784b7712b0b3a58d5e39025ba0dc", gitMirrorStatusRaw).required === false, "trigger-current must not sync mirror when local v0.2 already matches source commit", @@ -290,6 +296,7 @@ assertCondition( ); assertCondition(gitMirrorSummary.githubInSync === false, "git mirror status summary must expose GitHub GitOps drift", gitMirrorSummary); assertCondition(gitMirrorSummary.sourceInSync === true && gitMirrorSummary.gitopsInSync === false, "git mirror status must split source and gitops GitHub sync state", gitMirrorSummary); +assertCondition(gitMirrorSummary.v03SourceInSync === true && gitMirrorSummary.v03GitopsInSync === false, "git mirror status must split v0.3 source and gitops sync state", gitMirrorSummary); const renderScript = v02ControlPlaneRenderScript("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); const renderScriptHash = v02ControlPlaneRefreshScriptHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); const sourceText = await Bun.file(new URL("./src/hwlab-g14.ts", import.meta.url)).text(); diff --git a/scripts/src/hwlab-g14.ts b/scripts/src/hwlab-g14.ts index f97eab00..7a2c48c9 100644 --- a/scripts/src/hwlab-g14.ts +++ b/scripts/src/hwlab-g14.ts @@ -4693,14 +4693,21 @@ export function parseGitMirrorStatusRefs(raw: string): { refs: Record = {}; + for (const [key, value] of Object.entries(refs)) parsedRefs[key] = stringOrNull(value); return { refs: { + ...parsedRefs, localV02: stringOrNull(refs.localV02), githubV02: stringOrNull(refs.githubV02), localG14: stringOrNull(refs.localG14), githubG14: stringOrNull(refs.githubG14), localGitops: stringOrNull(refs.localGitops), githubGitops: stringOrNull(refs.githubGitops), + localV03: stringOrNull(refs.localV03), + githubV03: stringOrNull(refs.githubV03), + localV03Gitops: stringOrNull(refs.localV03Gitops), + githubV03Gitops: stringOrNull(refs.githubV03Gitops), }, pendingFlush: typeof parsed.pendingFlush === "boolean" ? parsed.pendingFlush : null, }; @@ -4730,15 +4737,23 @@ export function gitMirrorStatusSummary(raw: string): Record { const githubV02 = refs.refs.githubV02 ?? null; const localGitops = refs.refs.localGitops ?? null; const githubGitops = refs.refs.githubGitops ?? null; + const localV03 = refs.refs.localV03 ?? null; + const githubV03 = refs.refs.githubV03 ?? null; + const localV03Gitops = refs.refs.localV03Gitops ?? null; + const githubV03Gitops = refs.refs.githubV03Gitops ?? null; const sourceInSync = Boolean(localV02 && githubV02 && localV02 === githubV02); const gitopsInSync = Boolean(localGitops && githubGitops && localGitops === githubGitops); return { localV02, githubV02, + localV03, + githubV03, localG14: refs.refs.localG14 ?? null, githubG14: refs.refs.githubG14 ?? null, localGitops, githubGitops, + localV03Gitops, + githubV03Gitops, pendingFlush: refs.pendingFlush, lastSync: { status: stringOrNull(lastSync.status) ?? null, @@ -4759,6 +4774,8 @@ export function gitMirrorStatusSummary(raw: string): Record { flushCommand: refs.pendingFlush === true ? "bun scripts/cli.ts hwlab g14 git-mirror flush --confirm" : null, sourceInSync, gitopsInSync, + v03SourceInSync: Boolean(localV03 && githubV03 && localV03 === githubV03), + v03GitopsInSync: Boolean(localV03Gitops && githubV03Gitops && localV03Gitops === githubV03Gitops), githubInSync: sourceInSync && gitopsInSync, }; } @@ -5000,6 +5017,10 @@ function waitForV02GitMirrorPreSync(sourceCommit: string, waitMs: number): Recor } function gitMirrorCacheProbeScript(): string { + const runtimeLanesJson = JSON.stringify(hwlabRuntimeLaneIds().map((lane) => { + const spec = hwlabRuntimeLaneSpec(lane); + return { lane, sourceBranch: spec.sourceBranch, gitopsBranch: spec.gitopsBranch }; + })); return [ "printf 'lastSync='; cat /cache/HWLAB.last-sync.json 2>/dev/null || true; printf '\\n'", "printf 'lastWrite='; cat /cache/HWLAB.last-write.json 2>/dev/null || true; printf '\\n'", @@ -5015,19 +5036,34 @@ function gitMirrorCacheProbeScript(): string { " return null;", " }", "}", - "const localGitops = rev('refs/heads/v0.2-gitops');", - "const githubGitops = rev('refs/mirror-stage/heads/v0.2-gitops');", - "console.log(JSON.stringify({", - " refs: {", - " localV02: rev('refs/heads/v0.2'),", - " githubV02: rev('refs/mirror-stage/heads/v0.2'),", - " localG14: rev('refs/heads/G14'),", - " githubG14: rev('refs/mirror-stage/heads/G14'),", - " localGitops,", - " githubGitops,", - " },", - " pendingFlush: Boolean(localGitops && githubGitops && localGitops !== githubGitops),", - "}));", + `const runtimeLanes = ${runtimeLanesJson};`, + "const refs = {};", + "for (const spec of runtimeLanes) {", + " const key = spec.lane.toUpperCase();", + " const normalized = key.slice(0, 1) + key.slice(1).toLowerCase();", + " const localSource = rev('refs/heads/' + spec.sourceBranch);", + " const githubSource = rev('refs/mirror-stage/heads/' + spec.sourceBranch);", + " const localGitops = rev('refs/heads/' + spec.gitopsBranch);", + " const githubGitops = rev('refs/mirror-stage/heads/' + spec.gitopsBranch);", + " refs['local' + normalized] = localSource;", + " refs['github' + normalized] = githubSource;", + " refs['local' + normalized + 'Gitops'] = localGitops;", + " refs['github' + normalized + 'Gitops'] = githubGitops;", + " if (spec.lane === 'v02') {", + " refs.localV02 = localSource;", + " refs.githubV02 = githubSource;", + " refs.localGitops = localGitops;", + " refs.githubGitops = githubGitops;", + " }", + "}", + "refs.localG14 = rev('refs/heads/G14');", + "refs.githubG14 = rev('refs/mirror-stage/heads/G14');", + "const pendingFlush = runtimeLanes.some((spec) => {", + " const localGitops = rev('refs/heads/' + spec.gitopsBranch);", + " const githubGitops = rev('refs/mirror-stage/heads/' + spec.gitopsBranch);", + " return Boolean(localGitops && githubGitops && localGitops !== githubGitops);", + "});", + "console.log(JSON.stringify({ refs, pendingFlush }));", "NODE", ].join("\n"); }