Thanks to visit codestin.com
Credit goes to github.com

Skip to content

test: property-check table formatter alignment under unicode content - #595

Merged
ndycode merged 4 commits into
mainfrom
claude/audit-76-table-formatter-property
Jun 19, 2026
Merged

ndycode merged 4 commits into
mainfrom
claude/audit-76-table-formatter-property

Conversation

@ndycode

@ndycode ndycode commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds a fast-check property suite for lib/table-formatter.ts, the CLI table renderer whose alignment guarantee (ui-02) is "measure in display columns, not UTF-16 code units". Property generation is the right tool here: the interesting inputs are exactly the awkward ones — CJK doubles, emoji, wide glyphs straddling a truncation boundary, rows with missing or extra cells.

What Changed

New test/property/table-formatter.property.test.ts (4 properties over buildTable/buildTableRow, cell content drawn from a mixed ASCII/CJK/emoji alphabet):

  1. Lockstep layout — every line of any table (header, separator, every data row) has exactly the layout's display width, for any column set (widths 0–10), any alignment mix, and rows that are shorter or longer than the column count.
  2. Fit preservation — content that fits is rendered verbatim with padding on the declared side (left/right), padding computed in display columns.
  3. Truncation contract — overflowing content truncates to a prefix of the original plus an ellipsis, never exceeding the column width even when a wide glyph can't fill the final column (the case the ui-02 comment in formatCell documents).
  4. Zero-width columns — render empty rather than leaking a one-column ellipsis that would desync the row from the header/separator layout (the documented short-circuit in formatCell).

No SUT bugs found; the renderer's geometry held for every generated case.

Validation

  • npm test -- test/property/table-formatter.property.test.ts test/table-formatter.test.ts — 15/15 (new 4 + existing 11 untouched)
  • npm run typecheck (also via pre-commit hook)
  • npx eslint test/property/table-formatter.property.test.ts --max-warnings=0

Docs and Governance Checklist

  • Test-only; no behavior or docs surface changed

Risk and Rollback

  • Risk level: minimal — additive test file; conventions match the existing test/property/ suites (explicit vitest imports, plain fc.assert, fc.pre to partition fit vs overflow).
  • Rollback plan: revert the single commit.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB


Generated by Claude Code

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

adds a new property-based test suite for lib/table-formatter.ts, covering the four core invariants of the unicode-aware table renderer: lockstep layout width, fit-preservation with display-column padding, truncation correctness with wide-glyph boundaries, and zero-width column isolation. the previous review cycle's two issues (undefined align coverage gap, and the right-aligned prefix check conflating padding spaces with content spaces) are both addressed in this version.

  • lockstep layout: every line of any table (header, separator, data rows) is asserted to have exactly sum(widths) + (n-1) display columns for any generated column set, content mix, and ragged row length.
  • fit & truncation: single-column deep checks verify padding placement and prefix fidelity via a left-aligned side channel, sidestepping the space-in-content ambiguity that motivated the previous comment.
  • zero-width columns: the short-circuit path in formatCell is exercised by a standalone property to confirm no ellipsis leaks into the layout.

Confidence Score: 5/5

additive test-only change with no production code modifications; the two issues from the prior review cycle are both addressed in this version.

the test file introduces no new runtime code paths, both previously reported correctness issues in the property checks are resolved, the global fast-check seed is correctly applied via vitest setupFiles (confirmed in vitest.config.ts), and the four invariants cover the documented ui-02 display-column contract end-to-end.

no files require special attention.

Important Files Changed

