Paste a listing. Watch it normalize.
Clipper resolves any product URL against its writer, normalizes the listing into a typed
product object, and adds it to your Picks ledger — every field tagged with its provenance.
This is a fixture-backed demo with no live network requests.
-
Spec 1
Fixture-backed extraction engine
All clip operations resolve against a bundled fixture map keyed by URL. Zero live network requests at runtime. The fixture set ships inside the built bundle and is verifiable by inspecting the emitted JS.
-
Spec 2
URL-to-product normalization pipeline
A pasted URL passes through the resolver → writer selector → field extractor → provenance tagger pipeline. Each stage is pure and independently testable. The output is a typed NormalizedProduct object.
-
Spec 3
Per-field provenance attribution
Every field in a NormalizedProduct carries a Provenance tag: oracle (value read directly from authoritative origin) or asserted (value observed or inferred by a human or heuristic). The UI renders this tag as a coloured badge adjacent to each value.
-
Spec 4
Picks ledger data model
Clips accumulate in a session-scoped ledger (in-memory; no persistence). The ledger exposes landed_price as the canonical comparison column. Rows are sortable by any field and filterable by condition, source, and currency.
-
Spec 5
Writer registry with per-field-class authority
A Writer is the module responsible for extracting a field from a source. Each Writer declares authority per field-class (identity, pricing, condition, logistics, availability, metadata) as oracle | asserted | none. The registry is the single source of truth for permitted intents and stable_handle patterns.
-
Spec 6
Six-intent system with capability gate
Intents are: Save, Watch, Compare, Buy, Research, Monitor. Monitor requires a stable_handle from the writer — a re-producible, URL-independent identifier for the listing. If the writer reports no stable_handle, Monitor is disabled with an explanatory tooltip.
-
Spec 7
Canonical identity key sparseness
The canonical_identity_key is a globally stable cross-source identifier derived from manufacturer, model, and variant. Resale / secondary-market rows cannot reliably produce one — the field is left visibly blank (not hidden) to communicate sparseness rather than absence of data.
-
Spec 8
Dark visual identity
The site uses a near-black (#0A0A0B) background with indigo (#6366F1) accent throughout. The brand mark is the sparkle-clip glyph (✦✂). Typography follows the Apple design constitution — SF Pro stack, strict 4/8pt grid, one accent colour only.
-
Spec 9
Static site deployment target
Output is a pure Vite static bundle — no SSR, no server-side rendering, no Node runtime at serve time. Core Home and Spec content is accessible without JavaScript via <noscript> fallbacks in index.html. Deployable to any CDN or object-storage origin.
-
Decision 1
Transport layer: live network fetch vs fixture-only?
Fixture-only
Live fetches introduce network dependency, CORS constraints, and rate-limit risk inside a demo. Fixtures allow deterministic, reproducible demos with zero runtime network surface.
-
Decision 2
Writer trust model: per-field-class authority vs whole-writer trust?
Per-field-class authority
A scraper may read price reliably (oracle) but only infer condition from listing copy (asserted). Whole-writer trust overstates reliability. Per-field-class authority lets the UI surface exactly what was read vs. inferred.
-
Decision 3
canonical_identity_key on resale rows: blank vs omit?
Visible blank
Omitting the field hides an important signal — that this row has no stable cross-source identity. A visible blank communicates “we tried and there is none,” which is distinct from “this field does not exist.”
-
Decision 4
Intent gate mechanism: capability check vs feature flag?
Capability check on stable_handle
Whether Monitor is possible is a property of the source — not of the user or a global toggle. Tying the gate to the writer’s stable_handle declaration keeps the intent system honest and self-documenting.
-
Decision 5
Provenance badge granularity: per-field vs per-writer?
Per-field
A writer can be oracle for price and asserted for condition simultaneously. A single per-writer badge would misrepresent fields that were derived, not read. Per-field badges give the reviewer precise, actionable signal.
-
Decision 6
Data persistence: in-memory vs localStorage?
In-memory session state
The demo is fixture-backed — there is no real data to lose. localStorage would give a false impression of real persistence, and serializing typed ProvenanceField objects introduces schema-migration complexity that is out of scope for a demo.