Skip to content

fix(codemode): harden OpenAPI search and sandbox transport#23

Merged
robinbraemer merged 11 commits into
mainfrom
fix/openapi-search-graph
Jul 24, 2026
Merged

fix(codemode): harden OpenAPI search and sandbox transport#23
robinbraemer merged 11 commits into
mainfrom
fix/openapi-search-graph

Conversation

@robinbraemer

@robinbraemer robinbraemer commented Jul 24, 2026

Copy link
Copy Markdown
Member

Intent

Preserve a fully pre-resolved OpenAPI schema for AI CodeMode search while safely reusing reference expansions, bounding alias-expanded transport payloads, keeping circular/max-depth behavior correct, accurately classifying violations, and publishing 0.4.1 for CNAP production.

What changed

  • Pre-resolved, bounded OpenAPI reference expansion with concurrent preparation deduplication, retry after failure, and per-search isolation.
  • Built-in executor preflight for alias fan-out, encoded payload size, cycles, accessors, bigint, and custom JSON serialization before sandbox marshalling.
  • Correct native Date handling, removal of the legacy guard facade, and coverage across QuickJS, IsolatedVM, LLRT process, and native LLRT.

Risk

Low after automated remediation and re-review. The production-scale 4.35 MiB resolved graph remains accepted; oversized or unsafe inputs fail before transport.

Verification

Luna no-mistakes passed. Native LLRT, IsolatedVM, QuickJS, LLRT-process, production-scale search, adversarial transport checks, lint, documentation, publication metadata, and PR CI are green.

Rationale: Reuse acyclic component expansions across processed operations so large OpenAPI specs remain below the data-only graph guard while keeping endpoint-local cyclic expansion semantics.\n\nRisk: Cached schema objects are shared by identity for context-independent refs. Expansions containing circular or max-depth sentinels deliberately remain uncached to avoid reusing context-bound results.\n\nTested: mise exec -- pnpm --filter @robinbraemer/codemode exec vitest run test/spec.test.ts; mise exec -- pnpm --filter @robinbraemer/codemode run test; mise exec -- pnpm run lint
Rationale: A ref expansion cached from a shallow endpoint must not bypass a max-depth sentinel when that ref is reached later with less resolution budget.

Risk: Cache reuse is now narrower because entries are partitioned by remaining depth, preserving correctness at the cost of duplicate expansions across different budgets.

Tested: mise exec -- pnpm --filter @robinbraemer/codemode exec vitest run test/spec.test.ts; mise exec -- pnpm --filter @robinbraemer/codemode run test; mise exec -- pnpm run lint
Rationale: Cached processed specs now share acyclic ref objects, so every custom data executor must receive an independent graph per search while retaining aliases within that execution.

Risk: Search now pays one structured clone per invocation; it deliberately preserves shared schema identity inside the executor input and avoids rebuilding the cached spec.

Tested: mise exec -- pnpm --filter @robinbraemer/codemode exec vitest run test/codemode.test.ts; mise exec -- pnpm --filter @robinbraemer/codemode run test; mise exec -- pnpm run lint
Rationale: Keep graph-limit and accessor violations distinct from real function values so executor errors accurately explain why a data-only input was rejected.

Risk: Only error classification changes for accessor and oversized graphs; findFunctionPath preserves its existing compatibility strings for internal non-null checks.

Tested: mise exec -- pnpm --filter @robinbraemer/codemode exec vitest run test/data-only.test.ts; mise exec -- pnpm --filter @robinbraemer/codemode test; mise exec -- task lint.
Rationale: Preserve the legacy findFunctionPath strings used by executor compatibility checks while rejectDataOnlyFunctions formats classified errors.

Risk: Test-only change; it locks the existing wrapper messages for accessor and graph-limit violations.

Tested: mise exec -- pnpm --filter @robinbraemer/codemode exec vitest run test/data-only.test.ts; mise exec -- pnpm --filter @robinbraemer/codemode test; mise exec -- task lint.
Rationale: Concurrent first searches must share one async spec-provider resolution and processing pass while retaining isolated per-search inputs.

Risk: Failed provider resolutions must not poison later searches; the in-flight memo is identity-cleared on either outcome.

Tested: pnpm --dir packages/codemode exec vitest run test/codemode.test.ts; mise exec -- task ci
Rationale: Shared OpenAPI ref expansions intentionally form a DAG, but built-in JSON and QuickJS transports recreate each alias occurrence. Bound the expanded representation before marshalling so a small unique-object graph cannot exhaust host memory while preserving the production-scale pre-resolved spec.

Rejected: Preserving aliases inside every transport requires a larger cross-runtime protocol change and would not protect existing JSON backends.

Risk: The new 500k-occurrence and 10 MiB ceilings reject unusually large data-only inputs, cycles, bigint, and custom toJSON hooks before execution. The measured production fixture remains below both limits.

Tested: mise exec -- task ci (CodeMode 167 passed, 9 skipped; LLRT 27 passed, 22 skipped; lint, typechecks, and builds passed).

Not-tested: Native LLRT runtime contracts were skipped because upstream native preparation failed during yarn install; TypeScript/build integration passed.
@robinbraemer robinbraemer changed the title fix(codemode): safely pre-resolve OpenAPI search graphs fix(codemode): harden OpenAPI search and sandbox transport Jul 24, 2026
@robinbraemer
robinbraemer merged commit 9799581 into main Jul 24, 2026
1 check passed
@robinbraemer
robinbraemer deleted the fix/openapi-search-graph branch July 24, 2026 12:31
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.

1 participant