price를 amount로 바꾸려면, 새 필드를 추가한 서버부터 배포해야 합니다. 구형·신형 소비자를 다섯 응답 형태에 연결해 보니 HTTP 요청 열 번은 모두 200이었지만, 데이터 계약을 통과한 조합은 네 개였습니다.
| 서버 응답 | 구형: price 읽기 | 신형: amount 읽기 |
|---|---|---|
| price:12000 | 통과 | 필드 없음 |
| price:12000, amount:12000 | 통과 | 통과 |
| amount:12000 | 필드 없음 | 통과 |
| price:12000, amount:13000 | 값 충돌 | 값 충돌 |
| 두 필드 모두 문자열 “12000” | 자료형 오류 | 자료형 오류 |
2026년 10월 5일 Node.js 18.16.0의 임시 루프백 HTTP 서버와 두 소비자로 직접 실행했습니다. 모든 요청은 로컬에서 끝났습니다. 이 시험의 계약은 “0 이상의 안전한 정수 원화 금액, 호환 필드가 함께 있으면 같은 값”입니다. 어떤 API든 문자열 금액이 잘못됐다는 뜻이 아니라, 선언한 계약과 실제 응답이 같아야 한다는 비교입니다.
배포와 되돌리기 순서를 같이 정합니다
- 확장: 서버가 price와 amount를 같은 값으로 제공하게 합니다. 구형·신형 소비자 모두 검사합니다.
- 전환: 신형 소비자를 배포합니다. 이때 구형으로 되돌려도 price가 남아 있어야 합니다.
- 사용 종료 확인: 구형 웹, 모바일, 배치와 캐시의 사용 여부를 로그와 배포 목록으로 확인합니다. 서버 시험 한 번으로 종료를 추정하지 않습니다.
- 정리: 구형 필드를 제거합니다. 이후 구형 소비자로 되돌려야 한다면 서버의 호환 필드도 함께 복구해야 합니다.
AI에 서버와 화면 수정을 병렬로 맡길 때도 이 순서를 작업 지시서에 적으세요. 두 브랜치가 각각 통과했다는 결과는 혼합 버전의 호환성 증거가 아닙니다. 금액 0, null, 두 필드 불일치도 정상 입력과 함께 시험해야 합니다.
한 파일로 열 가지 조합을 재현합니다
아래를 새 빈 폴더의 contract.cjs로 저장합니다. 같은 폴더에 results 폴더를 만든 뒤 node contract.cjs를 실행하세요. 별도 패키지나 API 키는 필요 없습니다. 테스트 서버는 127.0.0.1의 임시 포트만 사용하고 종료 시 닫힙니다.
전체 재현 코드
/** Run: node contract.cjs. No dependencies, AI calls or external network.
* The disposable HTTP fixture deliberately includes invalid server contracts.
* A failed contract is an expected observation; assertions verify the matrix.
*/
const http = require('node:http');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const fixtures = {
old: {price:12000},
bridge: {price:12000, amount:12000},
next: {amount:12000},
conflict: {price:12000, amount:13000},
strings: {price:'12000', amount:'12000'}
};
// Presence alone is insufficient. This small KRW contract requires integer values.
function consume(body, field) {
if (!Object.hasOwn(body,field)) return {ok:false,reason:'MISSING_FIELD'};
if (!Number.isSafeInteger(body[field]) || body[field]<0) return {ok:false,reason:'INVALID_TYPE'};
// During the bridge period both field names must mean the same amount.
if (Object.hasOwn(body,'price') && Object.hasOwn(body,'amount') && body.price!==body.amount)
return {ok:false,reason:'CONFLICTING_ALIASES'};
return {ok:true,value:body[field]};
}
(async()=>{
const server=http.createServer((req,res)=>{
res.setHeader('Content-Type','application/json');
res.end(JSON.stringify(fixtures[req.url.slice(1)]));
});
await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));
const results=[];
try {
for(const [name,body] of Object.entries(fixtures)) for(const field of ['price','amount']) {
const response=await fetch(`http://127.0.0.1:${server.address().port}/${name}`);
const result=consume(await response.json(),field);
const expected=name==='bridge'||(name==='old'&&field==='price')||(name==='next'&&field==='amount');
assert.equal(response.status,200);
assert.equal(result.ok,expected);
results.push({server:name,consumer:field,http:response.status,...result});
}
assert.equal(consume({price:0,amount:0},'amount').value,0);
assert.equal(consume({amount:null},'amount').ok,false);
const output={environment:{node:process.version,host:'loopback only'},results,passedContracts:results.filter(x=>x.ok).length,failedContracts:results.filter(x=>!x.ok).length,assertions:22};
fs.writeFileSync(path.join(__dirname,'results','contract.json'),JSON.stringify(output,null,2));
console.log(JSON.stringify(output,null,2));
} finally {await new Promise(resolve=>server.close(resolve));}
})().catch(error=>{console.error(error);process.exitCode=1});
출력의 passedContracts=4, failedContracts=6이 기대값입니다. 실패 여섯 건은 버그를 숨긴 것이 아니라 부적합 응답을 의도대로 거절한 관찰입니다. 코드의 assertion이 실패하면 환경·출력·fixture 변경을 확인하고, 통과 숫자만 임의로 맞추지 마세요. results/contract.json에는 조합별 상태가 남습니다.
이 시험만으로 보장하지 못하는 것
읽기 응답의 필드 전환만 다뤘습니다. 쓰기 요청, 필수 값 변경, DB 마이그레이션, 여러 통화, API 인증, 실제 화면 렌더링과 모바일 잔존 버전은 따로 검사해야 합니다. 실제 Claude 제품이나 운영 서비스를 실행한 결과가 아닙니다. 특정 AI 제품 소개를 이 실험의 근거로 사용하던 이전 구성을 제거했습니다.
자료: 자체 HTTP 응답·소비자 코드·실행 기록. Node.js HTTP 및 assert API 문서와 함께 확인한 재현 예제입니다. 확장 후 정리하는 호환 변경 자체를 새로운 기법이라고 주장하지 않습니다. 이 글은 누락·값 충돌·자료형 오류를 한 번에 확인할 수 있는 실행 자료를 제공합니다.
관련 실험: 재시도와 중복 저장 · 빈 입력과 0원 주문
작성·실험 정리: HEYDLIFE 운영자와 AI 작성 보조. 개정: 2026년 10월 5일. 가상 자료로 수행한 시험과 실제 서비스 사용 성과를 구분했습니다.