mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-07 22:58:42 -10:00
fix(tui): agent-detail runtime field writes the NAME as the value (a4c9548a)
S19 follow-on founder ruling (bounds the marks ruling): where there is room,
write the runtime NAME as the value; an icon may accompany decoratively but never
substitutes. The agent-detail runtime field rendered mark-only (the ROUND-3/4
mark-as-value behavior); it now renders the name (honest placeholder when
unserved) with the mark trailing decoratively. Topology cards stay mark-only by
space (layout.ts/hatchet.ts untouched) — bounded, not reversed.
RED-first: new pin agent-detail-runtime-name.test.ts (2 cases) RED at 5de3b994,
GREEN after the fix. Two shipped-floor assertions in topology-view.test.ts that
pinned the reversed behavior ("the mark IS the value" / "spelled runtime is
dead") updated truthfully citing a4c9548a; every mark-styling-survival assertion
preserved. Full tui suite 214/214, tsc 0, build clean.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
5de3b994fc
commit
5a70e2005f
3 files changed
+60
-15
No files matched your search
@@ -215,14 +215,20 @@ function contentLines(state: ViewState, snap: FleetSnapshot, contentWidth: numbe
|
||||
if (!found) return [{ text: `agent "${leaf.name}" not in the current snapshot` }];
|
||||
const { agent, rig, pod } = found;
|
||||
const specInLibrary = !!agent.spec && !!findSpec(snap, agent.spec);
|
||||
// ROUND-3: the runtime MARK lives on the detail page (sparingly).
|
||||
// ROUND-4 (guard finding 2): the mark's OWN token segments ride the seg
|
||||
// channel so its colors/background survive stylization, and NO spelled
|
||||
// runtime word renders beside it (spelled runtime is dead everywhere).
|
||||
// a4c9548a — S19 FOLLOW-ON FOUNDER RULING (binding, bounds the S19 marks
|
||||
// ruling): where there is ROOM, WRITE THE NAME — an icon NEVER replaces text
|
||||
// as the value. The detail page has room, so the runtime NAME is the VALUE
|
||||
// (honest placeholder when unserved); the mark's OWN token segments still ride
|
||||
// the seg channel (ROUND-4: colors/background survive stylization) but only
|
||||
// ACCOMPANY the name decoratively, never substitute. Topology cards remain
|
||||
// mark-only by space (layout.ts/hatchet.ts) — the ruling is bounded, not reversed.
|
||||
const rtName = agent.runtime ?? "— (not served)";
|
||||
const rtSegs = [
|
||||
{ text: " " },
|
||||
{ text: "runtime:", token: "dim" as const },
|
||||
{ text: " ".repeat(LABEL_W - "runtime:".length + 1) },
|
||||
{ text: rtName },
|
||||
{ text: " " },
|
||||
...runtimeMarkSegs(agent.runtime),
|
||||
];
|
||||
const runtimeLine: ContentLine = { text: rtSegs.map((g) => g.text).join(""), segs: rtSegs };
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// a4c9548a — S19 FOLLOW-ON FOUNDER RULING (binding, bounds the S19 marks ruling):
|
||||
// icons are DECORATIVE or for no-room contexts; where there is ROOM, WRITE THE NAME —
|
||||
// an icon NEVER replaces text as the value. The agent-DETAIL page has room, so its
|
||||
// runtime field must render the runtime NAME as text (claude-code / codex / ...); a
|
||||
// mark MAY accompany decoratively but never substitutes for the value. Topology cards
|
||||
// (space-constrained) KEEP their marks — the ruling is BOUNDED, not reversed (see
|
||||
// topology-view / navigator-reskin suites, untouched by this fix). (qitem a4c9548a)
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { demoSnapshot } from "../src/demo-data.js";
|
||||
import { renderScreen } from "../src/render.js";
|
||||
import { createViewState } from "../src/state.js";
|
||||
|
||||
function renderAgentDetail(name: string): string {
|
||||
const snap = demoSnapshot();
|
||||
const view = createViewState({ instanceId: "t", getSnapshot: () => snap });
|
||||
view.dispatch({
|
||||
type: "drill",
|
||||
resource: "agent",
|
||||
name,
|
||||
target: { host: "vm-host", rig: "openrig-build", pod: "dev50" },
|
||||
});
|
||||
return renderScreen(view.get(), snap, { cols: 140, rows: 34 }).lines.join("\n");
|
||||
}
|
||||
|
||||
describe("agent-detail runtime field renders the NAME as the value (founder rule a4c9548a)", () => {
|
||||
it("a claude-code agent's runtime field shows `claude-code` as TEXT — the name is the value, not only the mark", () => {
|
||||
const out = renderAgentDetail("dev50.driver");
|
||||
expect(out).toMatch(/runtime:\s+claude-code/);
|
||||
});
|
||||
|
||||
it("a codex agent's runtime field shows `codex` as TEXT", () => {
|
||||
const out = renderAgentDetail("dev50.guard");
|
||||
expect(out).toMatch(/runtime:\s+codex/);
|
||||
});
|
||||
});
|
||||
@@ -548,8 +548,12 @@ describe("ROUND-3 LOCKED SET (orch locked-scope GO; pins 02259adb/29a10b62)", ()
|
||||
// detail page shows the mark as the runtime field — spelled runtime is dead
|
||||
s.dispatch({ type: "drill", resource: "agent", name: "dev.driver", target: { host: "vm-host", rig: FIXTURE_RIG_NAME, pod: "dev" } });
|
||||
const detail = renderScreen(s.get(), snap, { cols: 150, rows: 40 }).lines.join("\n");
|
||||
expect(detail).toMatch(/runtime:\s+></); // the mark IS the runtime value
|
||||
expect(detail).not.toMatch(/>< claude-code/); // no spelled runtime beside the mark
|
||||
// a4c9548a (S19 follow-on founder ruling, bounds the marks ruling): on the detail
|
||||
// page there is room, so the runtime NAME is the VALUE; the mark only accompanies
|
||||
// decoratively, never substitutes. (Supersedes the earlier "the mark IS the value /
|
||||
// spelled runtime is dead" pin — topology cards above stay mark-only, bounded not reversed.)
|
||||
expect(detail).toMatch(/runtime:\s+claude-code/); // the NAME is the runtime value
|
||||
expect(detail).toMatch(/claude-code\s+></); // the clawd mark still accompanies decoratively
|
||||
});
|
||||
|
||||
it("the clawd eyes are the picks-v4 INWARD SQUINTY pair `><` (founder amendment 14afeb74, supersedes the round-4 quadrant geometry)", async () => {
|
||||
@@ -563,7 +567,7 @@ describe("ROUND-3 LOCKED SET (orch locked-scope GO; pins 02259adb/29a10b62)", ()
|
||||
expect(markText(runtimeMarkSegs("claude-code"))).toBe("><"); // shipped claude mark = the refined face
|
||||
});
|
||||
|
||||
it("agent-detail runtime marks keep their OWN styling in compiled output (guard round-4 finding 2)", () => {
|
||||
it("agent-detail runtime NAME is the value AND the mark keeps its OWN styling in compiled output (a4c9548a + guard round-4 finding 2)", () => {
|
||||
const node = (id: string, name: string, runtime: string) => ({
|
||||
id, type: "rigNode", parentId: "pod-D",
|
||||
data: { logicalId: name, podNamespace: "d", runtime, model: null, status: "running",
|
||||
@@ -599,18 +603,18 @@ describe("ROUND-3 LOCKED SET (orch locked-scope GO; pins 02259adb/29a10b62)", ()
|
||||
const cl = drillDetail("d.cl");
|
||||
expect(cl.styled).toMatch(/38;2;24;24;24;48;2;173;103;85m[^\x1b]*>/);
|
||||
expect(cl.styled).toMatch(/38;2;24;24;24;48;2;173;103;85m[^\x1b]*</); // both inward eyes carry the eye-on-terracotta SGR
|
||||
expect(cl.plain).not.toMatch(/claude/); // spelled runtime is dead
|
||||
expect(cl.plain).toMatch(/runtime:\s+claude-code/); // a4c9548a: the NAME is the value (the mark's SGR above proves it still accompanies decoratively)
|
||||
// terminal: the dark-cell background survives to the compiled detail line
|
||||
const tty = drillDetail("d.tty");
|
||||
expect(tty.styled).toMatch(/48;2;12;10;9m?[^\x1b]*>/);
|
||||
expect(tty.plain.slice(31)).not.toMatch(/terminal/);
|
||||
// codex: ASCII >_ text with the picks-v4 CHEVRON-ONLY blue hint — the `>`
|
||||
// carries the OFFICIAL sampled #6867aa (38;2;104;103;170) on detail; the
|
||||
// `_` stays light ink; no ❯, no outline, no spelled runtime
|
||||
expect(tty.plain.slice(31)).toMatch(/runtime:\s+terminal/); // a4c9548a: the NAME is the value; the >_ mark still trails (SGR above)
|
||||
// codex: the NAME `codex` is the value (a4c9548a), with the picks-v4 CHEVRON-ONLY
|
||||
// blue hint accompanying — the `>` carries the OFFICIAL sampled #6867aa
|
||||
// (38;2;104;103;170) on detail; the `_` stays light ink; no ❯, no outline.
|
||||
const cx = drillDetail("d.cx");
|
||||
expect(cx.plain.slice(31).trimEnd()).toMatch(/runtime:\s+>_$/);
|
||||
expect(cx.styled).toMatch(/38;2;104;103;170m[^\x1b]*>/); // chevron pick (picks v4 item a)
|
||||
expect(cx.plain).not.toMatch(/❯|codex/);
|
||||
expect(cx.plain.slice(31)).toMatch(/runtime:\s+codex/); // a4c9548a: the NAME is the value
|
||||
expect(cx.styled).toMatch(/38;2;104;103;170m[^\x1b]*>/); // chevron pick (picks v4 item a) still accompanies
|
||||
expect(cx.plain).not.toMatch(/❯/); // no ❯ outline (the codex name renders as the value, not an icon substitute)
|
||||
});
|
||||
|
||||
it("rig glyph is ▦ and pod glyph is ≡ (founder picks of record)", () => {
|
||||
|
||||
Reference in new issue
Block a user