mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-08 17:31:56 -10:00
shell-redesign V1 polish slice Phase 5.1 P5.1-3: pod name truncation fix
V1 founder-walk surfaced a rendering bug: pod names display with
the first 2-3 characters truncated (e.g., "discovery" rendering as
"covery", "planning" as "anning") across topology surfaces.
Root cause: lib/display-name.ts displayPodName called shortId(podId, 6)
which returns the LAST 6 chars of any string — designed for 26-char
ULIDs (random tail more distinguishable than timestamp head) but
WRONG for human-readable pod namespaces. "discovery" (9 chars) → last
6 = "covery"; "planning" (8 chars) → "anning"; "kernel" (6 chars)
unchanged because shortId returns id verbatim when len ≤ 6.
Fix: displayPodName returns podId verbatim (no shortId call). Pod
IDs in OpenRig are namespace strings ("discovery" / "planning" /
"kernel" / "product-lab" / etc.), not ULIDs.
shortId import dropped from display-name.ts; the helper is still
exported for actual ULID display surfaces (rig IDs, qitem tails)
elsewhere in the codebase.
NEW packages/ui/test/p5-1-pod-name-truncation.test.ts (12 tests):
- "discovery" → "discovery"
- "planning" → "planning"
- "kernel" / "orch" / "product-lab" / multi-hyphen pass-through
- null/empty → "ungrouped" fallback preserved
- Source-assertion (ritual #9): displayPodName does NOT call shortId
in code (comment-stripped grep)
- inferPodName + displayAgentName neighbor-function preserved
(split-on-dot semantics unchanged)
Verification:
- pnpm -F @openrig/ui exec tsc --noEmit: clean
- vitest p5-1-pod-name-truncation: 12/12 pass
- vitest full UI suite: 672/674 PASS (pre-existing library-review
baseline failure UNCHANGED; 1 skipped)
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
f3780c0656
commit
49108fea01
2 files changed
+96
-2
No files matched your search
@@ -1,4 +1,14 @@
|
||||
import { shortId } from "./display-id.js";
|
||||
// V1 polish slice Phase 5.1 P5.1-3: pod name truncation bug fix.
|
||||
// Founder noticed pod names rendering as "covery" / "anning" — first 2-3
|
||||
// chars cut. Root cause: displayPodName was calling shortId(podId, 6)
|
||||
// which returns the LAST 6 chars of any string — fine for 26-char ULIDs
|
||||
// (random tail more distinguishable than timestamp head) but WRONG for
|
||||
// human-readable pod namespaces ("discovery" / "planning" / "kernel"
|
||||
// etc.). Pod IDs in OpenRig are namespace strings, not ULIDs; the
|
||||
// shortId path should never have applied. Returning the podId verbatim.
|
||||
//
|
||||
// shortId is still imported elsewhere for actual ULID display surfaces
|
||||
// (rig IDs, qitem tails, etc.) — this fix only touches the pod path.
|
||||
|
||||
export function inferPodName(logicalId: string | null | undefined): string | null {
|
||||
if (!logicalId) return null;
|
||||
@@ -8,7 +18,9 @@ export function inferPodName(logicalId: string | null | undefined): string | nul
|
||||
}
|
||||
|
||||
export function displayPodName(podId: string | null | undefined): string {
|
||||
return podId && podId.length > 0 ? shortId(podId) : "ungrouped";
|
||||
// Pod IDs are human-readable namespace strings, not ULIDs — return
|
||||
// verbatim so "discovery" stays "discovery" (NOT "covery").
|
||||
return podId && podId.length > 0 ? podId : "ungrouped";
|
||||
}
|
||||
|
||||
export function displayAgentName(logicalId: string | null | undefined): string {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// V1 polish slice Phase 5.1 P5.1-3 — pod name truncation regression guard.
|
||||
//
|
||||
// Founder noticed pod names rendering as "covery" / "anning" / etc.
|
||||
// at the live VM walk post-V1-ship. Root cause: displayPodName was
|
||||
// calling shortId(podId, 6) which returns the LAST 6 chars of any
|
||||
// input — designed for 26-char ULIDs but WRONG for human-readable pod
|
||||
// namespaces. The fix returns podId verbatim. This test permanently
|
||||
// guards the symptoms the founder reported plus the underlying contract.
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { displayPodName, inferPodName, displayAgentName } from "../src/lib/display-name.js";
|
||||
|
||||
describe("displayPodName P5.1-3 regression: human-readable pod names pass through verbatim", () => {
|
||||
it("'discovery' stays 'discovery' (NOT 'covery')", () => {
|
||||
expect(displayPodName("discovery")).toBe("discovery");
|
||||
});
|
||||
|
||||
it("'planning' stays 'planning' (NOT 'anning')", () => {
|
||||
expect(displayPodName("planning")).toBe("planning");
|
||||
});
|
||||
|
||||
it("'kernel' stays 'kernel'", () => {
|
||||
expect(displayPodName("kernel")).toBe("kernel");
|
||||
});
|
||||
|
||||
it("'orch' stays 'orch'", () => {
|
||||
expect(displayPodName("orch")).toBe("orch");
|
||||
});
|
||||
|
||||
it("'product-lab' stays 'product-lab'", () => {
|
||||
expect(displayPodName("product-lab")).toBe("product-lab");
|
||||
});
|
||||
|
||||
it("'recursive-self-improvement-v2' stays full (NOT '-v2')", () => {
|
||||
expect(displayPodName("recursive-self-improvement-v2")).toBe(
|
||||
"recursive-self-improvement-v2",
|
||||
);
|
||||
});
|
||||
|
||||
it("null / empty returns 'ungrouped' fallback", () => {
|
||||
expect(displayPodName(null)).toBe("ungrouped");
|
||||
expect(displayPodName(undefined)).toBe("ungrouped");
|
||||
expect(displayPodName("")).toBe("ungrouped");
|
||||
});
|
||||
|
||||
it("source-assertion: displayPodName does NOT call shortId for pod names (ritual #9)", async () => {
|
||||
const { readFileSync } = await import("node:fs");
|
||||
const path = await import("node:path");
|
||||
const src = readFileSync(
|
||||
path.resolve(__dirname, "../src/lib/display-name.ts"),
|
||||
"utf8",
|
||||
);
|
||||
// Strip comments to ignore historical mention.
|
||||
const codeOnly = src
|
||||
.replace(/\/\*[\s\S]*?\*\//g, "")
|
||||
.replace(/^\s*\/\/[^\n]*\n/gm, "");
|
||||
// Locate displayPodName function body.
|
||||
const fnMatch = codeOnly.match(/export function displayPodName[\s\S]*?^}/m);
|
||||
expect(fnMatch).not.toBeNull();
|
||||
const body = fnMatch![0];
|
||||
expect(body).not.toMatch(/shortId\s*\(/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("inferPodName + displayAgentName preserved (P5.1-3 cleanup didn't regress neighbors)", () => {
|
||||
it("inferPodName splits 'discovery.intake-router' → 'discovery'", () => {
|
||||
expect(inferPodName("discovery.intake-router")).toBe("discovery");
|
||||
});
|
||||
|
||||
it("displayAgentName splits 'discovery.intake-router' → 'intake-router'", () => {
|
||||
expect(displayAgentName("discovery.intake-router")).toBe("intake-router");
|
||||
});
|
||||
|
||||
it("inferPodName returns the whole id when no dot", () => {
|
||||
expect(inferPodName("solo-agent")).toBe("solo-agent");
|
||||
});
|
||||
|
||||
it("inferPodName returns null for null/undefined", () => {
|
||||
expect(inferPodName(null)).toBe(null);
|
||||
expect(inferPodName(undefined)).toBe(null);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user