Filename Overview
test/property/table-formatter.property.test.ts new property suite; both previously flagged issues (align undefined gap, right-aligned prefix check) are resolved; global fc seed config applies correctly via vitest setupFiles; test logic is sound across all four invariants.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[arbCellText\nASCII/CJK/emoji\nmixed alphabet] --> P1
    A --> P2
    A --> P3
    A --> P4

    subgraph P1["Property 1: Lockstep Layout"]
        B[arbOptions\nn columns, widths 0-10\nalign left/right/undefined] --> C[buildTable rows]
        C --> D{every line\ndisplayWidth ==\nsum widths + n-1?}
        D -->|yes| OK1[pass]
        D -->|no| FAIL1[fail]
    end

    subgraph P2["Property 2: Fit Preservation"]
        E[width 1-14\nalign left/right/undef] --> F{fc.pre:\ndisplayWidth <= width}
        F --> G[buildTableRow single col]
        G --> H{row == value + pad\nor pad + value?}
        H -->|yes| OK2[pass]
        H -->|no| FAIL2[fail]
    end

    subgraph P3["Property 3: Truncation Contract"]
        I[width 1-6\nalign left/right] --> J{fc.pre:\ndisplayWidth > width}
        J --> K[buildTableRow single col]
        K --> L{displayWidth == width\nand trimEnd ends with ellipsis?}
        L --> M[left-aligned side channel\nfor prefix fidelity]
        M --> N{value.startsWith\nvisible prefix?}
        N -->|yes| OK3[pass]
        N -->|no| FAIL3[fail]
    end

    subgraph P4["Property 4: Zero-Width Columns"]
        O[width = 0] --> Q[buildTableRow single col]
        Q --> R{row == empty string?}
        R -->|yes| OK4[pass]
        R -->|no| FAIL4[fail]
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[arbCellText\nASCII/CJK/emoji\nmixed alphabet] --> P1
    A --> P2
    A --> P3
    A --> P4

    subgraph P1["Property 1: Lockstep Layout"]
        B[arbOptions\nn columns, widths 0-10\nalign left/right/undefined] --> C[buildTable rows]
        C --> D{every line\ndisplayWidth ==\nsum widths + n-1?}
        D -->|yes| OK1[pass]
        D -->|no| FAIL1[fail]
    end

    subgraph P2["Property 2: Fit Preservation"]
        E[width 1-14\nalign left/right/undef] --> F{fc.pre:\ndisplayWidth <= width}
        F --> G[buildTableRow single col]
        G --> H{row == value + pad\nor pad + value?}
        H -->|yes| OK2[pass]
        H -->|no| FAIL2[fail]
    end

    subgraph P3["Property 3: Truncation Contract"]
        I[width 1-6\nalign left/right] --> J{fc.pre:\ndisplayWidth > width}
        J --> K[buildTableRow single col]
        K --> L{displayWidth == width\nand trimEnd ends with ellipsis?}
        L --> M[left-aligned side channel\nfor prefix fidelity]
        M --> N{value.startsWith\nvisible prefix?}
        N -->|yes| OK3[pass]
        N -->|no| FAIL3[fail]
    end

    subgraph P4["Property 4: Zero-Width Columns"]
        O[width = 0] --> Q[buildTableRow single col]
        Q --> R{row == empty string?}
        R -->|yes| OK4[pass]
        R -->|no| FAIL4[fail]
    end
Loading

Reviews (3): Last reviewed commit: "Merge branch 'main' into claude/audit-76..." | Re-trigger Greptile

Four fast-check properties over buildTable/buildTableRow with cell
content mixing ASCII, CJK, and emoji so widths are exercised in
display columns rather than UTF-16 units (ui-02):

- every line of any table (header, separator, all rows) has exactly
  the layout's display width, for any column set, alignment mix,
  missing cells, or extra cells beyond the column count
- content that fits is preserved verbatim with padding on the
  declared side
- overflowing content truncates to a prefix of the original plus an
  ellipsis, never exceeding the column width even when a wide glyph
  cannot fill the final column
- zero-width columns render empty and never leak an ellipsis that
  would desync the row from the header layout

Companion to the property suites in #574/#575/#592-#594.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@ndycode, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 29 minutes and 53 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 441cbe9b-47a7-4ff1-9509-c0b8028699a2

📥 Commits

Reviewing files that changed from the base of the PR and between 82ff3b0 and 148b38a.

📒 Files selected for processing (1)
  • test/property/table-formatter.property.test.ts
📝 Walkthrough

Walkthrough

property test suite validates table-formatter behavior using randomized inputs: ensuring all output lines maintain expected display widths, padding respects alignment when content fits, overflow truncates with ellipsis without exceeding width, and zero-width columns render empty.

Changes

Table formatter property tests

Layer / File(s) Summary
Display width and truncation validation
test/property/table-formatter.property.test.ts
Property-based test suite uses vitest + fast-check to generate randomized table options and cell contents (ascii, cjk, emoji) asserting four invariants: output lines preserve expected display widths, fitted content preserves original characters with alignment-specific padding, overflow truncates with ellipsis respecting column width constraints, and zero-width columns render empty.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


