Skip to content

feat(performance): add progressive disclosure tests and compositional routing acceptance#6341

Draft
ericksoa wants to merge 38 commits into
mainfrom
feat/tool-disclosure-benchmarks
Draft

feat(performance): add progressive disclosure tests and compositional routing acceptance#6341
ericksoa wants to merge 38 commits into
mainfrom
feat/tool-disclosure-benchmarks

Conversation

@ericksoa

@ericksoa ericksoa commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an opt-in, repeatable performance-test harness for direct versus progressive tool disclosure and an independent compositional tool-routing experiment. The full two-campaign procedure is hardware-neutral and records privacy-safe, statistically gated evidence on any compatible host. The routing experiment has a strict route-only acceptance command plus a separate claim-ineligible agent replay that verifies task correctness and reduced model-visible schemas.

This pull request remains a draft while maintainers review the implementation and evidence boundaries. No measured results are checked in, and no performance test runs automatically.

Related Issue

Related to #6251.

Changes

  • Add npm run performance:tool-disclosure -- prepare|execute|summarize with a deterministic 2,209-tool catalog, frozen task sets, and a paired two-campaign schedule.
  • Add route-acceptance, which evaluates a 20-tool, eight-case corpus spanning zero through five capabilities with a recorded decomposer and either portable or semantic embeddings.
  • Add a compositional router with one shared initial decomposition and retrieval stage, bounded tool-name hints, one refinement pass, normalized exact retrieval, fail-open behavior, and prompt-free evidence.
  • Gate actual forwarded schemas, not only logical selections. Any fallback is a non-configurable failure, including a failed-open no-tool request that would forward the complete catalog.
  • Validate decomposition output before accepting an attempt; retry only transient failures, with hard request, retry, and whole-run bounds.
  • Record explicit whole-run timeout status and evidence so unattempted cases are not attributed to model or embedding failures.
  • Add a recorder request-transform boundary that preserves the caller-owned executor registry, filters only a copied model request, isolates concurrent cache consumers, and cancels unfinished shared work after its final waiter leaves.
  • Split decomposition and embedding request, token, failure, and duration accounting in route evidence.
  • Extend the explicit-only GitHub-hosted smoke with the route-only corpus and a separate routed agent replay. The frozen direct/progressive cells remain unchanged.
  • Route the ordinary-runner replay through an authenticated private Docker bridge, replace the ephemeral ingress credential before upstream forwarding, and restore the original provider route during both the normal and cleanup paths.
  • Keep remote model and recorder endpoints opt-in, HTTPS-only outside loopback, credential-free in configuration, and absent from public route evidence.
  • Document the hardware-neutral workflow, strict acceptance gates, remote-content boundary, limitations, and claim scope.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification:
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: Pending maintainer review of recorder, remote-content, routing, bearer-token, tunnel, Docker-inspection, and public-evidence boundaries.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Verification

  • PR description includes the DCO sign-off declaration and every authored commit includes a sign-off.
  • npm run check:diff passed at exact head a8a2f41c after merging current main.
  • npm run typecheck and npm run typecheck:cli passed.
  • npx vitest run --project integration test/performance/tool-disclosure-*.test.ts passed: 16 files, 138 tests.
  • The focused E2E workflow-boundary, live-gating, and combined uploader-inventory suites passed.
  • Agent-variant docs are synchronized.
  • Public changed surfaces contain no external project or paper references and use neutral performance-test terminology.
  • No secrets, API keys, endpoint URLs, prompts, or decomposed subtask text are written to route evidence.
  • Applicable broad gate passed — exact-head CI / Pull Request run 28884386525 passed.
  • Quality Gates section completed with required justifications or waivers — exact-head CI and maintainer sensitive-path review remain pending.

Live evidence

  • Normal-runner capability smoke: run 28835849685, exact prior head 20a64a8c; 3/3 runtime scenarios passed.
  • Frozen hosted-inference smoke: run 28839899839, exact prior head 2ce14274; progressive and direct each completed the frozen task with one expected synthetic call. This was one fixed-order, claim-ineligible observation.
  • Earlier routing observation: run 28879556882, exact prior head 559f268e; refinement improved exact decomposition from 5/8 to 7/8 cases and exact ordered forwarding from 4/8 to 7/8, but the run correctly failed because one five-step route did not complete.
  • Transport diagnosis: run 28881548680, exact prior head e0d1deb7; route-only acceptance passed, while the routed replay failed before the recorder because the gateway could not reach runner loopback. This led to the authenticated private-bridge path.
  • Final-head ordinary-runner smoke: run 28884388865, exact head a8a2f41c; all jobs passed. The route-only corpus completed 8/8 cases with no fallback and all refined strict gates at 1.0. Refinement improved exact decomposition from 0.75 to 1.0, exact tool recall at one from 0.944 to 1.0, and exact ordered selection/forwarding from 0.875 to 1.0. The routed replay completed the frozen task with one expected call, no fallback or bypass, and reduced model-visible schemas from 79 to 16 on both model requests. Progressive and direct frozen cells also succeeded with one expected call each. Provider restore, proxy shutdown, sandbox cleanup, and MCP cleanup all passed.

The live smoke is operational acceptance evidence only. Its single fixed-order observations and portable lexical embedder do not support performance or universal quality claims; those require the documented full two-campaign procedure on a recorded hardware and software configuration.


Signed-off-by: Aaron Erickson aerickson@nvidia.com

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@ericksoa ericksoa added integration: openclaw OpenClaw integration behavior security integration: hermes Hermes integration behavior provider: vllm vLLM local or hosted provider behavior area: docs Documentation, examples, guides, or docs build area: inference Inference routing, serving, model selection, or outputs area: integrations Third-party service integration behavior area: security Security controls, permissions, secrets, or hardening feature PR adds or expands user-visible functionality platform: dgx-station Affects DGX Station hardware or workflows area: performance Latency, throughput, resource use, benchmarks, or scaling integration: dcode LangChain Deep Code integration behavior labels Jul 6, 2026
@ericksoa ericksoa self-assigned this Jul 6, 2026
@github-code-quality

github-code-quality Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the branch is 96%. Coverage data for the branch is not yet available.

Show a code coverage summary of the most covered files.
File e971120 +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/li...bprocess-env.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the branch is 76%. Coverage data for the branch is not yet available.

Show a code coverage summary of the most covered files.
File e971120 +/-
src/lib/onboard/preflight.ts 82%
src/lib/actions...all/run-plan.ts 81%
src/lib/state/o...oard-session.ts 81%
src/lib/actions...licy-channel.ts 79%
src/lib/state/sandbox.ts 75%
src/lib/actions...dbox/connect.ts 72%
src/lib/onboard...er-gpu-patch.ts 69%
src/lib/policy/index.ts 66%
src/lib/shields/index.ts 61%
src/lib/onboard.ts 28%

Updated July 07, 2026 22:14 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 2dff9458-4d40-413d-bb66-bb8db0dabfdb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds the progressive tool-disclosure benchmark stack: deterministic synthetic inputs, live execution and recording infrastructure, statistical reporting, frozen-evidence validation, CLI wiring, docs, navigation, and tests.

Changes

Progressive Tool-Disclosure Benchmark

Layer / File(s) Summary
Schema and deterministic inputs
scripts/bench/tool-disclosure/types.ts, scripts/bench/tool-disclosure/catalog.ts, scripts/bench/tool-disclosure/tasks.ts, scripts/bench/tool-disclosure/schedule.ts
Defines the benchmark schema and generates the synthetic catalog, task sets, and deterministic run schedule used by the harness.
Artifact and sandbox helpers
scripts/bench/tool-disclosure/artifacts.ts, scripts/bench/tool-disclosure/subprocess.ts, scripts/bench/tool-disclosure/drivers.ts, scripts/bench/tool-disclosure/openclaw-fixture.ts, scripts/bench/tool-disclosure/quick-tunnel.ts, test/bench/tool-disclosure-catalog.test.ts, test/bench/tool-disclosure-schedule.test.ts, test/bench/tool-disclosure-fixture.test.ts, test/bench/tool-disclosure-drivers.test.ts, test/bench/tool-disclosure-quick-tunnel.test.ts
Adds safe artifact handling, bounded subprocess execution, driver command construction, OpenClaw fixture generation, quick tunnels, and coverage for the deterministic catalog/task/fixture paths.
MCP, recording, telemetry, and live execution
scripts/bench/tool-disclosure/mcp-server.ts, scripts/bench/tool-disclosure/recorder.ts, scripts/bench/tool-disclosure/telemetry.ts, scripts/bench/tool-disclosure/execute.ts, test/bench/tool-disclosure-mcp-server.test.ts, test/bench/tool-disclosure-recorder.test.ts, test/bench/tool-disclosure-telemetry.test.ts, test/bench/tool-disclosure-execute.test.ts
Implements the local MCP server, loopback recording proxy, vLLM telemetry helpers, campaign execution flow, and tests for run recovery, attestation, and proxy behavior.
Statistics, reporting, and validation
scripts/bench/tool-disclosure/grading.ts, scripts/bench/tool-disclosure/assemble-run.ts, scripts/bench/tool-disclosure/statistics.ts, scripts/bench/tool-disclosure/report.ts, scripts/bench/tool-disclosure/validation.ts, test/bench/tool-disclosure-report.test.ts, test/bench/tool-disclosure-validation.test.ts
Computes grading, bootstrap comparisons, claim gates, markdown output, and frozen-evidence validation, with tests for summary and validation behavior.
CLI, docs, and script wiring
scripts/bench/tool-disclosure/run.ts, docs/index.yml, docs/inference/progressive-tool-disclosure-benchmark.mdx, scripts/bench/README.md, package.json
Adds the benchmark CLI, navigation entries, protocol documentation, README guidance, and npm script wiring.

Estimated code review effort: 5 (Critical) | ~120 minutes
Suggested labels: bug-fix, chore

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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 Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the benchmark harness and test additions, though it underdescribes the broader docs, scripts, and validation changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tool-disclosure-benchmarks

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

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: tool-disclosure-performance-smoke, tool-disclosure-performance-smoke, network-policy, cloud-onboard
Optional E2E: security-posture, mcp-bridge-dev

Dispatch hint: tool-disclosure-performance-smoke,network-policy

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • tool-disclosure-performance-smoke (high): This is the targeted live E2E for the changed Deep Agents Code tool-disclosure path. It onboards fresh LangChain Deep Agents Code sandboxes in progressive and direct modes, uses hosted NVIDIA inference, exercises synthetic MCP transport and managed MCP snapshot behavior, and verifies the new performance-smoke plumbing end to end.
  • tool-disclosure-performance-smoke (high): The PR also changes the Brev branch-validation implementation for this suite. Run the branch-validation version to prove source install, OpenShell setup, SSH/MCP forwarding, cloudflared prerequisite installation, Brev artifact collection, and secret scanning work on a fresh Brev VM.
  • network-policy (medium): The PR changes a sandbox policy file and grants /dev/shm writable access for the Deep Agents Code runtime fallback. Because this affects filesystem/network policy boundaries, run the live network-policy job to catch policy enforcement regressions beyond static and unit checks.
  • cloud-onboard (high): Changed onboard, trace timing, scorecard, or E2E workflow code can affect cloud onboard wall-clock behavior and should refresh the trusted cloud-onboard trace timing signal.

Optional E2E

  • security-posture (medium): Useful additional confidence for sandbox hardening and non-root/runtime posture after changes to agent Dockerfiles, entrypoint behavior, writable filesystem areas, and credential-sensitive runtime scripts. It is adjacent rather than fully targeted because the current matrix covers OpenClaw/Hermes, not a dedicated Deep Agents Code posture lane.
  • mcp-bridge-dev (medium): Optional coverage for adjacent MCP transport and cloudflared workflow behavior, especially because this PR changes MCP-oriented performance smoke transport and cloudflared pin/update checks. The targeted required signal remains tool-disclosure-performance-smoke.

New E2E recommendations

  • langchain-deepagents-code managed runtime security (high): There is no dedicated low-cost live E2E job for Deep Agents Code runtime hardening separate from the expensive performance smoke. A targeted job should onboard one Deep Agents Code sandbox and verify direct exec/login shell behavior, trusted root-owned tool-disclosure/proxy files, /tmp-to-/dev/shm anonymous MCP snapshot fallback, credential-free /tmp/nemoclaw-proxy-env.sh, and policy denial of unapproved egress.
    • Suggested test: langchain-deepagents-code-managed-runtime

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: tool-disclosure-performance-smoke,network-policy

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: tool-disclosure-performance-smoke, ubuntu-repo-cloud-langchain-deepagents-code
Optional E2E targets: None

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=tool-disclosure-performance-smoke
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-langchain-deepagents-code

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • tool-disclosure-performance-smoke: Focused free-standing E2E job wired for changed live test test/e2e/live/tool-disclosure-performance-smoke.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=tool-disclosure-performance-smoke
  • ubuntu-repo-cloud-langchain-deepagents-code: The PR changes the LangChain Deep Agents Code image, launcher, startup, managed runtime, and sandbox policy. This live-supported typed target onboards and validates the Deep Agents Code sandbox surface affected by those changes.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-langchain-deepagents-code

Optional E2E targets

  • None.

