agent-dealer 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/server/dist/coordinator/admission.test.js +115 -0
- package/bundle/server/dist/coordinator/reviewer-browser-probe.js +1004 -0
- package/bundle/server/dist/coordinator/reviewer-browser-probe.test.js +680 -0
- package/bundle/server/dist/coordinator/worker-loop.js +1 -1
- package/bundle/server/dist/repository/admission-settings.js +5 -5
- package/bundle/server/dist/repository/admission-settings.test.js +71 -15
- package/bundle/server/dist/routes/queue.js +1 -1
- package/bundle/server/dist/routes/queue.test.js +55 -20
- package/bundle/server/dist/runners/process-registry.js +1 -1
- package/bundle/server/package.json +2 -2
- package/bundle/server/static-ui/assets/{index-Bm74Vq_X.js → index-Bz_c-UbO.js} +13 -13
- package/bundle/server/static-ui/index.html +1 -1
- package/bundle/shared/dist/queue-entries.d.ts +5 -4
- package/bundle/shared/dist/queue-entries.js +5 -4
- package/bundle/shared/package.json +1 -1
- package/package.json +1 -1
- package/templates/prod.env.example +5 -2
|
@@ -985,6 +985,121 @@ test("NOT-215: lowering 2 → 1 never preempts; admission pauses until occupancy
|
|
|
985
985
|
assert.equal((await admitNext())?.issueId, c.id);
|
|
986
986
|
assert.equal(getIssue(c.id).status, "developing");
|
|
987
987
|
});
|
|
988
|
+
test("NOT-378: limit 5 fills all five slots in one tick across same and different repositories; a sixth waits on global capacity", async () => {
|
|
989
|
+
setMaxActiveIssues(5);
|
|
990
|
+
const repo = fs.mkdtempSync(path.join(os.tmpdir(), "dealer-admit-five-"));
|
|
991
|
+
const same1 = readyIssueInRepo("five-s1", repo);
|
|
992
|
+
const same2 = readyIssueInRepo("five-s2", repo);
|
|
993
|
+
const same3 = readyIssueInRepo("five-s3", repo);
|
|
994
|
+
const diff1 = readyIssue("five-d1");
|
|
995
|
+
const diff2 = readyIssue("five-d2");
|
|
996
|
+
const sixth = readyIssue("five-d3");
|
|
997
|
+
enqueueIssue(same1.id);
|
|
998
|
+
enqueueIssue(same2.id);
|
|
999
|
+
enqueueIssue(same3.id);
|
|
1000
|
+
enqueueIssue(diff1.id);
|
|
1001
|
+
enqueueIssue(diff2.id);
|
|
1002
|
+
enqueueIssue(sixth.id);
|
|
1003
|
+
const first = await admitNext();
|
|
1004
|
+
assert.equal(first?.issueId, same1.id);
|
|
1005
|
+
for (const issue of [same1, same2, same3, diff1, diff2]) {
|
|
1006
|
+
assert.equal(getIssue(issue.id).status, "developing");
|
|
1007
|
+
assert.equal(instanceCount(issue.id), 1);
|
|
1008
|
+
}
|
|
1009
|
+
const instanceIds = new Set([same1, same2, same3, diff1, diff2].map((issue) => getActiveWorkflowInstance(issue.id).id));
|
|
1010
|
+
assert.equal(instanceIds.size, 5, "each issue gets its own active workflow instance");
|
|
1011
|
+
assert.equal(getIssue(sixth.id).status, "ready");
|
|
1012
|
+
assert.equal(getActiveWorkflowInstance(sixth.id), null);
|
|
1013
|
+
assert.equal(instanceCount(sixth.id), 0);
|
|
1014
|
+
// Live global wait reason on read — never a repository-slot reason anywhere.
|
|
1015
|
+
const live = queueStatusForIssue(sixth.id)?.waitReason ?? "";
|
|
1016
|
+
assert.match(live, /waiting for slot/);
|
|
1017
|
+
assert.doesNotMatch(live, /repository slot/);
|
|
1018
|
+
for (const read of listQueuedEntriesForRead()) {
|
|
1019
|
+
assert.doesNotMatch(read.waitReason ?? "", /repository slot/);
|
|
1020
|
+
}
|
|
1021
|
+
// A second tick persists the slot reason and admits nothing new.
|
|
1022
|
+
assert.equal(await admitNext(), null);
|
|
1023
|
+
assert.match(getQueuedEntryForIssue(sixth.id)?.waitReason ?? "", /waiting for slot/);
|
|
1024
|
+
assert.equal(instanceCount(sixth.id), 0);
|
|
1025
|
+
});
|
|
1026
|
+
test("NOT-378: declared blockers skip ahead correctly with five slots; the waiter admits once its blocker clears", async () => {
|
|
1027
|
+
setMaxActiveIssues(5);
|
|
1028
|
+
const repo = fs.mkdtempSync(path.join(os.tmpdir(), "dealer-admit-fiveblk-"));
|
|
1029
|
+
const blocked = linearIssueInRepo("fblk", "lin-378-blk", repo);
|
|
1030
|
+
setBlockersProviderForTests(async (issues) => new Map(issues.map((i) => [
|
|
1031
|
+
i.externalId,
|
|
1032
|
+
i.externalId === "lin-378-blk"
|
|
1033
|
+
? [{ id: "", identifier: "NOT-1", stateName: "In Progress", stateType: "started" }]
|
|
1034
|
+
: [],
|
|
1035
|
+
])));
|
|
1036
|
+
const free = [
|
|
1037
|
+
readyIssueInRepo("fblk-f1", repo),
|
|
1038
|
+
readyIssueInRepo("fblk-f2", repo),
|
|
1039
|
+
readyIssue("fblk-f3"),
|
|
1040
|
+
readyIssue("fblk-f4"),
|
|
1041
|
+
readyIssue("fblk-f5"),
|
|
1042
|
+
];
|
|
1043
|
+
enqueueIssue(blocked.id);
|
|
1044
|
+
for (const issue of free)
|
|
1045
|
+
enqueueIssue(issue.id);
|
|
1046
|
+
assert.equal((await admitNext())?.issueId, free[0].id);
|
|
1047
|
+
for (const issue of free) {
|
|
1048
|
+
assert.equal(getIssue(issue.id).status, "developing");
|
|
1049
|
+
assert.equal(instanceCount(issue.id), 1);
|
|
1050
|
+
}
|
|
1051
|
+
assert.equal(getIssue(blocked.id).status, "ready");
|
|
1052
|
+
assert.equal(getActiveWorkflowInstance(blocked.id), null);
|
|
1053
|
+
assert.equal(instanceCount(blocked.id), 0);
|
|
1054
|
+
const entry = getQueuedEntryForIssue(blocked.id);
|
|
1055
|
+
assert.equal(entry.state, "queued");
|
|
1056
|
+
assert.match(entry.waitReason ?? "", /waiting on NOT-1/);
|
|
1057
|
+
assert.doesNotMatch(entry.waitReason ?? "", /repository slot/);
|
|
1058
|
+
// The declared blocker is satisfied and a slot frees — the next tick admits the waiter.
|
|
1059
|
+
setBlockersProviderForTests(async (issues) => new Map(issues.map((i) => [i.externalId, []])));
|
|
1060
|
+
releaseToNeedsHuman(free[0].id);
|
|
1061
|
+
assert.equal((await admitNext())?.issueId, blocked.id);
|
|
1062
|
+
assert.equal(getIssue(blocked.id).status, "developing");
|
|
1063
|
+
});
|
|
1064
|
+
test("NOT-378: lowering 5 → 2 never preempts; admission pauses until occupancy drops below 2", async () => {
|
|
1065
|
+
setMaxActiveIssues(5);
|
|
1066
|
+
const active = [
|
|
1067
|
+
readyIssue("low5-a"),
|
|
1068
|
+
readyIssue("low5-b"),
|
|
1069
|
+
readyIssue("low5-c"),
|
|
1070
|
+
readyIssue("low5-d"),
|
|
1071
|
+
readyIssue("low5-e"),
|
|
1072
|
+
];
|
|
1073
|
+
for (const issue of active)
|
|
1074
|
+
enqueueIssue(issue.id);
|
|
1075
|
+
await admitNext();
|
|
1076
|
+
for (const issue of active) {
|
|
1077
|
+
assert.equal(getIssue(issue.id).status, "developing");
|
|
1078
|
+
}
|
|
1079
|
+
setMaxActiveIssues(2);
|
|
1080
|
+
const waiter = readyIssue("low5-w");
|
|
1081
|
+
enqueueIssue(waiter.id);
|
|
1082
|
+
assert.equal(await admitNext(), null);
|
|
1083
|
+
for (const issue of active) {
|
|
1084
|
+
assert.equal(getIssue(issue.id).status, "developing", "lowering never stops running work");
|
|
1085
|
+
}
|
|
1086
|
+
assert.equal(getIssue(waiter.id).status, "ready");
|
|
1087
|
+
assert.match(getQueuedEntryForIssue(waiter.id)?.waitReason ?? "", /waiting for slot/);
|
|
1088
|
+
const over = getAdmissionStatus();
|
|
1089
|
+
assert.equal(over.active, 5);
|
|
1090
|
+
assert.equal(over.limit, 2);
|
|
1091
|
+
assert.equal(over.overCap, true);
|
|
1092
|
+
// Occupancy at the new limit is still not enough — it must fall *below* 2.
|
|
1093
|
+
releaseToNeedsHuman(active[0].id);
|
|
1094
|
+
releaseToNeedsHuman(active[1].id);
|
|
1095
|
+
releaseToNeedsHuman(active[2].id);
|
|
1096
|
+
assert.equal(await admitNext(), null);
|
|
1097
|
+
assert.equal(getIssue(waiter.id).status, "ready");
|
|
1098
|
+
assert.equal(getAdmissionStatus().overCap, false);
|
|
1099
|
+
releaseToNeedsHuman(active[3].id);
|
|
1100
|
+
assert.equal((await admitNext())?.issueId, waiter.id);
|
|
1101
|
+
assert.equal(getIssue(waiter.id).status, "developing");
|
|
1102
|
+
});
|
|
988
1103
|
test("NOT-215: restart recovery observes the persisted setting without duplicate admission", async () => {
|
|
989
1104
|
setMaxActiveIssues(2);
|
|
990
1105
|
const a = readyIssue("rs-a");
|