From ca5abbec7d7a5bc0d38593dbd471952d01509f30 Mon Sep 17 00:00:00 2001 From: Mike Levin Date: Mon, 20 Jul 2026 16:25:14 -0400 Subject: [PATCH] chore: Refactor MAPPER LANE documentation and banking details (2026-07-20) --- foo_files.py | 1 + 1 file changed, 1 insertion(+) diff --git a/foo_files.py b/foo_files.py index 1bf2191a..2e3388d6 100644 --- a/foo_files.py +++ b/foo_files.py @@ -1231,6 +1231,7 @@ # - EARMARK: TWO-GATE 403 DIAGNOSIS (banked 2026-07-20): a Google service-account 403 has two independent causes that clear IN ORDER — SERVICE_DISABLED (API toggle in the key's Cloud project; once per API per project, forever) then PERMISSION_DENIED (resource not shared with client_email; once per document). Conviction: sheets.py's first live LIST died on SERVICE_DISABLED for the key's project while sharing remained untested. Auth is never the blocker when it fits a pattern already on the shelf: four wallet auth kinds cover every connector so far, and each new OAuth is a wallet-hygiene rep, not a delay. # - ADVERSARIAL TQM LANE (reordered 2026-07-20 at dismount): acquisition (connectors) -> MAPPING (see MAPPER LANE) -> judgment (measure.py) -> packaging (evidence.py). measure.py v1 + variant_rollup_v1.json were drafted in the sheets-STACK article transcript but deliberately NOT applied — judgment against unmapped columns is judgment against a riddle. Recover the drafts from that article once a mapper exists. evidence.py unstarted. # - MAPPER LANE (opened 2026-07-20, coachman-steered): before ANY automation or QA against a client sheet, mint the mapping artifact — sheet_map.json (working name; map-gsheet-columns-to-api-fields-for-qa.json IS the mentality). One entry per tab answering exactly three questions: (1) which row holds the column labels — if unanswerable per tab, the client has the bigger problem and the mapper is the conversation you hand back; (2) which column feeds the API call, addressed by BOTH numeric index and fuzzy name (case-insensitive; tolerate punctuation, abbreviation, hyphenation, parens); (3) which columns get QA'd against which API fields. Left side of the map = the Mutation Machine (riddle); right side = the API (fixed, discoverable three ways: OpenAPI swagger tree walk, datamodel/datasets endpoints via imports/botify/true_schema_discoverer.py, CDP wire sniff). Stable side for this campaign: Botify RealKeywords/search_console, not raw GSC — cross-client, BigQuery-fed, one auth. The mapper is a DELIVERABLE, not plumbing: toss it back at the sheet owner so they internalize the pain. Never automate against a spreadsheet without one. +# - MAPPER LANE v1 BANKED 2026-07-20 (all 8 gates receipt-green across two compiles): scripts/map_sheet.py completes the scaffold acquisition -> explicit draft mapping -> human confirmation -> judgment. Structural: acquired_at_utc x2 in sheets.py; README downstream-stages seam; AST OK. Behavioral: headers 3/3/3/4 exact; Summary exposed as needs_human (mixed layout never coerced); value-sampled lookup accepted Product URL / Variant URL and REJECTED the numeric "Variant URL rows" trap; Current Impressions/Clicks -> search_console.period_0 fields on all four metric tabs; ZERO Diff correspondences (DERIVED_TERMS held). Receipts bundle (timestamped TSV + sheet_map.json) lives in Notebooks/Client_Work// (gitignored by construction, not Desktop/Downloads). Known deliverable weakness: bare score floats read as numerology to sheet owners — candidate --deliverable rendering, only if the first real client artifact demands it. measure.py stays parked until a HUMAN-CONFIRMED mapping exists. # - EARMARK: THE COACHMAN'S VETO (banked 2026-07-20): an emitted patch train is a PROPOSAL until the human runs `app`; refusing an entire train costs nothing (no dead cars — nothing was applied) and is the correct move when the strategy beneath it shifts. The Horse has instincts; the coachman has been down the road. Witness: the measure.py train of 2026-07-20, refused at the platform, redirected into the MAPPER LANE. # - TODO (ratify wording, then retitle EARMARK): PATCH CAR BUNDLING — a car = one commit story. Bundle blocks into one fenced payload when they form one atomic change deserving one commit message, even across files; split cars when the commits should teach separately (feature vs docs vs constitution flip), so `m`'s message and the human's internalization track each lesson. Evidence: the 2026-07-20 five-block sheets.py car cut the human loop from O(blocks) to O(cars) with zero exact-match failures. # - EARMARK: AUTH-KIND RESIDUE (convicted 2026-07-20): sheets.py v1 inherited gsc's service_account plumbing by pattern-proximity, so the API-enablement toggle went to the right console page for the WRONG credential's project — SERVICE_DISABLED persisted post-enablement and only the human caught the identity-model mismatch. Auth kind is a USER-story decision, never nearest-neighbor: Pipulate humans own Google accounts -> oauth_token_file (gmail pattern, per-scope token files, NO sharing gate); unattended robots -> service_account_file. Every connector's identity mode must print its credential's project_id so wrong-project convictions take seconds, not console archaeology.