flagged observations

  • missing regression coverage: confirm existing table-formatter unit tests (test/unit/table-formatter* or similar) still cover edge cases like empty strings, single-character content, and mixed-width boundaries. property tests excel at invariants but unit tests catch specific known regressions.

  • windows line-ending risk: verify test/property/table-formatter.property.test.ts:1-110 does not assume unix line endings when validating display width across row separators. if the formatter emits \r\n on windows, computed display widths may drift. check what buildTable returns on windows.

  • cjk/emoji width assumptions: fast-check generates cjk and emoji—confirm the table-formatter uses a consistent display-width library (like string-width) across all platforms. if width calculation differs between node versions or terminals, the assertions may flake on ci.

  • no concurrency or state-mutation risk detected: this is a stateless property test. good.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed title follows conventional commits format (test: summary), summary is 53 chars in lowercase imperative, clearly describes the property test addition for table formatter unicode handling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed pr description is comprehensive and well-structured, covering summary, what changed, validation steps, and risk assessment with concrete details about the four properties and edge cases tested.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/audit-76-table-formatter-property
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/audit-76-table-formatter-property

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/property/table-formatter.property.test.ts`:
- Around line 77-98: Add a symmetric property test for right-aligned truncation:
copy the existing test block that uses buildTableRow, arbCellText and
displayWidth but set columns: [{ header: "h", width, align: "right" }], strip
leading padding with visible = row.replace(/^ +/, "") (instead of trimming
trailing spaces), and assert the same properties: visible endsWith("…"), the
original value startsWith(visible.slice(0, -1)), and displayWidth(visible) <=
width to verify truncation + ellipsis is correct for right alignment.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b0ba59fb-bdf9-4f95-b979-75cf5197b9fd

📥 Commits

Reviewing files that changed from the base of the PR and between c255e14 and 82ff3b0.

📒 Files selected for processing (1)
  • test/property/table-formatter.property.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,js,mts,cjs}

📄 CodeRabbit inference engine (AGENTS.md)

Use ESM only with "type": "module" in package.json; Node >= 18.17 required

Files:

  • test/property/table-formatter.property.test.ts
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Do not use as any, @ts-ignore, or @ts-expect-error TypeScript assertions

Files:

  • test/property/table-formatter.property.test.ts
**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

OAuth callback server uses port 1455; do not hardcode OAuth ports—use existing constants/helpers

Files:

  • test/property/table-formatter.property.test.ts
**/*.{js,ts}

📄 CodeRabbit inference engine (README.md)

**/*.{js,ts}: Use JSON format for machine-readable output in diagnostic and reporting commands (status, check, report, monitor, why-selected)
Implement interactive terminal dashboard with hotkeys (Up/Down for navigation, Enter for selection, 1-9 for quick switch, / for search, ? for help, Q for back)
Support device authentication flow via --device-auth flag and manual OAuth callback paste fallback via --manual flag for headless environments
Run npm version check during normal forwarded Codex startup and print upgrade notices only on interactive TTY or when CODEX_MULTI_AUTH_DEBUG=1 is set

Files:

  • test/property/table-formatter.property.test.ts
test/**/*.test.ts

📄 CodeRabbit inference engine (test/AGENTS.md)

test/**/*.test.ts: Write Vitest test suites with globals enabled (describe, it, expect)
Maintain 80%+ coverage threshold across statements, branches, functions, and lines
Use removeWithRetry() for Windows filesystem cleanup instead of bare fs.rm to handle EBUSY, EPERM, and ENOTEMPTY errors
Do not rely on dist/ in tests; use source files instead
Do not skip tests without justification
Relax lint rules for test files as configured in eslint.config.js

Files:

  • test/property/table-formatter.property.test.ts
test/**/property/**/*.test.ts

📄 CodeRabbit inference engine (test/AGENTS.md)

Use fast-check for property-based testing in test files

Files:

  • test/property/table-formatter.property.test.ts
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/property/table-formatter.property.test.ts
**

⚙️ CodeRabbit configuration file

**: # PROJECT KNOWLEDGE BASE

Generated: 2026-04-25
Commit: a87e005
Validated: 2026-06-10 against commit 98d9819 (repo audit; claims re-checked against the tree, content not regenerated)
Branch: main
Package version: 2.3.0-beta.3

OVERVIEW

codex-multi-auth is a Codex CLI-first OAuth account manager and optional forwarding wrapper for the official Codex CLI. The installed codex-multi-auth entrypoint handles account-management commands locally, codex-multi-auth-codex forwards official Codex commands through this package's wrapper when explicitly used, and runtime rotation can route live Responses traffic through a localhost account-rotation proxy by default. The plugin-host entrypoint remains exported for compatibility, but the primary product surface is the account manager, optional wrapper, storage, runtime proxy, and repair tooling.

STRUCTURE

./
├── scripts/
│   ├── codex.js              # codex-multi-auth-codex wrapper, official CLI forwarder, shadow CODEX_HOME/runtime proxy setup
│   ├── codex-multi-auth.js   # standalone package CLI entrypoint
│   ├── codex-routing.js      # auth command and compatibility alias routing
│   ├── codex-bin-resolver.js # official Codex binary discovery
│   ├── codex-app-router.js   # persistent localhost router for packaged Codex app bind
│   └── codex-app-launcher.js # reversible user-level app launcher routing helper
├── index.ts                  # optional plugin-host runtime entry
├── lib/                      # core runtime logic (see lib/AGENTS.md)
│   ├── auth/                 # OAuth flow, PKCE, callback server
│   ├── runtime/              # Codex CLI/app integration helpers, app bind, live sync, runtime observability
│   ├── request/              # request transform, SSE, failover, backoff
│   ├── storage/              # path resolution, migrations, backups, restore, import/export
│   ├── codex-cli/            # Codex CLI state sync and writer helpers
│   ├── codex-manager/        # command modules and...

Files:

  • test/property/table-formatter.property.test.ts
🧠 Learnings (2)
📚 Learning: 2026-06-04T06:14:18.093Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/scheduling-strategy-config.test.ts:1-1
Timestamp: 2026-06-04T06:14:18.093Z
Learning: In ndycode/codex-multi-auth, do not flag explicit imports from "vitest" (e.g., describe, it, expect, beforeEach/afterEach, etc.) in test files as issues—even if the Vitest config sets `globals: true`. The repo’s established convention is to keep these imports for consistency with neighboring tests; removing them would make files outliers.

Applied to files:

  • test/property/table-formatter.property.test.ts
📚 Learning: 2026-06-04T06:14:24.975Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/runtime-rotation-proxy.test.ts:2478-2491
Timestamp: 2026-06-04T06:14:24.975Z
Learning: In ndycode/codex-multi-auth test files (e.g. `test/*.test.ts`), when creating V3 storage fixtures for accounts, it’s an intentional convention to use `as never` for deliberately minimal stored-account objects that only include `refreshToken`, `addedAt`, and `lastUsed`. Do not treat `as never` here as a type-safety problem: optional/other fields are expected to be populated by the runtime during execution, and the cast is used solely to keep the fixture minimal and consistent across existing tests.

Applied to files:

  • test/property/table-formatter.property.test.ts
🔇 Additional comments (5)
test/property/table-formatter.property.test.ts (5)

1-9: LGTM!


11-33: LGTM!


35-57: LGTM!


59-75: LGTM!


100-109: LGTM!

Comment thread test/property/table-formatter.property.test.ts
Comment thread test/property/table-formatter.property.test.ts
Comment thread test/property/table-formatter.property.test.ts Outdated
…align

Greptile P1: stripping leading spaces on a right-aligned row conflated
alignment padding with spaces that belong to the truncated content
(latent spurious failure under a different fast-check seed - e.g.
' a<CJK>' at width 3 right-aligned). Prefix fidelity now checks the
left-aligned rendering of the same value, where the cell starts at
column 0, while the right-aligned row keeps its width and trailing-
ellipsis assertions. Verified at FAST_CHECK_NUM_RUNS=1000.

Greptile P2: arbColumn and the fit property now generate undefined
align too, exercising formatCell's default-left branch.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
@ndycode
ndycode merged commit 23e4263 into main Jun 19, 2026
1 of 2 checks passed
@ndycode
ndycode deleted the claude/audit-76-table-formatter-property branch June 19, 2026 06:04
ndycode added a commit that referenced this pull request Jun 19, 2026
)

* test: property-check plugin health classification and report shape

Three fast-check properties over getAccountHealth/formatHealthReport:

- counts and status derive exactly from the per-account classification
  for any pool (timestamps straddling now, undefined fallbacks, health
  0..100): healthy iff not rate-limited, not cooling, health >= 50,
  circuit closed; status partitions empty->healthy, none->unhealthy,
  some->degraded, all->healthy
- an open circuit disqualifies an otherwise perfect account: tripping
  the account:<index> fallback breaker for any subset is reflected in
  circuitState, subtracted from healthyAccountCount, and drives the
  status partition
- the formatted report names every account with its health percentage
  and exactly the flags its classification implies, and the summary
  lines appear iff their counts are nonzero

Companion to the property suites in #574/#575/#592-#595.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB

* test: exercise half-open disqualification and email-aliased circuits

Greptile flagged two coverage gaps: the half-open state was unreachable
without advancing the clock, and accounts sharing an email silently
shared a breaker without an explicit contract. Property 2 now probes
open -> half-open under fake timers (both states disqualify, and the
report renders the precise circuit flag), pool emails are unique by
construction, and a dedicated property pins shared-email accounts to
one breaker while distinct emails stay isolated - derived through the
same getAccountIdentityKey the SUT uses.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB

---------

Co-authored-by: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants