Files
PaperClipAI/packages
DottaandPaperclip 313c1db2c3 fix(evals): share bounded request policy with qualification (#17765)
## Thinking Path

> - Paperclip manages agents and their work.
> - Product E2E evaluations send model work through a gateway with cost
limits.
> - The gateway checks the request body before it reserves money or
contacts a provider.
> - A qualification probe needs that same check before it records a
spending-cap denial.
> - Namespace support already exists. Qualification must share that
policy without sending a paid request.
> - This pull request exposes the pure request validator and bounds the
supported local tool definitions.
> - The benefit is one request policy for qualification and forwarding.

## Linked Issues or Issue Description

Refs: #17452, #17469.

**What happened?**

The request validator was private to `forwardEvalRequest`. A
qualification caller could not reuse the request policy before
admission. A separate check could accept a request body that forwarding
rejects before a reservation.

**Expected behavior**

Qualification and forwarding use the same pure validator. One-level
OpenAI namespaces with local function or custom tools remain supported.
Invalid tool definitions fail before accounting or transport work.

**Steps to reproduce**

Use the synthetic native-daemon request fixture in
`eval-gateway.test.ts`. It has seven local function tools and one
namespace with five local function tools. Call the shared validator,
then forward through the fake provider. Run the malformed namespace and
tool-count cases to check rejection before side effects.

The namespace behavior follows the [OpenAI function-calling
guide](https://developers.openai.com/api/docs/guides/function-calling).
This change preserves the one-level contract introduced in #17452 and
hardened in #17469.

## What Changed

- Export `boundedEvalPayload` with credential-free route fields.
`forwardEvalRequest` calls that function.
- Keep one namespace level with function or custom leaves. Require exact
leaf types, nonblank string leaf names, and a closed namespace wrapper.
- Limit OpenAI tool definitions to 1,024 per request. Count namespace
wrappers and their children.
- Add native-daemon-shaped forwarding coverage, malformed and hosted
tool rejection, count and depth boundaries, and Anthropic compatibility
checks.
- Document the shared qualification policy in the Product E2E security
guide.
- Compile the real observability validator in the test parent. The owned
CLI fixture imports JavaScript, so its process group does not include a
test-only TypeScript compiler service. The parent resolves the compiler
from the root package, which declares that dependency. Production
cleanup checks and attempt deadlines stay intact.

## Verification

- `pnpm exec vitest run --config tests/runner-e2e/vitest.config.ts
eval-gateway.test.ts cost-ledger.test.ts provider-usage.test.ts
operating-overhead.test.ts operations.test.ts`: 173 passed.
- `pnpm test:e2e:runner:typecheck`: passed.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- Separate Node support checks: 137 passed.
- `pnpm test:e2e:runner:unit`: 4,271 passed, two skipped, four failed in
unchanged Daytona image and Pi catalog contracts. The same four failures
reproduce on untouched base commit
`a67a18c171816b097f46eae78fc58c7e55c9c565` (79 passed, four failed in
those files).
- `pnpm test:run`: interrupted and incomplete after required CI
completed. Initial database startup failed because this checkout omitted
the embedded PostgreSQL package postinstall aliases. The package
hydrator restored them, and 14 real database checks passed. Earlier
failures and the full output remain preserved; this local full run is
not counted as passing verification. Its owned process group exited
after SIGINT, with no owned survivors.
- An offline full native authentication probe used the real Rust daemon
and pinned Codex 0.160.0 Darwin SDK. The same captured request failed
the older operations policy before reservation and reached a mock
reservation with this policy. The OS sandbox allowed loopback only. It
used synthetic credentials, retained no raw model payload, and made no
provider calls.
- Controller fixture suite: 70 passed. Three cold comparisons each
confirmed that the old child started an owned compiler service and the
corrected child did not. On Darwin the old compiler also exited cleanly,
so this does not prove the exact historical Linux process race. Fresh
Linux CI is required.
- Independent review passed. The private qualification integration
passed 14 exact-source compatibility checks and 67 shared-source tests
without provider calls.

- Required GitHub CI checks passed on the current head. The separate
Entire approval gate still awaits an eligible reviewer; the delegated
author account's explicitly AI-assisted approval does not satisfy it.

## Risks

Requests with more than 1,024 OpenAI tool definitions or extra namespace
wrapper fields now fail closed. New provider schema fields will need
review. Anthropic tool handling, model prices, billing restrictions,
output caps, and reservation ordering remain unchanged. This offline
request-policy proof does not establish a completed model turn or Linux
or Cloud onboarding acceptance.

## Model Used

OpenAI Codex, GPT-6 family. The exact serving model identifier and
context window are not exposed in this session. The model used
reasoning, tools, and code execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 14:14:47 -05:00
..