test(tools): make the deep oneOf-object test a real quadratic tripwire

The 60k oneOf-object test had only one object node (the innermost), so the
pre-fix code called allocateClassName once — linear, never tripping the
timeout, so it did not cover the class-name Θ(depth²) it named. Give every
level an object branch (both oneOf arms are objects) so each level propagates
a one-segment-longer class name; the pre-fix rope slice is then Θ(depth²)
(~9.5s, past the 5s default) while the capped path stays linear. Also extract
the shared cap expression into capClassNameBase (used by allocateClassName and
childClassName). py-types.ts stays at 100% per-file coverage.
This commit is contained in:
Chinesezjc
2026-08-02 17:48:33 +08:00
parent 345375747e
commit 0d6191d0db
2 changed files with 15 additions and 9 deletions

View File

@@ -485,15 +485,17 @@ describe('renderToolsSdkPy', () => {
})
it('names a deep oneOf-of-object chain in linear time (bounded propagated class names)', () => {
// Every level is a oneOf whose first branch is a closed empty object (a
// named TypedDict) and recurses. Propagating the full ancestor path as the
// class name and slicing it in allocateClassName at every level would be
// Theta(depth^2); childClassName caps the propagated base so it stays
// linear. The quadratic path at this depth exceeds the 5s default.
// Every level is a oneOf whose SECOND branch is a named object (a closed
// empty TypedDict) and whose first branch recurses — so every level has an
// object node, each propagating a class name one segment longer. Without a
// propagation cap, allocateClassName slices an ever-longer rope at every
// level → Theta(depth^2) (~9.5s at this depth, past the 5s default);
// childClassName caps the base so it stays linear (~ms). Assertions are
// shape-based but the depth is the tripwire: a regression times out.
const depth = 60000
let deep: Record<string, unknown> = { type: 'object', additionalProperties: false, properties: {} }
for (let i = 0; i < depth; i++) {
deep = { oneOf: [deep, { type: 'null' }] }
deep = { oneOf: [deep, { type: 'object', additionalProperties: false, properties: {} }] }
}
const tool: ToolSdkSchema = { name: 'deep', description: 'Deep oneOf-object chain.', parameters: { type: 'object', additionalProperties: false, properties: { root: deep }, required: ['root'] }, output: { type: 'string' } }
const text = renderToolsSdkPy([tool])