Enrichment waterfall planner
@gtmengineer/enrichment-waterfall-planner
Plan an enrichment waterfall with real math. Give it your providers with cost, match rate, and accuracy (or a sample test run), and it tries every order to find the cheapest setup that hits your fill target, with cost per usable record, the marginal cost of each step, and where to stop. Vendor-neutral.
- Activity
- New: be the first to try it
- Installs
- 0 installs
- Likes
- 0 likes
- Clones
- 0 clones
- 1{
- 2 "name": "enrichment-waterfall-planner",
- 3 "owner": "gtmengineer",
- 4 "version": "1.0.0",
- 5 "type": "skill",
- 6 "description": "Plan an enrichment waterfall with real math. Give it your providers with cost, match rate, and accuracy (or a sample test run), and it tries every order to find the cheapest setup that hits your fill target, with cost per usable record, the marginal cost of each step, and where to stop. Vendor-neutral.",
- 7 "category": "data",
- 8 "license": "MIT",
- 9 "compat": [
- 10 "claude-code"
- 11 ],
- 12 "permissions": {
- 13 "shell": [
- 14 "node scripts/waterfall.mjs"
- 15 ],
- 16 "files": {
- 17 "read": [
- 18 "./data/**"
- 19 ],
- 20 "write": [
- 21 "./data/**",
- 22 "./out/**"
- 23 ]
- 24 }
- 25 },
- 26 "tests": {
- 27 "cases": [
- 28 {
- 29 "name": "estimated rates with verification and a fill target",
- 30 "inputs": {
- 31 "data/providers.json": "{\n \"data_point\": \"verified work email\",\n \"records\": 10000,\n \"min_fill_rate\": 0.7,\n \"max_cost_per_record\": 1.0,\n \"verify\": { \"cost\": 0.004 },\n \"providers\": [\n { \"name\": \"provider-a\", \"cost\": 0.08, \"charge\": \"per_lookup\", \"match_rate\": 0.45, \"accuracy\": 0.92 },\n { \"name\": \"provider-b\", \"cost\": 0.30, \"charge\": \"per_match\", \"match_rate\": 0.55, \"accuracy\": 0.97 },\n { \"name\": \"provider-c\", \"cost\": 0.03, \"charge\": \"per_lookup\", \"match_rate\": 0.25, \"accuracy\": 0.80 },\n { \"name\": \"provider-d\", \"cost\": 0.50, \"charge\": \"per_match\", \"match_rate\": 0.35, \"accuracy\": 0.99 }\n ]\n}\n"
- 32 },
- 33 "checks": [
- 34 {
- 35 "type": "command_exits_zero",
- 36 "command": "node scripts/waterfall.mjs data/providers.json --out out"
- 37 },
- 38 {
- 39 "type": "file_contains",
- 40 "path": "out/waterfall.md",
- 41 "text": "**Recommended order: provider-c > provider-a > provider-b**"
- 42 },
- 43 {
- 44 "type": "output_matches_schema",
- 45 "path": "out/waterfall.json",
- 46 "schema": {
- 47 "type": "object",
- 48 "required": [
- 49 "recommended",
- 50 "best_by_depth",
- 51 "provider_rates"
- 52 ],
- 53 "properties": {
- 54 "recommended": {
- 55 "type": "object",
- 56 "properties": {
- 57 "order": {
- 58 "const": [
- 59 "provider-c",
- 60 "provider-a",
- 61 "provider-b"
- 62 ]
- 63 },
- 64 "fill_rate": {
- 65 "const": 0.781
- 66 },
- 67 "total_cost": {
- 68 "const": 1748.23
- 69 },
- 70 "steps": {
- 71 "type": "array",
- 72 "minItems": 3,
- 73 "maxItems": 3
- 74 }
- 75 }
- 76 },
- 77 "best_by_depth": {
- 78 "type": "array",
- 79 "minItems": 4,
- 80 "maxItems": 4
- 81 }
- 82 }
- 83 }
- 84 }
- 85 ]
- 86 },
- 87 {
- 88 "name": "rates and overlap measured from a sample run",
- 89 "inputs": {
- 90 "data/providers.json": "{\n \"data_point\": \"verified work email\",\n \"records\": 10000,\n \"min_fill_rate\": 0.7,\n \"max_cost_per_record\": 1.0,\n \"verify\": { \"cost\": 0.004 },\n \"providers\": [\n { \"name\": \"provider-a\", \"cost\": 0.08, \"charge\": \"per_lookup\", \"match_rate\": 0.45, \"accuracy\": 0.92 },\n { \"name\": \"provider-b\", \"cost\": 0.30, \"charge\": \"per_match\", \"match_rate\": 0.55, \"accuracy\": 0.97 },\n { \"name\": \"provider-c\", \"cost\": 0.03, \"charge\": \"per_lookup\", \"match_rate\": 0.25, \"accuracy\": 0.80 },\n { \"name\": \"provider-d\", \"cost\": 0.50, \"charge\": \"per_match\", \"match_rate\": 0.35, \"accuracy\": 0.99 }\n ]\n}\n",
- 91 "data/sample.csv": "record_id,provider-a,provider-b,provider-c,provider-d\n1,x,x,,x\n2,x,,x,\n3,,x,,x\n4,,x,x,\n5,x,x,,\n6,,,x,x\n7,,,,\n8,x,x,x,x\n9,,x,,\n10,,,,x\n"
- 92 },
- 93 "checks": [
- 94 {
- 95 "type": "command_exits_zero",
- 96 "command": "node scripts/waterfall.mjs data/providers.json --sample data/sample.csv --out out"
- 97 },
- 98 {
- 99 "type": "output_matches_schema",
- 100 "path": "out/waterfall.json",
- 101 "schema": {
- 102 "type": "object",
- 103 "properties": {
- 104 "source": {
- 105 "const": "sample of 10 records"
- 106 },
- 107 "recommended": {
- 108 "type": "object",
- 109 "properties": {
- 110 "fill_rate": {
- 111 "const": 0.771
- 112 },
- 113 "total_cost": {
- 114 "const": 1591.9
- 115 }
- 116 }
- 117 },
- 118 "provider_rates": {
- 119 "type": "array",
- 120 "items": {
- 121 "type": "object",
- 122 "required": [
- 123 "name",
- 124 "match_rate"
- 125 ]
- 126 }
- 127 }
- 128 }
- 129 }
- 130 }
- 131 ]
- 132 },
- 133 {
- 134 "name": "no target: cheap per-lookup provider goes before the per-match one",
- 135 "inputs": {
- 136 "data/p.json": "{\"records\":100,\"providers\":[{\"name\":\"pricey-per-match\",\"cost\":1,\"charge\":\"per_match\",\"match_rate\":0.5},{\"name\":\"cheap-per-lookup\",\"cost\":0.1,\"charge\":\"per_lookup\",\"match_rate\":0.5}]}"
- 137 },
- 138 "checks": [
- 139 {
- 140 "type": "command_exits_zero",
- 141 "command": "node scripts/waterfall.mjs data/p.json --out out"
- 142 },
- 143 {
- 144 "type": "output_matches_schema",
- 145 "path": "out/waterfall.json",
- 146 "schema": {
- 147 "type": "object",
- 148 "properties": {
- 149 "verification": {
- 150 "const": false
- 151 },
- 152 "recommended": {
- 153 "type": "object",
- 154 "properties": {
- 155 "order": {
- 156 "const": [
- 157 "cheap-per-lookup",
- 158 "pricey-per-match"
- 159 ]
- 160 },
- 161 "fill_rate": {
- 162 "const": 0.75
- 163 },
- 164 "total_cost": {
- 165 "const": 35
- 166 }
- 167 }
- 168 }
- 169 }
- 170 }
- 171 }
- 172 ]
- 173 }
- 174 ]
- 175 }
- 176}
