fix: drop untradable predictions instead of the whole proposal
One untradable ticker rejected everything alongside it. In a single day that was 93 proposals discarding 171 predictions, and 76 of those named something we could trade perfectly well. They were lost because a sibling in the same response said EURUSD. Tradability is a filter, so it applies per prediction now. The untradable one is dropped and logged, its siblings are kept, and the stored payload records what was removed so the filtering is auditable rather than invisible. Lookahead deliberately still rejects the entire proposal. Evidence that did not exist at the proposal's own cutoff means the response is corrupt rather than merely untradable, and keeping the rest of it would hide the one thing most worth seeing. Both halves are pinned by tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WnNxwxfXSbeNtjvtz5gayb
This commit is contained in:
@@ -354,3 +354,42 @@ test('a budget failure is transient but a bad key is not', () => {
|
||||
assert.equal(isTransientCoordinatorFailure('TypeError: fetch failed'), true);
|
||||
assert.equal(isTransientCoordinatorFailure('request failed with 503'), true);
|
||||
});
|
||||
|
||||
test('an untradable instrument drops itself, not its valid siblings', () => {
|
||||
const archive = new Database(':memory:');
|
||||
archive.exec('CREATE TABLE articles (id INTEGER PRIMARY KEY, pub_date_effective TEXT, pub_date TEXT, ingested_at TEXT)');
|
||||
archive.prepare("INSERT INTO articles VALUES (7, '2020-01-01T00:00:00Z', NULL, '2020-01-01T00:00:00Z')").run();
|
||||
const intelligence = new Database(':memory:');
|
||||
initAutonomySchema(intelligence);
|
||||
intelligence.prepare("INSERT INTO autonomy_instruments(symbol, broker, active, tradable) VALUES ('NVDA','test',1,1)").run();
|
||||
|
||||
const pred = (instrument) => ({
|
||||
instrument, direction: 'positive', event_type: 'earnings',
|
||||
horizon_days: 10, evidence_article_ids: [7],
|
||||
});
|
||||
|
||||
// EURUSD used to take NVDA down with it and lose the whole proposal
|
||||
const result = acceptProposal(intelligence, archive,
|
||||
{ predictions: [pred('NVDA'), pred('EURUSD')] },
|
||||
{ informationCutoff: '2026-01-01T00:00:00Z', strategyVersion: 'test' });
|
||||
|
||||
assert.equal(result.predictionCount, 1);
|
||||
assert.deepEqual(result.droppedInstruments, ['EURUSD']);
|
||||
const stored = intelligence.prepare('SELECT instrument FROM autonomy_predictions').all();
|
||||
assert.deepEqual(stored.map((r) => r.instrument), ['NVDA']);
|
||||
});
|
||||
|
||||
test('lookahead still rejects the whole proposal, not just one prediction', () => {
|
||||
const archive = new Database(':memory:');
|
||||
archive.exec('CREATE TABLE articles (id INTEGER PRIMARY KEY, pub_date_effective TEXT, pub_date TEXT, ingested_at TEXT)');
|
||||
archive.prepare("INSERT INTO articles VALUES (7, '2020-06-01T00:00:00Z', NULL, '2020-06-01T00:00:00Z')").run();
|
||||
const intelligence = new Database(':memory:');
|
||||
initAutonomySchema(intelligence);
|
||||
intelligence.prepare("INSERT INTO autonomy_instruments(symbol, broker, active, tradable) VALUES ('NVDA','test',1,1)").run();
|
||||
|
||||
// evidence postdates the cutoff: corrupt, not merely untradable
|
||||
assert.throws(() => acceptProposal(intelligence, archive, {
|
||||
predictions: [{ instrument: 'NVDA', direction: 'positive', event_type: 'earnings', horizon_days: 10, evidence_article_ids: [7] }],
|
||||
}, { informationCutoff: '2020-01-01T00:00:00Z' }), /missing evidence/);
|
||||
assert.equal(intelligence.prepare('SELECT COUNT(*) AS n FROM autonomy_predictions').get().n, 0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user