Relevant changed files

  • .github/workflows/e2e.yaml
  • agents/langchain-deepagents-code/Dockerfile
  • agents/langchain-deepagents-code/Dockerfile.base
  • agents/langchain-deepagents-code/dcode-launcher.sh
  • agents/langchain-deepagents-code/managed-dcode-runtime.py
  • agents/langchain-deepagents-code/policy-additions.yaml
  • agents/langchain-deepagents-code/start.sh
  • scripts/performance/tool-disclosure/artifacts.ts
  • scripts/performance/tool-disclosure/assemble-run.ts
  • scripts/performance/tool-disclosure/catalog.ts
  • scripts/performance/tool-disclosure/compositional-tool-router.ts
  • scripts/performance/tool-disclosure/compositional-tool-routing-acceptance.ts
  • scripts/performance/tool-disclosure/compositional-tool-routing-adapters.ts
  • scripts/performance/tool-disclosure/compositional-tool-routing-run.ts
  • scripts/performance/tool-disclosure/compositional-tool-routing-transform.ts
  • scripts/performance/tool-disclosure/drivers.ts
  • scripts/performance/tool-disclosure/execute.ts
  • scripts/performance/tool-disclosure/grading.ts
  • scripts/performance/tool-disclosure/mcp-server.ts
  • scripts/performance/tool-disclosure/openclaw-fixture.ts
  • scripts/performance/tool-disclosure/quick-tunnel.ts
  • scripts/performance/tool-disclosure/recorder.ts
  • scripts/performance/tool-disclosure/report.ts
  • scripts/performance/tool-disclosure/run.ts
  • scripts/performance/tool-disclosure/schedule.ts
  • scripts/performance/tool-disclosure/smoke-mcp-transport.ts
  • scripts/performance/tool-disclosure/statistics.ts
  • scripts/performance/tool-disclosure/subprocess.ts
  • scripts/performance/tool-disclosure/tasks.ts
  • scripts/performance/tool-disclosure/telemetry.ts
  • scripts/performance/tool-disclosure/types.ts
  • scripts/performance/tool-disclosure/validation.ts
  • test/e2e/brev-e2e.test.ts
  • test/e2e/live/tool-disclosure-performance-smoke.test.ts
  • test/e2e/support/jetson-workflow-boundary.test.ts
  • test/e2e/support/tool-disclosure-performance-smoke-workflow-boundary.test.ts
  • test/e2e/support/upload-e2e-artifacts-workflow-boundary.test.ts
  • tools/e2e/brev-remote-vitest.mts
  • tools/e2e/upload-e2e-artifacts-workflow-boundary.mts

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Comment thread scripts/performance/tool-disclosure/artifacts.ts Fixed
Comment thread scripts/performance/tool-disclosure/telemetry.ts Fixed
Comment thread scripts/performance/tool-disclosure/telemetry.ts Fixed
Comment thread scripts/performance/tool-disclosure/telemetry.ts Fixed
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Blocked

Merge posture: Do not merge until addressed
Primary next action: Fix PRA-3: Validate Brev smoke artifact tar members before extracting on the runner; then add or justify PRA-T1.
Open items: 1 required · 4 warnings · 0 suggestions · 6 test follow-ups
Since last review: 0 prior items resolved · 5 still apply · 0 new items found

Action checklist

  • PRA-3 Fix: Validate Brev smoke artifact tar members before extracting on the runner in .github/workflows/e2e-branch-validation.yaml:341
  • PRA-1 Resolve or justify: Source-of-truth review needed: Brev performance smoke artifact archive extraction
  • PRA-2 Resolve or justify: Source-of-truth review needed: Docker/vLLM process attestation parser
  • PRA-4 Resolve or justify: Revoke Docker auth before installer and bootstrap steps in the smoke job in .github/workflows/e2e.yaml:758
  • PRA-5 Resolve or justify: Reject duplicate or conflicting effective vLLM attestation options in scripts/performance/tool-disclosure/execute.ts:337
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Brev performance smoke artifact archive extraction
  • PRA-T6 Add or justify test follow-up: Docker/vLLM process attestation parser

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Required security .github/workflows/e2e-branch-validation.yaml:341 Write the SSH tar stream to a temporary archive, inspect its table of contents and entry types before any extraction, reject absolute paths, parent-directory paths, symlinks, hardlinks, devices, and unexpected names, then extract only an allowlisted artifact set with owner and permission restoration disabled. Keep the inference-key scan as a separate post-extraction leakage check.
PRA-4 Resolve/justify security .github/workflows/e2e.yaml:758 Move Docker authentication later if only sandbox image pulls require it, or add an immediate cleanup/unset boundary before `Install OpenShell CLI`. If the installer must run before final cleanup, run it with `DOCKER_CONFIG`, `DOCKERHUB_USERNAME`, `DOCKERHUB_TOKEN`, `NVIDIA_API_KEY`, `NVIDIA_INFERENCE_API_KEY`, and `GITHUB_TOKEN` explicitly unset while retaining the final `if: always()` Docker auth cleanup as defense in depth.
PRA-5 Resolve/justify correctness scripts/performance/tool-disclosure/execute.ts:337 Parse the attested vLLM argv into effective options and require manifest singleton options such as `--model`, `--revision`, `--tool-call-parser`, and `--reasoning-parser` to appear exactly once with the expected value. For `public_vllm_flags`, reject duplicate value-bearing flags with conflicting values, or narrow accepted Docker command forms to only the forms the harness can prove.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-3 Required — Validate Brev smoke artifact tar members before extracting on the runner

  • Location: .github/workflows/e2e-branch-validation.yaml:341
  • Category: security
  • Problem: The branch-validation workflow receives a tar stream from the Brev VM, writes it to `${RUNNER_TEMP}/brev-tool-disclosure-performance-smoke-artifacts.tar.gz`, and immediately runs `tar -C "$artifact_dir" -xzf "$archive"`. The result-file check and NVIDIA inference-key scan happen only after extraction, and the workflow does not preflight archive member paths, entry types, ownership, permissions, or unexpected names.
  • Impact: A compromised or buggy Brev VM can return an archive containing absolute paths, `..` paths, symlinks, hardlinks, device nodes, or unexpected entries. Extracting it first can overwrite files in or near the runner workspace, create misleading artifacts, or place attacker-controlled content before the credential scan runs.
  • Required action: Write the SSH tar stream to a temporary archive, inspect its table of contents and entry types before any extraction, reject absolute paths, parent-directory paths, symlinks, hardlinks, devices, and unexpected names, then extract only an allowlisted artifact set with owner and permission restoration disabled. Keep the inference-key scan as a separate post-extraction leakage check.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read the `Collect Brev tool-disclosure performance smoke artifacts` step and confirm archive member listing/type validation occurs before any `tar -x` command, and that extraction uses safe ownership and permission flags such as disabling owner/permission restoration where supported.
  • Missing regression test: Extend `test/brev-nightly-workflow.test.ts` with `rejects unsafe Brev performance smoke archive members before extraction`, asserting that the workflow lists archive members before extraction, rejects absolute and parent-directory paths, rejects symlink/hardlink/device entries, allowlists expected artifact names, and extracts with safe ownership and permission flags.
  • Done when: The required change is committed and verification passes: Read the `Collect Brev tool-disclosure performance smoke artifacts` step and confirm archive member listing/type validation occurs before any `tar -x` command, and that extraction uses safe ownership and permission flags such as disabling owner/permission restoration where supported.
  • Evidence: Current lines 318-341 create `archive="${RUNNER_TEMP}/brev-tool-disclosure-performance-smoke-artifacts.tar.gz"`, receive `tar -C '$remote_dir' -czf - .` over SSH, and then run `tar -C "$artifact_dir" -xzf "$archive"`. The changed `test/brev-nightly-workflow.test.ts` only asserts collection/scan/upload ordering and `tar -C` presence, not pre-extraction validation.
Review findings by urgency: 1 required fix, 4 items to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: Brev performance smoke artifact archive extraction

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing. Existing `test/brev-nightly-workflow.test.ts` asserts collection, scan, upload, and cleanup ordering but not archive member validation before extraction.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Covered by finding `Validate Brev smoke artifact tar members before extracting on the runner`.

PRA-2 Resolve/justify — Source-of-truth review needed: Docker/vLLM process attestation parser

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing duplicate/conflicting singleton and public value-flag tests in `test/performance/tool-disclosure-execute.test.ts`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Covered by finding `Reject duplicate or conflicting effective vLLM attestation options`.

PRA-4 Resolve/justify — Revoke Docker auth before installer and bootstrap steps in the smoke job

  • Location: .github/workflows/e2e.yaml:758
  • Category: security
  • Problem: The new `tool-disclosure-performance-smoke` job authenticates to Docker Hub near the start, then prepares the E2E workspace, installs the pinned cloudflared package, and invokes `bash scripts/install-openshell.sh`. The Docker auth cleanup remains only as the final step.
  • Impact: Docker Hub credentials remain available across installer, bootstrap, and downloaded-prerequisite boundaries. If an installer path, setup dependency, or workspace action is compromised, it can read or reuse the Docker auth configuration before the final cleanup step runs.
  • Recommended action: Move Docker authentication later if only sandbox image pulls require it, or add an immediate cleanup/unset boundary before `Install OpenShell CLI`. If the installer must run before final cleanup, run it with `DOCKER_CONFIG`, `DOCKERHUB_USERNAME`, `DOCKERHUB_TOKEN`, `NVIDIA_API_KEY`, `NVIDIA_INFERENCE_API_KEY`, and `GITHUB_TOKEN` explicitly unset while retaining the final `if: always()` Docker auth cleanup as defense in depth.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read the `tool-disclosure-performance-smoke` job and confirm a Docker auth cleanup or explicit environment-unset boundary occurs after `Authenticate to Docker Hub` and before `Install OpenShell CLI`, not only after artifact upload.
  • Missing regression test: Extend `test/e2e/support/tool-disclosure-performance-smoke-workflow-boundary.test.ts` with `revokes Docker auth before installing OpenShell in the tool-disclosure smoke job`, asserting that Docker auth is revoked or unset before `Install OpenShell CLI` and that the final always-run cleanup remains.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read the `tool-disclosure-performance-smoke` job and confirm a Docker auth cleanup or explicit environment-unset boundary occurs after `Authenticate to Docker Hub` and before `Install OpenShell CLI`, not only after artifact upload.
  • Evidence: Current job order is checkout, `Authenticate to Docker Hub`, `Prepare E2E workspace`, `Install and verify cloudflared prerequisite`, `Install OpenShell CLI`, live test, upload, then `Clean up Docker auth`. Existing workflow-boundary coverage asserts the auth step exists and final cleanup is last, but does not assert a pre-installer revoke/unset boundary.

PRA-5 Resolve/justify — Reject duplicate or conflicting effective vLLM attestation options

  • Location: scripts/performance/tool-disclosure/execute.ts:337
  • Category: correctness
  • Problem: `readAttestedVllmConfiguration` attests vLLM process arguments by checking whether expected options and public flag token sequences appear somewhere in the parsed argv. It does not prove singleton options appear exactly once, nor does it reject duplicate value-bearing public flags with conflicting effective values, including shell-form Docker commands.
  • Impact: A live vLLM process can include the expected manifest value and also a later conflicting value that is the one vLLM actually uses. The evidence bundle would then attest the wrong serving configuration, undermining performance-test reproducibility and claim validity.
  • Recommended action: Parse the attested vLLM argv into effective options and require manifest singleton options such as `--model`, `--revision`, `--tool-call-parser`, and `--reasoning-parser` to appear exactly once with the expected value. For `public_vllm_flags`, reject duplicate value-bearing flags with conflicting values, or narrow accepted Docker command forms to only the forms the harness can prove.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `readAttestedVllmConfiguration`, `optionMatches`, and `containsSequence`; confirm singleton options are counted and conflicting later values fail attestation rather than passing because the expected value appears earlier.
  • Missing regression test: Extend `test/performance/tool-disclosure-execute.test.ts` with `rejects duplicate or conflicting effective vLLM singleton options` and `rejects conflicting public vLLM value flags in shell-form Docker commands`, using commands where the expected value appears once and a conflicting later value would otherwise take effect.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `readAttestedVllmConfiguration`, `optionMatches`, and `containsSequence`; confirm singleton options are counted and conflicting later values fail attestation rather than passing because the expected value appears earlier.
  • Evidence: Current tests cover intended process config and env/label decoys. They do not cover duplicate/conflicting argv options. The implementation still uses `optionMatches(invocation.args, name, value)` and `containsSequence(invocation.args, flagTokens)`, which are presence checks rather than effective-option attestation.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Simplification opportunities: 1 possible cut

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-4 shrink (.github/workflows/e2e.yaml:758): Long-lived Docker credential exposure across setup and installer steps in the new smoke job.
    • Replacement: Move the Docker login closer to the first Docker pull that needs it, or run the installer under an explicit `env -u ...` credential boundary and keep the final cleanup.
    • Safety boundary: Do not remove Docker authentication needed for trusted image pulls, and keep the final `if: always()` cleanup as defense in depth.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — test/brev-nightly-workflow.test.ts: rejects unsafe Brev performance smoke archive members before extraction. The PR changes workflows, sandbox image/runtime boundaries, network policy, installer-adjacent E2E setup, HTTP proxying, and Docker/vLLM attestation. Many focused tests were added, but the remaining high-risk gaps require behavior-specific workflow and parser regression coverage rather than relying on external E2E outcomes.
  • PRA-T2 Runtime validation — test/e2e/support/tool-disclosure-performance-smoke-workflow-boundary.test.ts: revokes Docker auth before installing OpenShell in the tool-disclosure smoke job. The PR changes workflows, sandbox image/runtime boundaries, network policy, installer-adjacent E2E setup, HTTP proxying, and Docker/vLLM attestation. Many focused tests were added, but the remaining high-risk gaps require behavior-specific workflow and parser regression coverage rather than relying on external E2E outcomes.
  • PRA-T3 Runtime validation — test/performance/tool-disclosure-execute.test.ts: rejects duplicate or conflicting effective vLLM singleton options. The PR changes workflows, sandbox image/runtime boundaries, network policy, installer-adjacent E2E setup, HTTP proxying, and Docker/vLLM attestation. Many focused tests were added, but the remaining high-risk gaps require behavior-specific workflow and parser regression coverage rather than relying on external E2E outcomes.
  • PRA-T4 Runtime validation — test/performance/tool-disclosure-execute.test.ts: rejects conflicting public vLLM value flags in shell-form Docker commands. The PR changes workflows, sandbox image/runtime boundaries, network policy, installer-adjacent E2E setup, HTTP proxying, and Docker/vLLM attestation. Many focused tests were added, but the remaining high-risk gaps require behavior-specific workflow and parser regression coverage rather than relying on external E2E outcomes.
  • PRA-T5 Brev performance smoke artifact archive extraction — Missing. Existing `test/brev-nightly-workflow.test.ts` asserts collection, scan, upload, and cleanup ordering but not archive member validation before extraction.. Covered by finding `Validate Brev smoke artifact tar members before extracting on the runner`.
  • PRA-T6 Docker/vLLM process attestation parser — Missing duplicate/conflicting singleton and public value-flag tests in `test/performance/tool-disclosure-execute.test.ts`.. Covered by finding `Reject duplicate or conflicting effective vLLM attestation options`.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: Brev performance smoke artifact archive extraction

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing. Existing `test/brev-nightly-workflow.test.ts` asserts collection, scan, upload, and cleanup ordering but not archive member validation before extraction.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Covered by finding `Validate Brev smoke artifact tar members before extracting on the runner`.

PRA-2 Resolve/justify — Source-of-truth review needed: Docker/vLLM process attestation parser

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Missing duplicate/conflicting singleton and public value-flag tests in `test/performance/tool-disclosure-execute.test.ts`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Covered by finding `Reject duplicate or conflicting effective vLLM attestation options`.

