A failed source read can leave enough supplied material for a review candidate. I built a small independent contract that preserves that difference instead of presenting the candidate as successful retrieval. It connects no real collector or company data.

Separate retrieved observations from supplied material

decide_intake takes a fetch classification and separate fetched and provided dictionaries. The classification is retrieved, unavailable or blocked. A connector declares the observations it obtained in one dictionary; a person or another supplied document contributes the other. Keeping those inputs separate allows the result to explain which value it selected instead of losing origins in a single merged object.

Retrieved describes the caller's transport classification, not authenticated product truth. A trustworthy connector or server must prepare that classification and the scope actually observed. This function does not interpret an original application's error message. Nor can a browser-supplied success flag establish that an external source was actually read.

A blocked observation cannot fall back into a candidate

A blocked observation returns no candidate even when supplied material includes a title. An unavailable observation may retain a supplied title as a review candidate while keeping the failed source-read classification. This explicit policy prevents an unavailable response and a blocking decision from being collapsed into one interchangeable failure. It does not itself block network traffic.

Declaring an unavailable or blocked read while supplying nonempty fetched observations is rejected as contradictory. There is no access-control check, bypass, retry job or network classifier in the package. An integrating system must decide where classifications originate and who may change them. A decision returned by this example is not a grant of security authority.

Missing is different from zero

The allowed fields are title, price_minor, shipping_minor and stock. A title is trimmed text of at most one hundred and twenty characters. Numeric values are nonboolean integers from zero to one billion. The caller must agree on currency and the money minor-unit convention before integration; the function performs no exchange or fractional-unit conversion. It checks no current product price.

None and a blank title mean an absent observation; numeric zero remains present. A blank fetched title does not erase a supplied title. A malformed title or negative amount, however, raises an error instead of silently using replacement data. Having a valid fallback should not hide a malformed observed field or make an unsupported conversion look successful.

Explore the implementation

Complete independent synthetic implementation

"""Independent synthetic intake decision. No fetch, parser, storage or publishing."""
FIELDS=('title','price_minor','shipping_minor','stock')
STATES=('retrieved','unavailable','blocked')

def _fields(value):
 if not isinstance(value,dict) or set(value)-set(FIELDS):raise ValueError('FIELD_CONTRACT')
 out={}
 for key,item in value.items():
  if item is None:continue
  if key=='title':
   if not isinstance(item,str) or len(item)>120:raise ValueError('TITLE_CONTRACT')
   if item.strip():out[key]=item.strip()
  elif type(item) is not int or not 0<=item<=1_000_000_000:raise ValueError('INTEGER_CONTRACT')
  else:out[key]=item
 return out

def decide_intake(fetch_status,fetched,provided):
 """Caller must supply trustworthy classified observations, not raw error text.

 Integers share an externally declared minor-money/count unit; no conversion.
 Retrieved means a transport classification, never verification of product truth.
 """
 if fetch_status not in STATES or type(fetch_status) is not str:raise ValueError('FETCH_STATE')
 a,b=_fields(fetched),_fields(provided)
 if fetch_status!='retrieved' and a:raise ValueError('CONTRADICTORY_FETCH_FIELDS')
 base={'fetch_status':fetch_status,'candidate':None,'field_origins':{},'missing_fields':list(FIELDS),'review_required':True,'publish_ready':False,'performs_action':False,'authenticates_sources':False}
 if fetch_status=='blocked':return {**base,'decision':'blocked'}
 selected={};origins={}
 for key in FIELDS:
  if key in a:selected[key]=a[key];origins[key]='fetched'
  elif key in b:selected[key]=b[key];origins[key]='provided'
 if 'title' not in selected:return {**base,'decision':'insufficient'}
 return {**base,'decision':'fetched_candidate' if origins['title']=='fetched' else 'provided_candidate','candidate':selected,'field_origins':origins,'missing_fields':[key for key in FIELDS if key not in selected]}

Return origins for individual fields

For each present valid field the gate prefers fetched observations, then supplied material. If the title came from a read but shipping came from supplied data, field_origins retains both distinctions. A price without a title cannot invent a product name. Even when a candidate exists, absent price, shipping or stock fields remain in missing_fields rather than receiving plausible defaults.

The fetched_candidate and provided_candidate decisions summarize the selected title's origin; they do not replace individual field origins. Consumers must inspect field_origins for the complete account. The function neither mutates its input dictionaries nor aliases them into the returned candidate. Persisting a candidate and recording its later revisions require a separate implementation.

Even a complete candidate still needs review

Every decision keeps review_required true and publish_ready false, including a candidate with every permitted field. performs_action and authenticates_sources also remain false. These flags do not implement a publishing authorization system. They express that constructing a candidate cannot complete source authentication or an approval step that this package does not perform.

Twenty-six independent synthetic tests ran in the source folder and again after ZIP extraction. Five separate illustrative records cover a fetched title, supplied material after an unavailable read, a blocked observation, mixed fields including zero, and an empty response. The selector below reads saved JSON; it runs neither Python nor a collector in the browser. DOM-stub checks are distinct from rendered-screen inspection.

A read-only viewer of synthetic local records

Read the remaining integration responsibilities

The ZIP includes the independent implementation, tests, example runner, actual synthetic output records and scope documentation. Run python -B -m unittest -v from the extracted folder to check it. Modification, redistribution and commercial reuse are permitted without warranty. This is a newly authored explanatory example, not private customer code or an extracted operational dataset.

URL validation, document parsing, CSV ingestion, real product identity, server permissions, persistence and publishing are outside the package. Values declared as retrieved may still be stale or wrong. An integrator must connect review evidence and keep candidate creation, source verification and publication counts separate. The original application and external accounts were not executed or changed in this work.

Download code, tests and records
Python standard library, synthetic data, modification and reuse permitted