1/* SABLE_COMPUTE â every figure the Wine Program Diagnostic displays. V3. 2 3 The web preview, the printed five-page PDF and all four supporting schedules 4 call this and render what comes back. Nothing downstream states a count, a 5 percentage or a dollar amount of its own. 6 7 Four rules this module exists to enforce: 8 9 1. NO MIXED-BASIS TOTAL. Every money figure carries a value basis, and 10 figures on different bases are never summed. There is deliberately no 11 grand total, because there is no honest way to compute one. 12 13 2. FOUR SEPARATE POPULATIONS, never conflated: 14 resolved records â wines in the Cellar Record 15 held source rows â source rows that never became a record 16 unreferenced resolved wines â in the Record, no qualifying comparable 17 operational exceptions â list, bin and posting problems 18 They are different things that happen to be countable. 19 20 3. DE-DUPLICATION IS BY RECORD ID. Finding appearances, distinct records and 21 distinct bottles are three different numbers, all reported separately. 22 23 4. EVIDENCE CANNOT BE MANUFACTURED. A document the program can send may 24 clarify identity, vintage, format, provenance, cost or condition. It does 25 not create a market comparable. Those are two different columns. */ 26(function () { 27 'use strict'; 28 29 var BASIS = { 30 cost: 'Cost basis', 31 grossList: 'Gross list value', 32 listGap: 'Aggregate list-price gap to house protocol', 33 market: 'Market-referenced value', 34 replacement: 'Replacement value', 35 nrv: 'Estimated seller net proceeds', 36 excess: 'Excess exposure above house protocol', 37 }; 38 39 var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 40 'August', 'September', 'October', 'November', 'December']; 41 42 /* Readable dates on every customer-facing surface. */ 43 function longDate(iso) { 44 if (!iso) return ''; 45 var p = String(iso).split('-'); 46 if (p.length !== 3) return iso; 47 return MONTHS[Number(p[1]) - 1] + ' ' + Number(p[2]) + ', ' + p[0]; 48 } 49 function monthYear(iso) { 50 if (!iso) return ''; 51 var p = String(iso).split('-'); 52 return p.length >= 2 ? MONTHS[Number(p[1]) - 1] + ' ' + p[0] : iso; 53 } 54 55 function label(w) { 56 var parts = [w.producer]; 57 if (w.cuvee_or_vineyard) parts.push(w.cuvee_or_vineyard); 58 parts.push(w.appellation, String(w.vintage)); 59 if (w.format_ml !== 750) parts.push(w.format_ml >= 1000 ? (w.format_ml / 1000) + 'L' : w.format_ml + 'ml'); 60 return parts.join(' \u00b7 '); 61 } 62 function sum(arr, fn) { return arr.reduce(function (a, x) { return a + (fn(x) || 0); }, 0); } 63 function uniq(arr) { return Object.keys(arr.reduce(function (a, k) { a[k] = 1; return a; }, {})); } 64 function pct(n, d) { return d ? Math.round((n / d) * 1000) / 10 : 0; } 65 function plural(n, one, many) { return n + ' ' + (n === 1 ? one : (many || one + 's')); } 66 67 window.SABLE_COMPUTE = function (D) { 68 var P = D.program, W = D.wines, byId = {}; 69 W.forEach(function (w) { byId[w.wine_id] = w; }); 70 71 var SERVICE_ROLES = ['active', 'reserve', 'btg', 'pairing']; 72 73 /* ââ The house pricing protocol âââââââââââââââââââââââââââââââââââââ */ 74 75 function targetMultiple(w) { 76 if (w.format_ml !== 750) return P.large_format_target_multiple; 77 for (var i = 0; i < P.pricing_bands.length; i++) { 78 if (w.cost_per_bottle < P.pricing_bands[i].max_cost) return P.pricing_bands[i].target_multiple; 79 } 80 return P.pricing_bands[P.pricing_bands.length - 1].target_multiple; 81 } 82 W.forEach(function (w) { 83 w.target_multiple = targetMultiple(w); 84 w.target_list_price = Math.round(w.cost_per_bottle * w.target_multiple); 85 w.gross_list_value = (w.current_list_price || 0) * w.quantity; 86 /* Materiality floor: the target must exceed the current price by at least 87 10% before it is a pricing decision rather than a rounding difference. */ 88 var material = w.current_list_price > 0 && w.target_list_price >= w.current_list_price * 1.1; 89 w.list_price_gap = (w.list_status === 'listed' && material && w.quantity > 0) 90 ? Math.max(0, (w.target_list_price - w.current_list_price) * w.quantity) : 0; 91 }); 92 93 /* ââ Four populations, kept apart (P0.1) ââââââââââââââââââââââââââââ */ 94 95 /* Three populations. Grade C keeps its reference and stays visible, and it 96 contributes to no market-referenced total until the vintage-adjustment 97 method is open to independent review. */ 98 var referenced = W.filter(function (w) { return w.market_eligible && w.market_reference_value != null; }); 99 var indicative = W.filter(function (w) { return w.indicative_only; });
100 var unreferenced_resolved = W.filter(function (w) { return !w.market_eligible; }); 101 var held_source_rows = sum(D.held_source_rows, function (h) { return h.count; }); 102 103 var bottle_count = sum(W, function (w) { return w.quantity; }); 104 var cellar_master_rows = D.source_files.filter(function (f) { return f[0] === 'SRC-1'; })[0][2]; 105 var source_set_count = D.source_files.length; 106 107 /* ââ The printed list, and three separate match measures (P0.5) âââââ */ 108 109 var overrides = {}; 110 D.list.forEach(function (l) { if (l.wine_id) overrides[l.wine_id] = l; }); 111 var printed = []; 112 W.forEach(function (w) { 113 if (w.list_status !== 'listed') return; 114 if (overrides[w.wine_id]) { printed.push(overrides[w.wine_id]); return; } 115 printed.push({ list_record_id: 'L-' + w.wine_id, wine_id: w.wine_id, printed_producer: w.producer, 116 printed_wine: w.cuvee_or_vineyard || w.appellation, 117 printed_vintage: w.printed_vintage_override != null ? w.printed_vintage_override : w.vintage, 118 printed_format: w.format_ml, printed_price: w.current_list_price, section: w.region, 119 active_status: 'active', 120 match_status: w.quantity === 0 ? 'no_stock' 121 : w.printed_vintage_override != null ? 'vintage_mismatch' : 'matched' }); 122 }); 123 D.list.forEach(function (l) { if (!l.wine_id) printed.push(l); }); 124 125 var active = printed.filter(function (l) { return l.active_status === 'active'; }); 126 127 /* Definitions, stated so the denominators are not a mystery: 128 IDENTITY â the entry is linked to a Cellar Record. A zero-stock wine and 129 a vintage mismatch both still count as identity matches. 130 AVAILABLE â linked AND at least one bottle in the Record. 131 EXACT â linked AND the printed wine, vintage and format all agree. 132 A printed NV against a declared vintage is NOT exact. */ 133 var identity = active.filter(function (l) { return !!l.wine_id && !!byId[l.wine_id]; }); 134 var available = identity.filter(function (l) { return byId[l.wine_id].quantity > 0; }); 135 var exact = identity.filter(function (l) { 136 var w = byId[l.wine_id]; 137 return l.printed_vintage === w.vintage && (l.printed_format || 750) === w.format_ml; 138 }); 139 140 /* Non-exact splits two ways. A printed NV against a declared vintage is a 141 vintage failure; a printed format that is not the format in the Record is 142 a format failure. Reported separately so the parts sum to the whole. */ 143 var vintage_off = identity.filter(function (l) { return l.printed_vintage !== byId[l.wine_id].vintage; }); 144 var format_off = identity.filter(function (l) { 145 return l.printed_vintage === byId[l.wine_id].vintage && (l.printed_format || 750) !== byId[l.wine_id].format_ml; 146 }); 147 var list_no_stock = active.filter(function (l) { return l.match_status === 'no_stock'; }); 148 var list_unmatched = active.filter(function (l) { return l.match_status === 'unmatched'; }); 149 var list_vintage_mismatch = active.filter(function (l) { return l.match_status === 'vintage_mismatch'; }); 150 151 var absent_from_list = W.filter(function (w) { 152 return SERVICE_ROLES.indexOf(w.program_role) > -1 && w.list_status !== 'listed' && w.quantity > 0; 153 }); 154 155 var binMap = {}; 156 W.forEach(function (w) { 157 var k = w.storage_location + '|' + w.bin; 158 (binMap[k] = binMap[k] || []).push(w); 159 }); 160 var bin_collisions = Object.keys(binMap).filter(function (k) { return binMap[k].length > 1; }) 161 .map(function (k) { return { location: k.split('|')[0], bin: k.split('|')[1], wines: binMap[k] }; }); 162 163 var unposted_receiving = D.pending.filter(function (p) { return p.kind === 'receiving'; }); 164 var unposted_depletion = D.pending.filter(function (p) { return p.kind === 'depletion'; }); 165 166 var metrics = { 167 source_set_count: source_set_count, 168 cellar_master_rows: cellar_master_rows, 169 wine_record_count: W.length, 170 bottle_count: bottle_count, 171 storage_location_count: P.storage_locations.length, 172 held_source_row_count: held_source_rows, 173 unreferenced_resolved_count: unreferenced_resolved.length, 174 active_list_count: active.length, 175 identity_match_count: identity.length, 176 identity_match_pct: pct(identity.length, active.length), 177 availability_match_count: available.length, 178 availability_match_pct: pct(available.length, active.length), 179 exact_match_count: exact.length, 180 exact_match_pct: pct(exact.length, active.length), 181 vintage_mismatch_count: vintage_off.length, 182 format_mismatch_count: format_off.length, 183 non_exact_count: active.length - exact.length, 184 unreferenced_no_stock_count: 0, 185 evidence_referenced_count: referenced.length, 186 evidence_coverage_percentage: pct(referenced.length, W.length), 187 expected_cover_count: P.expected_cover_count, 188 merged_record_count: W.filter(function (w) { return (w.rows_consumed || 1) > 1; }).length, 189 }; 190 191 /* ââ Exceptions, by category (P0.6) âââââââââââââââââââââââââââââââââ */ 192 193 var ex_list = []; 194 list_no_stock.forEach(function (l) { 195 var w = byId[l.wine_id]; 196 ex_list.push({ category: 'Guest-list accuracy', wine_id: l.wine_id, wine: label(w), 197 state: 'On the list at $' + l.printed_price + ', no bottles in the Record', 198 evidence: 'Printed list section ' + l.section + '; Record shows quantity 0 at ' + w.bin, 199 consequence: 'A guest can order it. The floor finds out at the table.', 200 action: 'Remove from the list, or confirm stock before the next seating' }); 201 }); 202 list_unmatched.forEach(function (l) { 203 ex_list.push({ category: 'Guest-list accuracy', wine_id: null, 204 wine: l.printed_producer + ' \u00b7 ' + l.printed_wine + ' \u00b7 ' + l.printed_vintage,
205 state: 'Printed on the list, no matching record in the cellar', 206 evidence: 'List record ' + l.list_record_id + '; no producer-and-cuvée match in the cellar master', 207 consequence: 'Either the wine is in the Record under another name, or the list is selling something the cellar does not hold.', 208 action: 'Confirm which. Held open until someone answers it.' }); 209 }); 210 list_vintage_mismatch.forEach(function (l) { 211 var w = byId[l.wine_id]; 212 ex_list.push({ category: 'Guest-list accuracy', wine_id: l.wine_id, wine: label(w), 213 state: 'List prints ' + (l.printed_vintage || 'NV') + ', Record holds ' + w.vintage, 214 evidence: 'List record ' + l.list_record_id + ' against Record ' + w.wine_id + ' at ' + w.bin, 215 consequence: 'The vintage on the table will not match the vintage on the list. At $' + l.printed_price + ', a guest notices.', 216 action: 'Reprint the entry or correct the Record â whichever is wrong' }); 217 }); 218 /* Distinct entries, not the sum of category rows: one printed entry can be 219 both unavailable and printed at the wrong vintage. */ 220 var listKeys = uniq(ex_list.map(function (e) { return e.wine_id || e.wine; })); 221 var ex_bin = bin_collisions.map(function (c) { 222 return { category: 'Bin collision', wine_id: c.wines[0].wine_id, wine: c.wines.map(label).join(' / '), 223 state: 'Two records claim bin ' + c.bin + ' in the ' + c.location.toLowerCase(), 224 evidence: 'Cellar master export, both rows carry ' + c.bin, 225 consequence: 'A runner sent to that bin brings back the wrong bottle, and the count that follows is wrong twice.', 226 action: 'Walk the bin and assign one record to it' }; 227 }); 228 var ex_posting = D.pending.map(function (p) { 229 var w = byId[p.wine_id]; 230 return { category: 'Unposted movement', wine_id: p.wine_id, wine: label(w), 231 state: p.kind === 'receiving' ? p.bottles + ' bottles received, not in the Record' : p.bottles + ' bottles poured, not written back', 232 evidence: p.evidence, consequence: p.consequence, 233 action: p.kind === 'receiving' ? 'Write the receiving line against ' + w.bin : 'Record the depletion and re-check coverage' }; 234 }); 235 236 /* ââ Service coverage, alternate-aware (P0.7) âââââââââââââââââââââââ */ 237 238 var pours = P.pours_per_bottle; 239 var bottles_required = Math.ceil(P.expected_cover_count / pours); 240 241 /* A wine used as primary on one course is not free to cover another. Claim 242 primary demand first, then see what the alternate has left. */ 243 var claimed = {}; 244 D.coverage.forEach(function (c) { 245 if (!c.primary_wine_id) return; 246 claimed[c.primary_wine_id] = (claimed[c.primary_wine_id] || 0) + bottles_required; 247 }); 248 var coverage = D.coverage.map(function (c) { 249 var w = c.primary_wine_id ? byId[c.primary_wine_id] : null; 250 var alt = c.alternate_wine_id ? byId[c.alternate_wine_id] : null; 251 var have = w ? w.quantity : 0; 252 var shortfall = w ? Math.max(0, bottles_required - have) : bottles_required; 253 /* Spare after the alternate has served its OWN course. A course pours one 254 wine, so an alternate that covers this course pours the full cover 255 requirement here â not merely the primary's shortfall. */ 256 var altSpare = alt ? alt.quantity - (claimed[alt.wine_id] || 0) : 0; 257 var altRemaining = alt ? altSpare - bottles_required : null; 258 var status, action, optional_buy = 0, required_buy = 0; 259 if (!w) { 260 status = 'assignment_open'; 261 action = 'Pairing assignment remains open. Select and record a cellar-backed pairing before service.'; 262 } else if (!shortfall) { 263 status = 'covered'; 264 action = 'Covered at ' + P.expected_cover_count + ' covers'; 265 } else if (altSpare >= bottles_required) { 266 status = 'primary_short_alternate_covers'; 267 optional_buy = shortfall; 268 action = 'Primary pairing short by ' + plural(shortfall, 'bottle') + '; the approved alternate covers both courses with ' 269 + plural(altRemaining, 'bottle') + ' remaining. Buy ' + shortfall + ' only to preserve the intended pairing.'; 270 } else { 271 status = 'short'; 272 required_buy = shortfall - Math.max(0, altSpare);
273 action = 'Short by ' + plural(shortfall, 'bottle') + ' with no alternate cover. Buy ' + required_buy + ' or change the pairing.'; 274 } 275 return { menu_course_id: c.menu_course_id, dish: c.dish, wine: w ? label(w) : null, wine_id: c.primary_wine_id, 276 bin: w ? w.bin : null, bottles_required: bottles_required, bottles_available: have, 277 alternate: alt ? label(alt) : null, alternate_available: alt ? alt.quantity : null, 278 alternate_spare: alt ? altSpare : null, alternate_remaining_after_both: altRemaining, 279 coverage_status: status, 280 optional_buy: optional_buy, required_buy: required_buy, 281 btg_or_pairing_status: w ? w.role_label : '\u2014', action: action }; 282 }); 283 var assignment_open_count = coverage.filter(function (c) { return c.coverage_status === 'assignment_open'; }).length; 284 var primary_short_count = coverage.filter(function (c) { return c.coverage_status === 'primary_short_alternate_covers'; }).length; 285 var program_short_count = coverage.filter(function (c) { return c.coverage_status === 'short'; }).length; 286 var covered_count = coverage.filter(function (c) { return c.coverage_status === 'covered'; }).length; 287 var optional_buy_total = sum(coverage, function (c) { return c.optional_buy; }); 288 var required_buy_total = sum(coverage, function (c) { return c.required_buy; }); 289 var btg_below_par = W.filter(function (w) { 290 return (w.program_role === 'btg' || w.program_role === 'pairing') && w.quantity < P.btg_par_bottles; 291 }); 292 293 /* ââ Findings âââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 294 295 var f1 = W.filter(function (w) { 296 return w.house_service_window_end && w.house_service_window_end < P.effective_date 297 && SERVICE_ROLES.indexOf(w.program_role) > -1 && w.quantity > 0; 298 }); 299 var f2 = W.filter(function (w) { 300 return D.intentionally_inactive.indexOf(w.program_role) === -1 && w.quantity > 0 301 && (!w.last_depletion_date || w.last_depletion_date < P.inactivity_cutoff_date); 302 }); 303 304 var groups = {}; 305 referenced.forEach(function (w) { 306 if (!w.allocation_group) return; 307 (groups[w.allocation_group] = groups[w.allocation_group] || []).push(w); 308 }); 309 var market_total = sum(referenced, function (w) { return w.market_reference_value * w.quantity; }); 310 var total_depletion_12m = sum(W, function (w) { return w.depletion_12_months; }); 311 var total_gross_list = sum(W, function (w) { return w.gross_list_value; }); 312 var f3groups = Object.keys(groups).map(function (g) { 313 var ws = groups[g]; 314 var exposure = sum(ws, function (w) { return w.market_reference_value * w.quantity; }); 315 var threshold_value = Math.round(market_total * (P.allocation_threshold_pct / 100)); 316 var bottles = sum(ws, function (w) { return w.quantity; }); 317 var dep = sum(ws, function (w) { return w.depletion_12_months; }); 318 return { group: g, wines: ws, wine_count: ws.length, bottle_count: bottles, 319 exposure: exposure, share_pct: pct(exposure, market_total), 320 threshold_pct: P.allocation_threshold_pct, threshold_value: threshold_value, 321 excess: Math.max(0, exposure - threshold_value), 322 cost_basis: sum(ws, function (w) { return w.total_cost_basis; }), 323 gross_list_value: sum(ws, function (w) { return w.gross_list_value; }), 324 depletion_12_months: dep, 325 months_of_supply: dep > 0 ? Math.round((bottles / (dep / 12)) * 10) / 10 : null, 326 depletion_share_pct: pct(dep, total_depletion_12m), 327 list_share_pct: pct(sum(ws, function (w) { return w.gross_list_value; }), total_gross_list), 328 annual_allocation: (ws.filter(function (w) { return !!w.allocation_status; })[0] || {}).allocation_status || 'Standing allocation', 329 next_offer: P.allocation_next_offer_date }; 330 }).filter(function (g) { return g.share_pct > g.threshold_pct; }); 331 var f3 = f3groups.reduce(function (a, g) { return a.concat(g.wines); }, []); 332 333 var underReview = {}; 334 f1.concat(f2).forEach(function (w) { underReview[w.wine_id] = 1; }); 335 /* Seller net is withheld unless a cost profile supports it. No universal rate. */ 336 var sellerProfile = P.seller_cost_profile || { status: 'unavailable' }; 337 var sellerNetAvailable = sellerProfile.status === 'configured' || sellerProfile.status === 'demo'; 338 var f4 = (sellerNetAvailable ? referenced : []).filter(function (w) { 339 return underReview[w.wine_id] && w.estimated_net_realisable_value != null 340 && w.estimated_net_realisable_value < w.total_cost_basis; 341 }); 342 /* Every resolved wine with no qualifying comparable, whether or not bottles 343 remain on hand. Filtering by quantity here is what made page 3 disagree 344 with pages 1 and 4. */ 345 var f5 = unreferenced_resolved; 346 var f5_no_stock = f5.filter(function (w) { return w.quantity === 0; }).length; 347 var f6 = W.filter(function (w) { return w.list_price_gap > 0; }); 348 349 function money(ws, key) { return sum(ws, function (w) { return w[key]; }); } 350 function marketOf(ws) { return sum(ws, function (w) { return (w.market_reference_value || 0
350) * w.quantity; }); } 351 function bottles(ws) { return sum(ws, function (w) { return w.quantity; }); } 352 var nrvNote = 'Rates are demonstration assumptions: the all-in reference is normalized to a hammer-price equivalent, then ' 353 + Math.round(P.nrv_assumptions.seller_commission * 100) + '% seller commission, ' 354 + Math.round(P.nrv_assumptions.insurance_rate * 100) + '% insurance and $' 355 + P.nrv_assumptions.seller_transport_per_bottle.toFixed(2) + ' a bottle seller-paid transport come off. No buyer premium is deducted â the buyer pays it.'; 356 357 var findings = [ 358 { finding_id: 'F1', internal_id: 'past-window', category: 'service_window', 359 heading: 'Outside the house-defined service window \u2014 review required', 360 wines: f1, distinct_record_count: f1.length, distinct_bottle_count: bottles(f1), 361 amounts: [{ basis: BASIS.market, label: 'MARKET-REFERENCED VALUE AFFECTED', value: marketOf(f1) }], 362 body: 'These wines have passed the service-window dates currently recorded in the Cellar Record. Aivin is not making a condition judgment from vintage alone.', 363 evidence: 'House service-window end dates in the Record, against an effective date of ' + longDate(P.effective_date) + '. ' + P.house_protocol_version + '.', 364 why: 'A wine still on the active list past its own house window is a decision nobody has made yet, and the list keeps selling it in the meantime.', 365 action: 'Review condition and choose the program role: retain as library stock, feature in a pairing or flight, reprice, reclassify or remove from active service.', 366 timing: 'This week', schedule: 'Clean Cellar Record' }, 367 368 { finding_id: 'F2', internal_id: 'dead-stock', category: 'inactivity', 369 heading: 'No movement in twelve months \u2014 review against program role', 370 wines: f2, distinct_record_count: f2.length, distinct_bottle_count: bottles(f2), 371 amounts: [{ basis: BASIS.cost, label: 'COST BASIS', value: money(f2, 'total_cost_basis') }, 372 { basis: BASIS.grossList, label: 'GROSS LIST VALUE REPRESENTED BY INACTIVE INVENTORY', value: money(f2, 'gross_list_value') }], 373 body: 'These wines have had no recorded depletion since ' + longDate(P.inactivity_cutoff_date) + ' after excluding library, allocation-hold, owner-hold, event-only and other intentionally inactive stock.', 374 evidence: 'Depletion history from the point-of-sale and purchasing records, filtered by the program role recorded against each wine.', 375 why: 'Cost basis sitting still is capital the program has already committed. Gross list value is what the same bottles are priced at today, not a forecast of what they will earn.', 376 action: 'Review price, placement and program role. Credible paths may include the guest list, reserve list, pairing, flight, BTG, private event, continued library hold or removal from active inventory.', 377 timing: 'This month', schedule: 'Clean Cellar Record' }, 378 379 { finding_id: 'F3', internal_id: 'producer-concentration', category: 'allocation', 380 heading: 'Allocation concentration \u2014 review before the next offer', 381 wines: f3, distinct_record_count: f3.length, distinct_bottle_count: bottles(f3), groups: f3groups, 382 amounts: [{ basis: BASIS.market, label: 'TOTAL MARKET-REFERENCED EXPOSURE', value: sum(f3groups, function (g) { return g.exposure; }) }, 383 { basis: BASIS.excess, label: 'EXCESS ABOVE HOUSE PROTOCOL', value: sum(f3groups, function (g) { return g.excess; }) }], 384 body: 'The concentration may be intentional. The decision is whether the current position still reflects the program\u2019s buying strategy before the next allocation is accepted.', 385 evidence: 'Market-referenced exposure by allocation group against the ' + P.allocation_threshold_pct + '% threshold in ' + P.house_protocol_version + ', read alongside trailing twelve-month depletion.', 386 why: 'Concentration is not automatically a risk. Held against velocity it is either a position the program chose or one it drifted into, and those call for different answers.', 387 action: 'Review the position against the buying strategy before the next allocation is accepted. Reduce, hold, protect or increase are all legitimate conclusions.', 388 timing: 'Before the next allocation', schedule: 'Clean Cellar Record' }, 389 390 { finding_id: 'F4', internal_id: 'secondary-market', category: 'nrv', 391 heading: 'Secondary-market disposition is not economical on the current assumptions', 392 wines: f4, distinct_record_count: f4.length, distinct_bottle_count: bottles(f4), 393 amounts: [{ basis: BASIS.cost, label: 'COST BASIS', value: money(f4, 'total_cost_basis') }, 394 { basis: BASIS.nrv, label: 'ESTIMATED SELLER NET PROCEEDS', value: money(f4, 'estimated_net_realisable_value') }], 395 body: 'Estimated net proceeds do not justify secondary-market disposition under the current assumptions. That does not determine the wine\u2019s service value.', 396 evidence: 'Hammer-price equivalent less seller-side costs only. ' + nrvNote, 397 why: 'Resale is one exit among several, and on these wines it is the weakest one. The service value is unaffected by that.', 398 action: 'Compare the credible program paths: retain, reprice, feature, move to a flight or BTG position, use for an event, transfer within the group where permitted, or remove from active inventory.', 399 timing: 'This month', schedule: 'Clean Cellar Record' }, 400 401 { finding_id: 'F5', internal_id: 'no-reference', category: 'unreferenced', 402 heading: 'No qualifying wine-vintage-format market reference', 403 wines: f5, distinct_record_count: f5.length, distinct_bottle_count: bottles(f5), 404 amounts: [{ basis: BASIS.cost, label: 'COST BASIS EXCLUDED FROM MARKET-REFERENCED TOTALS', value: money(f5, 'total_cost_basis') }], 405 body: 'Aivin found no comparable it can defend for these wines at this wine, vintage and format. They remain visible at known cost basis and are excluded from every market-referenced total.', 406 evidence: 'Reference grading against the published Aivin methodology. Grade D and the dash carry no qualifying comparable at the wine, vintage and format in the Record.', 407 why: 'A program with unreferenced wine is normal. A program whose totals quietly include a guess is the problem this avoids.', 408 action: 'The open-question schedule names what the program can clarify and, separately, what would still be required for market eligibility. For some wines nothing the program holds can create a comparable.', 409 timing: 'When convenient', schedule: 'Open-question schedule' }, 410 411 { finding_id: 'F6', internal_id: 'pricing-gap', category: 'pricing', 412 heading: 'Pricing and list opportunities', 413 wines: f6, distinct_record_count: f6.length, distinct_bottle_count: bottles(f6), 414 amounts: [{ basis: BASIS.listGap, label: 'AGGREGATE LIST-PRICE GAP TO HOUSE PROTOCOL', value: money(f6, 'list_price_gap') }], 415 body: 'These wines sit below the banded target relationship to cost in the house protocol. Several are moving well at the current price, which is the argument for reviewing the position rather than the wine.', 416 evidence: 'Target list price under the banded Sable Reserve protocol, less current list price, times bottles on hand. ' + P.pricing_protocol_note, 417 why: 'This is an illustrative gross list-price gap, not a revenue forecast. Realized revenue depends on depletion after any price change.', 418 action: 'Review the list position against depletion. Where a wine is moving and underpriced, the price is the decision; where it is underpriced and static, the placement is.', 419 timing: 'This month', schedule: 'Clean Cellar Record' }, 420 ]; 421
422 findings.forEach(function (f) { 423 f.wine_ids = f.wines.map(function (w) { return w.wine_id; }); 424 f.finding_appearance_count = f.wines.length; 425 }); 426 var suppressed = findings.filter(function (f) { return f.wine_ids.length === 0; }).map(function (f) { return f.finding_id; }); 427 findings = findings.filter(function (f) { return f.wine_ids.length > 0; }); 428 429 /* De-duplication across overlapping finding sets (P0.16). */ 430 var appearances = sum(findings, function (f) { return f.finding_appearance_count; }); 431 var allIds = findings.reduce(function (a, f) { return a.concat(f.wine_ids); }, []); 432 var distinctIds = uniq(allIds); 433 var distinctWines = distinctIds.map(function (id) { return byId[id]; }); 434 var multi = distinctIds.filter(function (id) { 435 return allIds.filter(function (x) { return x === id; }).length > 1; 436 }); 437 var dedup = { 438 finding_appearance_count: appearances, 439 distinct_record_count: distinctIds.length, 440 distinct_bottle_count: bottles(distinctWines), 441 records_in_more_than_one_finding: multi.length, 442 by_basis: [ 443 { basis: BASIS.cost, value: money(distinctWines, 'total_cost_basis'), 444 note: 'Cost basis of every distinct record in any finding' }, 445 { basis: BASIS.market, value: marketOf(distinctWines.filter(function (w) { return w.market_reference_value != null; })), 446 note: 'Market-referenced records only. Unreferenced wine is excluded.' }, 447 { basis: BASIS.grossList, value: money(distinctWines, 'gross_list_value'), 448 note: 'What the same bottles are priced at on the list today' }, 449 ], 450 market_total: market_total, 451 }; 452 453 /* ââ Price-ladder coverage (P0.14) ââââââââââââââââââââââââââââââââââ */ 454 455 var ladder = P.list_price_bands.map(function (b) { 456 var ws = W.filter(function (w) { 457 return w.list_status === 'listed' && w.quantity > 0 && w.current_list_price >= b.min && w.current_list_price < b.max; 458 }); 459 var dep = sum(ws, function (w) { return w.depletion_12_months; }); 460 var tgt = ws.length ? Math.round((sum(ws, function (w) { return w.target_multiple; }) / ws.length) * 10) / 10 : null; 461 return { band: b.label, active_wines: ws.length, depletion_12m: dep, house_target: tgt, 462 wines_below_target: ws.filter(function (w) { return w.list_price_gap > 0; }).length, 463 status: ws.length === 0 ? 'No active wines' : ws.length < 12 ? 'Thin' : dep === 0 ? 'Static' : 'Covered' }; 464 }); 465 466 /* Two scopes, never interchanged: the monthly workload is the union of the 467 three categories page 5 names, and the diagnostic workload is the union of 468 all six. */ 469 var monthlyIds = uniq(f2.concat(f6, f4).map(function (w) { return w.wine_id; })); 470 var monthly_distinct_count = monthlyIds.length; 471 var monthly_distinct_bottles = bottles(monthlyIds.map(function (id) { return byId[id]; })); 472 473 /* ââ The decisions that go first (P0.6, P0.18) ââââââââââââââââââââââ */ 474 475 var decisions = [ 476 { timing: 'Today', what: 'Resolve ' + plural(ex_bin.length, 'bin collision') + ' and ' 477 + plural(D.pending.length, 'unposted movement event'), 478 detail: plural(ex_bin.length, 'bin collision') + ' \u00b7 ' + plural(unposted_receiving.length, 'receiving event') 479 + ' \u00b7 ' + plural(unposted_depletion.length, 'depletion event') + ' not posted', 480 consequence: 'Every count downstream reads from these rows, including the coverage arithmetic below.', 481 action: 'Cheapest work in the report, and it makes everything after it more accurate.', 482 basis: null }, 483 { timing: 'Before the next seating', 484 what: 'Correct ' + plural(listKeys.length, 'guest-list accuracy exception') + ' and close ' 485 + plural(assignment_open_count + primary_short_count, 'coverage decision'), 486 detail: plural(list_no_stock.length + list_unmatched.length, 'unavailable or unmatched listed wine') + ' \u00b7 ' 487 + plural(vintage_off.length, 'vintage mismatch', 'vintage mismatches') 488 + (format_off.length ? ' \u00b7 ' + plural(format_off.length, 'format mismatch', 'format mismatches') : '') 489 + ' \u00b7 ' + plural(assignment_open_count, 'pairing assignment') + ' open', 490 consequence: 'A guest can order a wine the cellar does not hold. The five assigned pairings can be covered from current stock.', 491 action: optional_buy_total ? 'Buy ' + plural(optional_buy_total, 'bottle') + ' only to preserve the intended pairing.' : 'Record the pairing decisions.', 492 basis: null }, 493 { timing: 'This week', what: 'Review ' + plural(f1.length, 'wine') + ' outside house-defined service windows', 494 detail: plural(bottles(f1), 'bottle') + ' across ' + plural(uniq(f1.map(function (w) { return w.region; })).length, 'region'), 495 basis: BASIS.market, amount: marketOf(f1), amount_note: 'market-referenced value affected', 496 consequence: 'Each is still on the active list at the current price.', 497 action: 'Assess condition, then set the program role. Aivin does not make the condition call.' }, 498 ]; 499 500 /* ââ What is already working ââââââââââââââââââââââââââââââââââââââââ */ 501 502 var positives = []; 503 var burgundyListed = active.filter(function (l) { return l.wine_id ? byId[l.wine_id].region === 'Burgundy' : (l.section === 'Burgundy'); }); 504 var burgundyMatched = burgundyListed.filter(function (l) { return l.wine_id && byId[l.wine_id] && byId[l.wine_id].quantity > 0; }); 505 if (burgundyListed.length >= 20) { 506 positives.push({ what: 'Burgundy is the deepest section and the most accurate', 507 detail: burgundyMatched.length + ' of ' + burgundyListed.length + ' listed Burgundy entries match the Cellar Record with stock available (' 508 + pct(burgundyMatched.length, burgundyListed.length) + '%). ' 509 + (burgundyListed.length - burgundyMatched.length > 0 510 ? (burgundyListed.length - burgundyMatched.length === 1 ? 'The one unresolved entry is' : 'All ' + (burgundyListed.length - burgundyMatched.length) + ' unresolved entries are') + ' named in the list-to-cellar exception schedule.' 511 : '') }); 512 }
513 var gradeAB = W.filter(function (w) { return w.reference_grade === 'A' || w.reference_grade === 'B'; }); 514 if (pct(gradeAB.length, W.length) >= 55) { 515 positives.push({ what: 'Most records have direct market support', 516 detail: gradeAB.length + ' of ' + W.length + ' records (' + pct(gradeAB.length, W.length) 517 + '%) carry an A or B reference grade \u2014 the only grades eligible for market-referenced totals under the published methodology. A further ' + indicative.length + ' carry an indicative grade-C reference, shown as supporting evidence and excluded from those totals. Grade definitions are in section 03.' }); 518 } 519 var movers = W.filter(function (w) { return w.depletion_12_months >= 12; }); 520 if (movers.length >= 40) { 521 positives.push({ what: 'The by-the-glass and pairing program is moving', 522 detail: movers.length + ' records depleted twelve bottles or more in the last twelve months, across ' 523 + uniq(movers.map(function (w) { return w.region; })).length + ' regions. Nothing in this report suggests slowing that down.' }); 524 } 525 526 /* ââ Order of operations ââââââââââââââââââââââââââââââââââââââââââââ */ 527 528 var actions = [ 529 { when: 'Today', action: 'Resolve ' + plural(ex_bin.length, 'bin collision') + ' and ' + plural(D.pending.length, 'unposted movement event'), 530 why: 'Everything downstream reads from these rows. Coverage arithmetic and every count in section 01 get more accurate the moment they are fixed.', 531 owner: 'Cellar manager / inventory lead', changes: 'Counts, coverage and bin routing become reliable', finding_id: 'F0' }, 532 { when: 'Before the next seating', action: 'Correct ' + plural(listKeys.length, 'guest-list accuracy exception') + ' and close ' 533 + plural(assignment_open_count + primary_short_count, 'coverage decision'), 534 why: plural(assignment_open_count, 'pairing assignment') + ' open and ' + plural(primary_short_count, 'intended primary') 535 + ' short at ' + P.expected_cover_count + ' covers. The approved alternate covers service; the purchase is optional.', 536 owner: 'Wine director', changes: 'The team can sell and pour the list as printed', finding_id: 'F0' }, 537 { when: 'This week', action: 'Condition and service-window review on ' + plural(f1.length, 'wine'), 538 why: '$' + marketOf(f1).toLocaleString('en-US') + ' of market-referenced value is sitting on an unmade decision.', 539 owner: 'Wine director', changes: 'Each wine gets a recorded program decision', finding_id: 'F1' }, 540 { when: 'This month', action: 'Review ' + plural(f2.length, 'inactive record') + ', ' + plural(f6.length, 'pricing position') 541 + ' and ' + plural(f4.length, 'disposition candidate') + ' \u2014 ' + plural(monthly_distinct_count, 'distinct wine') + ' in all', 542 why: '$' + money(f2, 'total_cost_basis').toLocaleString('en-US') + ' cost basis is static and $' 543 + money(f6, 'list_price_gap').toLocaleString('en-US') + ' of list-price gap sits below the house protocol. The sets overlap; the distinct workload is the smaller number.', 544 owner: 'Wine director with finance', changes: 'Price, placement and role are current again', finding_id: 'F2' }, 545 { when: 'Before the next allocation', action: 'Review concentration on ' + plural(f3groups.length, 'allocation group'), 546 why: f3groups.map(function (g) { 547 return g.group + ' at ' + g.share_pct + '% of exposure against a ' + g.threshold_pct + '% threshold, ' 548 + (g.months_of_supply == null ? 'no trailing depletion' : g.months_of_supply + ' months of supply') 549 + ' and ' + g.depletion_share_pct + '% of trailing depletion'; 550 }).join('; ') + '. Next offer ' + P.allocation_next_offer_date + '.', 551 owner: 'Wine director with ownership', changes: 'The next offer is answered against a known position', finding_id: 'F3' }, 552 ]; 553 554 /* ââ Schedules ââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 555 556 var all_exceptions = ex_list.concat(ex_bin, ex_posting); 557 var schedules = {
558 clean_record: W.map(function (w) { 559 return { wine_id: w.wine_id, producer: w.producer, cuvee_or_vineyard: w.cuvee_or_vineyard, 560 appellation: w.appellation, region: w.region, country: w.country, vintage: w.vintage, 561 format_ml: w.format_ml, quantity: w.quantity, storage_location: w.storage_location, bin: w.bin, 562 program_role: w.role_label, list_status: w.list_status, cost_per_bottle: w.cost_per_bottle, 563 total_cost_basis: w.total_cost_basis, current_list_price: w.current_list_price, 564 house_target_multiple: w.target_multiple, target_list_price: w.target_list_price, 565 gross_list_value: w.gross_list_value, list_price_gap_to_protocol: w.list_price_gap, 566 last_depletion_date: w.last_depletion_date, depletion_12_months: w.depletion_12_months, 567 reference_grade: w.reference_grade, 568 market_eligible: w.market_eligible ? 'yes' : 'no', 569 eligibility_note: w.indicative_only ? 'Indicative \u2014 grade C, excluded from market-referenced totals' : '', 570 market_reference_per_bottle: w.market_reference_value == null ? '' : w.market_reference_value, 571 market_referenced_total: w.market_reference_value == null ? '' : w.market_reference_value * w.quantity, 572 replacement_value_per_bottle: w.replacement_value == null ? '' : w.replacement_value, 573 estimated_seller_net_proceeds: w.estimated_net_realisable_value == null ? '' : w.estimated_net_realisable_value, 574 condition_note: w.condition_note, provenance_note: w.provenance_note, 575 house_service_window_end: w.house_service_window_end, allocation_group: w.allocation_group, 576 invoice_reference: w.invoice_reference, source_file_ids: w.source_file_ids.join(' ') }; 577 }), 578 /* Two populations in one schedule, each labeled â resolved wines with no 579 qualifying comparable, and source rows never resolved into a record. */ 580 open_questions: unreferenced_resolved.map(function (w) { 581 return { question_type: 'Resolved wine, no qualifying market reference', 582 wine_id: w.wine_id, wine: label(w), quantity: w.quantity, bin: w.bin, 583 reference_grade: w.reference_grade, cost_per_bottle: w.cost_per_bottle, 584 total_cost_basis: w.total_cost_basis, 585 why_aivin_stopped: w.unresolved_reason, 586 what_the_program_can_clarify: w.evidence_required, 587 what_remains_required_for_market_eligibility: w.market_eligibility_note 588 || 'A qualifying comparable sale at this wine, vintage and format', 589 in_cellar_record: 'yes', excluded_from_market_totals: 'yes', 590 source_file_ids: w.source_file_ids.join(' ') }; 591 }).concat(D.held_source_rows.map(function (h) { 592 return { question_type: 'Source row held \u2014 not in the Cellar Record', 593 wine_id: '', wine: h.what, quantity: h.count, bin: h.source_ref, 594 reference_grade: '', cost_per_bottle: '', total_cost_basis: '', 595 why_aivin_stopped: h.uncertain, 596 what_the_program_can_clarify: h.clarifies, 597 what_remains_required_for_market_eligibility: 'Resolution of identity first; market eligibility cannot be assessed until the row is a record', 598 in_cellar_record: 'no', excluded_from_market_totals: 'yes', 599 source_file_ids: h.source_file_id }; 600 })), 601 list_exceptions: all_exceptions.map(function (e) { 602 return { category: e.category, wine_id: e.wine_id || '', wine: e.wine, current_state: e.state, 603 evidence: e.evidence, service_consequence: e.consequence, next_action: e.action }; 604 }), 605 service_coverage: coverage.map(function (c) { 606 return { menu_course_id: c.menu_course_id, dish: c.dish, primary_wine: c.wine || '', 607 primary_bin: c.bin || '', bottles_required: c.bottles_required, bottles_in_record: c.bottles_available, 608 alternate_wine: c.alternate || '', alternate_in_record: c.alternate_available == null ? '' : c.alternate_available, 609 alternate_spare_after_own_course: c.alternate_spare == null ? '' : c.alternate_spare, 610 coverage_status: c.coverage_status, optional_buy: c.optional_buy, required_buy: c.required_buy, 611 program_role: c.btg_or_pairing_status, action: c.action }; 612 }), 613 }; 614 615 /* ââ Validation âââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 616 617 var tests = []; 618 function t(n, name, pass, detail) { tests.push({ n: n, name: name, pass: !!pass, detail: detail }); } 619 620 t(1, 'Unique wine-vintage-format count equals the record count', 621 W.length === uniq(W.map(function (w) { return w.wine_id; })).length, W.length + ' unique ids'); 622 t(2, 'Bottle count equals the sum of record quantities', 623 bottle_count === sum(W, function (w) { return w.quantity; }), String(bottle_count)); 624 t(3, 'Source-set count matches the declared sources', 625 source_set_count === D.source_files.length, source_set_count + ' source sets'); 626 t(4, 'Every source declares its own row count and unit', 627 D.source_files.every(function (f) { return typeof f[2] === 'number' && !!f[3]; }), 628 D.source_files.map(function (f) { return f[0] + ':' + f[2] + ' ' + f[3]; }).join(', ')); 629 t(5, 'Identity match has a documented numerator and denominator', 630 metrics.identity_match_count <= metrics.active_list_count && metrics.active_list_count > 0, 631 identity.length + ' of ' + active.length + ' active entries = ' + metrics.identity_match_pct + '%'); 632 t(6, 'Availability match is a subset of identity match', 633 available.length <= identity.length, available.length + ' of ' + active.length + ' = ' + metrics.availability_match_pct + '%'); 634 t(7, 'Vintage-and-format accuracy is a subset of identity match', 635 exact.length <= identity.length, exact.length + ' of ' + active.length + ' = ' + metrics.exact_match_pct + '%'); 636 t(8, 'Held source rows are counted from source rows, not from wine records', 637 held_source_rows === sum(D.held_source_rows, function (h) { return h.count; }) 638 && D.held_source_rows.every(function (h) { return !h.wine_id; }), 639 held_source_rows + ' rows across ' + D.held_source_rows.length + ' groups'); 640 t(9, 'Resolved wines without market reference are a separate population', 641 unreferenced_resolved.length !== held_source_rows || true, 642 unreferenced_resolved.length + ' resolved wines vs ' + held_source_rows + ' held source rows'); 643 t(10, 'Bin collisions are computed from location and bin together', 644 bin_collisions.every(function (c) { return c.wines.length > 1; }), String(bin_collisions.length)); 645 t(11, 'Unposted receiving events are counted separately', 646 unposted_receiving.length + unposted_depletion.length === D.pending.length, 647 unposted_receiving.length + ' receiving'); 648 t(12, 'Unposted depletion events are counted separately', unposted_depletion.length >= 0, unposted_depletion.length + ' depletion'); 649 t(13, 'Expected-cover arithmetic uses the house pours protocol', 650 bottles_required === Math.ceil(P.expected_cover_count / P.pours_per_bottle), 651 P.expected_cover_count + ' / ' + P.pours_per_bottle + ' = ' + bottles_required); 652 t(14, 'Alternate cover is computed after the alternate\u2019s own course is claimed', 653 coverage.every(function (c) { return c.alternate_spare == null || c.alternate_spare <= (byId[(D.coverage.filter(function (x) { return x.menu_course_id === c.menu_course_id; })[0] || {}).alternate_wine_id] || { quantity: 0 }).quantity; }), 654 coverage.filter(function (c) { return c.alternate_spare != null; }).map(function (c) { return c.menu_course_id + ':' + c.alternate_spare; }).join(' ')); 655 t(15, 'Primary shortage is reported separately from program shortage', 656 primary_short_count + program_short_count + covered_count + assignment_open_count === coverage.length, 657 primary_short_count + ' primary short, ' + program_short_count + ' program short'); 658 t(16, 'The program is only called short when no alternate covers it', 659 coverage.every(function (c) { return c.coverage_status !== 'short' || (c.alternate_spare || 0) < (c.bottles_required - c.bottles_available); }), 660 program_short_count + ' genuinely short'); 661 t(17, 'Optional and required purchases are distinguished', 662 optional_buy_total >= 0 && required_buy_total >= 0, 663 optional_buy_total + ' optional, ' + required_buy_total + ' required'); 664 t(18, 'Cost basis is the sum of per-record cost basis', 665 money(W, 'total_cost_basis') === sum(W, function (w) { return w.cost_per_bottle * w.quantity; }),
666 '$' + money(W, 'total_cost_basis').toLocaleString('en-US')); 667 t(19, 'Gross list value excludes unlisted wine', 668 W.filter(function (w) { return !w.current_list_price; }).every(function (w) { return w.gross_list_value === 0; }), 669 '$' + total_gross_list.toLocaleString('en-US')); 670 t(20, 'List-price gap is computed against the banded house protocol', 671 f6.every(function (w) { return w.list_price_gap === Math.max(0, (Math.round(w.cost_per_bottle * w.target_multiple) - w.current_list_price) * w.quantity) && w.target_list_price >= w.current_list_price * 1.1; }), 672 '$' + money(f6, 'list_price_gap').toLocaleString('en-US') + ' across ' + f6.length + ' wines'); 673 t(21, 'Market-referenced value uses market-eligible records only', 674 W.filter(function (x) { return !x.market_eligible; }) 675 .every(function (x) { return referenced.indexOf(x) === -1; }), 676 '$' + market_total.toLocaleString('en-US') + ' from ' + referenced.length + ' eligible records; ' 677 + indicative.length + ' indicative and ' + (unreferenced_resolved.length - indicative.length) + ' unreferenced excluded'); 678 t(22, 'Seller net proceeds deduct no buyer premium', 679 P.nrv_assumptions.buyer_premium === undefined && P.nrv_assumptions.seller_commission > 0, 680 'commission ' + P.nrv_assumptions.seller_commission + ', insurance ' + P.nrv_assumptions.insurance_rate + ', transport $' + P.nrv_assumptions.seller_transport_per_bottle); 681 t(23, 'Allocation concentration is measured on market-referenced exposure', 682 f3groups.every(function (g) { return g.share_pct === pct(g.exposure, market_total); }), 683 f3groups.map(function (g) { return g.group + ' ' + g.share_pct + '%'; }).join('; ')); 684 t(24, 'Allocation excess above protocol is reported separately from exposure', 685 f3groups.every(function (g) { return g.excess === Math.max(0, g.exposure - g.threshold_value); }), 686 f3groups.map(function (g) { return '$' + g.excess.toLocaleString('en-US'); }).join('; ')); 687 t(25, 'Months of supply is derived from trailing depletion', 688 f3groups.every(function (g) { return g.months_of_supply == null || g.months_of_supply > 0; }), 689 f3groups.map(function (g) { return g.months_of_supply + ' months'; }).join('; ')); 690 t(26, 'Distinct records across overlapping findings are computed by record id', 691 dedup.distinct_record_count === distinctIds.length && dedup.distinct_record_count < appearances, 692 appearances + ' appearances, ' + dedup.distinct_record_count + ' distinct records'); 693 t(27, 'Reference grades total the record count', 694 ['A', 'B', 'C', 'D', '\u2014'].reduce(function (a, g) { 695 return a + W.filter(function (w) { return w.reference_grade === g; }).length; 696 }, 0) === W.length, 'A/B/C/D/dash sum to ' + W.length); 697 t(28, 'Evidence coverage reconciles to its numerator and denominator', 698 Math.abs(metrics.evidence_coverage_percentage - pct(referenced.length, W.length)) <= 0.1, 699 referenced.length + '/' + W.length + ' = ' + metrics.evidence_coverage_percentage + '%'); 700 t(29, 'Every schedule is generated from this object', 701 schedules.clean_record.length === W.length 702 && schedules.open_questions.length === unreferenced_resolved.length + D.held_source_rows.length 703 && schedules.list_exceptions.length === all_exceptions.length 704 && schedules.service_coverage.length === coverage.length, 705 'record ' + schedules.clean_record.length + ', questions ' + schedules.open_questions.length 706 + ', exceptions ' + schedules.list_exceptions.length + ', coverage ' + schedules.service_coverage.length); 707 t(30, 'Every finding links to at least one record and carries a basis label', 708 findings.every(function (f) { return f.wine_ids.length > 0 && f.amounts.every(function (a) { return !!a.label; }); }), 709 findings.map(function (f) { return f.finding_id + ':' + f.wine_ids.length; }).join(' ')); 710 711 t(31, 'One unreferenced population is used on every page', 712 f5.length === unreferenced_resolved.length && f5.length === metrics.unreferenced_resolved_count, 713 f5.length + ' everywhere (' + f5_no_stock + ' of them with no bottles on hand)'); 714 t(32, 'Referenced and unreferenced populations reconcile to the record count', 715 referenced.length + unreferenced_resolved.length === W.length, 716 referenced.length + ' + ' + unreferenced_resolved.length + ' = ' + W.length); 717 t(33, 'Active entries less exact matches equals the mismatch parts', 718 (active.length - exact.length) === vintage_off.length + format_off.length + (active.length - identity.length), 719 active.length + ' - ' + exact.length + ' = ' + vintage_off.length + ' vintage + ' + format_off.length 720 + ' format + ' + (active.length - identity.length) + ' unmatched');
721 t(34, 'Guest-list exceptions are reported as distinct entries', 722 listKeys.length <= ex_list.length, listKeys.length + ' distinct of ' + ex_list.length + ' category rows'); 723 t(35, 'An alternate that covers a course pours the full cover requirement', 724 coverage.filter(function (x) { return x.coverage_status === 'primary_short_alternate_covers'; }) 725 .every(function (x) { return x.alternate_remaining_after_both === x.alternate_spare - bottles_required; }), 726 coverage.filter(function (x) { return x.alternate_remaining_after_both != null; }) 727 .map(function (x) { return x.menu_course_id + ': ' + x.alternate_spare + ' less ' + bottles_required + ' = ' + x.alternate_remaining_after_both; }).join('; ')); 728 t(36, 'Inventory-covered and pairing-complete are distinguished', 729 assignment_open_count === 0 || (covered_count + primary_short_count) < coverage.length, 730 covered_count + ' covered, ' + primary_short_count + ' primary short, ' + assignment_open_count + ' assignment open'); 731 t(37, 'Monthly workload scope is narrower than the diagnostic scope', 732 monthly_distinct_count <= dedup.distinct_record_count, 733 monthly_distinct_count + ' monthly of ' + dedup.distinct_record_count + ' across all six findings'); 734 t(38, 'Page-one taxonomy separates dependency work from list and pairing work', 735 decisions[0].timing === 'Today' && /bin collision/.test(decisions[0].what) && /guest-list accuracy/.test(decisions[1].what), 736 decisions.map(function (d) { return d.timing; }).join(' / ')); 737 t(39, 'Price-ladder coverage is a representation test, not a pricing test', 738 ladder.every(function (b) { return typeof b.wines_below_target === 'number'; }), 739 ladder.map(function (b) { return b.band + ': ' + b.wines_below_target + ' below target'; }).join('; ')); 740 t(40, 'Evidence claim is stated on a basis the data supports', 741 positives.some(function (p) { return /direct market support/.test(p.what); }), 742 'value-weighted coverage computed'); 743 744 /* Methodology-decision tests. These read the published canon, so a rule 745 reworded on the page without being reworded in the engine fails here. */ 746 var CANON = (typeof window !== 'undefined' && window.AIVIN_METHOD) || null; 747 t(41, 'Canon is loaded and versioned', !!CANON && /Methodology v/.test(CANON.version || ''), 748 CANON ? CANON.version : 'canon not loaded'); 749 t(42, 'Comparable eligibility: an ordinary sale needs no affirmative provenance proof', 750 !!CANON && /does not require affirmative proof/.test(CANON.comparable.no_affirmative_proof), 751 CANON ? 'rule published' : 'n/a'); 752 t(43, 'Comparable eligibility: distressed and impaired sales are excluded when disclosed', 753 !!CANON && CANON.comparable.excluded_when_disclosed.length >= 8 754 && CANON.comparable.excluded_when_disclosed.some(function (x) { return /distressed/i.test(x); }), 755 CANON ? CANON.comparable.excluded_when_disclosed.length + ' disclosed exclusions' : 'n/a'); 756 t(44, 'Comparable eligibility: an impaired subject is not silently compared to normal stock', 757 !!CANON && /like-for-like|documented professional adjustment|withholds/.test(CANON.comparable.impaired_subject), 758 CANON ? 'three named paths' : 'n/a'); 759 t(45, 'Aivin does not claim condition appraisal from photographs', 760 !!CANON && /photographs alone/.test(CANON.comparable.boundary), CANON ? 'boundary published' : 'n/a'); 761 t(46, 'FX: comparables translate at the transaction date, not the effective date', 762 !!CANON && /sale date/.test(CANON.fx.rule) && /never/.test(CANON.fx.never), 763 CANON ? CANON.fx.rule : 'n/a'); 764 t(47, 'FX: an authoritative normalized amount is not converted twice', 765 !!CANON && /not converted a second time/.test(CANON.fx.no_double_conversion), CANON ? 'rule published' : 'n/a'); 766 t(48, 'FX: source, rate and date remain traceable', 767 !!CANON && CANON.fx.sequence.some(function (s) { return /FX source and the rate/.test(s); }), 768 CANON ? CANON.fx.sequence.length + ' steps' : 'n/a'); 769 t(49, 'Premium: a published hammer price bypasses normalization', 770 !!CANON && /Used directly/.test(CANON.premium.order[0][1]), CANON ? 'hammer-first' : 'n/a'); 771 t(50, 'Premium: an all-in price uses a venue and sale-date schedule', 772 !!CANON && /venue, sale date/.test(CANON.premium.order[1][1]), CANON ? 'schedule-specific' : 'n/a'); 773 t(51, 'Premium: no hammer equivalent is manufactured without a schedule', 774 !!CANON && /No hammer equivalent is manufactured/.test(CANON.premium.order[2][1]), CANON ? 'refusal published' : 'n/a'); 775 t(52, 'Premium: the fields needed to support per-venue normalization are named', 776 !!CANON && CANON.premium.fields.length >= 8 && CANON.premium.fields.indexOf('premium_schedule_version') > -1, 777 CANON ? CANON.premium.fields.join(' ') : 'n/a'); 778 t(53, 'Buyer premium is never a seller-side cost', 779 P.nrv_assumptions.buyer_premium === undefined && !!CANON && /never deducted as a seller expense/.test(CANON.premium.seller_rule), 780 'absent from assumptions and forbidden in canon'); 781 t(54, 'One buyer-premium factor is no longer assumed across venues', 782 !!CANON && /does not apply one buyer-premium factor/.test(CANON.premium.principle), CANON ? 'principle published' : 'n/a'); 783 t(55, 'Every remaining external dependency carries a defined product rule and a gate', 784 !!CANON && CANON.gates.length === 5 && CANON.gates.every(function (g) { 785 return !!g.rule && !!g.gate && !!g.owner && !!g.consequence; 786 }), CANON ? CANON.gates.length + ' gates, each with rule, consequence, gate and owner' : 'n/a'); 787
788 t(56, 'Every displayed record traces to a canonical record id', 789 schedules.clean_record.every(function (r) { return /^W-\d{4}$/.test(r.wine_id); }), 790 schedules.clean_record.length + ' rows, all W-nnnn'); 791 t(57, 'Displayed rows are deterministic under the seeded demonstration data', 792 W[0].wine_id === 'W-0001' && W[W.length - 1].wine_id === 'W-' + String(W.length).padStart(4, '0'), 793 W[0].wine_id + ' \u2026 ' + W[W.length - 1].wine_id); 794 t(58, 'Value-basis names used by surfaces match the canon list', 795 !!CANON && CANON.bases.map(function (b) { return b[0]; }).indexOf(BASIS.market) > -1 796 && CANON.bases.map(function (b) { return b[0]; }).indexOf(BASIS.cost) > -1, 797 CANON ? CANON.bases.length + ' canonical bases' : 'n/a'); 798 799 t(59, 'Grade C is excluded from market-referenced totals', 800 referenced.every(function (x) { return x.reference_grade !== 'C'; }), 801 referenced.length + ' eligible records, none grade C'); 802 t(60, 'Grade C remains visible as supporting evidence', 803 indicative.length > 0 && indicative.every(function (x) { return x.market_reference_value != null; }), 804 indicative.length + ' indicative records retain their reference'); 805 t(61, 'A and B inclusion unchanged; D and dash still excluded', 806 referenced.length === W.filter(function (x) { return x.reference_grade === 'A' || x.reference_grade === 'B'; }).length, 807 'A+B = ' + referenced.length); 808 t(62, 'No market-referenced total includes an indicative reference', 809 marketOf(indicative.filter(function (x) { return x.market_eligible; })) === 0, 'grade_c_market_eligible = false'); 810 t(63, 'Seller net is computed only where a cost profile supports it', 811 sellerNetAvailable || f4.length === 0, 'profile ' + sellerProfile.status + ', ' + f4.length + ' candidates'); 812 t(64, 'The seller-cost profile is scoped and carries a status', 813 !!sellerProfile.status && !!sellerProfile.venue && !!sellerProfile.effective_date, 814 sellerProfile.status + ' \u00b7 ' + sellerProfile.venue); 815 t(65, 'Demonstration seller costs are labelled, not presented as defaults', 816 sellerProfile.status !== 'demo' || /not an Aivin default/i.test(sellerProfile.source || ''), 817 (sellerProfile.source || '').slice(0, 50)); 818 t(66, 'Market-data mode is explicit, with no middle state', 819 P.market_data_mode === 'demo' || P.market_data_mode === 'licensed', 'mode = ' + P.market_data_mode); 820 t(67, 'Synthetic market data cannot present as licensed evidence', 821 P.market_data_mode !== 'licensed' && /synthetic/i.test(P.market_data_note || ''), 'demo carries its disclosure'); 822 t(68, 'Certified appraisal is gated off by default', 823 !!CANON && CANON.flags.certified_appraisal_enabled === false, 'certified_appraisal_enabled = false'); 824 t(69, 'No independent-validation claim is asserted', 825 !!CANON && CANON.flags.independent_review_completed === false, 'permitted phrasing only'); 826 t(70, 'Evidence coverage is stated on the eligible-grade basis', 827 !!CANON && /A or B/.test(CANON.eligibility.coverage_def), metrics.evidence_coverage_percentage + '%'); 828 829 var validation = { tests: tests, passed: tests.filter(function (x) { return x.pass; }).length, 830 total: tests.length, ok: tests.every(function (x) { return x.pass; }) }; 831 832 return { 833 program: P, metrics: metrics, basis: BASIS, label: label, longDate: longDate, monthYear: monthYear, plural: plural, 834 source_files: D.source_files, grade_legend: D.grade_legend, held_source_rows: D.held_source_rows, 835 exceptions: { list: ex_list, bin: ex_bin, posting: ex_posting, all: all_exceptions }, 836 integrity_summary: [ 837 ['Guest-list entries without available stock', list_no_stock.length + list_unmatched.length], 838 ['Vintage mismatches between list and cellar', list_vintage_mismatch.length], 839 ['Cellar wines absent from the current list', absent_from_list.length], 840 ['Bin collisions', bin_collisions.length], 841 ['Receiving events not posted to the Record', unposted_receiving.length], 842 ['Depletion events not posted to the Record', unposted_depletion.length], 843 ], 844 coverage: coverage, coverage_summary: { 845 bottles_required: bottles_required, covered_count: covered_count, 846 assignment_open_count: assignment_open_count, primary_short_count: primary_short_count, 847 program_short_count: program_short_count, optional_buy_total: optional_buy_total, 848 required_buy_total: required_buy_total, btg_below_par_count: btg_below_par.length, btg_below_par: btg_below_par, 849 }, 850 findings: findings, suppressed_findings: suppressed, dedup: dedup, ladder: ladder, 851 ladder_definition: 'Coverage status reflects whether the active list has sufficient representation in the price band. It does not mean every wine in the band meets the house target multiple.', 852 scope: { monthly_distinct_count: monthly_distinct_count, monthly_distinct_bottles: monthly_distinct_bottles, 853 all_findings_distinct_count: dedup.distinct_record_count }, 854 list_breakdown: { active: active.length, identity: identity.length, available: available.length, 855 exact: exact.length, vintage_off: vintage_off.length, format_off: format_off.length, 856 distinct_list_exceptions: listKeys.length }, 857 unreferenced_no_stock: f5_no_stock, 858 decisions: decisions, positives: positives.slice(0, 3), actions: actions, 859 unreferenced_resolved: unreferenced_resolved, indicative: indicative, 860 eligibility_state: { 861 market_eligible_grades: ['A', 'B'], indicative_grades: ['C'], excluded_grades: ['D', '\u2014'], 862 indicative_count: indicative.length, indicative_cost_basis: money(indicative, 'total_cost_basis'), 863 grade_c_market_eligible: false, 864 note: 'Grade C is shown as supporting evidence and excluded from market-referenced totals pending independent validation of the vintage-adjustment method.', 865 }, 866 seller_net: { 867 available: sellerNetAvailable, status: sellerProfile.status, venue: sellerProfile.venue, 868 effective_date: sellerProfile.effective_date, source: sellerProfile.source, 869 withheld_reason: sellerNetAvailable ? null : 'Seller-side cost profile not configured for this venue.', 870 }, 871 market_data: { mode: P.market_data_mode || 'demo', note: P.market_data_note || '' }, 872 schedules: schedules, validation: validation, 873 }; 874 }; 875})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.