PRA-3 Required — Validate Brev smoke artifact tar members before extracting on the runner

  • Location: .github/workflows/e2e-branch-validation.yaml:341
  • Category: security
  • Problem: The branch-validation workflow receives a tar stream from the Brev VM, writes it to `${RUNNER_TEMP}/brev-tool-disclosure-performance-smoke-artifacts.tar.gz`, and immediately runs `tar -C "$artifact_dir" -xzf "$archive"`. The result-file check and NVIDIA inference-key scan happen only after extraction, and the workflow does not preflight archive member paths, entry types, ownership, permissions, or unexpected names.
  • Impact: A compromised or buggy Brev VM can return an archive containing absolute paths, `..` paths, symlinks, hardlinks, device nodes, or unexpected entries. Extracting it first can overwrite files in or near the runner workspace, create misleading artifacts, or place attacker-controlled content before the credential scan runs.
  • Required action: Write the SSH tar stream to a temporary archive, inspect its table of contents and entry types before any extraction, reject absolute paths, parent-directory paths, symlinks, hardlinks, devices, and unexpected names, then extract only an allowlisted artifact set with owner and permission restoration disabled. Keep the inference-key scan as a separate post-extraction leakage check.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read the `Collect Brev tool-disclosure performance smoke artifacts` step and confirm archive member listing/type validation occurs before any `tar -x` command, and that extraction uses safe ownership and permission flags such as disabling owner/permission restoration where supported.
  • Missing regression test: Extend `test/brev-nightly-workflow.test.ts` with `rejects unsafe Brev performance smoke archive members before extraction`, asserting that the workflow lists archive members before extraction, rejects absolute and parent-directory paths, rejects symlink/hardlink/device entries, allowlists expected artifact names, and extracts with safe ownership and permission flags.
  • Done when: The required change is committed and verification passes: Read the `Collect Brev tool-disclosure performance smoke artifacts` step and confirm archive member listing/type validation occurs before any `tar -x` command, and that extraction uses safe ownership and permission flags such as disabling owner/permission restoration where supported.
  • Evidence: Current lines 318-341 create `archive="${RUNNER_TEMP}/brev-tool-disclosure-performance-smoke-artifacts.tar.gz"`, receive `tar -C '$remote_dir' -czf - .` over SSH, and then run `tar -C "$artifact_dir" -xzf "$archive"`. The changed `test/brev-nightly-workflow.test.ts` only asserts collection/scan/upload ordering and `tar -C` presence, not pre-extraction validation.

PRA-4 Resolve/justify — Revoke Docker auth before installer and bootstrap steps in the smoke job

  • Location: .github/workflows/e2e.yaml:758
  • Category: security
  • Problem: The new `tool-disclosure-performance-smoke` job authenticates to Docker Hub near the start, then prepares the E2E workspace, installs the pinned cloudflared package, and invokes `bash scripts/install-openshell.sh`. The Docker auth cleanup remains only as the final step.
  • Impact: Docker Hub credentials remain available across installer, bootstrap, and downloaded-prerequisite boundaries. If an installer path, setup dependency, or workspace action is compromised, it can read or reuse the Docker auth configuration before the final cleanup step runs.
  • Recommended action: Move Docker authentication later if only sandbox image pulls require it, or add an immediate cleanup/unset boundary before `Install OpenShell CLI`. If the installer must run before final cleanup, run it with `DOCKER_CONFIG`, `DOCKERHUB_USERNAME`, `DOCKERHUB_TOKEN`, `NVIDIA_API_KEY`, `NVIDIA_INFERENCE_API_KEY`, and `GITHUB_TOKEN` explicitly unset while retaining the final `if: always()` Docker auth cleanup as defense in depth.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read the `tool-disclosure-performance-smoke` job and confirm a Docker auth cleanup or explicit environment-unset boundary occurs after `Authenticate to Docker Hub` and before `Install OpenShell CLI`, not only after artifact upload.
  • Missing regression test: Extend `test/e2e/support/tool-disclosure-performance-smoke-workflow-boundary.test.ts` with `revokes Docker auth before installing OpenShell in the tool-disclosure smoke job`, asserting that Docker auth is revoked or unset before `Install OpenShell CLI` and that the final always-run cleanup remains.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read the `tool-disclosure-performance-smoke` job and confirm a Docker auth cleanup or explicit environment-unset boundary occurs after `Authenticate to Docker Hub` and before `Install OpenShell CLI`, not only after artifact upload.
  • Evidence: Current job order is checkout, `Authenticate to Docker Hub`, `Prepare E2E workspace`, `Install and verify cloudflared prerequisite`, `Install OpenShell CLI`, live test, upload, then `Clean up Docker auth`. Existing workflow-boundary coverage asserts the auth step exists and final cleanup is last, but does not assert a pre-installer revoke/unset boundary.

PRA-5 Resolve/justify — Reject duplicate or conflicting effective vLLM attestation options

  • Location: scripts/performance/tool-disclosure/execute.ts:337
  • Category: correctness
  • Problem: `readAttestedVllmConfiguration` attests vLLM process arguments by checking whether expected options and public flag token sequences appear somewhere in the parsed argv. It does not prove singleton options appear exactly once, nor does it reject duplicate value-bearing public flags with conflicting effective values, including shell-form Docker commands.
  • Impact: A live vLLM process can include the expected manifest value and also a later conflicting value that is the one vLLM actually uses. The evidence bundle would then attest the wrong serving configuration, undermining performance-test reproducibility and claim validity.
  • Recommended action: Parse the attested vLLM argv into effective options and require manifest singleton options such as `--model`, `--revision`, `--tool-call-parser`, and `--reasoning-parser` to appear exactly once with the expected value. For `public_vllm_flags`, reject duplicate value-bearing flags with conflicting values, or narrow accepted Docker command forms to only the forms the harness can prove.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `readAttestedVllmConfiguration`, `optionMatches`, and `containsSequence`; confirm singleton options are counted and conflicting later values fail attestation rather than passing because the expected value appears earlier.
  • Missing regression test: Extend `test/performance/tool-disclosure-execute.test.ts` with `rejects duplicate or conflicting effective vLLM singleton options` and `rejects conflicting public vLLM value flags in shell-form Docker commands`, using commands where the expected value appears once and a conflicting later value would otherwise take effect.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `readAttestedVllmConfiguration`, `optionMatches`, and `containsSequence`; confirm singleton options are counted and conflicting later values fail attestation rather than passing because the expected value appears earlier.
  • Evidence: Current tests cover intended process config and env/label decoys. They do not cover duplicate/conflicting argv options. The implementation still uses `optionMatches(invocation.args, name, value)` and `containsSequence(invocation.args, flagTokens)`, which are presence checks rather than effective-option attestation.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Blocked

Merge posture: Do not merge until addressed
Primary next action: Fix PRA-5: Compositional router accepts unbounded query strings to external TaskDecomposer; then add or justify PRA-T1.
Open items: 1 required · 16 warnings · 7 suggestions · 8 test follow-ups
Since last review: 0 prior items resolved · 20 still apply · 8 new items found

Action checklist

  • PRA-5 Fix: Compositional router accepts unbounded query strings to external TaskDecomposer in scripts/performance/tool-disclosure/compositional-tool-router.ts:448
  • PRA-1 Resolve or justify: Source-of-truth review needed: scripts/performance/tool-disclosure/compositional-tool-router.ts — fail-open passthrough behavior
  • PRA-2 Resolve or justify: Source-of-truth review needed: scripts/performance/tool-disclosure/execute.ts — attempt-journal JSONL recovery
  • PRA-3 Resolve or justify: Source-of-truth review needed: scripts/performance/tool-disclosure/artifacts.ts — readJsonLines tolerant parsing
  • PRA-4 Resolve or justify: Source-of-truth review needed: scripts/performance/tool-disclosure/validation.ts — validateFrozenManifest strict enforcement
  • PRA-6 Resolve or justify: Fail-open behavior lacks source-of-truth documentation in scripts/performance/tool-disclosure/compositional-tool-router.ts:1
  • PRA-7 Resolve or justify: Attempt-journal recovery logic lacks source-of-truth documentation in scripts/performance/tool-disclosure/execute.ts:77
  • PRA-8 Resolve or justify: readJsonLines error handling lacks source-of-truth documentation in scripts/performance/tool-disclosure/artifacts.ts:72
  • PRA-9 Resolve or justify: Manifest validation fallback lacks source-of-truth documentation in scripts/performance/tool-disclosure/validation.ts:105
  • PRA-10 Resolve or justify: DEFAULT_MAX_REQUEST_BODY_BYTES = 64MB is high for test-scoped recording proxy in scripts/performance/tool-disclosure/recorder.ts:19
  • PRA-11 Resolve or justify: Quick-tunnel Cloudflare credential isolation not verified by integration test in scripts/performance/tool-disclosure/quick-tunnel.ts:1
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Runtime validation
  • PRA-T6 Add or justify test follow-up: No test for oversized query rejection
  • PRA-T7 Add or justify test follow-up: Recorder security tests have gaps in SSRF, header filtering, auth rotation coverage
  • PRA-T8 Add or justify test follow-up: Validation tests incomplete for nested secret/URL/path detection
  • PRA-18 In-scope improvement: CLI command 'performance:tool-disclosure' has 4 subcommands in ~760 lines — split into modules in scripts/performance/tool-disclosure/run.ts:1
  • PRA-19 In-scope improvement: recorder.ts is 1018 lines — split into proxy-core, transform, evidence modules in scripts/performance/tool-disclosure/recorder.ts:19
  • PRA-20 In-scope improvement: E2E_DEFAULT_ENABLED: '0' single-use config in tool-disclosure-performance-smoke job in .github/workflows/e2e.yaml:738
  • PRA-21 In-scope improvement: AbortSignal propagation to decomposer/embedder not verified in scripts/performance/tool-disclosure/compositional-tool-router.ts:448
  • PRA-22 In-scope improvement: Private bridge test-only topology not explicitly documented in test/e2e/live/tool-disclosure-performance-smoke.test.ts:1
  • PRA-23 In-scope improvement: Documentation claims need cross-verification against implementation constants in docs/inference/progressive-tool-disclosure-performance-test.mdx:1
  • PRA-24 In-scope improvement: DEFAULT_SYNTHETIC_PERFORMANCE_TEST_CATALOG_SEED used in only 3 locations — evaluate inlining in scripts/performance/tool-disclosure/catalog.ts:8

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-4 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-5 Required security scripts/performance/tool-disclosure/compositional-tool-router.ts:448 Add input query length validation (e.g., max 4096 chars) in prepareInitialRoutingStage before calling decomposer.decompose(). Document that TaskDecomposer implementations must handle untrusted input. Add security test for oversized query rejection.
PRA-6 Resolve/justify architecture scripts/performance/tool-disclosure/compositional-tool-router.ts:1 Add code comment near RoutingFailure catch block in prepareInitialRoutingStage and routeFromInitialStage documenting: (1) invalid state = malformed/unavailable model output, (2) source boundary = external TaskDecomposer/TextEmbedder implementations, (3) why not source fix = upstream models inherently unreliable, (4) regression test = tool-disclosure-compositional-router.test.ts malformed/unavailable/disagreement cases, (5) removal = when router can guarantee valid output via constrained decoding.
PRA-7 Resolve/justify architecture scripts/performance/tool-disclosure/execute.ts:77 Add code comment at recoverAttemptJournal documenting: (1) invalid state = truncated/incomplete JSONL line at process crash boundary, (2) created by appendJsonLine without atomic write-rename per run, (3) source fix = atomic write-rename per entry not feasible due to append-only evidence stream, (4) regression test = recoverAttemptJournal handles corrupt final line, (5) removal when append-only stream replaced with transactional log.
PRA-8 Resolve/justify architecture scripts/performance/tool-disclosure/artifacts.ts:72 Add code comment at readJsonLines documenting the five fields. Improve error message to include truncated line content (first 200 chars) and line number.
PRA-9 Resolve/justify architecture scripts/performance/tool-disclosure/validation.ts:105 Add code comment at validateFrozenManifest documenting: (1) invalid state = manifest missing claim-grade metadata or violating frozen constants, (2) source boundary = human-authored manifest.json, (3) why not source fix = manifest is human-completed from template, (4) regression test = tool-disclosure-validation.test.ts rejection cases, (5) removal when manifest generation is automated and verified by CI.
PRA-10 Resolve/justify security scripts/performance/tool-disclosure/recorder.ts:19 Reduce DEFAULT_MAX_REQUEST_BODY_BYTES to a more conservative value (e.g., 10MB) appropriate for performance test requests, or add documentation justifying 64MB. Ensure tests cover the default limit enforcement.
PRA-11 Resolve/justify security scripts/performance/tool-disclosure/quick-tunnel.ts:1 Add integration test that places dummy Cloudflare credentials in a simulated operator home, runs startQuickTunnel with isolated home, and verifies the tunnel process cannot access those credentials. Verify cloudflared runs with --config= and --no-autoupdate flags.
PRA-12 Resolve/justify security scripts/performance/tool-disclosure/mcp-server.ts:34 Add test for token entropy (64 hex chars = 256 bits) and verify token does not appear in JSON-serialized events, artifacts, or any logging path.
PRA-13 Resolve/justify tests test/performance/tool-disclosure-compositional-router.test.ts:1 Add test for oversized query rejection (>4096 chars) before decomposer invocation; verify RoutingFallbackReason 'invalid-query' is returned and decomposer is not called.
PRA-14 Resolve/justify tests test/performance/tool-disclosure-recorder.test.ts:1 Add tests for: redirect rejection, DNS rebinding TOCTOU, all HOP_BY_HOP_HEADERS stripped both directions, auth token rotation on retry, verify no request/response bodies in events.
PRA-15 Resolve/justify tests test/performance/tool-disclosure-validation.test.ts:1 Add test cases for nested secret-like field names/values in nested objects and arrays. Verify detection works at any depth.
PRA-16 Resolve/justify workflow agents/langchain-deepagents-code/Dockerfile:1 Coordinate with PR #6340 author. Compare diffs for Dockerfile, dcode-launcher.sh, start.sh. Ensure combined changes pass all proxy launcher tests after merge.
PRA-17 Resolve/justify workflow .github/workflows/e2e.yaml:738 Add validateToolDisclosurePerformanceSmokeJob function in tools/e2e/workflow-boundary.mts and register it in validateFreeStandingWorkflowInventory. Ensure generate-matrix step outputs correct explicit_only_jobs_csv.
PRA-18 Improvement correctness scripts/performance/tool-disclosure/run.ts:1 Split run.ts into prepare.ts, execute.ts, summarize.ts, route-acceptance.ts with a thin CLI dispatcher in run.ts.
PRA-19 Improvement correctness scripts/performance/tool-disclosure/recorder.ts:19 Split recorder.ts into proxy-core.ts (server start/stop, connection handling), transform.ts (requestTransform integration), evidence.ts (ToolDisclosureRecordingEvent, ToolMetrics, inspectTools).
PRA-20 Improvement workflow .github/workflows/e2e.yaml:738 Evaluate if E2E_DEFAULT_ENABLED is needed or can be removed; grep across workflows and test code confirms single use.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-5 Required — Compositional router accepts unbounded query strings to external TaskDecomposer

  • Location: scripts/performance/tool-disclosure/compositional-tool-router.ts:448
  • Category: security
  • Problem: prepareInitialRoutingStage validates query is non-empty string but has no length constraint before calling decomposer.decompose(). An oversized query (MB+) could cause excessive token usage, cost overruns, latency spikes, or DoS on external model endpoints. COMPOSITIONAL_ROUTER_MAX_SUBTASK_CHARS=512 limits subtask output but not input query length.
  • Impact: Malicious or buggy caller could send arbitrarily large queries to external decomposer models, causing uncontrolled costs and denial of service. No defense-in-depth at the router boundary.
  • Required action: Add input query length validation (e.g., max 4096 chars) in prepareInitialRoutingStage before calling decomposer.decompose(). Document that TaskDecomposer implementations must handle untrusted input. Add security test for oversized query rejection.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read compositional-tool-router.ts prepareInitialRoutingStage function; confirm query length check exists before calling decomposer.decompose()
  • Missing regression test: Add test in test/performance/tool-disclosure-compositional-router.test.ts for oversized query rejection (>4096 chars) before decomposer invocation; verify RoutingFallbackReason 'invalid-query' is returned and decomposer is not called
  • Done when: The required change is committed and verification passes: Read compositional-tool-router.ts prepareInitialRoutingStage function; confirm query length check exists before calling decomposer.decompose().
  • Evidence: compositional-tool-router.ts:448 validates query is non-empty string but has no length constraint; routeCompositionalTools calls prepareInitialRoutingStage without prior length check
