Skip to content

feat(plugin): prototype TypeScript candidate normalization - #643

Open
mldangelo-oai wants to merge 3 commits into
mainfrom
mdangelo/codex/prototype-normalize-candidates-ts
Open

feat(plugin): prototype TypeScript candidate normalization#643
mldangelo-oai wants to merge 3 commits into
mainfrom
mdangelo/codex/prototype-normalize-candidates-ts

Conversation

@mldangelo-oai

@mldangelo-oai mldangelo-oai commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add a side-by-side TypeScript candidate normalizer with Python as the executable oracle. Python remains the production entrypoint.

Changes

  • Generate the standalone JavaScript helper from TypeScript and check generated-file freshness during type validation.
  • Fix decimal/exponent line-token rejection, symlinked entrypoints and help processing after missing option values.
  • Preserve Python's native Windows output line endings, case-insensitive overwrite checks and junction/parent resolution. Accept LF, CRLF and CR-only candidate JSONL.
  • Replace the manual temporary-file retry loop, remove four helper functions and duplicated assertions/types, and retain private atomic output replacement.
  • Merge current main and advance both bundle markers to 0.1.80. Keep existing commands, arguments, candidate identities and output ordering.

Testing

  • Final affected suites, seed 643: 165 passed, 14 platform skips. The token, symlink, help-order and CR-only regressions were reproduced before their fixes.

  • Generated helper under Node 22.0.0: 21 passed, two Windows-only skips across all three differential suites. A separate expanded property run used 32 cases per property plus explicit invalid cases.

  • Types, generated models/helper checks, formatting and build passed.

  • Real Codex upgrades from cache versions 0.1.37 and 0.1.60 replaced a stale helper and executed the installed normalizer.

  • Fresh 283-entry package check and full installed smoke passed with 119 plugin files, SDK import, NodeNext consumer, CLI, credential locking and a nested worker.

  • Native Windows and Linux, the full suite and live model execution were not rerun. Current-head CI is left for a separate pass; the old Windows failures are not presented as a green current-head run.

  • Final main refresh (fd98a90): package 0.1.21 includes the MCP launcher-permission fix; SDK implementation and bundled payload are unchanged. Types/model generation, formatting, build, 49 focused tests (2 platform skips), static artifact verification and full installed-package smoke passed, including MCP initialization. CI was not awaited.

Risk and rollout

No production cutover or public CLI change. The prototype remains bundled alongside Python for parity testing. Windows regressions are included but require native CI verification. The cleanup removes nine source/generated lines; fixes and regression coverage add 72 net lines overall. Existing review discussions remain open; no approval or PR merge is included.

Public disclosure review

  • No customer, partner, prospect, or user identities, data, or identifying details are included.
  • No credentials, personal data, private source, scan findings, or nonpublic links or tickets are included.
  • I reviewed the branch name, title, description, commits, changes, comments, logs, screenshots, attachments, and links for public disclosure.

Historical commit contact metadata and restricted links in automated comments remain, so the second attestation is unchecked. This update uses synthetic fixtures and a GitHub noreply commit identity; other authors' comments are unchanged.

