Slow repo Face CTB cadence range

This commit is contained in:
Meta Vens 2026-05-25 19:53:44 +01:00
commit 579a8fd026
3 changed files with 11 additions and 10 deletions

View file

@ -1325,7 +1325,7 @@ function renderHtml(snapshot) {
const controls = snapshot.controls || {};
const latest = (controls.manualTurnRequests || [])[0];
return "<div class=\\"control-grid\\"><p class=\\"kicker\\">Controls</p>" +
"<div><div class=\\"muted\\">Heartbeat cadence</div><div class=\\"control-row\\"><input id=\\"cadence-input\\" type=\\"range\\" min=\\"0.1\\" max=\\"12\\" step=\\"0.1\\" value=\\"" + esc(controls.cadenceMultiplier || 1) + "\\"><strong id=\\"cadence-value\\" class=\\"mono\\">x" + esc(number(controls.cadenceMultiplier || 1)) + "</strong></div><button id=\\"cadence-apply\\" type=\\"button\\">Apply</button></div>" +
"<div><div class=\\"muted\\">Heartbeat cadence</div><div class=\\"control-row\\"><input id=\\"cadence-input\\" type=\\"range\\" min=\\"0.01\\" max=\\"12\\" step=\\"0.01\\" value=\\"" + esc(controls.cadenceMultiplier || 1) + "\\"><strong id=\\"cadence-value\\" class=\\"mono\\">x" + esc(number(controls.cadenceMultiplier || 1)) + "</strong></div><button id=\\"cadence-apply\\" type=\\"button\\">Apply</button></div>" +
"<div><div class=\\"muted\\">Manual next turn</div><div class=\\"force-row\\"><select id=\\"force-identity\\">" + participants.map((agent) => "<option value=\\"" + esc(agent.identityId) + "\\">" + esc(agent.displayName) + " / " + esc(agent.repoName) + "</option>").join("") + "</select><button id=\\"force-turn\\" type=\\"button\\">Pull</button></div></div>" +
"<div class=\\"mono muted\\">Latest request: " + esc(latest?.identityId || "none") + " " + esc(latest?.status || "") + "</div>" +
"</div>";
@ -1603,7 +1603,7 @@ function renderHtml(snapshot) {
const forceButton = document.getElementById("force-turn");
if (forceSelect && selectedIdentity) forceSelect.value = selectedIdentity;
if (cadenceInput && cadenceValue) {
cadenceInput.addEventListener("input", () => cadenceValue.textContent = "x" + Number(cadenceInput.value).toLocaleString(undefined, { maximumFractionDigits: 1 }));
cadenceInput.addEventListener("input", () => cadenceValue.textContent = "x" + Number(cadenceInput.value).toLocaleString(undefined, { maximumFractionDigits: 2 }));
}
if (cadenceApply && cadenceInput) {
cadenceApply.addEventListener("click", async () => {
@ -1771,8 +1771,8 @@ async function handleControlUpdate(request, response) {
}
const body = await readRequestJson(request);
const multiplier = Number(body.cadenceMultiplier);
if (!Number.isFinite(multiplier) || multiplier < 0.1 || multiplier > 12) {
writeJsonResponse(response, 400, { ok: false, error: "cadenceMultiplier must be between 0.1 and 12." });
if (!Number.isFinite(multiplier) || multiplier < 0.01 || multiplier > 12) {
writeJsonResponse(response, 400, { ok: false, error: "cadenceMultiplier must be between 0.01 and 12." });
return;
}
const state = await readMutableHeartbeatState();
@ -1827,7 +1827,7 @@ async function writeMutableHeartbeatState(state) {
function normalizeDashboardControls(value) {
const controls = value && typeof value === "object" ? value : {};
return {
cadenceMultiplier: Math.min(12, Math.max(0.1, Number(controls.cadenceMultiplier) || 1)),
cadenceMultiplier: Math.min(12, Math.max(0.01, Number(controls.cadenceMultiplier) || 1)),
manualTurnRequests: Array.isArray(controls.manualTurnRequests) ? controls.manualTurnRequests : [],
updatedAt: typeof controls.updatedAt === "string" ? controls.updatedAt : undefined,
};

View file

@ -272,7 +272,7 @@ async function main(): Promise<void> {
}
state.baseRecoveryMinutes = config.repoFaceHeartbeats.baseRecoveryMinutes;
const cadenceMultiplier = clamp(state.controls.cadenceMultiplier, 0.1, 12);
const cadenceMultiplier = clamp(state.controls.cadenceMultiplier, 0.01, 12);
const effectiveGlobalHeat = config.repoFaceHeartbeats.globalHeat * cadenceMultiplier;
state.globalHeat = effectiveGlobalHeat;
const completedThisTick = new Set<string>();
@ -1502,7 +1502,7 @@ function reconcileParticipants(
const groups = initiativeGroupsFor(spec);
const heat = heatFor(spec, groups, globalHeat, heatOverrides);
const urgency = urgencyFor(pressureByIdentity.get(spec.id));
const effectiveSpeed = clamp(speed * heat * urgency, 0.1, 12);
const effectiveSpeed = clamp(speed * heat * urgency, 0.01, 12);
const defaultNextTurnAt = Number.isFinite(current?.nextTurnAt)
? current.nextTurnAt
: initiativeClock + ((baseRecoveryMinutes / count) * index);
@ -1596,7 +1596,7 @@ function pullNextTurnTowardUrgency(
return nextTurnAt;
}
const maxWait = Math.max(0.75, baseRecoveryMinutes / Math.max(effectiveSpeed, 0.1));
const maxWait = Math.max(0.75, baseRecoveryMinutes / Math.max(effectiveSpeed, 0.01));
return Math.min(nextTurnAt, round3(initiativeClock + maxWait));
}
@ -5006,7 +5006,7 @@ function projectCharacterDescription(description: string | undefined): string |
function recoveryFor(participant: FaceHeartbeatParticipant): number {
const loadPenalty = 1 + participant.currentLoad * 0.75;
return (participant.baseRecoveryMinutes * loadPenalty) / Math.max(participant.effectiveSpeed, 0.1);
return (participant.baseRecoveryMinutes * loadPenalty) / Math.max(participant.effectiveSpeed, 0.01);
}
async function readHeartbeatState(path: string): Promise<FaceHeartbeatState> {
@ -5157,7 +5157,7 @@ function normalizeHeartbeatControls(value: unknown): FaceHeartbeatControls {
: [];
return {
cadenceMultiplier: Number.isFinite(cadenceMultiplier) ? clamp(cadenceMultiplier, 0.1, 12) : 1,
cadenceMultiplier: Number.isFinite(cadenceMultiplier) ? clamp(cadenceMultiplier, 0.01, 12) : 1,
manualTurnRequests: manualTurnRequests.slice(-20),
updatedAt: typeof record.updatedAt === "string" ? record.updatedAt : undefined,
};