Review findings by urgency: 1 required fix, 16 items to resolve/justify, 7 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: scripts/performance/tool-disclosure/compositional-tool-router.ts — fail-open passthrough behavior

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: tool-disclosure-compositional-router.test.ts: malformed decomposition, unavailable embedder, refinement disagreement cases all return passthrough with correct fallback reason
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: compositional-tool-router.ts:534, 537, 603 return finish('passthrough', fallback) on any RoutingFailure; no source-of-truth comment

PRA-2 Resolve/justify — Source-of-truth review needed: scripts/performance/tool-disclosure/execute.ts — attempt-journal JSONL recovery

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: recoverAttemptJournal handles corrupt final line gracefully; valid lines preserved
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: execute.ts:77-103 recoverAttemptJournal handles truncated final line; no source-of-truth comment

PRA-3 Resolve/justify — Source-of-truth review needed: scripts/performance/tool-disclosure/artifacts.ts — readJsonLines tolerant parsing

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: readJsonLines throws on malformed lines with line number; truncated final line handled
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: artifacts.ts:72-82 readJsonLines catches parse error only for final truncated line; no source-of-truth comment

PRA-4 Resolve/justify — Source-of-truth review needed: scripts/performance/tool-disclosure/validation.ts — validateFrozenManifest strict enforcement

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: tool-disclosure-validation.test.ts: missing model revision, mutable image digest, secret-like fields, URL values, private vLLM flags all rejected
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: validation.ts:105 validateFrozenManifest starts; no source-of-truth comment

PRA-6 Resolve/justify — Fail-open behavior lacks source-of-truth documentation

  • Location: scripts/performance/tool-disclosure/compositional-tool-router.ts:1
  • Category: architecture
  • Problem: The router returns 'passthrough' disposition on any malformed decomposition, unavailable retrieval, or model error — preserving the complete original tool catalog. No code comment documents the five source-of-truth fields for this localized workaround.
  • Impact: Future maintainers cannot verify why fail-open is acceptable, what invalid state it handles, where that state originates, why the source (upstream model reliability) cannot be fixed here, what regression test guards it, or when it can be removed.
  • Recommended action: Add code comment near RoutingFailure catch block in prepareInitialRoutingStage and routeFromInitialStage documenting: (1) invalid state = malformed/unavailable model output, (2) source boundary = external TaskDecomposer/TextEmbedder implementations, (3) why not source fix = upstream models inherently unreliable, (4) regression test = tool-disclosure-compositional-router.test.ts malformed/unavailable/disagreement cases, (5) removal = when router can guarantee valid output via constrained decoding.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search compositional-tool-router.ts for 'invalid state' or 'source boundary' comment near RoutingFailure/fallback handling
  • Missing regression test: Existing tests in tool-disclosure-compositional-router.test.ts cover passthrough behavior (malformed, unavailable, disagreement cases). Ensure these remain passing and document them as the regression gate.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search compositional-tool-router.ts for 'invalid state' or 'source boundary' comment near RoutingFailure/fallback handling.
  • Evidence: compositional-tool-router.ts:534, 537, 603 return finish('passthrough', fallback) on any error; no source-of-truth comment present

PRA-7 Resolve/justify — Attempt-journal recovery logic lacks source-of-truth documentation

  • Location: scripts/performance/tool-disclosure/execute.ts:77
  • Category: architecture
  • Problem: recoverAttemptJournal uses JSONL append with best-effort truncation handling for incomplete final lines. No code comment documents the five source-of-truth fields for this recovery behavior.
  • Impact: Invalid state (truncated line at crash boundary) handled locally; source (appendJsonLine without atomic write-rename) cannot be fixed due to append-only evidence stream requirement; removal condition unclear.
  • Recommended action: Add code comment at recoverAttemptJournal documenting: (1) invalid state = truncated/incomplete JSONL line at process crash boundary, (2) created by appendJsonLine without atomic write-rename per run, (3) source fix = atomic write-rename per entry not feasible due to append-only evidence stream, (4) regression test = recoverAttemptJournal handles corrupt final line, (5) removal when append-only stream replaced with transactional log.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read execute.ts recoverAttemptJournal function; look for source-of-truth comment
  • Missing regression test: Existing test coverage for journal recovery in tool-disclosure-execute.test.ts should be verified against the five fields
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read execute.ts recoverAttemptJournal function; look for source-of-truth comment.
  • Evidence: execute.ts:77-103 recoverAttemptJournal handles truncated final line but throws on other corruption; no source-of-truth comment

PRA-8 Resolve/justify — readJsonLines error handling lacks source-of-truth documentation

  • Location: scripts/performance/tool-disclosure/artifacts.ts:72
  • Category: architecture
  • Problem: readJsonLines throws on any parse error except a specific truncated-final-line case. No code comment documents the five source-of-truth fields. Error message lacks truncated line content and line number.
  • Impact: Malformed JSONL lines (not final) throw with generic 'invalid JSONL at line N' message; no context for debugging. Source-of-truth gap for why this tolerant parsing exists.
  • Recommended action: Add code comment at readJsonLines documenting the five fields. Improve error message to include truncated line content (first 200 chars) and line number.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read artifacts.ts readJsonLines function; look for source-of-truth comment and error message enhancement
  • Missing regression test: Add test for malformed JSONL line (not final) throwing with line number; test truncated final line handled gracefully
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read artifacts.ts readJsonLines function; look for source-of-truth comment and error message enhancement.
  • Evidence: artifacts.ts:72-82 readJsonLines catches parse error only for final truncated line; error message lacks line content

PRA-9 Resolve/justify — Manifest validation fallback lacks source-of-truth documentation

  • Location: scripts/performance/tool-disclosure/validation.ts:105
  • Category: architecture
  • Problem: validateFrozenManifest enforces strict protocol conformance but no comment documents the five fields for why this validation exists as a localized check rather than making invalid manifests impossible at source.
  • Impact: Human-authored manifest.json from manifest.template.json can have typos/omissions; validation catches them but doesn't prevent them at source. No documentation of why source fix (automated manifest generation) isn't feasible.
  • Recommended action: Add code comment at validateFrozenManifest documenting: (1) invalid state = manifest missing claim-grade metadata or violating frozen constants, (2) source boundary = human-authored manifest.json, (3) why not source fix = manifest is human-completed from template, (4) regression test = tool-disclosure-validation.test.ts rejection cases, (5) removal when manifest generation is automated and verified by CI.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search validation.ts for 'invalid state' or 'source boundary' comment near validateFrozenManifest/validateCompleteEvidence
  • Missing regression test: Existing validation tests in tool-disclosure-validation.test.ts cover rejection cases; verify they serve as regression gate
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search validation.ts for 'invalid state' or 'source boundary' comment near validateFrozenManifest/validateCompleteEvidence.
  • Evidence: validation.ts:105 validateFrozenManifest starts; no source-of-truth comment

PRA-10 Resolve/justify — DEFAULT_MAX_REQUEST_BODY_BYTES = 64MB is high for test-scoped recording proxy

  • Location: scripts/performance/tool-disclosure/recorder.ts:19
  • Category: security
  • Problem: Default 64MB request body limit could allow large bodies to consume memory before rejection. No test covers the default limit enforcement.
  • Impact: Memory exhaustion risk if proxy receives large request bodies. No test verifies limit enforcement.
  • Recommended action: Reduce DEFAULT_MAX_REQUEST_BODY_BYTES to a more conservative value (e.g., 10MB) appropriate for performance test requests, or add documentation justifying 64MB. Ensure tests cover the default limit enforcement.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read recorder.ts line 19 and 491; check test/performance/tool-disclosure-recorder.test.ts for maxRequestBodyBytes test coverage
  • Missing regression test: Add test in tool-disclosure-recorder.test.ts sending request body >64MB (or configured limit) and verify rejection with error_reason 'request-body-too-large'
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read recorder.ts line 19 and 491; check test/performance/tool-disclosure-recorder.test.ts for maxRequestBodyBytes test coverage.
  • Evidence: recorder.ts:19 const DEFAULT_MAX_REQUEST_BODY_BYTES = 64 * 1024 * 1024; line 491 uses options.maxRequestBodyBytes ?? DEFAULT_MAX_REQUEST_BODY_BYTES; no test for limit enforcement

PRA-11 Resolve/justify — Quick-tunnel Cloudflare credential isolation not verified by integration test

  • Location: scripts/performance/tool-disclosure/quick-tunnel.ts:1
  • Category: security
  • Problem: Unit test only checks environment construction (HOME/XDG_CONFIG_HOME replacement) but doesn't test that a real cloudflared process cannot load operator credentials from ambient configuration.
  • Impact: If cloudflared loads operator credentials from ~/.cloudflared/credentials.json, tunnel could access unauthorized resources. Isolation relies on HOME replacement only.
  • Recommended action: Add integration test that places dummy Cloudflare credentials in a simulated operator home, runs startQuickTunnel with isolated home, and verifies the tunnel process cannot access those credentials. Verify cloudflared runs with --config= and --no-autoupdate flags.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/performance/tool-disclosure-quick-tunnel.test.ts; confirm integration test with real cloudflared binary and credential isolation verification
  • Missing regression test: Integration test: create fake ~/.cloudflared/credentials.json with dummy token, run startQuickTunnel with isolated HOME, verify tunnel starts but credentials not used (e.g., by checking cloudflared log for credential load attempts)
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/performance/tool-disclosure-quick-tunnel.test.ts; confirm integration test with real cloudflared binary and credential isolation verification.
  • Evidence: quick-tunnel.ts:157-165 buildQuickTunnelEnvironment replaces HOME/XDG_CONFIG_HOME; test only verifies environment object construction, not actual cloudflared behavior

PRA-12 Resolve/justify — MCP bearer token entropy and leakage not fully verified

  • Location: scripts/performance/tool-disclosure/mcp-server.ts:34
  • Category: security
  • Problem: Token is 64 hex chars (256 bits) but no test explicitly asserts entropy. Test verifies token not in JSON events but not in all possible serialization paths.
  • Impact: Token could have lower entropy if randomBytes fails, or leak via logging/serialization paths not covered by test.
  • Recommended action: Add test for token entropy (64 hex chars = 256 bits) and verify token does not appear in JSON-serialized events, artifacts, or any logging path.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/performance/tool-disclosure-mcp-server.test.ts; check for explicit entropy assertion and comprehensive leakage test
  • Missing regression test: Add test generating token, serializing server events/artifacts, and asserting token absent from all JSON output
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/performance/tool-disclosure-mcp-server.test.ts; check for explicit entropy assertion and comprehensive leakage test.
  • Evidence: mcp-server.ts:34 validates token length ≤4096 but not exact 64 hex chars; test verifies token not in JSON events but not entropy or all serialization paths

PRA-13 Resolve/justify — No test for oversized query rejection

  • Location: test/performance/tool-disclosure-compositional-router.test.ts:1
  • Category: tests
  • Problem: Missing regression test for PRA-5 blocker. No test verifies oversized query (>4096 chars) returns 'invalid-query' fallback without calling decomposer.
  • Impact: Security fix cannot be verified without test. Regression risk if validation is accidentally removed.
  • Recommended action: Add test for oversized query rejection (>4096 chars) before decomposer invocation; verify RoutingFallbackReason 'invalid-query' is returned and decomposer is not called.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search test/performance/tool-disclosure-compositional-router.test.ts for 'oversized' or 'invalid-query' or query length test
  • Missing regression test: This IS the missing regression test — add it in tool-disclosure-compositional-router.test.ts
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search test/performance/tool-disclosure-compositional-router.test.ts for 'oversized' or 'invalid-query' or query length test.
  • Evidence: test/performance/tool-disclosure-compositional-router.test.ts has 12 test blocks covering malformed, unavailable, empty, paired routes — no oversized query test

