Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/scripts/__tests__/sync-run-contract.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,32 @@ const test = require('node:test');
const assert = require('node:assert/strict');

const {
buildNoChangeEvidence,
buildNoChangeCanaryEvidence,
buildMarkdownSummary,
buildSyncRunReport,
summarizeResults,
} = require('../sync_run_contract');

test('buildNoChangeEvidence binds unchanged delivery repos to an immutable campaign plan', () => {
const planId = `sha256:${'a'.repeat(64)}`;
const sourceCommit = 'b'.repeat(40);
const result = buildNoChangeEvidence({
expectedRepositories: ['stranske/Ready'],
planId,
planScope: 'full',
sourceCommit,
results: [{
repo: 'stranske/Ready', status: 'no_changes', plan_id: planId,
plan_scope: 'full', scope_base_sha: '', source_commit: sourceCommit,
consumer_head_sha: 'c'.repeat(40),
}],
});
assert.equal(result.ok, true);
assert.equal(result.evidence.schema, 'workflows.consumer-sync-no-change-evidence/v1');
assert.equal(result.evidence.results[0].evidence_source, 'no-change-delivery');
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.

test('buildNoChangeCanaryEvidence binds no-diff canaries to the exact plan and head', () => {
const planId = `sha256:${'a'.repeat(64)}`;
const sourceCommit = 'b'.repeat(40);
Expand Down
45 changes: 43 additions & 2 deletions .github/scripts/__tests__/sync_dependency_campaign.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ test('mergeDeliveryHandoffs retains one current record per generated PR', () =>
...current,
branch: '',
lane: '',
continuation: { class: '', lane: '', reason: '', resume_after: '' },
plan_id: '',
plan_scope: '',
scope_base_sha: '',
source_commit: '',
canary_baseline_evidence_json: '',
campaign_no_change_evidence_json: '',
continuation: { class: '', lane: '', reason: '', resume_after: '', key: '' },
observed_at: '2026-08-02T00:00:00Z',
}]);
});
Expand Down Expand Up @@ -87,7 +93,7 @@ test('plans only due transient Maint 71 lanes and suppresses candidates during d
}).length, 0);
assert.deepEqual(planMaint71Continuations([candidate], {
now: '2026-08-15T12:10:00Z',
}), []);
}).map((item) => item.lane), ['candidate']);
assert.deepEqual(planMaint71Continuations([candidate], {
now: '2026-08-15T12:10:00.001Z',
}).map((item) => ({ lane: item.lane, branch: item.branch })), [{
Expand All @@ -106,6 +112,41 @@ test('plans only due transient Maint 71 lanes and suppresses candidates during d
}).map((item) => item.lane), ['candidate']);
});

test('campaign continuations preserve idempotency and immutable plan bindings', () => {
const campaign = {
schema: 'workflows-generated-delivery-handoff/v1',
repository: 'stranske/Travel',
pr: 11,
branch: 'sync/workflows-candidate',
head_sha: 'abc',
delivery_generation: 'g1',
disposition: 'awaiting-checks',
blocker_owner: 'ci',
next_command: 'await-required-checks',
check_state: 'checks_pending',
review_state: 'clear',
plan_id: 'plan-abc',
plan_scope: 'source-delta',
scope_base_sha: 'base-abc',
source_commit: 'source-abc',
continuation: {
class: 'transient', lane: 'campaign', reason: 'checks_pending',
resume_after: '2026-08-15T12:10:00Z', key: 'continuation-abc',
},
};
const [planned] = planMaint71Continuations([campaign], {
now: '2026-08-15T12:10:00Z',
});
assert.equal(planned.lane, 'campaign');
assert.equal(planned.continuation_key, 'continuation-abc');
assert.deepEqual(planned.immutable_handoff, {
plan_id: 'plan-abc',
plan_scope: 'source-delta',
scope_base_sha: 'base-abc',
source_commit: 'source-abc',
});
});

