{
  "meta": {
    "name": "TroveSnap capture-to-sale pipeline",
    "version": "1.0.0",
    "date": "2026-06-17",
    "description": "Machine-readable model of the full capture-to-sale decision flow: stages, decisions, branches, loop-backs, badges, data writes, the tagging model, and integrations. Data backbone behind the CC-Analysis diagrams and the Codex handoff.",
    "notes": [
      "AI cataloging is commoditizing (Gavelist/EstateSail/AuctionWriter/Estimint). Differentiation is downstream: demand graph + marketplace + recovery, free/local cataloging, data ownership, coexistence.",
      "Illustrative model; not certified appraisals or guaranteed values; nothing canonical/published without seller approval."
    ]
  },

  "lenses": {
    "runsOn": {
      "on_device_free": "Runs on the seller's device, offline-capable, no API cost (capture, Whisper transcribe, condense).",
      "deterministic_free": "Server-side but keyless/deterministic; ships green in CI (base tagging, label generation, reconciliation).",
      "token_metered": "Premium AI; costs tokens; spent only on the seller's explicit choice (deep appraisal, comparable research, image enhancement).",
      "auth_connector": "Requires Supabase Auth and/or a connector (checkout-scan PWA, POS sync, settlement)."
    },
    "badges": {
      "free": "On-device / free.",
      "auto": "Automatic / deterministic.",
      "tokens": "Token-metered premium AI.",
      "optional": "Optional step.",
      "needs_research": "Identification/value uncertain; resolve before listing.",
      "needs_approval": "Requires explicit seller approval before it happens.",
      "review": "Human review queue.",
      "buyer_facing": "Public / buyer-facing surface.",
      "action": "A seller/team task."
    }
  },

  "tagging": {
    "policy": "Itemize selectively; quick-price the rest. Mirrors PROSALE 'inventory everything or nothing — your choice'. Sticker/track the auctionable + high-value pieces; price-point the bulk.",
    "code": {
      "format": "opaque id, e.g. ts:ITEM",
      "permanent": true,
      "contains_no": ["price", "internal pricing guidance", "PII"],
      "resolves_to": "public buyer listing only (staff/checkout view is auth-gated)"
    },
    "binding": {
      "model": "mutable pointer (code -> current item) with an append-only binding history",
      "states": ["unbound", "bound", "released", "rebound"],
      "idempotent": true,
      "offline_first": true,
      "two_scan_bind_seconds_target": 5,
      "tables": "planned per docs/technical/data-model.md: qr_codes / item_identity_bindings (code, item_id, estate_sale_id, state, bound_at, released_at, binding_history) + scan events feeding anonymous demand metrics and item-level sold capture"
    },
    "types": [
      {
        "id": "disposable",
        "label": "Disposable sticker pack",
        "reusable": false,
        "leaves_with_item": true,
        "best_for": "sale-floor goods expected to sell and walk out",
        "sku": ["standard label", "weatherproof", "hang-tag"],
        "fulfillment": "print-on-demand / dropship",
        "monetization": "recurring consumable; plan allotments + overflow packs"
      },
      {
        "id": "reusable",
        "label": "Reusable durable tag",
        "reusable": true,
        "leaves_with_item": false,
        "best_for": "high-value / auction / consignment / unsold items; agency recurring inventory across many sales",
        "reuse_cycle": "collect at sale end -> release -> rebind to a new item next sale",
        "sku": ["durable tag kit (laminated hang-tag / clip)"],
        "monetization": "durable kit (higher unit price, sustainable, agency-friendly)",
        "note": "removed before a sold item leaves; buyer link can transfer to a receipt QR"
      },
      {
        "id": "print_your_own",
        "label": "Print-your-own label",
        "reusable": false,
        "leaves_with_item": true,
        "best_for": "shops with a label printer",
        "note": "codes minted from the record at print time; synchronize identically to pack codes"
      }
    ]
  },

  "integrations": {
    "rule": "Coexist, never required. The QR code is the shared identity key; TroveSnap pushes catalog/labels out and pulls results back. Do not rebuild payments.",
    "checkout": [
      { "name": "Square", "how": "card processing; QR captures the item, Square captures the money; reconcile by code" },
      { "name": "PROSALE", "how": "estate-sale POS; code as SKU; sold report (CSV/API) back, matched by code" },
      { "name": "EstateSail", "how": "AI-cataloging POS; tap-to-pay (Stripe Terminal); sold data back, matched by code" }
    ],
    "auction": [
      { "name": "LiveAuctioneers", "how": "spreadsheet (LotNum/Title/Desc/LowEst/HighEst/StartPrice) + lot-numbered image bundle" },
      { "name": "Proxibid", "how": "Bulk Loader CSV; image naming 1-1, 1-2" },
      { "name": "Invaluable", "how": "Catalog Upload API (partner); covers AuctionZip + private-label" },
      { "name": "Auction Flex / HiBid", "how": "spreadsheet import -> one-click upload to HiBid" },
      { "name": "Wavebid", "how": "Universal Export + two-way sale-results pull-back" }
    ],
    "ai_catalogers": {
      "category_status": "commoditizing (table stakes)",
      "examples": ["Gavelist", "EstateSail", "AuctionWriter", "Estimint", "aListEngine"],
      "stance": "interop / consume; differentiate on demand graph + marketplace + recovery, not on the act of cataloging"
    }
  },

  "signals": {
    "scan_interest": "Anonymous buyer/hunter QR scans, counted per item, feed the demand graph and gauge auction demand (interest, not identity).",
    "wishlist_match": "Cross-sale buyer demand matched to items; powers recovery and notify-buyers.",
    "markdown_watch": "QR resolves to the item/sale page (links back to the seller profile, not to it). A shopper can watch an item and be notified when it hits the next discount phase (day-2/day-3 markdown), or make an offer on the spot - keeps lingering, marked-down inventory moving. Reuses discount_phases, buyer_offers, notifications."
  },

  "nodes": [
    { "id": "capture", "type": "stage", "phase": "capture", "label": "Capture: photo + spoken note", "runsOn": "on_device_free", "badges": ["free"], "dataWrites": ["photo", "voice_note"] },
    { "id": "transcribe", "type": "stage", "phase": "capture", "label": "Transcribe locally (Whisper)", "runsOn": "on_device_free", "badges": ["free"], "dataWrites": ["transcript"] },
    { "id": "condense", "type": "stage", "phase": "capture", "label": "Condense -> candidate fields (token-trimmed)", "runsOn": "on_device_free", "badges": ["free"], "dataWrites": ["draft.title", "draft.attributes", "draft.condition", "draft.asking_price"] },
    { "id": "tag", "type": "stage", "phase": "enrich", "label": "Tag & categorize (description-seeded LLM)", "runsOn": "deterministic_free", "badges": ["auto"], "dataWrites": ["inventory_candidate", "item_treasure_tags", "marketplace_score"] },

    { "id": "d_highvalue", "type": "decision", "phase": "enrich", "label": "High-value category flagged?" },
    { "id": "trigger_notification", "type": "trigger", "phase": "enrich", "label": "Notification: appraisal may be in order", "note": "system trigger from tagging" },
    { "id": "trigger_seller", "type": "trigger", "phase": "enrich", "label": "Seller suspects higher value", "note": "human trigger" },

    { "id": "d_appraise", "type": "decision", "phase": "enrich", "label": "Appraise with tokens?", "runsOn": "token_metered", "badges": ["optional", "tokens"], "note": "system only suggests; tokens spent on seller's choice" },
    { "id": "appraise_run", "type": "stage", "phase": "enrich", "label": "Token appraisal + comparable research", "runsOn": "token_metered", "badges": ["tokens"], "dataWrites": ["appraisal", "appraisal_recommendation", "enhanced_photo"] },
    { "id": "d_confirmed", "type": "decision", "phase": "enrich", "label": "Higher value confirmed?" },
    { "id": "act_confirmed", "type": "outcome", "phase": "enrich", "label": "Re-price + re-tag, apply sticker, route to auction / wishlist recovery", "note": "see appraisal-decision-loop" },

    { "id": "d_certain", "type": "decision", "phase": "enrich", "label": "ID & price certain enough?" },
    { "id": "out_research", "type": "outcome", "phase": "enrich", "label": "Comparable research / manual lookup", "badges": ["needs_research"] },

    { "id": "d_photos", "type": "decision", "phase": "enrich", "label": "Photos good enough?" },
    { "id": "out_reshoot", "type": "outcome", "phase": "enrich", "label": "Reshoot checklist (close-up, maker mark, scale)", "badges": ["action"] },

    { "id": "d_sticker", "type": "decision", "phase": "enrich", "label": "Sticker this item? (auctionable / high-value)", "badges": ["optional"] },
    { "id": "out_bind", "type": "outcome", "phase": "enrich", "label": "Bind QR (disposable pack, reusable tag, or print-your-own; all sync)", "dataWrites": ["qr_binding"] },

    { "id": "review", "type": "stage", "phase": "review", "label": "Review & appraisal queue", "badges": ["review"] },
    { "id": "d_publish", "type": "decision", "phase": "review", "label": "Publish-ready & approved?", "badges": ["needs_approval"] },
    { "id": "out_sendback", "type": "outcome", "phase": "review", "label": "Send back: missing photos / appraisal / price" },
    { "id": "promote", "type": "stage", "phase": "review", "label": "Promote -> canonical item", "note": "promoteInventoryCandidate(); QR code travels", "dataWrites": ["estate_sale_items", "qr_code"] },

    { "id": "floor", "type": "stage", "phase": "floor", "label": "Publish -> on the floor (QR price tag + buyer portal)", "badges": ["buyer_facing"], "dataWrites": ["public_listing", "scan_count", "item_watch", "markdown_alert", "buyer_offer"], "note": "QR -> item/sale page (links back to profile); watch-for-markdown + make-offer keep lingering inventory moving" },
    { "id": "d_sold", "type": "decision", "phase": "floor", "label": "Sold?" },
    { "id": "out_soldcapture", "type": "outcome", "phase": "floor", "label": "Checkout scan / POS -> sold event -> reconcile", "runsOn": "auth_connector", "badges": ["auto"], "dataWrites": ["inventory_status_events(sold, final_price)"] },
    { "id": "recovered", "type": "terminal", "phase": "floor", "label": "Recovered revenue / done" },

    { "id": "d_whatsnext", "type": "decision", "phase": "disposition", "label": "Unsold - What's Next route?" },
    { "id": "out_notify", "type": "outcome", "phase": "disposition", "label": "Notify buyers / accept offers", "badges": ["buyer_facing", "needs_approval"] },
    { "id": "out_auction_export", "type": "outcome", "phase": "disposition", "label": "Auction export (per-platform drafts)", "badges": ["needs_approval"] },
    { "id": "out_consignment", "type": "outcome", "phase": "disposition", "label": "Consignment" },
    { "id": "out_clearance", "type": "outcome", "phase": "disposition", "label": "Clearance" },
    { "id": "out_donation", "type": "outcome", "phase": "disposition", "label": "Donation + IRS 8283 manifest", "badges": ["needs_approval"] },
    { "id": "out_responsible_disposal", "type": "outcome", "phase": "disposition", "label": "Responsible disposal (recycle / e-waste / scrap / textile)", "note": "terminal route per data-model.md; completes the lifecycle for non-sellable items" },
    { "id": "out_archive", "type": "outcome", "phase": "disposition", "label": "Archive" }
  ],

  "edges": [
    { "from": "capture", "to": "transcribe", "kind": "flow" },
    { "from": "transcribe", "to": "condense", "kind": "flow" },
    { "from": "condense", "to": "tag", "kind": "flow" },
    { "from": "tag", "to": "d_highvalue", "kind": "flow" },

    { "from": "d_highvalue", "to": "trigger_notification", "kind": "branch", "when": "yes" },
    { "from": "trigger_notification", "to": "d_appraise", "kind": "trigger", "label": "informs" },
    { "from": "trigger_seller", "to": "d_appraise", "kind": "trigger", "label": "informs" },
    { "from": "d_highvalue", "to": "d_appraise", "kind": "flow", "when": "either" },

    { "from": "d_appraise", "to": "appraise_run", "kind": "branch", "when": "yes (spend tokens)" },
    { "from": "d_appraise", "to": "d_certain", "kind": "branch", "when": "no / later", "label": "revisit anytime" },
    { "from": "appraise_run", "to": "d_confirmed", "kind": "flow" },
    { "from": "d_confirmed", "to": "act_confirmed", "kind": "branch", "when": "yes" },
    { "from": "d_confirmed", "to": "d_certain", "kind": "branch", "when": "no" },
    { "from": "act_confirmed", "to": "tag", "kind": "loopback", "label": "updates record: pricing guidance + tags" },

    { "from": "d_certain", "to": "out_research", "kind": "branch", "when": "no" },
    { "from": "out_research", "to": "tag", "kind": "loopback", "label": "after research" },
    { "from": "d_certain", "to": "d_photos", "kind": "branch", "when": "yes" },

    { "from": "d_photos", "to": "out_reshoot", "kind": "branch", "when": "no" },
    { "from": "out_reshoot", "to": "capture", "kind": "loopback", "label": "reshoot -> re-capture" },
    { "from": "d_photos", "to": "d_sticker", "kind": "branch", "when": "yes" },

    { "from": "d_sticker", "to": "out_bind", "kind": "branch", "when": "yes" },
    { "from": "d_sticker", "to": "review", "kind": "branch", "when": "no / skip" },
    { "from": "out_bind", "to": "review", "kind": "flow" },

    { "from": "review", "to": "d_publish", "kind": "flow" },
    { "from": "d_publish", "to": "out_sendback", "kind": "branch", "when": "no" },
    { "from": "out_sendback", "to": "capture", "kind": "loopback", "label": "fix & resubmit" },
    { "from": "d_publish", "to": "promote", "kind": "branch", "when": "yes" },
    { "from": "promote", "to": "floor", "kind": "flow" },

    { "from": "floor", "to": "d_sold", "kind": "flow" },
    { "from": "floor", "to": "out_notify", "kind": "signal", "label": "scan interest -> demand graph" },
    { "from": "d_sold", "to": "out_soldcapture", "kind": "branch", "when": "yes" },
    { "from": "out_soldcapture", "to": "recovered", "kind": "flow" },
    { "from": "d_sold", "to": "d_whatsnext", "kind": "branch", "when": "no" },

    { "from": "d_whatsnext", "to": "out_notify", "kind": "branch", "when": "demand exists" },
    { "from": "d_whatsnext", "to": "out_auction_export", "kind": "branch", "when": "auction candidate" },
    { "from": "d_whatsnext", "to": "out_consignment", "kind": "branch", "when": "value, thin demand" },
    { "from": "d_whatsnext", "to": "out_clearance", "kind": "branch", "when": "low value" },
    { "from": "d_whatsnext", "to": "out_donation", "kind": "branch", "when": "donate" },
    { "from": "d_whatsnext", "to": "out_responsible_disposal", "kind": "branch", "when": "non-sellable" },
    { "from": "d_whatsnext", "to": "out_archive", "kind": "branch", "when": "none" },
    { "from": "out_clearance", "to": "floor", "kind": "loopback", "label": "republish" }
  ],

  "guardrails": [
    "Ingestion contract: connectors/scans write candidates + events only; promoteInventoryCandidate() is the single canonical writer, post-review.",
    "Nothing canonical or published without explicit seller approval.",
    "Tokens spent only on the seller's explicit choice; the system only suggests.",
    "Public QR resolves to the buyer listing only; never exposes internal pricing guidance.",
    "Language rules: suggested ranges / internal pricing guidance; never 'certified appraisal' or 'guaranteed value'.",
    "Don't rebuild payments; reconcile item <-> money by QR code.",
    "Don't compete on the scan/AI-catalog; interop and differentiate on demand + marketplace + recovery."
  ]
}