PRA-14 Resolve/justify — Recorder security tests have gaps in SSRF, header filtering, auth rotation coverage

  • Location: test/performance/tool-disclosure-recorder.test.ts:1
  • Category: tests
  • Problem: Missing tests for: redirect rejection (follow redirects=false), DNS rebinding (TOCTOU on DNS), all HOP_BY_HOP_HEADERS stripped on request/response, auth token rotation on retry, no request/response bodies in recorded events.
  • Impact: SSRF via redirects or DNS rebinding possible if not tested. Header leakage or auth token reuse not verified.
  • Recommended action: Add tests for: redirect rejection, DNS rebinding TOCTOU, all HOP_BY_HOP_HEADERS stripped both directions, auth token rotation on retry, verify no request/response bodies in events.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/performance/tool-disclosure-recorder.test.ts; check for each security test case
  • Missing regression test: Add missing test cases from security checklist: redirect rejection, DNS rebinding, HOP_BY_HOP stripping, auth rotation, body exclusion
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/performance/tool-disclosure-recorder.test.ts; check for each security test case.
  • Evidence: recorder.ts has HOP_BY_HOP_HEADERS set, follow redirects disabled, timingSafeEqual for auth — but tests don't cover all paths

PRA-15 Resolve/justify — Validation tests incomplete for nested secret/URL/path detection

  • Location: test/performance/tool-disclosure-validation.test.ts:1
  • Category: tests
  • Problem: validatePublicManifestValue recurses into objects/arrays but tests only cover top-level fields. Nested secret-like names/values at depth ≥2 not tested.
  • Impact: Secret-like field at environment.nested.api_key or similar could bypass detection.
  • Recommended action: Add test cases for nested secret-like field names/values in nested objects and arrays. Verify detection works at any depth.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/performance/tool-disclosure-validation.test.ts; search for 'nested' or deep object test cases
  • Missing regression test: Add test with manifest containing secret-like field at depth 2+ (e.g., environment.nested.api_key) and verify rejection
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/performance/tool-disclosure-validation.test.ts; search for 'nested' or deep object test cases.
  • Evidence: validation.ts:59-78 validatePublicManifestValue recurses into objects/arrays; test file only tests top-level fields

PRA-16 Resolve/justify — PR #6340 overlaps on Dockerfile, dcode-launcher.sh, start.sh

  • Location: agents/langchain-deepagents-code/Dockerfile:1
  • Category: workflow
  • Problem: PR feat(dcode): add backend-neutral OTLP observability #6340 (feat(dcode): add backend-neutral OTLP observability) modifies the same files. Must coordinate to ensure combined changes pass all proxy launcher tests after merge.
  • Impact: Merge conflicts or behavioral regressions in proxy launcher if both PRs merge without coordination.
  • Recommended action: Coordinate with PR feat(dcode): add backend-neutral OTLP observability #6340 author. Compare diffs for Dockerfile, dcode-launcher.sh, start.sh. Ensure combined changes pass all proxy launcher tests after merge.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Compare this PR's Dockerfile/dcode-launcher.sh/start.sh diffs with PR feat(dcode): add backend-neutral OTLP observability #6340 diffs; identify conflicts
  • Missing regression test: Run test/langchain-deepagents-code-proxy-launcher.test.ts after both PRs merged
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Compare this PR's Dockerfile/dcode-launcher.sh/start.sh diffs with PR feat(dcode): add backend-neutral OTLP observability #6340 diffs; identify conflicts.
  • Evidence: Both PRs modify Dockerfile (lines 55-73), dcode-launcher.sh (lines 59-65), start.sh (lines 81-87) — same root-owned file validation logic

PRA-17 Resolve/justify — tool-disclosure-performance-smoke job not validated in workflow-boundary.mts

  • Location: .github/workflows/e2e.yaml:738
  • Category: workflow
  • Problem: New explicit-only job added but validateToolDisclosurePerformanceSmokeJob function not in tools/e2e/workflow-boundary.mts. generate-matrix step must output correct explicit_only_jobs_csv including this job.
  • Impact: Workflow boundary validation will not catch drift in the new job; selector validation may fail.
  • Recommended action: Add validateToolDisclosurePerformanceSmokeJob function in tools/e2e/workflow-boundary.mts and register it in validateFreeStandingWorkflowInventory. Ensure generate-matrix step outputs correct explicit_only_jobs_csv.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read tools/e2e/workflow-boundary.mts; search for validateToolDisclosurePerformanceSmokeJob or tool-disclosure-performance-smoke
  • Missing regression test: test/e2e/support/tool-disclosure-performance-smoke-workflow-boundary.test.ts should pass and validateFreeStandingWorkflowInventory should include the new job
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read tools/e2e/workflow-boundary.mts; search for validateToolDisclosurePerformanceSmokeJob or tool-disclosure-performance-smoke.
  • Evidence: e2e.yaml adds tool-disclosure-performance-smoke job; workflow-boundary.mts has validators for other explicit-only jobs but not this one

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

PRA-18 Improvement — CLI command 'performance:tool-disclosure' has 4 subcommands in ~760 lines — split into modules

  • Location: scripts/performance/tool-disclosure/run.ts:1
  • Category: correctness
  • Problem: run.ts contains prepare, execute, summarize, route-acceptance subcommands in one file. Splitting improves maintainability.
  • Impact: Large single file harder to navigate and test. Each subcommand is independent.
  • Suggested action: Split run.ts into prepare.ts, execute.ts, summarize.ts, route-acceptance.ts with a thin CLI dispatcher in run.ts.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read run.ts; assess subcommand separation — each exports a Command class with distinct options
  • Missing regression test: N/A — refactor; existing tests cover each subcommand via integration tests
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: run.ts exports prepareCommand, executeCommand, summarizeCommand, routeAcceptanceCommand; each ~150-200 lines

PRA-19 Improvement — recorder.ts is 1018 lines — split into proxy-core, transform, evidence modules

  • Location: scripts/performance/tool-disclosure/recorder.ts:19
  • Category: correctness
  • Problem: recorder.ts combines HTTP proxy server, request/response handling, transform integration, and evidence recording. Splitting improves maintainability and testability.
  • Impact: Large file mixes concerns: server lifecycle, header filtering, body reading, transform invocation, event recording.
  • Suggested action: Split recorder.ts into proxy-core.ts (server start/stop, connection handling), transform.ts (requestTransform integration), evidence.ts (ToolDisclosureRecordingEvent, ToolMetrics, inspectTools).
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read recorder.ts; assess module boundaries — createServer, handleRequest, inspectTools, forwardRequest are distinct concerns
  • Missing regression test: N/A — refactor; existing recorder tests cover all paths
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: recorder.ts:19-1018 contains createToolDisclosureRecordingProxy, RecordingProxy class, inspectTools, forwardedRequestHeaders, forwardedResponseHeaders, fixedResponse, ToolMetrics, EphemeralToolSchemaSnapshot

PRA-20 Improvement — E2E_DEFAULT_ENABLED: '0' single-use config in tool-disclosure-performance-smoke job

  • Location: .github/workflows/e2e.yaml:738
  • Category: workflow
  • Problem: E2E_DEFAULT_ENABLED env var only set in this one job. Not referenced elsewhere. Consider removing or documenting why it exists.
  • Impact: Unused configuration variable adds noise; may indicate incomplete feature.
  • Suggested action: Evaluate if E2E_DEFAULT_ENABLED is needed or can be removed; grep across workflows and test code confirms single use.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: grep E2E_DEFAULT_ENABLED across workflows and test code
  • Missing regression test: N/A — workflow cleanup
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: e2e.yaml:738 E2E_DEFAULT_ENABLED: "0" only in tool-disclosure-performance-smoke job; not in other jobs or test fixtures

PRA-21 Improvement — AbortSignal propagation to decomposer/embedder not verified

  • Location: scripts/performance/tool-disclosure/compositional-tool-router.ts:448
  • Category: correctness
  • Problem: Options accept signal but tests don't verify abort propagation through prepareInitialRoutingStage and routeFromInitialStage.
  • Impact: Cancellation may not work correctly for long-running decompose/embed calls; resource leaks possible.
  • Suggested action: Add test verifying AbortSignal aborts in-flight decomposer/embedder calls and returns appropriate fallback.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Search compositional-tool-router tests for 'AbortSignal' or 'abort'
  • Missing regression test: Add test with AbortSignal that aborts during decompose/embed; verify clean abort and fallback evidence
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: compositional-tool-router.ts passes options.signal to decomposer.decompose and embedder.embed; tests use vi.fn mocks without AbortSignal

PRA-22 Improvement — Private bridge test-only topology not explicitly documented

  • Location: test/e2e/live/tool-disclosure-performance-smoke.test.ts:1
  • Category: correctness
  • Problem: Test uses OPENSHELL_DOCKER_NETWORK gateway IP for recorder listenHost — this is a test-only authenticated bridge topology that should be documented in code.
  • Impact: Future maintainers may not understand why private bridge is used instead of loopback, or that it's test-only.
  • Suggested action: Add code comment in test explaining the private bridge topology: why it's test-only, how it differs from full campaign local recorder, and that it's inside trusted runner boundary.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read test/e2e/live/tool-disclosure-performance-smoke.test.ts lines around OPENSHELL_DOCKER_NETWORK and recorderListenHost (around line 100-120)
  • Missing regression test: N/A — documentation
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: test uses networkInspect to get gateway IP, then uses as listenHost for recorder with paired auth; no comment explains this is smoke-only topology

PRA-23 Improvement — Documentation claims need cross-verification against implementation constants

  • Location: docs/inference/progressive-tool-disclosure-performance-test.mdx:1
  • Category: acceptance
  • Problem: Documented constants ('10,000 bootstrap samples', '512-tool primary size', '95% CI', '5 percentage points noninferiority') must match code constants in types.ts, schedule.ts, compositional-tool-router.ts.
  • Impact: Drift between docs and implementation could mislead users or cause failed claim gates.
  • Suggested action: Cross-verify all documented constants against implementation. Add automated check or document verification procedure in release process.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Compare constants in docs MDX with DEFAULT_BOOTSTRAP_SAMPLES=10000, STATIC_CATALOG_SIZES=[16,64,256,512,2209], DEFAULT_NONINFERIORITY_MARGIN_PP=5 in types.ts and schedule.ts
  • Missing regression test: Add doc-constant parity test or document manual verification in release process
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: MDX documents bootstrap samples=10000, primary catalog=512, CI=95%, noninferiority=5pp; types.ts has DEFAULT_BOOTSTRAP_SAMPLES=10000, DEFAULT_NONINFERIORITY_MARGIN_PP=5; schedule.ts has STATIC_CATALOG_SIZES

PRA-24 Improvement — DEFAULT_SYNTHETIC_PERFORMANCE_TEST_CATALOG_SEED used in only 3 locations — evaluate inlining

  • Location: scripts/performance/tool-disclosure/catalog.ts:8
  • Category: correctness
  • Problem: Constant used in catalog.ts, tasks.ts, and tool-disclosure-performance-smoke.test.ts. Only 3 call sites — consider inlining or justifying as shared default.
  • Impact: Minor: constant adds indirection without clear reuse benefit.
  • Suggested action: Evaluate constant usage; inline at 3 call sites or justify as shared default in catalog.ts.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: grep DEFAULT_SYNTHETIC_PERFORMANCE_TEST_CATALOG_SEED across codebase; count usages
  • Missing regression test: N/A — code quality improvement
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: catalog.ts:8 exports constant; used in tasks.ts:generatePrimaryTaskSet, catalog.ts:generateCatalogPrefix, test.ts:generateSyntheticCatalog
Simplification opportunities: 5 possible cuts, net -201 lines possible

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-18 shrink (scripts/performance/tool-disclosure/run.ts:1): run.ts monolithic 760-line file with 4 subcommands
    • Replacement: prepare.ts, execute.ts, summarize.ts, route-acceptance.ts + thin CLI dispatcher in run.ts
    • Net: -100 lines
    • Safety boundary: CLI command surface unchanged; subcommand behavior preserved
  • PRA-19 shrink (scripts/performance/tool-disclosure/recorder.ts:19): recorder.ts 1018-line monolith
    • Replacement: proxy-core.ts (~400 lines), transform.ts (~200 lines), evidence.ts (~200 lines), recorder.ts (~200 lines facade)
    • Net: -100 lines
    • Safety boundary: Public API createToolDisclosureRecordingProxy unchanged; RecordingProxy internal class not exported
  • PRA-20 delete (.github/workflows/e2e.yaml:738): E2E_DEFAULT_ENABLED: "0" from tool-disclosure-performance-smoke job env
    • Replacement: Remove line entirely
    • Net: -1 lines
    • Safety boundary: No other code references this env var; test does not use it
  • PRA-22 native (test/e2e/live/tool-disclosure-performance-smoke.test.ts:1): Implicit topology assumption
    • Replacement: Explicit code comment documenting test-only private bridge topology
    • Net: 5 lines
    • Safety boundary: No behavior change; documentation only
  • PRA-24 shrink (scripts/performance/tool-disclosure/catalog.ts:8): DEFAULT_SYNTHETIC_PERFORMANCE_TEST_CATALOG_SEED exported constant
    • Replacement: Inline seed value at 3 call sites or keep as private constant in catalog.ts
    • Net: -5 lines
    • Safety boundary: Deterministic catalog generation unchanged; seed value identical
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — Oversized query rejection in compositional router (>4096 chars returns invalid-query fallback, decomposer not called). Runtime/sandbox/infrastructure paths need behavioral runtime validation: workflows, Dockerfile, launcher scripts, managed runtime, policy additions, start.sh. Performance test package has comprehensive unit/integration tests but security test gaps exist for SSRF, credential isolation, input limits.
  • PRA-T2 Runtime validation — Recorder maxRequestBodyBytes enforcement (64MB default or configured limit returns request-body-too-large). Runtime/sandbox/infrastructure paths need behavioral runtime validation: workflows, Dockerfile, launcher scripts, managed runtime, policy additions, start.sh. Performance test package has comprehensive unit/integration tests but security test gaps exist for SSRF, credential isolation, input limits.
  • PRA-T3 Runtime validation — Quick-tunnel Cloudflare credential isolation integration test (real cloudflared, dummy credentials in operator home, verify isolation). Runtime/sandbox/infrastructure paths need behavioral runtime validation: workflows, Dockerfile, launcher scripts, managed runtime, policy additions, start.sh. Performance test package has comprehensive unit/integration tests but security test gaps exist for SSRF, credential isolation, input limits.
  • PRA-T4 Runtime validation — Nested secret/URL/path detection in validation at object/array depth >= 2. Runtime/sandbox/infrastructure paths need behavioral runtime validation: workflows, Dockerfile, launcher scripts, managed runtime, policy additions, start.sh. Performance test package has comprehensive unit/integration tests but security test gaps exist for SSRF, credential isolation, input limits.
  • PRA-T5 Runtime validation — AbortSignal propagation through decomposer/embedder calls in compositional router. Runtime/sandbox/infrastructure paths need behavioral runtime validation: workflows, Dockerfile, launcher scripts, managed runtime, policy additions, start.sh. Performance test package has comprehensive unit/integration tests but security test gaps exist for SSRF, credential isolation, input limits.
  • PRA-T6 No test for oversized query rejection — Add test for oversized query rejection (>4096 chars) before decomposer invocation; verify RoutingFallbackReason 'invalid-query' is returned and decomposer is not called.
  • PRA-T7 Recorder security tests have gaps in SSRF, header filtering, auth rotation coverage — Add tests for: redirect rejection, DNS rebinding TOCTOU, all HOP_BY_HOP_HEADERS stripped both directions, auth token rotation on retry, verify no request/response bodies in events.
  • PRA-T8 Validation tests incomplete for nested secret/URL/path detection — Add test cases for nested secret-like field names/values in nested objects and arrays. Verify detection works at any depth.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: scripts/performance/tool-disclosure/compositional-tool-router.ts — fail-open passthrough behavior

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: tool-disclosure-compositional-router.test.ts: malformed decomposition, unavailable embedder, refinement disagreement cases all return passthrough with correct fallback reason
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: compositional-tool-router.ts:534, 537, 603 return finish('passthrough', fallback) on any RoutingFailure; no source-of-truth comment