@github-actions github-actions Bot added the enhancement New feature or request label Aug 25, 2026
@mldangelo-oai

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-27T09:14:05.559538Z 5af166b New commits
🔒 Security Review Completed 2026-08-25T06:58:55.753170Z f2a088a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2a088a5bb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +732 to +735
if (inputs.includes(output))
throw new Error("--out: must not also be an input");
if (output === scopePath) {
throw new Error("--out: must not replace --in-scope-files");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Canonicalize Windows paths before overwrite checks

On Windows, path identity is case-insensitive, but these string comparisons are case-sensitive and resolveAllowMissing() preserves the caller's spelling. If an existing input or scope file is passed as --out with different drive, directory, or filename casing, the check is bypassed and the final rename replaces that protected file; Python's Path comparison rejects the same invocation. Compare canonical Windows path keys or otherwise use case-insensitive path identity here.

AGENTS.md reference: sdk/typescript/AGENTS.md:L22-L27

Useful? React with 👍 / 👎.

Comment on lines +235 to +239
function positiveLine(value: unknown, field: string): number {
if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
throw new Error(`${field}: expected a positive integer`);
}
return value;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject decimal spellings for line numbers

When model output encodes a line as 1.0 or 1e0, JSON.parse produces the number 1, so this check accepts it and writes a candidate; the Python oracle parses those tokens as floats and rejects them because they are not int values. This breaks the documented rejected-input parity during migration and can cause previously invalid candidate rows to enter scan results, so the JSON token type must be preserved or validated before coercion.

AGENTS.md reference: AGENTS.md:L21-L24

Useful? React with 👍 / 👎.

Comment on lines +781 to +785
const entrypoint = process.argv[1];
if (
entrypoint !== undefined &&
import.meta.url === pathToFileURL(resolve(entrypoint)).href
) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Resolve symlinks before detecting the CLI entrypoint

When this script or any parent directory is invoked through a filesystem symlink, Node resolves import.meta.url to the real module while process.argv[1] retains the symlink spelling, so this condition is false and the process exits successfully without reading candidates or producing output. The Python helper works through the same symlink, so canonicalize both paths before comparing them to preserve executable behavior.

AGENTS.md reference: AGENTS.md:L21-L24

Useful? React with 👍 / 👎.

Comment on lines +762 to +764
async function runCli(): Promise<void> {
if (process.argv.slice(2).some(isHelpArgument)) {
console.log(HELP);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3 Badge Parse help after validating preceding option values

If --help or -h follows an option whose value is missing, such as --out --help or --input --help, this pre-scan prints help and exits successfully. The Python CLI instead reports the missing value and exits with status 2, so malformed automation can be silently treated as successful during migration; process help in argument order rather than bypassing parsing whenever it appears.

AGENTS.md reference: AGENTS.md:L28-L31

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 40df333b76

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +632 to +633
if (value === undefined || value.startsWith("-")) {
throw new Error(`${option}: expected a value`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept negative numeric path arguments

When a scalar path is supplied as a separate token that resembles a negative number, such as --out -1, this check rejects it as a missing value. The Python oracle’s argparse parser accepts -1 here—I checked --out -1 --help, which prints help and exits 0—so scripts using numeric-looking filenames fail after switching to this helper unless they rewrite the argument using =. Preserve the existing accepted path syntax rather than rejecting every dash-prefixed token.

AGENTS.md reference: AGENTS.md:L28-L31

Useful? React with 👍 / 👎.

Comment on lines +587 to +592
function expandUser(value: string): string {
if (value === "~") return homedir();
if (value.startsWith(`~${sep}`) || (sep === "\\" && value.startsWith("~/"))) {
return join(homedir(), value.slice(2));
}
return value;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Expand named-user home paths

On Unix, quoted or programmatically supplied paths such as ~alice/repo are expanded by every Path.expanduser() call in the Python oracle, but this implementation recognizes only the current-user forms ~ and ~/.... Consequently, any input, repository root, scope file, or output under another user’s accessible home is instead resolved relative to the current working directory and fails or addresses the wrong path, changing an existing accepted CLI value during migration.

AGENTS.md reference: AGENTS.md:L28-L31

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5af166bb68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

} from "node:path";
import { fileURLToPath } from "node:url";

const CWE = /^CWE-(\d+)$/iu;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept Unicode decimal digits in CWE IDs

When a candidate contains a CWE such as CWE-١ or CWE-12, the Python oracle accepts it because Python's \d matches Unicode decimal digits and int() normalizes them, while JavaScript's \d remains ASCII-only even with the u flag, so this prototype rejects an input the existing normalizer converts to CWE-1 or CWE-12. Use Unicode decimal-digit matching and normalization to preserve accepted-input and output parity.

AGENTS.md reference: AGENTS.md:L21-L22

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant