builds: drop per-entry agent grouping from DAG renderer

Removes entryAgents() and the two places it rendered agent names:
- rqe-agent code element in the entry header
- rqe-node-agent-label prefix per component chain when multi-component

The DAG structure split (WCC + fan-out) already communicates subgraph
boundaries visually via the separate .rqe-nodes rows; the agent-name
labels on top of that caused layout breakage (#2666) and duplicate
information. Closes #2666.

The live build log header still labels liveNode.agent (a single specific
node, not the whole DAG) — that .rqe-agent rule is kept.

Also removes the now-unused .rqe-node-agent-label CSS rule and its
comment.
This commit is contained in:
iris 2026-07-24 02:10:14 +02:00
commit ae8d1aaac4
2 changed files with 3 additions and 28 deletions

View file

@ -157,17 +157,6 @@ function firstFailedNode(entry) {
return (entry.nodes || []).find((n) => n.state === 'failed') || null;
}
// Distinct agents across a DAG's nodes, comma-joined for display. Agent is
// per-node now (a DAG can span agents, e.g. a hive-wide restart), so there's
// no DAG-level `agent` field — derive it from the nodes.
function entryAgents(entry) {
const seen = [];
for (const n of entry.nodes || []) {
if (n.agent && !seen.includes(n.agent)) seen.push(n.agent);
}
return seen.join(',');
}
// Further split one weakly-connected component's topo-ordered nodes on
// *fan-out* points — a node with more than one direct dependent — so a
// shared gate/lock node (e.g. MetaLock, which every agent's rebuild
@ -302,7 +291,6 @@ function rebuildQueueEntryFingerprint(entry) {
const nodes = entry.nodes || [];
return JSON.stringify({
state: rollupState(nodes),
agent: entryAgents(entry),
source: entry.source,
started_at: isoToSecs(entry.started_at),
created_at: entry.created_at,
@ -378,8 +366,6 @@ function renderQueueEntry(entry) {
el('span', { class: 'rqe-state', title: state }, QUEUE_STATE_GLYPH[state] || '?'),
' ',
el('span', { class: 'rqe-kind' }, entry.source),
' ',
el('code', { class: 'rqe-agent' }, entryAgents(entry)),
);
li.append(' ', el('span', { class: 'rqe-source rqe-source-' + entry.source }, entry.source));
if (state === 'queued') {
@ -411,16 +397,8 @@ function renderQueueEntry(entry) {
// live nodes appear here; `Failed` DAGs linger until the history cap.
if (nodes.length) {
const components = nodeComponents(nodes);
const multi = components.length > 1;
for (const compNodes of components) {
const chain = el('div', { class: 'rqe-nodes' });
if (multi) {
const agents = [];
for (const n of compNodes) {
if (n.agent && !agents.includes(n.agent)) agents.push(n.agent);
}
chain.append(el('code', { class: 'rqe-node-agent-label' }, agents.join(',')));
}
compNodes.forEach((n, i) => {
if (i > 0) chain.append(el('span', { class: 'rqe-node-arrow' }, ' → '));
const chip = el('span', {
@ -456,14 +434,14 @@ function renderQueueEntry(entry) {
class: 'inline rqe-cancel',
'data-async': '',
'data-confirm':
`cancel ${entry.source} for \`${entryAgents(entry)}\` (queue id ${entry.id})? ` +
`cancel ${entry.source} (queue id ${entry.id})? ` +
`the row drops from the queue and never runs. running / done / failed entries can't be cancelled this way.`,
});
cancelForm.append(el('button', {
type: 'submit',
class: 'rqe-cancel-btn',
title: 'cancel this queued ' + entry.source,
'aria-label': 'cancel queued ' + entry.source + ' for ' + entryAgents(entry),
'aria-label': 'cancel queued ' + entry.source,
}, '✗'));
li.append(cancelForm);
}

View file

@ -159,10 +159,7 @@
.rqe-node-cancelled { opacity: 0.55; text-decoration: line-through; }
.rqe-node-arrow { color: var(--muted); }
.rqe-node-log { margin-left: 0.1em; text-decoration: none; }
/* Per-agent subgraph label, shown only when a DAG's nodes span more than
one agent (independent concurrent subgraphs, one `.rqe-nodes` line each
see renderQueueEntry in builds.js). */
.rqe-node-agent-label { color: var(--amber); margin-right: 0.3em; }
.rqe-step {
flex-basis: 100%;
margin: 0.1em 0 0 1.8em;