PRA-2 Resolve/justify — Source-of-truth review needed: scripts/performance/tool-disclosure/execute.ts — attempt-journal JSONL recovery

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: recoverAttemptJournal handles corrupt final line gracefully; valid lines preserved
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: execute.ts:77-103 recoverAttemptJournal handles truncated final line; no source-of-truth comment

PRA-3 Resolve/justify — Source-of-truth review needed: scripts/performance/tool-disclosure/artifacts.ts — readJsonLines tolerant parsing

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: readJsonLines throws on malformed lines with line number; truncated final line handled
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: artifacts.ts:72-82 readJsonLines catches parse error only for final truncated line; no source-of-truth comment

PRA-4 Resolve/justify — Source-of-truth review needed: scripts/performance/tool-disclosure/validation.ts — validateFrozenManifest strict enforcement

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: tool-disclosure-validation.test.ts: missing model revision, mutable image digest, secret-like fields, URL values, private vLLM flags all rejected
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: validation.ts:105 validateFrozenManifest starts; no source-of-truth comment

PRA-5 Required — Compositional router accepts unbounded query strings to external TaskDecomposer

  • Location: scripts/performance/tool-disclosure/compositional-tool-router.ts:448
  • Category: security
  • Problem: prepareInitialRoutingStage validates query is non-empty string but has no length constraint before calling decomposer.decompose(). An oversized query (MB+) could cause excessive token usage, cost overruns, latency spikes, or DoS on external model endpoints. COMPOSITIONAL_ROUTER_MAX_SUBTASK_CHARS=512 limits subtask output but not input query length.
  • Impact: Malicious or buggy caller could send arbitrarily large queries to external decomposer models, causing uncontrolled costs and denial of service. No defense-in-depth at the router boundary.
  • Required action: Add input query length validation (e.g., max 4096 chars) in prepareInitialRoutingStage before calling decomposer.decompose(). Document that TaskDecomposer implementations must handle untrusted input. Add security test for oversized query rejection.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read compositional-tool-router.ts prepareInitialRoutingStage function; confirm query length check exists before calling decomposer.decompose()
  • Missing regression test: Add test in test/performance/tool-disclosure-compositional-router.test.ts for oversized query rejection (>4096 chars) before decomposer invocation; verify RoutingFallbackReason 'invalid-query' is returned and decomposer is not called
  • Done when: The required change is committed and verification passes: Read compositional-tool-router.ts prepareInitialRoutingStage function; confirm query length check exists before calling decomposer.decompose().
  • Evidence: compositional-tool-router.ts:448 validates query is non-empty string but has no length constraint; routeCompositionalTools calls prepareInitialRoutingStage without prior length check

PRA-6 Resolve/justify — Fail-open behavior lacks source-of-truth documentation

  • Location: scripts/performance/tool-disclosure/compositional-tool-router.ts:1
  • Category: architecture
  • Problem: The router returns 'passthrough' disposition on any malformed decomposition, unavailable retrieval, or model error — preserving the complete original tool catalog. No code comment documents the five source-of-truth fields for this localized workaround.
  • Impact: Future maintainers cannot verify why fail-open is acceptable, what invalid state it handles, where that state originates, why the source (upstream model reliability) cannot be fixed here, what regression test guards it, or when it can be removed.
  • Recommended action: Add code comment near RoutingFailure catch block in prepareInitialRoutingStage and routeFromInitialStage documenting: (1) invalid state = malformed/unavailable model output, (2) source boundary = external TaskDecomposer/TextEmbedder implementations, (3) why not source fix = upstream models inherently unreliable, (4) regression test = tool-disclosure-compositional-router.test.ts malformed/unavailable/disagreement cases, (5) removal = when router can guarantee valid output via constrained decoding.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search compositional-tool-router.ts for 'invalid state' or 'source boundary' comment near RoutingFailure/fallback handling
  • Missing regression test: Existing tests in tool-disclosure-compositional-router.test.ts cover passthrough behavior (malformed, unavailable, disagreement cases). Ensure these remain passing and document them as the regression gate.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search compositional-tool-router.ts for 'invalid state' or 'source boundary' comment near RoutingFailure/fallback handling.
  • Evidence: compositional-tool-router.ts:534, 537, 603 return finish('passthrough', fallback) on any error; no source-of-truth comment present

PRA-7 Resolve/justify — Attempt-journal recovery logic lacks source-of-truth documentation

  • Location: scripts/performance/tool-disclosure/execute.ts:77
  • Category: architecture
  • Problem: recoverAttemptJournal uses JSONL append with best-effort truncation handling for incomplete final lines. No code comment documents the five source-of-truth fields for this recovery behavior.
  • Impact: Invalid state (truncated line at crash boundary) handled locally; source (appendJsonLine without atomic write-rename) cannot be fixed due to append-only evidence stream requirement; removal condition unclear.
  • Recommended action: Add code comment at recoverAttemptJournal documenting: (1) invalid state = truncated/incomplete JSONL line at process crash boundary, (2) created by appendJsonLine without atomic write-rename per run, (3) source fix = atomic write-rename per entry not feasible due to append-only evidence stream, (4) regression test = recoverAttemptJournal handles corrupt final line, (5) removal when append-only stream replaced with transactional log.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read execute.ts recoverAttemptJournal function; look for source-of-truth comment
  • Missing regression test: Existing test coverage for journal recovery in tool-disclosure-execute.test.ts should be verified against the five fields
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read execute.ts recoverAttemptJournal function; look for source-of-truth comment.
  • Evidence: execute.ts:77-103 recoverAttemptJournal handles truncated final line but throws on other corruption; no source-of-truth comment

PRA-8 Resolve/justify — readJsonLines error handling lacks source-of-truth documentation

  • Location: scripts/performance/tool-disclosure/artifacts.ts:72
  • Category: architecture
  • Problem: readJsonLines throws on any parse error except a specific truncated-final-line case. No code comment documents the five source-of-truth fields. Error message lacks truncated line content and line number.
  • Impact: Malformed JSONL lines (not final) throw with generic 'invalid JSONL at line N' message; no context for debugging. Source-of-truth gap for why this tolerant parsing exists.
  • Recommended action: Add code comment at readJsonLines documenting the five fields. Improve error message to include truncated line content (first 200 chars) and line number.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read artifacts.ts readJsonLines function; look for source-of-truth comment and error message enhancement
  • Missing regression test: Add test for malformed JSONL line (not final) throwing with line number; test truncated final line handled gracefully
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read artifacts.ts readJsonLines function; look for source-of-truth comment and error message enhancement.
  • Evidence: artifacts.ts:72-82 readJsonLines catches parse error only for final truncated line; error message lacks line content

PRA-9 Resolve/justify — Manifest validation fallback lacks source-of-truth documentation

  • Location: scripts/performance/tool-disclosure/validation.ts:105
  • Category: architecture
  • Problem: validateFrozenManifest enforces strict protocol conformance but no comment documents the five fields for why this validation exists as a localized check rather than making invalid manifests impossible at source.
  • Impact: Human-authored manifest.json from manifest.template.json can have typos/omissions; validation catches them but doesn't prevent them at source. No documentation of why source fix (automated manifest generation) isn't feasible.
  • Recommended action: Add code comment at validateFrozenManifest documenting: (1) invalid state = manifest missing claim-grade metadata or violating frozen constants, (2) source boundary = human-authored manifest.json, (3) why not source fix = manifest is human-completed from template, (4) regression test = tool-disclosure-validation.test.ts rejection cases, (5) removal when manifest generation is automated and verified by CI.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search validation.ts for 'invalid state' or 'source boundary' comment near validateFrozenManifest/validateCompleteEvidence
  • Missing regression test: Existing validation tests in tool-disclosure-validation.test.ts cover rejection cases; verify they serve as regression gate
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search validation.ts for 'invalid state' or 'source boundary' comment near validateFrozenManifest/validateCompleteEvidence.
  • Evidence: validation.ts:105 validateFrozenManifest starts; no source-of-truth comment

PRA-10 Resolve/justify — DEFAULT_MAX_REQUEST_BODY_BYTES = 64MB is high for test-scoped recording proxy

  • Location: scripts/performance/tool-disclosure/recorder.ts:19
  • Category: security
  • Problem: Default 64MB request body limit could allow large bodies to consume memory before rejection. No test covers the default limit enforcement.
  • Impact: Memory exhaustion risk if proxy receives large request bodies. No test verifies limit enforcement.
  • Recommended action: Reduce DEFAULT_MAX_REQUEST_BODY_BYTES to a more conservative value (e.g., 10MB) appropriate for performance test requests, or add documentation justifying 64MB. Ensure tests cover the default limit enforcement.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read recorder.ts line 19 and 491; check test/performance/tool-disclosure-recorder.test.ts for maxRequestBodyBytes test coverage
  • Missing regression test: Add test in tool-disclosure-recorder.test.ts sending request body >64MB (or configured limit) and verify rejection with error_reason 'request-body-too-large'
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read recorder.ts line 19 and 491; check test/performance/tool-disclosure-recorder.test.ts for maxRequestBodyBytes test coverage.
  • Evidence: recorder.ts:19 const DEFAULT_MAX_REQUEST_BODY_BYTES = 64 * 1024 * 1024; line 491 uses options.maxRequestBodyBytes ?? DEFAULT_MAX_REQUEST_BODY_BYTES; no test for limit enforcement

PRA-11 Resolve/justify — Quick-tunnel Cloudflare credential isolation not verified by integration test

  • Location: scripts/performance/tool-disclosure/quick-tunnel.ts:1
  • Category: security
  • Problem: Unit test only checks environment construction (HOME/XDG_CONFIG_HOME replacement) but doesn't test that a real cloudflared process cannot load operator credentials from ambient configuration.
  • Impact: If cloudflared loads operator credentials from ~/.cloudflared/credentials.json, tunnel could access unauthorized resources. Isolation relies on HOME replacement only.
  • Recommended action: Add integration test that places dummy Cloudflare credentials in a simulated operator home, runs startQuickTunnel with isolated home, and verifies the tunnel process cannot access those credentials. Verify cloudflared runs with --config= and --no-autoupdate flags.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/performance/tool-disclosure-quick-tunnel.test.ts; confirm integration test with real cloudflared binary and credential isolation verification
  • Missing regression test: Integration test: create fake ~/.cloudflared/credentials.json with dummy token, run startQuickTunnel with isolated HOME, verify tunnel starts but credentials not used (e.g., by checking cloudflared log for credential load attempts)
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/performance/tool-disclosure-quick-tunnel.test.ts; confirm integration test with real cloudflared binary and credential isolation verification.
  • Evidence: quick-tunnel.ts:157-165 buildQuickTunnelEnvironment replaces HOME/XDG_CONFIG_HOME; test only verifies environment object construction, not actual cloudflared behavior

PRA-12 Resolve/justify — MCP bearer token entropy and leakage not fully verified

  • Location: scripts/performance/tool-disclosure/mcp-server.ts:34
  • Category: security
  • Problem: Token is 64 hex chars (256 bits) but no test explicitly asserts entropy. Test verifies token not in JSON events but not in all possible serialization paths.
  • Impact: Token could have lower entropy if randomBytes fails, or leak via logging/serialization paths not covered by test.
  • Recommended action: Add test for token entropy (64 hex chars = 256 bits) and verify token does not appear in JSON-serialized events, artifacts, or any logging path.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/performance/tool-disclosure-mcp-server.test.ts; check for explicit entropy assertion and comprehensive leakage test
  • Missing regression test: Add test generating token, serializing server events/artifacts, and asserting token absent from all JSON output
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/performance/tool-disclosure-mcp-server.test.ts; check for explicit entropy assertion and comprehensive leakage test.
  • Evidence: mcp-server.ts:34 validates token length ≤4096 but not exact 64 hex chars; test verifies token not in JSON events but not entropy or all serialization paths

PRA-13 Resolve/justify — No test for oversized query rejection

  • Location: test/performance/tool-disclosure-compositional-router.test.ts:1
  • Category: tests
  • Problem: Missing regression test for PRA-5 blocker. No test verifies oversized query (>4096 chars) returns 'invalid-query' fallback without calling decomposer.
  • Impact: Security fix cannot be verified without test. Regression risk if validation is accidentally removed.
  • Recommended action: Add test for oversized query rejection (>4096 chars) before decomposer invocation; verify RoutingFallbackReason 'invalid-query' is returned and decomposer is not called.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search test/performance/tool-disclosure-compositional-router.test.ts for 'oversized' or 'invalid-query' or query length test
  • Missing regression test: This IS the missing regression test — add it in tool-disclosure-compositional-router.test.ts
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search test/performance/tool-disclosure-compositional-router.test.ts for 'oversized' or 'invalid-query' or query length test.
  • Evidence: test/performance/tool-disclosure-compositional-router.test.ts has 12 test blocks covering malformed, unavailable, empty, paired routes — no oversized query test

