Order Zero Phase 1b: redaction detection + reference-policy curve
Two corrections to the first pass, both of which would have produced a false positive. 1) A non-empty body is NOT proof of access. PropLine's free tier returns the full STRUCTURE of tier-gated endpoints with values stripped plus an upgrade_url -- and the first pass classified /odds/closing and /movement as "works" on structure alone. detectRedaction() now counts actual prices and downgrades works -> partial when a body advertises an upgrade or carries outcomes with zero prices. Same class as the harness that returned a silent false, inverted. 2) One hard-coded reference set forces a yes/no on a question that is really a curve. reference_policy_curve reports strict eligibility (>=2 books, both sides, same line) under exchange_only / exchange_plus_sharp / exchange_plus_us / takeable_only, so the ruler decision is made on coverage-vs-quality rather than on a guess. DFS is absent from every policy by construction and a test asserts it. Also probes /markets/resolution-summary: /exports/resolved-props being 403 tells us we cannot PULL settlements; resolution-summary tells us whether they EXIST to be bought. Different questions. 19 unit tests, still hermetic. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
const { __internals } = require('../../src/services/proplineVerify');
|
||||
const { analyseBreadth, scrubKeys, probe, summarise, REFERENCE_CANDIDATES, DFS_PLATFORMS } = __internals;
|
||||
const { analyseBreadth, scrubKeys, probe, summarise, detectRedaction, REFERENCE_CANDIDATES, REFERENCE_POLICIES, DFS_PLATFORMS } = __internals;
|
||||
|
||||
const ALLOWED = new Set(['draftkings', 'fanduel', 'betmgm', 'betrivers', 'pinnacle']);
|
||||
|
||||
@@ -144,3 +144,55 @@ describe('proplineVerify — breadth', () => {
|
||||
expect(summarise([{ a: 1 }])).toContain('array(1)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('proplineVerify — redaction detection', () => {
|
||||
beforeEach(() => { process.env.PROPLINE_API_KEY_1 = 'k'; });
|
||||
|
||||
const priced = { bookmakers: [{ key: 'dk', markets: [{ outcomes: [{ price: -110 }, { price: -110 }] }] }] };
|
||||
const stripped = { bookmakers: [{ key: 'dk', markets: [{ outcomes: [{ price: null }, {}] }] }], upgrade_url: 'https://x' };
|
||||
|
||||
it('flags a structure-only body with an upgrade_url as redacted', () => {
|
||||
const r = detectRedaction(stripped);
|
||||
expect(r.outcomes).toBe(2);
|
||||
expect(r.priced).toBe(0);
|
||||
expect(r.redacted).toBe(true);
|
||||
});
|
||||
|
||||
it('does not flag a genuinely priced body', () => {
|
||||
const r = detectRedaction(priced);
|
||||
expect(r.priced).toBe(2);
|
||||
expect(r.redacted).toBe(false);
|
||||
});
|
||||
|
||||
it('DOWNGRADES a 200 redacted body from works to partial', async () => {
|
||||
const httpGet = async () => ({ status: 200, data: stripped, headers: {} });
|
||||
const r = await probe('/x', {}, '', httpGet);
|
||||
expect(r.verdict).toBe('partial'); // a non-empty body is NOT proof of access
|
||||
expect(r.redaction.redacted).toBe(true);
|
||||
});
|
||||
|
||||
it('keeps works when the body carries real prices', async () => {
|
||||
const httpGet = async () => ({ status: 200, data: priced, headers: {} });
|
||||
expect((await probe('/x', {}, '', httpGet)).verdict).toBe('works');
|
||||
});
|
||||
});
|
||||
|
||||
describe('proplineVerify — reference policies', () => {
|
||||
it('no policy admits a DFS platform', () => {
|
||||
for (const books of Object.values(REFERENCE_POLICIES)) {
|
||||
for (const dfs of DFS_PLATFORMS) expect(books).not.toContain(dfs);
|
||||
}
|
||||
});
|
||||
|
||||
it('the curve widens monotonically as the policy widens', () => {
|
||||
const raw = [event('e1', {
|
||||
novig: [{ player: 'A', point: 1.5, over: -104, under: -104 }],
|
||||
draftkings: [{ player: 'A', point: 1.5, over: -110, under: -110 }],
|
||||
betmgm: [{ player: 'A', point: 1.5, over: -112, under: -108 }],
|
||||
})];
|
||||
const c = analyseBreadth(raw, ALLOWED).reference_policy_curve;
|
||||
expect(c.exchange_only.n2).toBe(0); // one exchange only
|
||||
expect(c.exchange_plus_us.n2).toBe(1); // exchange + two US books
|
||||
expect(c.takeable_only.n2).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user