| … | … | @@ -117,22 +159,30 @@ const make = Effect.gen(function* () { | |
| 163 | + | if (values === undefined) | |
| 164 | + | return yield* new SecretRequestError({ reason: "fields_mismatch" }); | |
| 165 | + | const savedAt = yield* Clock.currentTimeMillis; | |
| 166 | + | yield* Effect.forEach(values, ([field, value]) => | |
🟠 High secrets/SecretRequests.ts:166
Concurrent answer calls can record a saved card containing fields from different clients, so the agent receives a mixed credential set. store.create arbitrates each field independently, and ignoring SecretAlreadyExists lets each client keep the fields it created; serialize the full answer operation per card, including the pending check.
✅ Resolved in f3b249caf92e26e7da080c4ed30a800b17b58c01
Fixed in f3b249caf9: answer now runs under a single-permit semaphore, so a second answer sees the card already answered. Added a test where two answers race on a fields card; it fails without the lock.
| … | … | @@ -62,16 +94,23 @@ export function secretRequestDisplay( | |
| 104 | + | const base = { threadId: item.threadId, turnItemId: item.id }; | |
| 105 | + | if (answer.type === "decline") return { ...base, answer: { type: "decline" } }; | |
| 106 | + | const entries = secretRequestInputs(item).map( | |
| 107 | + | (input) => [input.key, (answer.values[input.key] ?? "").trim()] as const, | |
🟠 High src/secretRequest.ts:107
A field named toString, constructor, or hasOwnProperty crashes the pending card during render when its value is unset, because answer.values[input.key] resolves to an inherited function and .trim() throws. Check that the key is an own property before reading it so missing values are treated as empty strings.
Also found in 1 other location(s)
apps/web/src/components/chat/SecretRequestCard.tsx:68
Initializing field values with
{}makes valid field names such asconstructorandtoStringresolve to inherited functions before the user types anything.RequestSecretFieldspermits those names, and the unconditionalsecretRequestAnswerInput(item, { type: "save", values })on line 77 calls.trim()on that function (client-runtime/src/secretRequest.ts:107), throwing during render. Such a request crashes the pending card instead of allowing an answer or decline. Use a prototype-free map or own-property lookups for missing values, including after resetting state.
No longer relevant as of f3b249caf92e26e7da080c4ed30a800b17b58c01
Fixed in f3b249caf9: card values are read by own key through a shared secretRequestValue helper (client-runtime, web and mobile), with a test using a field named constructor.