PRA-14 Resolve/justify — Recorder security tests have gaps in SSRF, header filtering, auth rotation coverage

  • Location: test/performance/tool-disclosure-recorder.test.ts:1
  • Category: tests
  • Problem: Missing tests for: redirect rejection (follow redirects=false), DNS rebinding (TOCTOU on DNS), all HOP_BY_HOP_HEADERS stripped on request/response, auth token rotation on retry, no request/response bodies in recorded events.
  • Impact: SSRF via redirects or DNS rebinding possible if not tested. Header leakage or auth token reuse not verified.
  • Recommended action: Add tests for: redirect rejection, DNS rebinding TOCTOU, all HOP_BY_HOP_HEADERS stripped both directions, auth token rotation on retry, verify no request/response bodies in events.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/performance/tool-disclosure-recorder.test.ts; check for each security test case
  • Missing regression test: Add missing test cases from security checklist: redirect rejection, DNS rebinding, HOP_BY_HOP stripping, auth rotation, body exclusion
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/performance/tool-disclosure-recorder.test.ts; check for each security test case.
  • Evidence: recorder.ts has HOP_BY_HOP_HEADERS set, follow redirects disabled, timingSafeEqual for auth — but tests don't cover all paths

PRA-15 Resolve/justify — Validation tests incomplete for nested secret/URL/path detection

  • Location: test/performance/tool-disclosure-validation.test.ts:1
  • Category: tests
  • Problem: validatePublicManifestValue recurses into objects/arrays but tests only cover top-level fields. Nested secret-like names/values at depth ≥2 not tested.
  • Impact: Secret-like field at environment.nested.api_key or similar could bypass detection.
  • Recommended action: Add test cases for nested secret-like field names/values in nested objects and arrays. Verify detection works at any depth.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read test/performance/tool-disclosure-validation.test.ts; search for 'nested' or deep object test cases
  • Missing regression test: Add test with manifest containing secret-like field at depth 2+ (e.g., environment.nested.api_key) and verify rejection
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read test/performance/tool-disclosure-validation.test.ts; search for 'nested' or deep object test cases.
  • Evidence: validation.ts:59-78 validatePublicManifestValue recurses into objects/arrays; test file only tests top-level fields

PRA-16 Resolve/justify — PR #6340 overlaps on Dockerfile, dcode-launcher.sh, start.sh

  • Location: agents/langchain-deepagents-code/Dockerfile:1
  • Category: workflow
  • Problem: PR feat(dcode): add backend-neutral OTLP observability #6340 (feat(dcode): add backend-neutral OTLP observability) modifies the same files. Must coordinate to ensure combined changes pass all proxy launcher tests after merge.
  • Impact: Merge conflicts or behavioral regressions in proxy launcher if both PRs merge without coordination.
  • Recommended action: Coordinate with PR feat(dcode): add backend-neutral OTLP observability #6340 author. Compare diffs for Dockerfile, dcode-launcher.sh, start.sh. Ensure combined changes pass all proxy launcher tests after merge.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Compare this PR's Dockerfile/dcode-launcher.sh/start.sh diffs with PR feat(dcode): add backend-neutral OTLP observability #6340 diffs; identify conflicts
  • Missing regression test: Run test/langchain-deepagents-code-proxy-launcher.test.ts after both PRs merged
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Compare this PR's Dockerfile/dcode-launcher.sh/start.sh diffs with PR feat(dcode): add backend-neutral OTLP observability #6340 diffs; identify conflicts.
  • Evidence: Both PRs modify Dockerfile (lines 55-73), dcode-launcher.sh (lines 59-65), start.sh (lines 81-87) — same root-owned file validation logic

PRA-17 Resolve/justify — tool-disclosure-performance-smoke job not validated in workflow-boundary.mts

  • Location: .github/workflows/e2e.yaml:738
  • Category: workflow
  • Problem: New explicit-only job added but validateToolDisclosurePerformanceSmokeJob function not in tools/e2e/workflow-boundary.mts. generate-matrix step must output correct explicit_only_jobs_csv including this job.
  • Impact: Workflow boundary validation will not catch drift in the new job; selector validation may fail.
  • Recommended action: Add validateToolDisclosurePerformanceSmokeJob function in tools/e2e/workflow-boundary.mts and register it in validateFreeStandingWorkflowInventory. Ensure generate-matrix step outputs correct explicit_only_jobs_csv.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read tools/e2e/workflow-boundary.mts; search for validateToolDisclosurePerformanceSmokeJob or tool-disclosure-performance-smoke
  • Missing regression test: test/e2e/support/tool-disclosure-performance-smoke-workflow-boundary.test.ts should pass and validateFreeStandingWorkflowInventory should include the new job
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read tools/e2e/workflow-boundary.mts; search for validateToolDisclosurePerformanceSmokeJob or tool-disclosure-performance-smoke.
  • Evidence: e2e.yaml adds tool-disclosure-performance-smoke job; workflow-boundary.mts has validators for other explicit-only jobs but not this one

PRA-18 Improvement — CLI command 'performance:tool-disclosure' has 4 subcommands in ~760 lines — split into modules

  • Location: scripts/performance/tool-disclosure/run.ts:1
  • Category: correctness
  • Problem: run.ts contains prepare, execute, summarize, route-acceptance subcommands in one file. Splitting improves maintainability.
  • Impact: Large single file harder to navigate and test. Each subcommand is independent.
  • Suggested action: Split run.ts into prepare.ts, execute.ts, summarize.ts, route-acceptance.ts with a thin CLI dispatcher in run.ts.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read run.ts; assess subcommand separation — each exports a Command class with distinct options
  • Missing regression test: N/A — refactor; existing tests cover each subcommand via integration tests
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: run.ts exports prepareCommand, executeCommand, summarizeCommand, routeAcceptanceCommand; each ~150-200 lines

PRA-19 Improvement — recorder.ts is 1018 lines — split into proxy-core, transform, evidence modules

  • Location: scripts/performance/tool-disclosure/recorder.ts:19
  • Category: correctness
  • Problem: recorder.ts combines HTTP proxy server, request/response handling, transform integration, and evidence recording. Splitting improves maintainability and testability.
  • Impact: Large file mixes concerns: server lifecycle, header filtering, body reading, transform invocation, event recording.
  • Suggested action: Split recorder.ts into proxy-core.ts (server start/stop, connection handling), transform.ts (requestTransform integration), evidence.ts (ToolDisclosureRecordingEvent, ToolMetrics, inspectTools).
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read recorder.ts; assess module boundaries — createServer, handleRequest, inspectTools, forwardRequest are distinct concerns
  • Missing regression test: N/A — refactor; existing recorder tests cover all paths
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: recorder.ts:19-1018 contains createToolDisclosureRecordingProxy, RecordingProxy class, inspectTools, forwardedRequestHeaders, forwardedResponseHeaders, fixedResponse, ToolMetrics, EphemeralToolSchemaSnapshot

PRA-20 Improvement — E2E_DEFAULT_ENABLED: '0' single-use config in tool-disclosure-performance-smoke job

  • Location: .github/workflows/e2e.yaml:738
  • Category: workflow
  • Problem: E2E_DEFAULT_ENABLED env var only set in this one job. Not referenced elsewhere. Consider removing or documenting why it exists.
  • Impact: Unused configuration variable adds noise; may indicate incomplete feature.
  • Suggested action: Evaluate if E2E_DEFAULT_ENABLED is needed or can be removed; grep across workflows and test code confirms single use.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: grep E2E_DEFAULT_ENABLED across workflows and test code
  • Missing regression test: N/A — workflow cleanup
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: e2e.yaml:738 E2E_DEFAULT_ENABLED: "0" only in tool-disclosure-performance-smoke job; not in other jobs or test fixtures

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@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: 6

🧹 Nitpick comments (5)
scripts/bench/tool-disclosure/catalog.ts (2)

242-249: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider readonly SyntheticTool[] for consistency with the immutability posture elsewhere.

SyntheticCatalog.tools is mutable while sibling contracts in types.ts consistently use readonly X[] for frozen evidence data. Given this catalog is meant to be a deterministic, frozen artifact, marking tools (and the SyntheticTool[] return types of generateSyntheticTools) as readonly would better signal and enforce immutability.

🤖 Prompt for 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.

In `@scripts/bench/tool-disclosure/catalog.ts` around lines 242 - 249,
SyntheticCatalog.tools is mutable while this catalog is intended to be a frozen
deterministic artifact. Update the SyntheticCatalog interface to use readonly
SyntheticTool[] for tools, and propagate the same readonly return type through
generateSyntheticTools so its output matches the immutability pattern used
elsewhere in types.ts and related contracts.

648-660: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Static-analysis regex flag is a false positive here, but worth a defensive note.

schema.pattern only ever originates from hardcoded literals in this file (resourceIdSchema, correlation_id), never from external input, so there's no current ReDoS exploit path. The patterns themselves are simple anchored character classes without nested quantifiers/backreferences.

That said, recompiling the RegExp on every validation call is wasted work given catalog sizes up to 2,209 tools, and validateAgainstSchema is a generic validator that could later be fed attacker-influenced patterns if reused elsewhere. Consider caching compiled patterns (e.g., a WeakMap/module-level cache keyed by pattern string) as a defensive/perf improvement.

🤖 Prompt for 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.

In `@scripts/bench/tool-disclosure/catalog.ts` around lines 648 - 660, The string
validation in validateAgainstSchema repeatedly recompiles schema.pattern with
new RegExp on every call, which is unnecessary work and could become risky if
reused with broader inputs later. Add a small compiled-regex cache in or near
validateAgainstSchema, keyed by the pattern string, and reuse the cached RegExp
when checking schema.pattern in the string branch. Keep the existing behavior
for minLength, maxLength, and enum unchanged.

Source: Linters/SAST tools

scripts/bench/tool-disclosure/statistics.ts (1)

237-282: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the frozen primary-task count 24 into a named constant.

The literal 24 appears in six places here (paired-task checks for success, schema, and latency gates plus their reason strings). It silently encodes the frozen 24-task primary corpus. A single named constant (e.g. PRIMARY_PAIRED_TASK_COUNT) improves clarity and prevents these gates from silently drifting apart if the count ever changes.

🤖 Prompt for 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.

In `@scripts/bench/tool-disclosure/statistics.ts` around lines 237 - 282, Extract
the hardcoded paired-task count used in the success, schema, and latency gate
checks into a shared named constant in statistics.ts, and replace every direct
24 comparison and matching reason-string reference in the gate logic with that
constant so the primary-task corpus size is defined in one place and the checks
stay consistent.
scripts/bench/tool-disclosure/execute.ts (1)

613-623: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Materialized evidence files aren't refreshed when a campaign aborts.

materializeAttemptJournal only runs after the full scheduled loop completes (Line 618); if a run exhausts its setup retries and throws (Line 613-614), execution jumps straight to finally without regenerating raw-events.jsonl/runs.jsonl for the runs already completed. The raw per-attempt data is safely persisted in attempt-journal.jsonl, so this isn't data loss, but it does make partial progress harder to inspect without re-running/resuming.

Consider calling materializeAttemptJournal(options.outputDir, journal) from the finally block so the summary artifacts always reflect the latest state.

🤖 Prompt for 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.

In `@scripts/bench/tool-disclosure/execute.ts` around lines 613 - 623,
materializeAttemptJournal is only invoked after the scheduled loop finishes, so
aborted campaigns skip refreshing the summary artifacts. Move or duplicate the
call into the execute() finally path so raw-events.jsonl and runs.jsonl are
regenerated even when a setup retry failure throws, while preserving the
existing cleanup of tunnels, servers, and proxy.
test/bench/tool-disclosure-execute.test.ts (1)

62-90: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider covering the non-trailing corruption path too.

Only the recoverable trailing-partial-write scenario is tested. Given recoverAttemptJournal also throws for corruption that isn't trailing (Line 59 in execute.ts), a companion case asserting that throw would round out coverage of this crash-recovery logic.

🤖 Prompt for 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.

In `@test/bench/tool-disclosure-execute.test.ts` around lines 62 - 90, The
crash-recovery tests only cover the trailing partial append case in
recoverAttemptJournal, so add a companion test for non-trailing corruption that
should fail. Use the existing recoverAttemptJournal and
materializeAttemptJournal test setup in tool-disclosure-execute.test.ts, but
write a malformed line in the middle of valid entries and assert the function
throws instead of recovering. Keep the new case adjacent to the current recovery
test so both the happy-path recovery and the non-trailing corruption behavior
are covered.
🤖 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 `@scripts/bench/tool-disclosure/assemble-run.ts`:
- Around line 79-105: The static-visibility handling in assembleRun is not
terminal for zero-token runs, which lets completed runs fall through into
gradeTaskRun and crash when options.task is absent. Update the
outcome/correctness branching in assembleRun so any static-visibility run with
initialSchemaTokens === 0 is handled before the grading branch and returns a
successful result without calling gradeTaskRun, using the existing
outcome/correctness paths and the related helpers failedCorrectness and
successfulStaticCorrectness to keep the flow consistent.

In `@scripts/bench/tool-disclosure/schedule.ts`:
- Around line 123-165: The schedule logic in buildToolDisclosureSchedule is
duplicating values that already have named constants, which risks drift if the
source constants change. Replace the hardcoded task-count checks and
catalog-size literals with the existing PRIMARY_TASK_COUNT, STRESS_TASK_COUNT,
and STATIC_CATALOG_SIZES values (or derived references) so the frozen schedule
stays aligned with the canonical definitions. Keep the behavior the same, but
ensure all size validation and pair construction in buildToolDisclosureSchedule
uses those shared symbols instead of repeated numeric literals.

In `@scripts/bench/tool-disclosure/subprocess.ts`:
- Around line 78-94: The SIGKILL fallback in the subprocess timeout flow leaves
hardStop active after the child finishes, so the later kill can target a reused
process-group id. Update the timeout handling around the child.once("close")
Promise in subprocess.ts to keep a reference to hardStop and clear it in the
same cleanup path as timer, so both timers are canceled once the child exits or
errors. Use the existing hardStop, timer, and child cleanup logic together to
prevent the delayed SIGKILL from firing after successful termination.

In `@test/bench/tool-disclosure-recorder.test.ts`:
- Around line 75-98: Update the test titles in tool-disclosure-recorder.test so
every describe/it string follows the required behavior-oriented format with a
trailing local issue reference suffix like "(`#1234`)". Adjust the title(s) in the
tool-disclosure recording proxy block to keep the same meaning while appending
the issue-ref suffix to each affected test name.

In `@test/bench/tool-disclosure-report.test.ts`:
- Around line 222-256: The two it(...) titles in the paired statistics test
block are missing the required local issue-ref suffix. Update the test names in
the pairedBootstrapDifference and buildComparisonCells cases to keep the same
behavior-oriented wording but append the trailing “(`#1234`)” to each title so
they match the test naming convention.

