Signals: Jev's request in the shape TypeSafe takes, and its reason kept when it refuses (#257)

Every call was refused with 422: a noul question's `criteria` is an object of what true and false
mean, and it was sent a sentence. The error kept only the status, from error_for_status, so the log
and the trace said 422 and not why; TypeSafe's body said "Input should be a valid dictionary"
at questions.3.noul.criteria. The body is now in the error and on the jev span, with the status.

A request refused as malformed (400, 422) ends the pass, since every other item's would be refused
the same way: the 50 warnings a pass were the same failure 50 times. The state is text now, as
TypeSafe's docs show it, rather than an object that sent null for a feed with no title, and the
questions are keyed signal_<id>. Checked against TypeSafe with the corrected request: 0.96 for an
item about the keywords, 0.02 for one that was not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-16 17:48:06 +00:00
parent 8d93b58deb
commit 20f53183ac
2 changed files with 87 additions and 31 deletions

View File

@@ -7,13 +7,18 @@ const dir = __dirname;
const port = Number(process.env.FIXTURE_PORT || 8792);
http.createServer((req, res) => {
// Jev, for Signals (#254): sure of an item whose title has a question's keyword in it.
// Jev, for Signals (#254): sure of an item whose text has a question's keyword in it. Refuses
// a request in the shape TypeSafe refuses, as it does (#257).
if (req.method === 'POST' && req.url === '/jev') {
let body = '';
req.on('data', c => { body += c; });
req.on('end', () => {
const { state, questions } = JSON.parse(body);
const title = (state.title || '').toLowerCase();
if (Object.values(questions).some(q => typeof q.criteria !== 'object')) {
res.writeHead(422, { 'content-type': 'application/json' }).end('{"detail":"criteria should be an object"}');
return;
}
const title = String(state).toLowerCase();
const answers = {};
for (const [id, q] of Object.entries(questions)) {
const words = q.instructions.replace(/^.*: /, '').replace(/\?$/, '').split(', ');