test('normalizeDeliveryHandoff rejects incomplete restart fields', () => {
assert.equal(normalizeDeliveryHandoff({
schema: 'workflows-generated-delivery-handoff/v1', repository: 'stranske/Ready', pr: 11,
Expand Down
170 changes: 165 additions & 5 deletions .github/scripts/__tests__/sync_pr_merge_contract.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ const path = require('node:path');

const {
buildMarkdownSummary,
buildCampaignCommitAuthorization,
buildDeliveryHandoff,
buildMergeReport,
candidateRefreshDecision,
candidatePromotionDecision,
deliveryRefreshDecision,
candidateEvidenceAllowsMutation,
campaignAuthorizationAllowsMerge,
classifyDeliveryContinuation,
classifyGeneratedPr,
classifySyncPrChecks,
Expand All @@ -38,9 +40,12 @@ const {
rulesetRefPatternMatches,
selectActiveSyncPr,
selectLatestMergedCandidatePr,
selectLatestMergedSyncPr,
campaignAuthorizationRowForRepository,
selectMergeEligibleSyncPr,
summarizeResults,
syncBranchForHash,
syncSelectorForRepository,
validateCanaryEvidence,
validateExpectedCandidateIdentity,
validateSourceDeltaEvidenceBinding,
Expand Down Expand Up @@ -103,7 +108,7 @@ test('transient delivery holds carry a durable due time and lane', () => {
}, '2026-08-15T12:00:00Z').resume_after, '2026-08-15T12:10:00.000Z');
});

test('promotion requires complete exact-plan evidence and terminal candidate rows', () => {
test('promotion requires complete exact-plan evidence and prepared candidate rows', () => {
const expectedCanaries = ['stranske/Travel', 'stranske/Portable'];
const evidence = {
results: expectedCanaries.map((repo, index) => ({
Expand All @@ -125,7 +130,7 @@ test('promotion requires complete exact-plan evidence and terminal candidate row
repo,
pr: index + 1,
branch: 'sync/workflows-candidate',
status: index ? 'evidence_recovered' : 'merged',
status: index ? 'evidence_recovered' : 'campaign_prepared',
};
}),
};
Expand All @@ -140,6 +145,146 @@ test('promotion requires complete exact-plan evidence and terminal candidate row
assert.match(blocked.errors.join('\n'), /stranske\/Travel/);
});

test('campaign maps canaries to candidate and the remaining fleet to delivery', () => {
assert.equal(syncSelectorForRepository({
syncHash: 'campaign',
repository: 'stranske/Travel',
canaryRepos: ['stranske/Travel'],
}), 'candidate');
assert.equal(syncSelectorForRepository({
syncHash: 'campaign',
repository: 'stranske/Other',
canaryRepos: ['stranske/Travel'],
}), 'delivery');
assert.equal(syncSelectorForRepository({
syncHash: 'candidate',
repository: 'stranske/Other',
canaryRepos: ['stranske/Travel'],
}), 'candidate');
});

test('campaign commit authorization binds every prepared exact head', () => {
const report = {
inputs: { sync_hash: 'campaign' },
results: [
{
owner: 'stranske', repo: 'Travel', pr: 11,
branch: 'sync/workflows-candidate', head_sha: 'head-11',
delivery_generation: 'generation-11', plan_id: 'plan-abc',
source_commit: 'source-abc',
status: 'campaign_prepared',
},
{
owner: 'stranske', repo: 'NoChange', status: 'campaign_no_change_verified',
plan_id: 'plan-abc', source_commit: 'source-abc',
},
],
};
const authorization = buildCampaignCommitAuthorization({
report,
expectedRepositories: ['stranske/Travel', 'stranske/NoChange'],
planId: 'plan-abc',
sourceCommit: 'source-abc',
generatedAt: '2026-08-16T12:00:00Z',
});
assert.equal(authorization.authorized, true);
assert.equal(campaignAuthorizationAllowsMerge({
authorization,
result: {
owner: 'stranske', repo: 'Travel', pr: 11,
branch: 'sync/workflows-candidate', head_sha: 'head-11',
delivery_generation: 'generation-11',
},
}), true);
assert.equal(campaignAuthorizationAllowsMerge({
authorization,
result: {
owner: 'stranske', repo: 'Travel', pr: 11,
branch: 'sync/workflows-candidate', head_sha: 'changed',
delivery_generation: 'generation-11',
},
}), false);
report.results[0].status = 'checks_pending';
assert.equal(buildCampaignCommitAuthorization({
report,
expectedRepositories: ['stranske/Travel', 'stranske/NoChange'],
planId: 'plan-abc',
}).authorized, false);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

test('campaign commit authorization accepts already-merged rows on resume', () => {
const report = {
inputs: { sync_hash: 'campaign' },
results: [
{
owner: 'stranske', repo: 'Travel', pr: 11,
branch: 'sync/workflows-delivery', head_sha: 'head-11',
delivery_generation: 'generation-11', plan_id: 'plan-abc',
source_commit: 'source-abc',
status: 'merged',
},
{
owner: 'stranske', repo: 'Portable', pr: 12,
branch: 'sync/workflows-delivery', head_sha: 'head-12',
delivery_generation: 'generation-12', plan_id: 'plan-abc',
source_commit: 'source-abc',
status: 'campaign_prepared',
},
],
};
const authorization = buildCampaignCommitAuthorization({
report,
expectedRepositories: ['stranske/Travel', 'stranske/Portable'],
planId: 'plan-abc',
sourceCommit: 'source-abc',
});
assert.equal(authorization.authorized, true);
assert.equal(authorization.rows.length, 2);
assert.equal(
campaignAuthorizationRowForRepository(authorization, 'stranske/Travel')?.head_sha,
'head-11',
);
});

test('selectLatestMergedSyncPr matches authorized campaign identity', () => {
const trusted = ['stranske'];
const deliveryBody = `<!-- sync-pr-delivery-record:v1 ${JSON.stringify({
schema: 'sync-pr-delivery-record/v1',
durable_issue_url: 'https://github.com/stranske/Workflows/issues/1836',
plan_id: 'plan-abc',
generation: 'generation-11',
repository: 'stranske/Travel',
desired_tree_hash: 'tree-11',
source_commit: 'source-abc',
lease_expires_at: '2099-08-14T00:00:00Z',
predecessor_prs: [],
successor_prs: [],
})} -->`;
const selected = selectLatestMergedSyncPr([
{
number: 11,
merged_at: '2026-08-16T12:00:00Z',
user: { login: 'stranske' },
head: { ref: 'sync/workflows-delivery', sha: 'head-11' },
body: deliveryBody,
},
{
number: 10,
merged_at: '2026-08-16T11:00:00Z',
user: { login: 'stranske' },
head: { ref: 'sync/workflows-delivery', sha: 'stale-head' },
body: deliveryBody,
},
], trusted, {
branch: 'sync/workflows-delivery',
planId: 'plan-abc',
sourceCommit: 'source-abc',
prNumber: 11,
headSha: 'head-11',
});
assert.equal(selected?.number, 11);
});

test('candidate base drift requests a no-filter refresh and stays transient', () => {
const result = {
owner: 'stranske',
Expand Down Expand Up @@ -426,8 +571,9 @@ test('maint71 accepts no-change canary evidence only while the exact base head i
},
};
const failures = [];
const notices = [];
const core = {
notice: () => {},
notice: (message) => notices.push(message),
setFailed: (message) => failures.push(message),
warning: () => {},
summary: { addRaw: () => ({ write: async () => {} }) },
Expand Down Expand Up @@ -491,7 +637,11 @@ test('maint71 accepts no-change canary evidence only while the exact base head i
});
const redReport = JSON.parse(fs.readFileSync(reportPath, 'utf8'));
assert.equal(redReport.summary.checks_failed, 1);
assert.match(failures.at(-1), /Canary evidence is incomplete or unsafe/);
assert.deepEqual(failures, []);
assert.equal(
notices.some((message) => /Canary evidence is incomplete or unsafe/.test(message)),
true,
);

checkConclusion = 'success';
requiredContexts = [];
Expand Down Expand Up @@ -1587,8 +1737,12 @@ test('buildDeliveryHandoff preserves the restart fields for a generated PR', ()
lane: 'dev-tool-sync', disposition: 'review-blocked', blocker_owner: 'closer',
next_command: 'resolve-active-review-threads',
check_state: 'ready', review_state: 'blocked',
plan_id: '', plan_scope: '', scope_base_sha: '', source_commit: '',
canary_baseline_evidence_json: '',
campaign_no_change_evidence_json: '',
continuation: {
class: 'actionable', lane: 'dev-tool', reason: 'review_blocked', resume_after: '',
key: '0e3dff884c95411fadee',
},
observed_at: '2026-08-15T12:00:00Z',
});
Expand All @@ -1605,7 +1759,13 @@ test('buildDeliveryHandoff rewrites terminal merge outcomes', () => {
branch: 'sync/workflows-abc', head_sha: 'abc', delivery_generation: 'g2',
lane: 'sync', disposition: 'merged', blocker_owner: 'none', next_command: 'none',
check_state: 'ready', review_state: 'clear',
continuation: { class: 'terminal', lane: '', reason: 'merged', resume_after: '' },
plan_id: '', plan_scope: '', scope_base_sha: '', source_commit: '',
canary_baseline_evidence_json: '',
campaign_no_change_evidence_json: '',
continuation: {
class: 'terminal', lane: '', reason: 'merged', resume_after: '',
key: '24402df1f7991fa96e63',
},
observed_at: '2026-08-15T12:00:00Z',
});
assert.equal(buildDeliveryHandoff({
Expand Down
Loading
Loading