In `@test/bench/tool-disclosure-validation.test.ts`:
- Around line 241-262: Add the required local issue-reference suffix to the
affected test names in the tool-disclosure validation suite. Update the describe
block and the relevant it titles in tool-disclosure-validation.test.ts so they
end with the trailing issue marker format used by the test/ convention (for
example, the same `(`#1234`)` suffix), keeping the existing wording intact and
applying it consistently to all affected titles.

---

Nitpick comments:
In `@scripts/bench/tool-disclosure/catalog.ts`:
- Around line 242-249: SyntheticCatalog.tools is mutable while this catalog is
intended to be a frozen deterministic artifact. Update the SyntheticCatalog
interface to use readonly SyntheticTool[] for tools, and propagate the same
readonly return type through generateSyntheticTools so its output matches the
immutability pattern used elsewhere in types.ts and related contracts.
- Around line 648-660: The string validation in validateAgainstSchema repeatedly
recompiles schema.pattern with new RegExp on every call, which is unnecessary
work and could become risky if reused with broader inputs later. Add a small
compiled-regex cache in or near validateAgainstSchema, keyed by the pattern
string, and reuse the cached RegExp when checking schema.pattern in the string
branch. Keep the existing behavior for minLength, maxLength, and enum unchanged.

In `@scripts/bench/tool-disclosure/execute.ts`:
- Around line 613-623: materializeAttemptJournal is only invoked after the
scheduled loop finishes, so aborted campaigns skip refreshing the summary
artifacts. Move or duplicate the call into the execute() finally path so
raw-events.jsonl and runs.jsonl are regenerated even when a setup retry failure
throws, while preserving the existing cleanup of tunnels, servers, and proxy.

In `@scripts/bench/tool-disclosure/statistics.ts`:
- Around line 237-282: Extract the hardcoded paired-task count used in the
success, schema, and latency gate checks into a shared named constant in
statistics.ts, and replace every direct 24 comparison and matching reason-string
reference in the gate logic with that constant so the primary-task corpus size
is defined in one place and the checks stay consistent.

In `@test/bench/tool-disclosure-execute.test.ts`:
- Around line 62-90: The crash-recovery tests only cover the trailing partial
append case in recoverAttemptJournal, so add a companion test for non-trailing
corruption that should fail. Use the existing recoverAttemptJournal and
materializeAttemptJournal test setup in tool-disclosure-execute.test.ts, but
write a malformed line in the middle of valid entries and assert the function
throws instead of recovering. Keep the new case adjacent to the current recovery
test so both the happy-path recovery and the non-trailing corruption behavior
are covered.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: cd9aa198-ba06-4772-9bbd-4a2e7488cdfb

📥 Commits

Reviewing files that changed from the base of the PR and between 0682ebc and b22a972.

📒 Files selected for processing (34)
  • docs/index.yml
  • docs/inference/progressive-tool-disclosure-benchmark.mdx
  • package.json
  • scripts/bench/README.md
  • scripts/bench/tool-disclosure/artifacts.ts
  • scripts/bench/tool-disclosure/assemble-run.ts
  • scripts/bench/tool-disclosure/catalog.ts
  • scripts/bench/tool-disclosure/drivers.ts
  • scripts/bench/tool-disclosure/execute.ts
  • scripts/bench/tool-disclosure/grading.ts
  • scripts/bench/tool-disclosure/mcp-server.ts
  • scripts/bench/tool-disclosure/openclaw-fixture.ts
  • scripts/bench/tool-disclosure/quick-tunnel.ts
  • scripts/bench/tool-disclosure/recorder.ts
  • scripts/bench/tool-disclosure/report.ts
  • scripts/bench/tool-disclosure/run.ts
  • scripts/bench/tool-disclosure/schedule.ts
  • scripts/bench/tool-disclosure/statistics.ts
  • scripts/bench/tool-disclosure/subprocess.ts
  • scripts/bench/tool-disclosure/tasks.ts
  • scripts/bench/tool-disclosure/telemetry.ts
  • scripts/bench/tool-disclosure/types.ts
  • scripts/bench/tool-disclosure/validation.ts
  • test/bench/tool-disclosure-catalog.test.ts
  • test/bench/tool-disclosure-drivers.test.ts
  • test/bench/tool-disclosure-execute.test.ts
  • test/bench/tool-disclosure-fixture.test.ts
  • test/bench/tool-disclosure-mcp-server.test.ts
  • test/bench/tool-disclosure-quick-tunnel.test.ts
  • test/bench/tool-disclosure-recorder.test.ts
  • test/bench/tool-disclosure-report.test.ts
  • test/bench/tool-disclosure-schedule.test.ts
  • test/bench/tool-disclosure-telemetry.test.ts
  • test/bench/tool-disclosure-validation.test.ts

Comment thread scripts/bench/tool-disclosure/assemble-run.ts Outdated
Comment thread scripts/performance/tool-disclosure/schedule.ts
Comment thread scripts/bench/tool-disclosure/subprocess.ts Outdated
Comment on lines +75 to +98
describe("tool-disclosure recording proxy", () => {
it("fails closed for non-loopback listeners and credential-bearing upstream URLs", () => {
expect(() =>
createToolDisclosureRecordingProxy({
upstreamBaseUrl: "https://inference.example/v1",
listenHost: "0.0.0.0",
}),
).toThrow("must be exactly 127.0.0.1");
expect(() =>
createToolDisclosureRecordingProxy({
upstreamBaseUrl: "https://user:password@inference.example/v1",
}),
).toThrow("must not contain credentials");
expect(() =>
createToolDisclosureRecordingProxy({
upstreamBaseUrl: "https://inference.example/v1?api_key=private-key",
}),
).toThrow("must not contain a query or fragment");
expect(() =>
createToolDisclosureRecordingProxy({
upstreamBaseUrl: "http://inference.example/v1",
}),
).toThrow("plaintext upstreamBaseUrl is allowed only on loopback");
});

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Test titles are missing the required local issue-ref suffix.

The describe/it titles are behavior-oriented but omit the trailing (#1234) local issue ref (e.g. it("fails closed for non-loopback listeners ... (#1234)")). This applies to every it(...) title in this file.

As per coding guidelines: "Root-level integration tests under test/ should import source code, use ESM imports, and use behavior-oriented titles with local issue refs in a final (#1234) suffix."

🤖 Prompt for 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.

In `@test/bench/tool-disclosure-recorder.test.ts` around lines 75 - 98, Update the
test titles in tool-disclosure-recorder.test so every describe/it string follows
the required behavior-oriented format with a trailing local issue reference
suffix like "(`#1234`)". Adjust the title(s) in the tool-disclosure recording
proxy block to keep the same meaning while appending the issue-ref suffix to
each affected test name.

Source: Coding guidelines

Comment on lines +222 to +256
describe("tool-disclosure paired statistics", () => {
it("uses a deterministic 10,000-sample paired task bootstrap by default", () => {
const observations = [
{ direct: 10, progressive: 5 },
{ direct: 20, progressive: 16 },
{ direct: 30, progressive: 24 },
];
const first = pairedBootstrapDifference(observations, { seed: 123 });
const second = pairedBootstrapDifference(observations, { seed: 123 });

expect(first).toEqual(second);
expect(first.bootstrap_samples).toBe(DEFAULT_BOOTSTRAP_SAMPLES);
expect(first.paired_tasks).toBe(3);
expect(first.estimate).toBe(-5);
expect(first.lower_95).toBeLessThanOrEqual(first.estimate);
expect(first.upper_95).toBeGreaterThanOrEqual(first.estimate);
});

it("averages repetitions within a task before resampling task pairs", () => {
const runs = [
makeRun({ mode: "direct", taskId: "task-a", repetition: 1, success: true }),
makeRun({ mode: "direct", taskId: "task-a", repetition: 2, success: false }),
makeRun({ mode: "progressive", taskId: "task-a", repetition: 1, success: true }),
makeRun({ mode: "progressive", taskId: "task-a", repetition: 2, success: true }),
makeRun({ mode: "direct", taskId: "task-b", success: true }),
makeRun({ mode: "progressive", taskId: "task-b", success: true }),
];
const [cell] = buildComparisonCells(runs, { samples: 100, seed: 1 });

expect(cell.differences.success_percentage_points.paired_tasks).toBe(2);
expect(cell.differences.success_percentage_points.estimate).toBe(25);
expect(cell.direct.success_rate_percent).toBe(75);
expect(cell.progressive.success_rate_percent).toBe(100);
});
});

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- file: test/bench/tool-disclosure-report.test.ts ---\n'
cat -n test/bench/tool-disclosure-report.test.ts | sed -n '1,320p'

printf '\n--- suffix examples in test/**/*.test.* ---\n'
rg -n --glob 'test/**/*.test.{js,ts,mjs,mts,cjs,cts}' '\(#\d+\)$' test || true

printf '\n--- titles without suffix in test/**/*.test.* (sample matches) ---\n'
rg -n --glob 'test/**/*.test.{js,ts,mjs,mts,cjs,cts}' 'it\(|describe\(' test/bench test || true

Repository: NVIDIA/NemoClaw

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf -- '--- file: test/bench/tool-disclosure-report.test.ts ---\n'
cat -n test/bench/tool-disclosure-report.test.ts | sed -n '1,320p'

printf -- '\n--- suffix examples in test/**/*.test.* ---\n'
rg -n --glob 'test/**/*.test.{js,ts,mjs,mts,cjs,cts}' '\(#\d+\)$' test || true

printf -- '\n--- titles in test/**/*.test.* under test/bench ---\n'
rg -n 'it\(|describe\(' test/bench --glob '**/*.test.*' || true

Repository: NVIDIA/NemoClaw

Length of output: 27695


Add the local issue-ref suffix to these test titles. The it(...) names in this block follow the behavior-oriented style, but they still need the trailing (#1234) to match the test naming convention.

🤖 Prompt for 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.

In `@test/bench/tool-disclosure-report.test.ts` around lines 222 - 256, The two
it(...) titles in the paired statistics test block are missing the required
local issue-ref suffix. Update the test names in the pairedBootstrapDifference
and buildComparisonCells cases to keep the same behavior-oriented wording but
append the trailing “(`#1234`)” to each title so they match the test naming
convention.

Source: Coding guidelines

Comment on lines +241 to +262
describe("tool-disclosure complete-evidence validation", () => {
let fixture: CompleteEvidenceFixture;

beforeAll(() => {
fixture = buildCompleteEvidenceFixture();
});

it("rejects incomplete or mutable claim-grade manifest metadata", () => {
expect(() => validateFrozenManifest(fixture.manifest)).not.toThrow();

const missingModelRevision = structuredClone(fixture.manifest);
missingModelRevision.inference.model_revision = "";
expect(() => validateFrozenManifest(missingModelRevision)).toThrow(/claim-grade/u);

const mutableInferenceImage = structuredClone(fixture.manifest);
mutableInferenceImage.inference.container_digest = "fixture:latest";
expect(() => validateFrozenManifest(mutableInferenceImage)).toThrow(/claim-grade/u);
});

it("accepts the exact 1,884-run frozen matrix and rejects reordered or tampered evidence", {
timeout: 30_000,
}, () => {

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== file excerpt ==\n'
sed -n '220,290p' test/bench/tool-disclosure-validation.test.ts

printf '\n== issue-ref suffix occurrences in file ==\n'
rg -n '\(#\d+\)' test/bench/tool-disclosure-validation.test.ts || true

printf '\n== nearby test title patterns ==\n'
rg -n 'it\(".*#\d+\)|describe\(".*#\d+' test -g '*.test.ts' | head -n 50 || true

Repository: NVIDIA/NemoClaw

Length of output: 9050


Add the local issue-ref suffix to these test titles. test/bench/tool-disclosure-validation.test.ts:241-262 follows the root test/ convention, but the describe/it names are missing the required trailing (#1234) issue reference. Append the tracking issue if one exists.

🤖 Prompt for 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.

In `@test/bench/tool-disclosure-validation.test.ts` around lines 241 - 262, Add
the required local issue-reference suffix to the affected test names in the
tool-disclosure validation suite. Update the describe block and the relevant it
titles in tool-disclosure-validation.test.ts so they end with the trailing issue
marker format used by the test/ convention (for example, the same `(`#1234`)`
suffix), keeping the existing wording intact and applying it consistently to all
affected titles.

Source: Coding guidelines

ericksoa added 5 commits July 6, 2026 14:50
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
…benchmarks

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
…benchmarks

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ⚠️ Run cancelled — no signal

Run: 28880310567
Workflow ref: feat/tool-disclosure-benchmarks
Requested targets: (default — all supported)
Requested jobs: tool-disclosure-performance-smoke
Summary: 0 passed, 0 failed, 1 cancelled, 0 skipped

Job Result
tool-disclosure-performance-smoke ⚠️ cancelled

@wscurran wscurran added the v0.0.76 Release target label Jul 7, 2026
ericksoa added 2 commits July 7, 2026 09:17
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
…benchmarks

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ❌ Some jobs failed

Run: 28881548680
Workflow ref: feat/tool-disclosure-benchmarks
Requested targets: (default — all supported)
Requested jobs: tool-disclosure-performance-smoke
Summary: 0 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
tool-disclosure-performance-smoke ❌ failure

Failed jobs: tool-disclosure-performance-smoke. Check run artifacts for logs.

ericksoa added 3 commits July 7, 2026 09:49
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
…benchmarks

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>

# Conflicts:
#	test/e2e/support/upload-e2e-artifacts-workflow-boundary.test.ts
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All requested jobs passed

Run: 28883408796
Workflow ref: feat/tool-disclosure-benchmarks
Requested targets: (default — all supported)
Requested jobs: tool-disclosure-performance-smoke
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
tool-disclosure-performance-smoke ✅ success

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All requested jobs passed

Run: 28884388865
Workflow ref: feat/tool-disclosure-benchmarks
Requested targets: (default — all supported)
Requested jobs: tool-disclosure-performance-smoke
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
tool-disclosure-performance-smoke ✅ success

ericksoa added 7 commits July 7, 2026 12:36
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: docs Documentation, examples, guides, or docs build area: inference Inference routing, serving, model selection, or outputs area: integrations Third-party service integration behavior area: performance Latency, throughput, resource use, benchmarks, or scaling area: security Security controls, permissions, secrets, or hardening feature PR adds or expands user-visible functionality integration: dcode LangChain Deep Code integration behavior integration: hermes Hermes integration behavior integration: openclaw OpenClaw integration behavior provider: vllm vLLM local or hosted provider behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants