원문을 읽지 못했어도 이미 제공된 자료로 후보를 만들 수 있다. 그 후보가 원문 수집 성공으로 보이지 않도록 작은 계약을 따로 구현했다. 실제 수집기와 회사 자료를 연결하지 않은 합성 모듈이다.

받아 온 결과와 제공된 자료를 다른 입력으로 둔다

decide_intake는 수집 상태와 fetched, provided를 따로 받는다. 상태는 retrieved, unavailable, blocked 중 하나다. 앞의 사전에는 연결기가 읽었다고 선언한 값, 뒤의 사전에는 사람이 입력하거나 별도 파일로 제공한 값을 넣는다. 두 사전을 한 번 합쳐 출처를 잊는 대신 어떤 값이 선택됐는지를 결과에 남기기 위한 입력 구조다.

retrieved는 연결 결과의 분류이지 상품 내용이 사실이라는 인증이 아니다. 호출자는 실제로 읽은 범위와 실패 종류를 신뢰할 수 있는 서버나 연결기에서 준비해야 한다. 원래 프로그램의 오류 문구를 이 함수가 해석하지 않으며 브라우저가 보낸 성공 플래그만으로 실제 수집을 확정하는 기능도 없다.

차단된 요청은 대체 자료가 있어도 후보로 넘기지 않는다

blocked이면 제공된 제목이 있어도 candidate는 None이다. unavailable일 때는 제공된 제목으로 검토 후보를 남길 수 있다. 원문을 못 읽었다는 상태는 그대로 유지한다. 일시적인 수집 불가와 차단 결정을 하나의 실패로 뭉쳐 같은 대체 처리를 적용하지 않도록 정한 작은 정책이다. 실제 네트워크 접근을 막는 장치는 아니다.

수집이 되지 않았다고 선언하면서 fetched에 유효한 값을 넣으면 모순으로 거절한다. 차단 여부 자체를 판단하거나 우회하는 코드, 접근 권한을 검사하는 서버, 재시도 작업은 없다. 다른 시스템에 적용할 때에는 그 분류를 어디서 만들고 누가 바꿀 수 있는지 먼저 정해야 한다. 이 예제의 반환값을 보안 권한으로 사용하지 않는다.

비어 있는 값과 0을 다른 입력으로 다룬다

허용 필드는 title, price_minor, shipping_minor, stock 네 개다. 제목은 공백을 정리한 120자 이내 문자열이고 숫자는 참·거짓을 제외한 0부터 십억 사이 정수다. 금액의 통화와 최소 단위는 연결 전에 맞춰야 하며 이 함수는 환율이나 소수 단위를 변환하지 않는다. 어떤 상품의 현재 가격을 확인한 예제도 아니다.

None과 빈 제목은 없는 관찰이지만 숫자 0은 존재하는 값이다. fetched의 빈 제목은 provided의 제목을 지우지 않는다. 반대로 제목에 숫자가 들어오거나 금액이 음수인 것처럼 계약을 어긴 값은 조용히 대체하지 않고 오류를 낸다. 유효한 대체 자료가 있다는 이유로 잘못된 원문 필드를 숨기지 않으려는 선택이다.

코드와 구현 살펴보기

독립 합성 전체 구현

"""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]}

후보의 출처를 필드별로 돌려준다

유효한 값은 필드마다 fetched를 먼저 고르고 그다음 provided를 본다. 제목은 원문에서 왔지만 배송비는 제공 자료에서 왔다면 field_origins에도 그 차이가 남는다. 제목이 어느 쪽에도 없으면 가격만으로 상품명을 만들어 후보를 채우지 않는다. 후보가 만들어져도 빠진 가격·배송비·재고는 missing_fields에 남긴다.

decision의 fetched_candidate와 provided_candidate는 제목의 선택 출처를 요약할 뿐 모든 필드의 출처를 대신하지 않는다. 자세한 판단은 field_origins로 읽어야 한다. 입력 사전을 수정하거나 결과와 같은 사전으로 공유하지 않으므로 화면이 후보를 편집해도 이번 함수 호출에 전달한 입력은 바뀌지 않는다. 지속 저장과 이력 보관은 별도 구현이다.

완전한 후보도 검토를 거쳐야 한다

모든 값이 있어도 review_required는 True이고 publish_ready는 False다. performs_action과 authenticates_sources도 False다. 이 고정된 경계는 실제 발행 권한을 구현했다는 뜻이 아니다. 이 패키지가 원문 진위나 검토 승인을 수행하지 않으므로 후보 구성 결과를 그 작업의 완료로 바꾸지 않는다는 뜻이다.

소스 폴더와 ZIP 추출 폴더에서 각각 독립 합성 시험 26개를 실행했다. 별도 다섯 사용 기록에는 제목만 읽은 경우, 원문 불가 뒤 제공 자료, 차단, 섞인 필드와 0, 빈 응답이 있다. 아래 선택기는 저장된 JSON을 보여 주며 Python이나 수집기를 브라우저에서 실행하지 않는다. DOM 대역 확인과 실제 화면 검수도 구별한다.

합성 로컬 기록의 읽기 뷰어

연결 전에 남은 책임을 읽는다

ZIP에는 독립 구현과 시험, 예제 실행기, 실제 합성 실행 기록과 적용 범위가 있다. 압축을 푼 폴더에서 python -B -m unittest -v로 확인할 수 있다. 수정·재배포·상업적 재사용을 허용하며 무보증으로 제공한다. 실제 업체 코드와 고객 자료를 꺼내 배포한 패키지가 아니라 이번 설명을 위해 새로 만든 예제다.

URL 검증, 원문 해석, CSV 읽기, 실제 상품 식별, 서버 권한, 저장과 발행은 포함하지 않는다. 수집이 성공했다고 선언된 값도 오래됐거나 잘못됐을 수 있다. 적용자는 그 자료를 검토한 근거와 후보 생성·원문 확인·실제 발행의 집계 기준을 따로 연결해야 한다. 원래 프로그램과 외부 계정은 이번 작업에서 실행하거나 바꾸지 않았다.

코드·시험·실행 기록 ZIP 받기
Python 표준 라이브러리 · 합성 자료 · 수정과 재사용 가능