@event4u/agent-config 5.6.1 → 5.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-src/commands/agent-handoff.md +1 -1
- package/.agent-src/commands/agent-status.md +1 -1
- package/.agent-src/commands/agents/audit.md +1 -1
- package/.agent-src/commands/agents/init.md +1 -1
- package/.agent-src/commands/agents/user/accept.md +3 -3
- package/.agent-src/commands/agents/user/init.md +4 -4
- package/.agent-src/commands/agents/user/show.md +3 -3
- package/.agent-src/commands/agents/user/update.md +3 -3
- package/.agent-src/commands/agents/user.md +1 -1
- package/.agent-src/commands/agents.md +1 -1
- package/.agent-src/commands/analytics/prune.md +1 -1
- package/.agent-src/commands/analytics/show.md +1 -1
- package/.agent-src/commands/analytics.md +1 -1
- package/.agent-src/commands/bug-fix.md +1 -1
- package/.agent-src/commands/challenge-me.md +1 -1
- package/.agent-src/commands/chat-history/import.md +1 -1
- package/.agent-src/commands/chat-history/learn.md +1 -1
- package/.agent-src/commands/chat-history/show.md +1 -1
- package/.agent-src/commands/chat-history.md +1 -1
- package/.agent-src/commands/check-current-md.md +1 -1
- package/.agent-src/commands/condense.md +1 -1
- package/.agent-src/commands/context.md +1 -1
- package/.agent-src/commands/cost-report.md +13 -8
- package/.agent-src/commands/council.md +3 -3
- package/.agent-src/commands/create-pr/description-only.md +1 -1
- package/.agent-src/commands/create-pr.md +1 -1
- package/.agent-src/commands/e2e-heal.md +1 -1
- package/.agent-src/commands/e2e-plan.md +1 -1
- package/.agent-src/commands/feature.md +1 -1
- package/.agent-src/commands/fix/ci.md +1 -1
- package/.agent-src/commands/fix/portability.md +1 -1
- package/.agent-src/commands/fix/pr-bot-comments.md +1 -1
- package/.agent-src/commands/fix/pr-comments.md +1 -1
- package/.agent-src/commands/fix/pr-developer-comments.md +1 -1
- package/.agent-src/commands/fix/refs.md +1 -1
- package/.agent-src/commands/fix/seeder.md +1 -1
- package/.agent-src/commands/fix.md +1 -1
- package/.agent-src/commands/judge.md +1 -1
- package/.agent-src/commands/knowledge/cross-repo.md +1 -1
- package/.agent-src/commands/knowledge/forget.md +1 -1
- package/.agent-src/commands/knowledge/ingest.md +1 -1
- package/.agent-src/commands/knowledge/list.md +1 -1
- package/.agent-src/commands/knowledge.md +1 -1
- package/.agent-src/commands/memory/add.md +1 -1
- package/.agent-src/commands/memory/learn-low-impact.md +1 -1
- package/.agent-src/commands/memory/load.md +1 -1
- package/.agent-src/commands/memory/mine-session.md +1 -1
- package/.agent-src/commands/memory/promote.md +1 -1
- package/.agent-src/commands/memory/propose.md +1 -1
- package/.agent-src/commands/memory.md +1 -1
- package/.agent-src/commands/mode.md +1 -1
- package/.agent-src/commands/optimize/agents-dir.md +1 -1
- package/.agent-src/commands/optimize/augmentignore.md +1 -1
- package/.agent-src/commands/optimize/rtk.md +1 -1
- package/.agent-src/commands/optimize/skills.md +1 -1
- package/.agent-src/commands/optimize.md +1 -1
- package/.agent-src/commands/orchestrate.md +1 -1
- package/.agent-src/commands/override/create.md +1 -1
- package/.agent-src/commands/override/manage.md +1 -1
- package/.agent-src/commands/override.md +1 -1
- package/.agent-src/commands/package-reset.md +1 -1
- package/.agent-src/commands/prediction-pool.md +234 -0
- package/.agent-src/commands/profile/activate.md +81 -0
- package/.agent-src/commands/profile/deactivate.md +68 -0
- package/.agent-src/commands/profile/show.md +70 -0
- package/.agent-src/commands/profile.md +68 -0
- package/.agent-src/commands/project-health.md +1 -1
- package/.agent-src/commands/quality-fix.md +1 -1
- package/.agent-src/commands/roadmap/process-full.md +1 -1
- package/.agent-src/commands/roadmap/process-phase.md +1 -1
- package/.agent-src/commands/roadmap/process-step.md +1 -1
- package/.agent-src/commands/roadmap.md +1 -1
- package/.agent-src/commands/set-cost-profile.md +9 -9
- package/.agent-src/commands/skill/preview.md +3 -3
- package/.agent-src/commands/skill.md +1 -1
- package/.agent-src/commands/skills/discover.md +1 -1
- package/.agent-src/commands/skills.md +1 -1
- package/.agent-src/commands/sync-agent-settings.md +3 -3
- package/.agent-src/commands/sync-gitignore/fix.md +1 -1
- package/.agent-src/commands/sync-gitignore.md +1 -1
- package/.agent-src/commands/update-form-request-messages.md +1 -1
- package/.agent-src/presets/README.md +1 -1
- package/.agent-src/profiles/README.md +1 -1
- package/.agent-src/rules/non-destructive-by-default.md +2 -1
- package/.agent-src/skills/check-refs/SKILL.md +1 -1
- package/.agent-src/skills/finishing-a-development-branch/SKILL.md +1 -1
- package/.agent-src/skills/git-workflow/SKILL.md +1 -1
- package/.agent-src/skills/jira-integration/SKILL.md +1 -1
- package/.agent-src/skills/markitdown/SKILL.md +1 -1
- package/.agent-src/skills/prediction-pool-optimizer/SKILL.md +314 -0
- package/.agent-src/skills/prediction-pool-optimizer/evals/triggers.json +20 -0
- package/.agent-src/skills/prediction-pool-optimizer/reference/ev-fixtures.md +175 -0
- package/.agent-src/skills/prediction-pool-optimizer/reference/odds-and-bonus.md +109 -0
- package/.agent-src/skills/rtk-output-filtering/SKILL.md +1 -1
- package/.agent-src/skills/script-writing/SKILL.md +1 -1
- package/.agent-src/skills/token-optimizer/SKILL.md +1 -1
- package/.agent-src/skills/using-git-worktrees/SKILL.md +1 -1
- package/.agent-src/templates/agent-settings.md +7 -7
- package/.agent-src/templates/agents/agent-project-settings.example.yml +2 -2
- package/.agent-src/templates/scripts/work_engine/_lib/agent_settings.py +54 -6
- package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +1 -1
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.py +9 -7
- package/.agent-src/templates/scripts/work_engine/hooks/settings.py +9 -10
- package/.agent-src/templates/scripts/work_engine/scoring/memory_visibility.py +17 -4
- package/.claude-plugin/marketplace.json +370 -364
- package/CHANGELOG.md +108 -0
- package/README.md +2 -2
- package/config/agent-settings.template.yml +11 -2
- package/config/discovery/packs.yml +11 -0
- package/config/discovery/session-profiles.yml +37 -0
- package/config/discovery/workspaces.yml +1 -1
- package/config/profiles/balanced.ini +1 -1
- package/config/profiles/full.ini +1 -1
- package/config/profiles/minimal.ini +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +254 -100
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -3
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +41 -6
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +19 -6
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/server/io/substituteTemplate.js +3 -3
- package/dist/server/io/substituteTemplate.js.map +1 -1
- package/dist/server/routes/settings.js +2 -2
- package/dist/server/routes/settings.js.map +1 -1
- package/dist/server/schemas/settings.js +4 -2
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/ui/assets/{index-DVsyUMZe.js → index-5lFqAKL0.js} +2 -2
- package/dist/ui/assets/index-5lFqAKL0.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/architecture/current-onboard-baseline.md +3 -3
- package/docs/architecture.md +2 -2
- package/docs/catalog.md +11 -5
- package/docs/contracts/adr-level-6-productization.md +1 -1
- package/docs/contracts/command-clusters.md +2 -0
- package/docs/contracts/config-presets.md +2 -2
- package/docs/contracts/cost-profile-defaults.md +5 -5
- package/docs/contracts/discovery-manifest.schema.json +1 -1
- package/docs/contracts/explain-trace.schema.json +3 -3
- package/docs/contracts/memory-visibility-v1.md +15 -7
- package/docs/contracts/profile-system.md +2 -2
- package/docs/contracts/session-profile-overlay.md +120 -0
- package/docs/contracts/settings-api.md +3 -3
- package/docs/contracts/value-report-schema.md +14 -1
- package/docs/customization.md +47 -5
- package/docs/decisions/ADR-010-profile-pack-preset-boundary.md +47 -11
- package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +16 -2
- package/docs/decisions/ADR-034-per-skill-model-recommendation-transport.md +1 -1
- package/docs/decisions/ADR-036-global-install-browser-wizard-handoff.md +106 -0
- package/docs/decisions/ADR-037-cost-profile-untangle.md +117 -0
- package/docs/decisions/ADR-038-canonical-settings-path.md +66 -0
- package/docs/decisions/ADR-039-claude-skills-untracked.md +139 -0
- package/docs/decisions/ADR-rule-kernel-and-router.md +1 -1
- package/docs/decisions/INDEX.md +4 -0
- package/docs/development.md +12 -0
- package/docs/getting-started.md +2 -2
- package/docs/guidelines/agent-infra/layered-settings.md +10 -4
- package/docs/installation.md +3 -3
- package/docs/setup/mcp-client-config.md +1 -1
- package/docs/skills-catalog.md +5 -1
- package/docs/value.md +9 -7
- package/docs/wizard.md +1 -1
- package/llms.txt +4 -0
- package/package.json +1 -1
- package/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
- package/scripts/_cli/cmd_doctor.py +3 -2
- package/scripts/_cli/cmd_explain.py +1 -1
- package/scripts/_cli/cmd_versions.py +2 -2
- package/scripts/_cli/explain_last/inputs.py +11 -8
- package/scripts/_cli/explain_last/sections/inputs.py +1 -1
- package/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
- package/scripts/_lib/agent_settings.py +54 -6
- package/scripts/_lib/agent_src.py +30 -0
- package/scripts/_lib/value_ladder.py +99 -2
- package/scripts/_lib/value_report.py +30 -16
- package/scripts/ai_council/modes.py +1 -1
- package/scripts/ai_council/session.py +5 -1
- package/scripts/audit_command_surface.py +7 -1
- package/scripts/audit_initial_context.py +26 -2
- package/scripts/check_gate_paths.py +117 -0
- package/scripts/check_references.py +51 -2
- package/scripts/check_skill_requires.py +143 -0
- package/scripts/check_test_coverage_diff.py +180 -0
- package/scripts/compile_router.py +5 -1
- package/scripts/condense.py +92 -4
- package/scripts/config/session_profiles.py +492 -0
- package/scripts/council_cli.py +5 -1
- package/scripts/first-run.sh +11 -11
- package/scripts/hook_manifest.yaml +15 -7
- package/scripts/hooks/dispatch_hook.py +8 -0
- package/scripts/install +14 -1
- package/scripts/install-hooks.sh +2 -1
- package/scripts/install.py +203 -433
- package/scripts/install_anthropic_key.sh +1 -1
- package/scripts/install_openai_key.sh +1 -1
- package/scripts/inventory_abstraction_budget.py +6 -1
- package/scripts/lint_agents_md.py +11 -4
- package/scripts/lint_discovery_vocabulary.py +5 -5
- package/scripts/lint_hook_concern_budget.py +5 -1
- package/scripts/lint_marketplace.py +18 -7
- package/scripts/lint_roadmap_ci_steps.py +5 -1
- package/scripts/lint_roadmap_complexity.py +5 -1
- package/scripts/lint_value_dashboard.py +1 -1
- package/scripts/mcp_server/prompts.py +5 -1
- package/scripts/prediction-pool/adapters/_schema.md +42 -0
- package/scripts/prediction-pool/adapters/kicktipp.yml +23 -0
- package/scripts/prediction-pool/poisson_sim.py +167 -0
- package/scripts/prediction-pool/pool_winsim.py +236 -0
- package/scripts/prediction-pool/score_ev.py +188 -0
- package/scripts/profile_staleness_hook.py +69 -0
- package/scripts/render_value_md.py +1 -0
- package/scripts/roadmap_progress_hook.py +56 -6
- package/scripts/schemas/agent-settings.schema.json +77 -0
- package/scripts/schemas/skill.schema.json +7 -0
- package/scripts/smoke_quickstart.py +7 -6
- package/scripts/sync_agent_settings.py +12 -5
- package/scripts/validate_agent_settings.py +124 -0
- package/scripts/validate_decision_engine.py +5 -1
- package/templates/minimal/.agent-settings.yml +1 -1
- package/dist/ui/assets/index-DVsyUMZe.js.map +0 -1
- package/scripts/measure_roadmap_trajectory.py +0 -112
- package/scripts/verify_roadmap_closure.py +0 -327
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
model_tier:
|
|
2
|
+
model_tier: medium
|
|
3
3
|
name: sync-agent-settings
|
|
4
4
|
tier: 1
|
|
5
5
|
description: Sync `.agent-settings.yml` against the current template + profile — adds new sections/keys, preserves user values, shows a diff before writing
|
|
@@ -41,7 +41,7 @@ Use when:
|
|
|
41
41
|
|
|
42
42
|
## When NOT to use
|
|
43
43
|
|
|
44
|
-
- To change a value (`ide`, `
|
|
44
|
+
- To change a value (`ide`, `rule_loading_tier`, `max_parallel`) → edit the
|
|
45
45
|
file directly or ask the agent; the sync only reconciles structure.
|
|
46
46
|
- To create `.agent-project-settings.yml` (team file) → that is a
|
|
47
47
|
separate concern; this command only touches the developer file.
|
|
@@ -95,7 +95,7 @@ Free-text replies (`"nö"`, `"leave it"`, unrecognized input) count as
|
|
|
95
95
|
|
|
96
96
|
### 4. Profile override
|
|
97
97
|
|
|
98
|
-
The script auto-detects the profile from the target's `
|
|
98
|
+
The script auto-detects the profile from the target's `rule_loading_tier`
|
|
99
99
|
key and falls back to `minimal`. To sync against a different profile
|
|
100
100
|
(e.g. during a profile change), pass `--profile balanced` or
|
|
101
101
|
`--profile full` — but ask the user first; changing the profile is a
|
|
@@ -4,7 +4,7 @@ Seed presets for the [preset system](../../docs/contracts/config-presets.md).
|
|
|
4
4
|
Each preset bundles governance knobs (autonomy / confidence / risk /
|
|
5
5
|
council / mcp / cost / notifications) so the user picks a stance, not
|
|
6
6
|
a dozen individual values. Boundary against `profile.id`, `pack.id`,
|
|
7
|
-
and `
|
|
7
|
+
and `rule_loading_tier` lives in
|
|
8
8
|
[ADR-010](../../docs/decisions/ADR-010-profile-pack-preset-boundary.md).
|
|
9
9
|
|
|
10
10
|
## Seed set (v2.x — fixed)
|
|
@@ -4,7 +4,7 @@ Seed profiles for the [profile system](../../docs/contracts/profile-system.md).
|
|
|
4
4
|
Each profile answers *who is the user?* — audience identity that
|
|
5
5
|
selects the default skill/command surface, README entry-paragraph,
|
|
6
6
|
and persona pre-selection. Boundary against `preset.id`, `pack.id`,
|
|
7
|
-
and `
|
|
7
|
+
and `rule_loading_tier` lives in
|
|
8
8
|
[ADR-010](../../docs/decisions/ADR-010-profile-pack-preset-boundary.md).
|
|
9
9
|
|
|
10
10
|
## Seed set (v2.x — fixed)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
type: "always"
|
|
3
3
|
tier: "safety-floor"
|
|
4
|
-
description: "
|
|
4
|
+
description: "Hard Floor: agent asks before prod-trunk commits/merges, deploys, pushes, prod data/infra, bulk deletions/infra commits; verify branch before each commit; no autonomy or roadmap bypass"
|
|
5
5
|
alwaysApply: true
|
|
6
6
|
load_context:
|
|
7
7
|
- ../contexts/authority/destructive-mechanics.md
|
|
@@ -28,6 +28,7 @@ Triggers below require explicit user confirmation **on this turn** — not from
|
|
|
28
28
|
| Trigger | Examples |
|
|
29
29
|
|---|---|
|
|
30
30
|
| **Production-branch merge** | `main`, `master`, `prod`, `production`, `release/*`, or any branch the project marks as deployment trunk |
|
|
31
|
+
| **Commit on a production branch** | any `git commit` while `HEAD` is on a prod trunk (set above). **Verify branch before every commit** — `main` is opt-in only, never inferred from a prior turn or a merged PR that left the repo on `main` |
|
|
31
32
|
| **Deploy / release** | `terraform apply` on prod, `kubectl apply` on prod, deploy scripts, release commands, tag pushes that trigger CI deployment |
|
|
32
33
|
| **Push to remote** | any `git push` (also covered by [`scope-control`](scope-control.md), restated so the floor never weakens) |
|
|
33
34
|
| **Production data / infra** | prod DB writes / migrations, prod config, secrets rotation, IAM / role / policy, DNS, anything in a `prod`-scoped path or pipeline |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
model_tier:
|
|
2
|
+
model_tier: medium
|
|
3
3
|
name: finishing-a-development-branch
|
|
4
4
|
description: "Use when the feature is implementation-complete and the next step is 'ship it' — verifies, cleans up, and routes to merge/PR/park/discard — even when the user just says 'I'm done, what now?'."
|
|
5
5
|
domain: process
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
model_tier:
|
|
2
|
+
model_tier: medium
|
|
3
3
|
name: git-workflow
|
|
4
4
|
description: "Use when working with Git — branch naming, commit messages, PR creation, rebasing, or the code review process — even when the user says 'push this' or 'merge the branch' without naming Git."
|
|
5
5
|
domain: process
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
model_tier:
|
|
2
|
+
model_tier: medium
|
|
3
3
|
name: markitdown
|
|
4
4
|
description: "Use when converting PDF, DOCX, XLSX, PPTX, EPUB, images, or audio to Markdown for LLM ingestion via the upstream markitdown-mcp server — 'extract this PDF', 'OCR this image', 'transcribe this audio'."
|
|
5
5
|
status: active
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
---
|
|
2
|
+
model_tier: high
|
|
3
|
+
name: prediction-pool-optimizer
|
|
4
|
+
description: "Optimize prediction-pool tips (kicktipp etc.): rules + multi-book consensus odds → expected-points-max answer for every question, scores AND bonus. Triggers 'optimize my pool tips', 'predict'."
|
|
5
|
+
domain: product
|
|
6
|
+
personas: []
|
|
7
|
+
workspaces:
|
|
8
|
+
- small-business
|
|
9
|
+
packs:
|
|
10
|
+
- fun
|
|
11
|
+
lifecycle: experimental
|
|
12
|
+
trust:
|
|
13
|
+
level: experimental
|
|
14
|
+
install:
|
|
15
|
+
default: false
|
|
16
|
+
removable: true
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# prediction-pool-optimizer
|
|
20
|
+
|
|
21
|
+
> Turn a prediction pool's **scoring rules** plus a **consensus of the major
|
|
22
|
+
> bookmakers' odds** into the answer that maximizes **expected points** — not
|
|
23
|
+
> the most likely outcome — for **every open question in the pool**: match
|
|
24
|
+
> scores AND every bonus / award / special question (top scorer, group
|
|
25
|
+
> winners, champion, most cards …). Sport-agnostic core with per-sport
|
|
26
|
+
> probability blocks. Consumed by [`/prediction-pool`](../../commands/prediction-pool.md).
|
|
27
|
+
> The optimization target is the pool's score, so the chain is always
|
|
28
|
+
> **rules → odds → expected value → participant field → answer**, never
|
|
29
|
+
> "who wins this match?".
|
|
30
|
+
|
|
31
|
+
## When to use
|
|
32
|
+
|
|
33
|
+
When someone wants the best tips for a prediction / betting pool
|
|
34
|
+
(kicktipp-style company pools — football WM, basketball WM, …) and the
|
|
35
|
+
target is **pool points**, not match truth. Triggered by
|
|
36
|
+
[`/prediction-pool`](../../commands/prediction-pool.md) (Steps 3–5) or directly
|
|
37
|
+
when a user asks to optimize / maximize their pool picks.
|
|
38
|
+
|
|
39
|
+
**The one idea that makes this skill correct:** the highest-probability
|
|
40
|
+
result is **not** the highest-expected-value tip. Under most pool rules a
|
|
41
|
+
2:1 or 1:0 scores the same partial points as the "obvious" pick but hits
|
|
42
|
+
more often; under quote/rarity rules a rare-but-plausible result is worth
|
|
43
|
+
more. **Always optimize the pool's points, never the truth of the match.**
|
|
44
|
+
|
|
45
|
+
## Hard rules
|
|
46
|
+
|
|
47
|
+
- **Rules before tips.** Never produce a tip before the pool's scoring is
|
|
48
|
+
parsed (Procedure step 1). Strategy is a function of the rules.
|
|
49
|
+
- **Answer EVERY open question.** A pool has scores *and* bonus / award /
|
|
50
|
+
special questions ("which team supplies the top scorer?", "most yellow
|
|
51
|
+
cards?", "champion?"). Scorelines only, bonus questions blank = a **failed
|
|
52
|
+
run** — enumerate every open question in step 1, carry each to an answer
|
|
53
|
+
(steps 5–6). No silent skips.
|
|
54
|
+
- **Odds are the primary signal — multi-book consensus, not one book.**
|
|
55
|
+
Bookmaker probabilities already fold in form, squad, injuries, travel,
|
|
56
|
+
climate. Build the base from a **consensus across the 5–10 biggest
|
|
57
|
+
publicly-viewable books** (step 2), de-vigged, **sharpness-weighted** —
|
|
58
|
+
never mirror a single portal. Override only with *current* info (confirmed
|
|
59
|
+
lineups, late injuries, suspensions, manager change).
|
|
60
|
+
- **No invented numbers.** Emit no probability you cannot derive from real
|
|
61
|
+
odds or **actually executed** code. Tournament/outright/award numbers come
|
|
62
|
+
from real markets **or** the executed Poisson helper — never a claimed
|
|
63
|
+
"I ran 10,000 simulations".
|
|
64
|
+
- **Scorelines computed, not guessed.** EV-max tip per match from the executed
|
|
65
|
+
grid optimiser (`score_ev.py`, step 4a), never the eye. A 3:2 / 4:1 / 1:4 in
|
|
66
|
+
the output = signature of a skipped computation.
|
|
67
|
+
- **One-sentence justification** per answer. Short.
|
|
68
|
+
|
|
69
|
+
## Procedure
|
|
70
|
+
|
|
71
|
+
### 1. Parse the pool rules AND enumerate every open question
|
|
72
|
+
|
|
73
|
+
From the pool's rule page, extract and document:
|
|
74
|
+
|
|
75
|
+
- Points for **exact result** / **goal (point) difference** / **tendency**.
|
|
76
|
+
- **Every bonus / award / special question** (champion, top scorer, "team of
|
|
77
|
+
the top scorer", group winners, most cards, longest unbeaten,
|
|
78
|
+
will-there-be-a-red-card, over/under totals …). **Write them all down as an
|
|
79
|
+
explicit checklist** — this list is the run's contract; every entry must
|
|
80
|
+
reach an answer.
|
|
81
|
+
- **Joker / multiplier** rules, per-question point weights.
|
|
82
|
+
- **Quote / rarity** scoring (rare correct tips score more)? — flips strategy
|
|
83
|
+
toward contrarian (step 4).
|
|
84
|
+
- Special scorings, **per-question deadlines**, **strategy limits** (e.g. max
|
|
85
|
+
N identical tips).
|
|
86
|
+
- **The goal**: place well, or *win* a large pool? (changes variance — step 4.)
|
|
87
|
+
|
|
88
|
+
### 2. Build the data base — a consensus across the major books
|
|
89
|
+
|
|
90
|
+
Primary signal: current bookmaker odds, **aggregated across the 5–10 biggest
|
|
91
|
+
publicly-viewable books**, not a single portal:
|
|
92
|
+
|
|
93
|
+
1. **Collect** odds for each market (1X2, exact-score, outrights, and each
|
|
94
|
+
special/award market a bonus question needs) from several books.
|
|
95
|
+
Odds-comparison aggregators (Oddschecker, Oddsportal / Betexplorer) show
|
|
96
|
+
many books at once; supplement with named books. Book list + weighting
|
|
97
|
+
recipe in [`reference/odds-and-bonus.md`](reference/odds-and-bonus.md).
|
|
98
|
+
2. **De-vig each book** independently (remove its margin) → per-book implied
|
|
99
|
+
probabilities. Raw odds sum to >100%; never treat them as probabilities.
|
|
100
|
+
3. **Aggregate with a healthy weighting**, not a blind average: weight
|
|
101
|
+
**sharp, low-margin books higher** (Pinnacle, Betfair Exchange),
|
|
102
|
+
recreational books lower; weighted mean or trimmed median so one outlier
|
|
103
|
+
book cannot swing the base. Result = the **consensus probability** — the
|
|
104
|
+
calibration base.
|
|
105
|
+
4. **Single-book outlier = flag, not truth** — investigate *why* (priced-in
|
|
106
|
+
injury? stale line?) before moving off consensus. Cross-portal agreement is
|
|
107
|
+
signal; one portal disagreeing is a prompt to check, not to follow.
|
|
108
|
+
|
|
109
|
+
Secondary (only when it adds signal the consensus has not absorbed): confirmed
|
|
110
|
+
lineups, injuries, suspensions, manager change, recent form, home advantage,
|
|
111
|
+
head-to-head, rest/travel, weather, model forecasts (Opta), Elo/SPI ratings.
|
|
112
|
+
|
|
113
|
+
### 3. Per-match probabilities (sport block)
|
|
114
|
+
|
|
115
|
+
Compute, per match, the outcome distribution and the most plausible exact
|
|
116
|
+
results. Pick the block for the event's sport:
|
|
117
|
+
|
|
118
|
+
**Football / soccer**
|
|
119
|
+
- Model goals as **Poisson** per side from each team's expected goals;
|
|
120
|
+
draws are real (~22–28% baseline) — people under-tip them.
|
|
121
|
+
- Outcome split: home-win / draw / away-win; then the exact-score grid.
|
|
122
|
+
- Common EV-strong exact results: 1:0, 2:1, 1:1, 2:0.
|
|
123
|
+
|
|
124
|
+
**Basketball**
|
|
125
|
+
- **No draws.** Model the points margin as roughly **Gaussian** around the
|
|
126
|
+
market spread; pair with the moneyline for win probability and the
|
|
127
|
+
total (over/under) for the score level.
|
|
128
|
+
- Tendency = sign of (margin); "exact result" rules are rare — read step 1.
|
|
129
|
+
|
|
130
|
+
**Generic fallback (other sports)**
|
|
131
|
+
- Derive the outcome split straight from de-vigged moneyline odds; estimate
|
|
132
|
+
a plausible score from the market total. State the model used.
|
|
133
|
+
|
|
134
|
+
Cross-check the model against the consensus; on a large divergence, re-check
|
|
135
|
+
the data and explain the cause before trusting it.
|
|
136
|
+
|
|
137
|
+
### 4. Convert to the EV-maximizing tip
|
|
138
|
+
|
|
139
|
+
Map probabilities to the tip with the **highest expected points under the
|
|
140
|
+
step-1 rules** — not the prettiest match.
|
|
141
|
+
|
|
142
|
+
#### 4a. The EV-max scoreline is computed, never eyeballed
|
|
143
|
+
|
|
144
|
+
Don't hand-pick a scoreline. Run the executed grid optimiser — builds the full
|
|
145
|
+
Poisson score grid, returns the EV-max tip under the step-1 point tiers:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
python3 scripts/prediction-pool/score_ev.py --lh <home-xg> --la <away-xg> \
|
|
149
|
+
--tendency <t> --diff <d> --exact <e> # one match
|
|
150
|
+
python3 scripts/prediction-pool/score_ev.py matches.json \
|
|
151
|
+
--tendency <t> --diff <d> --exact <e> # batch, prints a ranked table
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Two facts the grid makes unavoidable, intuition gets wrong:
|
|
155
|
+
|
|
156
|
+
- **High scorelines almost never EV-max.** Under partial points a moderate
|
|
157
|
+
favourite peaks at **1:0 / 2:0 / 2:1**; **1:0 wins surprisingly often**, top
|
|
158
|
+
of the surface is *flat* (1:0 vs 2:1 vs 2:0 within hundredths). 3:2 / 4:1 /
|
|
159
|
+
1:4 never optimal — such a tip means the grid wasn't run.
|
|
160
|
+
- **Draws under-tipped.** A correct draw banks the goal-difference tier on
|
|
161
|
+
every draw scoreline, so in a close match (xG within ~0.4) a 1:1 can
|
|
162
|
+
out-score a 1:0 — and for low-scoring even games (λ ≲ 1.0/side) a 0:0 is the
|
|
163
|
+
EV-max. Let the grid decide; the eye tips too few draws.
|
|
164
|
+
|
|
165
|
+
- **Standard fixed-point scoring + goal "place well"** → tip the grid's EV-max
|
|
166
|
+
per match. **No contrarian** — only your tip scores, tipping "different"
|
|
167
|
+
burns EV.
|
|
168
|
+
- **Quote / rarity scoring** → weigh rarer-but-plausible results against payout;
|
|
169
|
+
take rarity when `payout × probability` wins (raise `--exact` or post-process
|
|
170
|
+
the ranked table by the multiplier).
|
|
171
|
+
|
|
172
|
+
#### 4b. Large pool, goal "win it" — measure P(finish 1st), don't guess
|
|
173
|
+
|
|
174
|
+
Goal = **win** a large pool → target flips from E(points) to **P(finish ahead
|
|
175
|
+
of the field)**; pure EV-max converges with the crowd, can't open a gap.
|
|
176
|
+
Measure it with the executed field simulator, not a "rough Kelly" hand-wave:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
python3 scripts/prediction-pool/pool_winsim.py pool.json --runs 4000 --max-flips 4
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Models the field as softmax-EV tippers, reports `P(win)` for EV-max-everywhere,
|
|
183
|
+
then greedily reports **which few tips to flip** off EV-max (EV cost + P(win)
|
|
184
|
+
gain each). Read it as the field threshold, empirically:
|
|
185
|
+
|
|
186
|
+
- Pool **N < 20** → sim shows flips barely move P(win); maximize EV, ignore the
|
|
187
|
+
field.
|
|
188
|
+
- **20 ≤ N < 100 and in the prize positions** → maximize EV.
|
|
189
|
+
- **N ≥ 100, or outside the top ~20%** → take the sim's suggested flips: a
|
|
190
|
+
handful of higher-variance scorelines on high-consensus matches lift P(win)
|
|
191
|
+
most per unit EV given up. Flip only what the sim says pays — variance you
|
|
192
|
+
don't need is wasted EV.
|
|
193
|
+
|
|
194
|
+
Respect all strategy limits from step 1 (max identical tips, etc.).
|
|
195
|
+
|
|
196
|
+
### 5. Tournament, bonus & special questions — answer every one (no hallucination)
|
|
197
|
+
|
|
198
|
+
Walk the **step-1 checklist** and answer **each** entry. Pick the method by
|
|
199
|
+
question type — full taxonomy + per-type method in
|
|
200
|
+
[`reference/odds-and-bonus.md`](reference/odds-and-bonus.md):
|
|
201
|
+
|
|
202
|
+
- **Tournament structure** (group winners, KO rounds, finalists, champion):
|
|
203
|
+
real **outright market odds** ("to win group", "to reach final", "outright
|
|
204
|
+
winner") aggregated per step 2, **or** the executed Poisson simulator:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
python3 scripts/prediction-pool/poisson_sim.py <teams-xg.json> --runs 20000
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
It plays the bracket from per-team expected goals and prints empirical
|
|
211
|
+
advancement / title probabilities. **Run it — never report simulated
|
|
212
|
+
numbers you did not actually compute.**
|
|
213
|
+
|
|
214
|
+
- **Award / player markets** (top scorer, most assists, "which team supplies
|
|
215
|
+
the top scorer", golden boot, most cards): use the matching **special
|
|
216
|
+
market** — e.g. aggregate per-player "top goalscorer" odds **by team** to
|
|
217
|
+
answer "which team has the top scorer". No clean market → derive from a
|
|
218
|
+
stated model (squad strength × games-expected) and **label it a model
|
|
219
|
+
estimate**, not a market number.
|
|
220
|
+
|
|
221
|
+
- **Binary / over-under specials** (red card yes/no, over/under total
|
|
222
|
+
goals/cards): de-vig the consensus probability for the line, pick the EV-max
|
|
223
|
+
side under the question's point weight.
|
|
224
|
+
|
|
225
|
+
Optimize every answer on the same expected-points basis as the scores. Re-run
|
|
226
|
+
as late as each question's deadline allows: re-check confirmed lineups,
|
|
227
|
+
injuries, suspensions, odds movement, then adjust. The per-question deadline is
|
|
228
|
+
the only hard constraint.
|
|
229
|
+
|
|
230
|
+
## Output format
|
|
231
|
+
|
|
232
|
+
1. **Approval table** — one row per match:
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
Match | Tip | Prob / EV | Risk (low/med/high) | 1-line reason | Books used
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
`Books used` names the consensus base (e.g. "consensus of 7 books, sharp-weighted").
|
|
239
|
+
|
|
240
|
+
2. **Bonus & special answers** — one row per open question from the step-1
|
|
241
|
+
checklist, **every entry answered** (none blank):
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
Question | Answer | Prob / EV | Risk | 1-line reason | Source (market / model)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
3. **Group standings and the full bracket** where the event has them.
|
|
248
|
+
4. **Self-check note** — (a) tips reconcile with
|
|
249
|
+
[`reference/ev-fixtures.md`](reference/ev-fixtures.md) (known rules + odds →
|
|
250
|
+
known-good EV tip); (b) bonus table has the **same number of rows as the
|
|
251
|
+
step-1 checklist** — a shorter table means a question was dropped. If your
|
|
252
|
+
method disagrees with a fixture, your method is wrong — find the error
|
|
253
|
+
(usually a forgotten partial-points term, un-de-vigged odds, or following
|
|
254
|
+
one book instead of the consensus), don't ship the tip.
|
|
255
|
+
|
|
256
|
+
Handed back to [`/prediction-pool`](../../commands/prediction-pool.md) for the approval
|
|
257
|
+
gate — the skill never enters or submits anything.
|
|
258
|
+
|
|
259
|
+
## Gotcha
|
|
260
|
+
|
|
261
|
+
- **Answering only the scores.** Bonus / award questions carry real points;
|
|
262
|
+
leaving them blank because they are "not a scoreline" forfeits them. The
|
|
263
|
+
step-1 checklist exists so every question is answered.
|
|
264
|
+
- **Following one portal.** A single book can be stale or shaded; build the
|
|
265
|
+
base from a sharp-weighted consensus across several; an outlier is a flag to
|
|
266
|
+
investigate, not a number to copy.
|
|
267
|
+
- **Tipping the modal result, not the EV-maximal one.** The single most likely
|
|
268
|
+
scoreline rarely maximizes partial points — run `score_ev.py` across the
|
|
269
|
+
result grid, don't eyeball the favourite.
|
|
270
|
+
- **Hand-picking a high scoreline.** 3:2 / 4:1 / 1:4 never EV-max under partial
|
|
271
|
+
points — moderate favourites peak at 1:0 / 2:0 / 2:1. A high tip = grid
|
|
272
|
+
skipped; run `score_ev.py`.
|
|
273
|
+
- **Under-tipping draws.** A correct draw banks the goal-difference tier on
|
|
274
|
+
every draw scoreline, so a close match can want 1:1 (or 0:0). Let the grid
|
|
275
|
+
decide; the eye tips too few draws.
|
|
276
|
+
- **"Rough Kelly" variance for a large pool.** Don't guess deviation amount —
|
|
277
|
+
run `pool_winsim.py`; returns the exact flips that raise P(finish 1st) most
|
|
278
|
+
per unit EV given up.
|
|
279
|
+
- **Forgetting to de-vig.** Raw bookmaker odds sum to >100%; treating them as
|
|
280
|
+
probabilities inflates the favourite. Remove the margin **per book** before
|
|
281
|
+
aggregating.
|
|
282
|
+
- **Contrarian under fixed points.** Deviating "to stand out" only helps under
|
|
283
|
+
quote/rarity rules or a win-a-large-pool goal — otherwise it burns EV.
|
|
284
|
+
- **Claimed-but-unrun simulation.** "I ran 10,000 tournaments" without
|
|
285
|
+
executing `poisson_sim.py` is hallucinated — run the code or use outright odds.
|
|
286
|
+
|
|
287
|
+
## Do NOT
|
|
288
|
+
|
|
289
|
+
- Leave any open pool question (bonus / award / special) unanswered.
|
|
290
|
+
- Build the base from a single bookmaker, or skip de-vigging before aggregating.
|
|
291
|
+
- Tip the most likely result instead of the EV-maximal one.
|
|
292
|
+
- Hand-pick a scoreline instead of running `score_ev.py` — never emit a
|
|
293
|
+
3:2 / 4:1 / 1:4 tip, never EV-max under partial points.
|
|
294
|
+
- Go contrarian under standard fixed-point scoring with a "place well" goal.
|
|
295
|
+
- Guess large-pool variance ("rough Kelly") instead of running `pool_winsim.py`.
|
|
296
|
+
- Report Monte-Carlo numbers without running `poisson_sim.py` / `pool_winsim.py`.
|
|
297
|
+
- Treat raw odds as probabilities without removing the vig.
|
|
298
|
+
- Give betting or financial advice — this optimizes a game; the human submits.
|
|
299
|
+
|
|
300
|
+
## See also
|
|
301
|
+
|
|
302
|
+
- [`/prediction-pool`](../../commands/prediction-pool.md) — the orchestrator (event,
|
|
303
|
+
persistence, Playwright entry, gates).
|
|
304
|
+
- [`reference/odds-and-bonus.md`](reference/odds-and-bonus.md) — major-book list
|
|
305
|
+
+ sharpness-weighted consensus recipe, and the bonus / award / special
|
|
306
|
+
question taxonomy with a per-type method.
|
|
307
|
+
- [`reference/ev-fixtures.md`](reference/ev-fixtures.md) — known-good
|
|
308
|
+
rules+odds → EV examples.
|
|
309
|
+
- [`scripts/prediction-pool/score_ev.py`](../../../../scripts/prediction-pool/score_ev.py) —
|
|
310
|
+
executed exact-score EV optimiser (step 4a; λ + rule → EV-max scoreline).
|
|
311
|
+
- [`scripts/prediction-pool/pool_winsim.py`](../../../../scripts/prediction-pool/pool_winsim.py) —
|
|
312
|
+
executed field model + P(finish 1st) simulator and flip-finder (step 4b).
|
|
313
|
+
- [`scripts/prediction-pool/poisson_sim.py`](../../../../scripts/prediction-pool/poisson_sim.py) —
|
|
314
|
+
the executed tournament simulator (step 5).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "prediction-pool-optimizer",
|
|
3
|
+
"description": "9 should-trigger + 5 should-not-trigger queries. Should-trigger covers DE + EN phrasings and the core intent (pool tips, kicktipp, expected-points optimization across sports, plus answering the bonus / award questions and using bookmaker-consensus odds). Should-not-trigger covers near-miss neighbours: regulated financial advice (finance pack), plain match-result prediction with no pool, generic web research, AI video, and real-money sportsbook betting (out of scope / refuse).",
|
|
4
|
+
"queries": [
|
|
5
|
+
{"q": "optimize my kicktipp tips for the football WM 2026", "trigger": true},
|
|
6
|
+
{"q": "fill my company Tippspiel for the basketball world cup", "trigger": true},
|
|
7
|
+
{"q": "welche Tipps maximieren meine Punkte im kicktipp-Tippspiel?", "trigger": true},
|
|
8
|
+
{"q": "best picks for our office prediction pool given the scoring rules", "trigger": true},
|
|
9
|
+
{"q": "maximiere meine erwarteten Punkte im Tippspiel, nicht nur wer gewinnt", "trigger": true},
|
|
10
|
+
{"q": "predict our office kicktipp pool for the WM", "trigger": true},
|
|
11
|
+
{"q": "mach mein Tippspiel für die WM", "trigger": true},
|
|
12
|
+
{"q": "beantworte auch alle Bonusfragen im kicktipp, z.B. welche Mannschaft den Torschützenkönig stellt", "trigger": true},
|
|
13
|
+
{"q": "use the odds from the big betting sites to optimize my pool picks", "trigger": true},
|
|
14
|
+
{"q": "should we invest in this startup based on a DCF?", "trigger": false, "note": "regulated financial valuation → dcf-modeling / finance pack"},
|
|
15
|
+
{"q": "who will win tonight's match?", "trigger": false, "note": "plain result prediction, no pool / no scoring rules to optimize"},
|
|
16
|
+
{"q": "research the best running shoes for me", "trigger": false, "note": "generic web research → research / deep-research"},
|
|
17
|
+
{"q": "make a hype video for the world cup final", "trigger": false, "note": "AI video pipeline → /video"},
|
|
18
|
+
{"q": "place a €50 bet on the favourite at my bookmaker", "trigger": false, "note": "real-money sportsbook wagering — out of scope, not what this fun pool tool does"}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# EV fixtures — known-good rules + odds → tip
|
|
2
|
+
|
|
3
|
+
Sanity-check fixtures for `prediction-pool-optimizer` Step "Self-check". Each
|
|
4
|
+
fixture states a scoring rule, the (de-vigged) market probabilities, and
|
|
5
|
+
the expected-points-maximizing tip. If your method disagrees with a
|
|
6
|
+
fixture, your method is wrong — find the error before shipping a tip.
|
|
7
|
+
|
|
8
|
+
These are illustrative, not exhaustive. Add fixtures for any pool rule
|
|
9
|
+
shape you encounter so future runs catch the same class of drift.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Fixture 1 — standard fixed points, goal "place well"
|
|
14
|
+
|
|
15
|
+
**Rule:** exact result = 4, goal-difference = 3, tendency = 2, else 0.
|
|
16
|
+
No quote rule. No strategy limit. Goal: place well.
|
|
17
|
+
|
|
18
|
+
**Match (football):** Poisson on market xG ≈ 1.7 : 0.8.
|
|
19
|
+
|
|
20
|
+
**Script-verified** (`score_ev.py --lh 1.7 --la 0.8 --exact 4 --diff 3 --tendency 2`):
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
EV-max tip : 1:0 (EV 1.574)
|
|
24
|
+
1:0 1.574 <- EV-max
|
|
25
|
+
2:1 1.530
|
|
26
|
+
2:0 1.477
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Reasoning:** top of the EV surface is **flat** — 1:0, 2:1, 2:0 all bank the
|
|
30
|
+
tendency (2) plus goal-difference (3) on many neighbours, within hundredths of
|
|
31
|
+
each other. Grid puts **1:0 narrowly first**; eyeballing the modal *result*
|
|
32
|
+
(2:1) lands a near-tie, not the optimum. Run the grid — don't assert the
|
|
33
|
+
favourite's "obvious" score.
|
|
34
|
+
|
|
35
|
+
**Known-good tip:** **1:0 home** (2:1 essentially tied; with the real de-vigged
|
|
36
|
+
λ either can lead — the grid decides). (Risk: low.) **Not** contrarian — under
|
|
37
|
+
fixed points only your own tip scores, so deviating costs EV.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Fixture 2 — quote / rarity scoring
|
|
42
|
+
|
|
43
|
+
**Rule:** points = base × rarity multiplier (rarer correct tips score
|
|
44
|
+
more); tendency still banks a small base.
|
|
45
|
+
|
|
46
|
+
**Match (football):** same probabilities as Fixture 1.
|
|
47
|
+
|
|
48
|
+
**Reasoning:** the rarity multiplier can make a plausible-but-uncommon
|
|
49
|
+
exact result (e.g. 3:1, 2:2) outscore the modal 2:1 when
|
|
50
|
+
`payout(result) × P(result)` is higher. Compute EV per candidate including
|
|
51
|
+
the multiplier; take the max.
|
|
52
|
+
|
|
53
|
+
**Known-good tip:** the result with the highest `multiplier × probability`,
|
|
54
|
+
**not** the highest probability — typically a step rarer than 2:1
|
|
55
|
+
(e.g. 3:1 or 2:2 depending on the multiplier curve). (Risk: medium.)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Fixture 3 — large pool, goal "win it"
|
|
60
|
+
|
|
61
|
+
**Rule:** standard fixed points. Pool N = 400. You are outside the top 20%.
|
|
62
|
+
|
|
63
|
+
**Match (football):** a near-coin-flip favourite, Home 52% / Draw 26% /
|
|
64
|
+
Away 22%.
|
|
65
|
+
|
|
66
|
+
**Reasoning:** N ≥ 100 and you behind → pure EV converges with the field, can't
|
|
67
|
+
create the gap; target is **P(finish 1st)**, not E(points). Don't guess the
|
|
68
|
+
variance: run `pool_winsim.py` with the pool's `N` and your `my_lead`. Shows
|
|
69
|
+
P(win) collapsing under EV-max-everywhere, returns the **specific flips**
|
|
70
|
+
(higher-variance scorelines on high-consensus matches) that raise P(win) most
|
|
71
|
+
per unit EV given up.
|
|
72
|
+
|
|
73
|
+
**Known-good tip:** EV-max on the safe matches; the **simulator's suggested
|
|
74
|
+
flips** on the 2–4 matches it names, to manufacture upside. (Risk: high —
|
|
75
|
+
intentional.) Verify the sim shows a P(win) gain — flips not moving it (small
|
|
76
|
+
N) → don't add variance you don't need.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Fixture 4 — basketball, no draws
|
|
81
|
+
|
|
82
|
+
**Rule:** correct winner = 3, correct margin bucket = +2.
|
|
83
|
+
|
|
84
|
+
**Match (basketball):** market spread Home −6.5, moneyline Home 78%.
|
|
85
|
+
Margin modelled Gaussian, mean ≈ 6.5, sd ≈ 11.
|
|
86
|
+
|
|
87
|
+
**Reasoning:** no draw term exists; optimize winner first (Home banks 3 at
|
|
88
|
+
78%), then the margin bucket from the Gaussian (most mass straddles the
|
|
89
|
+
spread). Tip the winner plus the modal margin bucket.
|
|
90
|
+
|
|
91
|
+
**Known-good tip:** **Home win, margin ~5–9.** (Risk: low on winner.)
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Fixture 5 — multi-book consensus (de-vig per book, sharp-weighted)
|
|
96
|
+
|
|
97
|
+
**Rule:** any — checks the **odds base**, not the EV map.
|
|
98
|
+
|
|
99
|
+
**Market (football, 1X2):** two books.
|
|
100
|
+
- Book S (sharp, weight 3): 1.80 / 3.60 / 4.50 → de-vig 0.526 / 0.263 / 0.210.
|
|
101
|
+
- Book R (recreational, weight 1): 1.75 / 3.50 / 4.20 → de-vig 0.522 / 0.261 / 0.217.
|
|
102
|
+
|
|
103
|
+
**Reasoning:** de-vig **each book** first (raw `1/o` sums to >1; normalise),
|
|
104
|
+
then sharp-weighted mean per outcome and renormalise. Aggregating raw odds, or
|
|
105
|
+
using one book, is wrong.
|
|
106
|
+
|
|
107
|
+
**Known-good base:** **Home 0.525 / Draw 0.262 / Away 0.212.** A run that fed
|
|
108
|
+
the EV grid one book's raw odds has the wrong base — fix it before the tip.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Fixture 6 — "team of the top scorer" (aggregate player market by team)
|
|
113
|
+
|
|
114
|
+
**Rule:** bonus question = 6 points: "which team supplies the tournament top
|
|
115
|
+
scorer?"
|
|
116
|
+
|
|
117
|
+
**Market (top-goalscorer outright, de-vigged player probabilities):**
|
|
118
|
+
- Team A: A1 14%, A2 5% → team A total **19%**.
|
|
119
|
+
- Team B: B1 16% → team B total **16%**.
|
|
120
|
+
- Team C: C1 9%, C2 4% → team C total **13%**.
|
|
121
|
+
|
|
122
|
+
**Reasoning:** the most-likely *player* (B1, 16%) is on team B, but the
|
|
123
|
+
question asks the **team** — sum each squad's players. Team A 19% beats team B
|
|
124
|
+
16%. Answer the asked question, not the adjacent one.
|
|
125
|
+
|
|
126
|
+
**Known-good answer:** **Team A.** (Source: market, aggregated by team. Risk:
|
|
127
|
+
medium.) **Not** team B — the modal-player trap.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Fixture 7 — high-scoreline trap (the "EV-optimized" model that wasn't)
|
|
132
|
+
|
|
133
|
+
**Rule:** kicktipp 2 / 3 / 5 — tendency = 2, goal-difference = 3, exact = 5.
|
|
134
|
+
|
|
135
|
+
**Matches (script-verified, `score_ev.py … --tendency 2 --diff 3 --exact 5`):**
|
|
136
|
+
|
|
137
|
+
| Match (λ) | EV-max | a high tip's EV | verdict |
|
|
138
|
+
|---|---|---|---|
|
|
139
|
+
| Senegal–Iraq (2.0:0.7) | **1:0** (1.881) | 4:1 ≈ 1.55 | high tip leaks ~0.33 |
|
|
140
|
+
| Qatar–Switzerland (0.6:2.1) | **0:1** (1.981) | 1:4 ≈ 1.65 | tipping the underdog's goals = costliest move on the board |
|
|
141
|
+
| Spain–CapeVerde (2.3:0.6) | **2:0** (2.033) | 3:1 ≈ 1.88 | only at λ ≳ 2.3 does 2:0 edge past 1:0; never higher |
|
|
142
|
+
|
|
143
|
+
**Reasoning:** under partial points the value sits in the tendency and
|
|
144
|
+
goal-difference tiers, not the exact high score. **1:0 is the optimum
|
|
145
|
+
astonishingly often** (even for clear favourites at λ ≈ 2.0); 2:0 takes over
|
|
146
|
+
only near λ ≈ 2.3–2.4; above that, never. **3:2 / 4:1 / 4:2 / 1:4 are never
|
|
147
|
+
EV-max.** Adding goals — especially the underdog's — only shrinks the hit
|
|
148
|
+
probability without protecting the diff/tendency points.
|
|
149
|
+
|
|
150
|
+
**Known-good behaviour:** any 3:2 / 4:x / x:4 tip in the run → the grid wasn't
|
|
151
|
+
run; `score_ev.py` is the gate. (Risk: low; correctness fixture, not strategy.)
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Fixture 8 — draws are under-tipped
|
|
156
|
+
|
|
157
|
+
**Rule:** kicktipp 2 / 3 / 5 (as Fixture 7).
|
|
158
|
+
|
|
159
|
+
**Matches (script-verified, `score_ev.py … --tendency 2 --diff 3 --exact 5`):**
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
λ 1.0:1.0 -> EV-max 0:0 (1.196), 1:1 tied (1.196) # a draw IS the optimum
|
|
163
|
+
λ 0.9:0.9 -> EV-max 0:0 (1.317), 1:1 second
|
|
164
|
+
λ 1.2:1.2 -> EV-max 1:0 (1.150), draw third (1.091) # 1-goal win edges it
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Reasoning:** people tip too few draws. A correct draw banks the
|
|
168
|
+
goal-difference tier (3) on *every* draw scoreline, so in a **low-scoring even
|
|
169
|
+
match (λ ≲ 1.0/side) the draw — usually 0:0 — is the EV-max**, tied with 1:1.
|
|
170
|
+
As λ rises past ~1.1 a one-goal win edges ahead, but the draw stays in the top
|
|
171
|
+
tips. Grid surfaces this; intuition suppresses it.
|
|
172
|
+
|
|
173
|
+
**Known-good behaviour:** a tip set with **near-zero draws across many
|
|
174
|
+
low-scoring even matches** is a red flag — re-run `score_ev.py`, let the grid
|
|
175
|
+
decide, don't default every close game to 1:0.
|