맥락과 사용량 관리 - 대화 압축·새 세션·작업 쪼개기
이 장에서 배우는 것
같은 대화를 오래 이어 간다고 해서 AI가 작업의 모든 근거를 같은 정밀도로 유지하는 것은 아니다. 대화가 길어지면 처음 합의한 조건보다 최근의 오류 메시지가 더 두드러질 수 있다. 도구 실행 결과를 계속 붙이다 보면 정작 다음 수정에 필요한 결정 사항을 찾기 어려워지기도 한다. 맥락 관리는 대화를 짧게 만드는 요령이 아니라, 다음 판단에 필요한 정보를 골라 유지하는 작업이다.
이 장에서는 작은 팀이 대화 기록을 정리하고 작업을 넘기는 기준을 만든다. 완성 코드는 실제 AI 도구를 호출하지 않는다. 낱말 수로 기록의 글자 수를 어림하고, 보호할 기록을 남긴 채 요약 후보 구간을 고르는 계산기를 만든다. 계산 결과는 실제 모델의 한도를 보장하는 값이 아니라 팀이 기록을 정리할 시점을 판단하는 보조 자료다.
- 맥락 창이 차는 현상과 서비스 사용량 한도를 구분한다.
- 대화를 계속할 때와 새 세션을 열 때의 판단 기준을 세운다.
- 큰 파일과 실행 로그에서 필요한 범위만 전달한다.
- 요청을 독립적으로 검증할 수 있는 작업 단위로 묶는다.
- 요약할 구간을 선택하는 Python 프로그램을 실행하고 검증한다.
문제 상황
작은 팀이 명령줄 보고서 생성기를 고치고 있다. 처음에는 빈 입력 처리만 바꾸기로 했다. 그런데 대화에 소스 파일 전체, 여러 번의 실행 로그, 다른 기능의 개선 아이디어가 차례로 들어갔다. 작업자는 같은 오류를 설명하는 요청을 반복했고, AI는 이미 보류한 출력 형식 변경을 다시 제안했다.
문제는 기록이 부족해서가 아니다. 현재 작업의 조건과 지나간 탐색 기록이 같은 무게로 쌓인 것이 문제다. 팀은 먼저 다음 세 가지를 구분하기로 한다. 계속 지켜야 할 조건, 이미 끝난 탐색 과정, 다음 행동을 정하는 최근 기록이다.
이번 작업은 빈 입력 처리만 수정한다. 출력 형식은 유지한다. 원인 탐색의 상세 로그는 요약해도 되지만, 이 조건과 최종 검증 결과는 남긴다.
앞 장에서 외부 도구 연결을 다뤘다면, 여기서는 그 도구가 돌려준 결과까지 얼마나 대화에 남길지 판단한다. 연결된 도구의 출력이 길수록 원문 전체를 보존할 이유와 다음 판단에 필요한 이유를 구분해야 한다.
맥락 창과 사용량 한도는 다르다
맥락 창(context window)은 한 번의 판단에 참고할 수 있는 입력과 출력의 범위다. 대화뿐 아니라 지침, 읽은 파일, 도구의 반환 내용도 이 범위에 영향을 줄 수 있다. 텍스트는 보통 토큰(token)이라는 처리 단위로 다뤄진다. 낱말 하나가 토큰 하나라는 뜻은 아니다. 한국어 문장, 경로, 숫자, 소스 코드는 서로 다른 방식으로 나뉠 수 있다.
맥락이 길어질 때 앞 내용을 놓치는 현상에는 여러 원인이 있다. 기록이 입력 범위를 벗어날 수도 있고, 요약 과정에서 세부 사항이 빠질 수도 있다. 기록이 여전히 포함되어 있어도 필요한 조건을 답변에 제대로 반영하지 못할 수 있다. 따라서 “대화에 썼으니 기억할 것이다”라는 기대보다 현재 조건을 확인하는 절차가 필요하다.
대화 압축(compaction)은 긴 기록을 더 짧은 표현으로 바꾸는 과정이다. 압축은 원문 전체의 보존과 다르다. 오류를 찾으려고 시도한 순서는 줄여도 되지만, 채택한 결정과 그 이유, 아직 확인하지 못한 항목은 남겨야 한다. 잘못된 가정이 요약에 들어가면 이후 판단의 출발점도 잘못될 수 있다.
사용량 한도는 일정한 이용 조건에서 서비스를 얼마나 사용할 수 있는지에 관한 별도의 제약이다. 새 세션을 열어도 같은 계정이나 이용 조건에 묶인 한도가 초기화된다고 볼 수 없다. 반대로 사용량이 남아 있어도 한 대화에 너무 많은 정보를 넣으면 맥락 관리가 필요하다.
| 관찰한 현상 | 확인할 점 | 대응 |
|---|---|---|
| 처음 조건과 다른 수정을 제안한다 | 현재 입력에 조건이 남아 있는가 | 결정 사항을 확인하고 불필요한 기록을 줄인다 |
| 긴 기록을 압축했다는 안내가 나온다 | 요약에 빠진 제약과 미해결 항목이 있는가 | 요약을 원문과 대조한다 |
| 사용량 제한 안내가 나온다 | 안내에 적힌 적용 범위와 재개 조건은 무엇인가 | 반복 실행을 멈추고 작업 상태를 보존한다 |
| 새 세션에서도 이용이 제한된다 | 대화가 아닌 이용 조건에 걸린 제한인가 | 공식 안내를 확인하고 로컬 검증을 진행한다 |
제품별 동작은 달라질 수 있다. 다음 표의 도구 사실은 모두 2026년 10월 기준 예시다. 이 장에서는 확인되지 않은 압축 명령이나 사용량 조회 명령을 제시하지 않는다. 실제 압축 방식, 현재 기록 확인 방법, 이용 제한의 적용 범위는 각 도구의 공식 문서에서 확인한다.
| 도구 | 확인된 재개 수단 | 팀에서 확인할 사항 |
|---|---|---|
| Claude Code | -c 또는 --continue, -r 또는 --resume | 이어서 작업할 목표와 조건이 여전히 유효한가 |
| Antigravity CLI | -c 또는 --continue, --conversation <ID> | 재개할 대화에 다른 작업의 기록이 섞였는가 |
| Gemini CLI | 이 장에서는 재개 명령을 제시하지 않는다 | 사용 환경의 공식 문서에서 재개 방법을 확인한다 |
| Codex CLI | resume 하위 명령 | 대화에서 말한 상태와 현재 파일 상태가 일치하는가 |
이 표의 재개 수단은 기록을 이어 쓰는 기능에 관한 것이다. 요약의 정확성을 보장하거나 사용량 제한을 해제하는 수단으로 해석하지 않는다.
새 세션과 작업 단위를 정하는 기준
같은 목표를 해결하고 있고 앞선 관찰이 다음 수정에 직접 필요하다면 대화를 이어 가는 편이 자연스럽다. 반면 목표가 바뀌었거나, 보류한 접근이 반복해서 되살아나거나, 현재 상태를 설명하는 데 오래된 기록을 여러 번 정정해야 한다면 새 세션을 고려한다. 메시지 개수만으로 결정하지 않는다.
새 세션에는 대화 전체 대신 인계 메모를 전달한다. 메모에는 목표, 유지할 조건, 현재 변경, 실행한 검증과 결과, 남은 의문을 적는다. “테스트 통과”라는 문장만 적지 말고 무엇을 실행했는지와 확인하지 못한 범위를 함께 남긴다. 메모의 주장도 현재 파일과 변경 차이로 확인해야 한다.
목표: 빈 입력을 정상 종료로 처리한다.
조건: 기존 출력 형식을 유지한다.
현재 변경: 입력이 비었을 때의 분기를 추가했다.
검증: 빈 입력과 정상 입력을 직접 실행해 예상 결과와 비교했다.
미확인: 긴 입력에서의 처리 시간은 측정하지 않았다.
다음 행동: 변경 차이를 검토하고 누락된 경계 조건을 찾는다.
큰 파일도 같은 기준으로 다룬다. 파일 전체를 붙이기 전에 관련 함수, 호출 지점, 실패 입력을 먼저 고른다. 잘라 낸 부분에는 파일 경로와 범위, 생략한 부분의 역할을 덧붙인다. 필요한 정의가 빠져 AI가 추측하기 시작하면 그때 근거를 추가한다. 비밀값과 무관한 데이터까지 보내는 일을 줄이는 효과도 있다.
작업을 쪼갠다는 것은 한 줄씩 요청한다는 뜻이 아니다. 입력과 완료 조건이 분명하고, 한 번에 검증할 수 있는 변경으로 나눈다는 뜻이다. “함수를 읽어라”, “조건을 찾아라”, “수정해라”를 따로 보내기보다 관련 범위와 실패 사례를 한 요청에 묶으면 설명을 반복할 필요가 줄어든다. 다만 원인도 모르는 여러 오류를 한꺼번에 고치도록 묶으면 검증이 어려워진다.
보고서 입력 처리 함수와 호출 지점을 확인하고 빈 입력에서 실패하는 원인을 설명하라. 출력 형식을 유지하는 작은 수정을 제안하고, 빈 입력과 정상 입력의 검증 결과를 함께 보고하라. 관련 없는 정리는 보류하라.
사용량 제한 안내가 나오면 같은 요청을 곧바로 반복하지 않는다. 먼저 파일과 변경 차이를 확인하고, 완료한 일과 남은 일을 기록한다. 이후 재개 조건은 서비스 안내에 따른다. 기다리는 동안에도 로컬 실행, 테스트, 변경 차이 검토는 진행할 수 있다. 도구를 바꿔 이어 간다면 인계 메모와 현재 파일 상태를 다시 대조한다.
낱말로 만드는 보수적인 정리 기준
완성 프로그램은 공백으로 구분한 덩어리를 낱말로 센다. 각 낱말의 평균 길이를 네 글자로 가정하고, 낱말 사이의 공백을 더한다. 낱말이 여섯 개라면 추정치는 스물아홉 글자다. 이 값은 제품의 실제 한도와 무관한 연습용 지표다. 여기서 쓰는 예산과 여유분도 서비스가 제공하는 수치가 아니라 프로그램의 고정 입력이다.
이 계산은 실제 글자 수를 정확히 세려는 방법이 아니다. 실제 문자열이 있으면 글자 수 자체는 직접 셀 수 있다. 낱말 기반 추정은 팀이 가진 낱말 수 통계로 기록의 대략적인 크기를 비교하는 상황을 흉내 낸다. 긴 식별자나 공백 없는 코드가 많으면 크게 빗나갈 수 있으므로 실제 토큰 한도 판정에 사용하지 않는다.
프로그램은 예산에서 다음 응답과 추가 자료를 위한 여유분을 뺀 값을 정리 기준으로 삼는다. 명시적으로 보호한 기록과 최근 두 기록은 요약하지 않는다. 나머지 기록을 연속 구간으로 묶고 오래된 구간부터 검토한다. 요약문도 공간을 차지하므로 원문 추정치에서 요약문 추정치를 뺀 만큼만 절감으로 계산한다.
예제의 요약문은 사람이 미리 작성한 입력이다. 프로그램이 내용을 이해해 요약하거나 실제 대화를 삭제하지 않는다. 선택할 구간이 없거나 요약문이 너무 길면 예산 초과 상태를 그대로 보고한다. 이 구분이 있어야 계산 결과를 자동 삭제 승인으로 오해하지 않는다.
완성 코드
다음 내용을 main.py로 저장한다. 파일과 네트워크 입력 없이 고정된 대화 기록을 처리한다. 검증에 사용하는 숫자는 모두 예제 자료에서 나온 값이다.
from dataclasses import dataclass
@dataclass(frozen=True)
class Message:
number: int
text: str
protected: bool = False
@dataclass(frozen=True)
class Selection:
start: int
end: int
summary: str
saved: int
def estimate_chars(text: str, average: int = 4) -> int:
if average < 1:
raise ValueError("평균 낱말 길이는 양수여야 한다")
words = len(text.split())
return words * average + max(words - 1, 0)
def candidate_groups(
messages: list[Message], recent: int
) -> list[list[Message]]:
if recent < 0:
raise ValueError("최근 기록 수는 음수일 수 없다")
cutoff = max(0, len(messages) - recent)
groups: list[list[Message]] = []
current: list[Message] = []
for index, message in enumerate(messages):
if message.protected or index >= cutoff:
if current:
groups.append(current)
current = []
else:
current.append(message)
if current:
groups.append(current)
return groups
def choose_summaries(
messages: list[Message],
summaries: dict[tuple[int, int], str],
budget: int,
reserve: int,
recent: int = 2,
) -> tuple[list[Selection], int, int]:
if budget <= 0 or not 0 <= reserve < budget:
raise ValueError("예산과 여유분의 범위를 확인해야 한다")
target = budget - reserve
total = sum(estimate_chars(m.text) for m in messages)
selected: list[Selection] = []
for group in candidate_groups(messages, recent):
if total <= target:
break
key = (group[0].number, group[-1].number)
summary = summaries.get(key)
if summary is None or not summary.strip():
continue
original = sum(estimate_chars(m.text) for m in group)
saved = original - estimate_chars(summary)
if saved <= 0:
continue
selected.append(Selection(*key, summary, saved))
total -= saved
return selected, total, target
def main() -> None:
messages = [
Message(1, "이번 작업은 출력 형식을 유지하며 요약한다", True),
Message(2, "오류 재현에 필요한 입력 파일과 실행 순서를 확인했다"),
Message(3, "빈 입력에서 실패하는 원인을 찾고 재현에 성공했다"),
Message(4, "기존 출력 형식은 바꾸지 않고 빈 입력만 처리하기로 결정했다", True),
Message(5, "수정 후보를 비교하고 변경 하나를 선택했다"),
Message(6, "수정 빈 입력과 정상 입력을 실행하여 결과를 확인했다"),
Message(7, "검토자는 변경 차이와 테스트 결과를 확인해야 한다"),
Message(8, "다음 요청에서는 검토 결과를 보고한다"),
]
summaries = {
(2, 3): "오류 원인과 재현 조건을 확인했다",
(5, 6): "검증 결과와 남은 작업을 정리했다",
}
counts = [len(m.text.split()) for m in messages]
selected, after, target = choose_summaries(
messages, summaries, budget=260, reserve=60
)
before = sum(estimate_chars(m.text) for m in messages)
assert counts == [6, 8, 7, 9, 6, 8, 7, 5]
assert estimate_chars("") == 0
assert [(s.start, s.end) for s in selected] == [(2, 3), (5, 6)]
assert after == 179 and target == 200
no_choice, unchanged, _ = choose_summaries(
messages, {}, budget=260, reserve=60
)
assert not no_choice and unchanged == before
print("검증: 통과")
print(f"기록 수: {len(messages)}")
print(f"낱말 수: {sum(counts)}")
print(f"정리 전 추정 글자 수: {before}")
print(f"정리 기준: {target} (예산 260 - 여유분 60)")
print("보호 기록: 1, 4, 7, 8")
for item in selected:
print(f"요약 후보: {item.start}~{item.end}, 절감 {item.saved}")
print(f"정리 후 예상 글자 수: {after}")
print(f"판정: {'기준 이내' if after <= target else '추가 정리 필요'}")
if __name__ == "__main__":
main()
줄별 해설
Message와 Selection 선언. Message는 기록 번호, 본문, 명시적인 보호 여부를 담는다. Selection은 선택한 구간과 대체할 요약문, 예상 절감량을 담는다. 두 자료형 모두 생성 후 필드를 바꾸지 않도록 했다. 원문을 수정하는 대신 별도의 선택 결과를 만들어 검토할 수 있다.
estimate_chars 함수. split은 연속 공백과 줄바꿈을 낱말 경계로 처리한다. 빈 문자열의 낱말 수는 영이다. 낱말 사이의 공백 수가 음수가 되지 않도록 max를 사용한다. 평균 길이가 양수가 아니면 입력 오류로 처리한다. 이 함수는 문자열의 실제 길이나 모델의 토큰 수를 반환하지 않는다.
candidate_groups 함수. cutoff는 최근 기록을 보호하기 시작할 위치다. 보호 기록을 만나면 그 앞에 쌓은 후보를 하나의 구간으로 확정한다. 따라서 보호 기록을 사이에 둔 두 구간이 합쳐지지 않는다. 최근 기록 수가 전체 기록보다 많으면 모든 기록이 보호된다. 최근 기록 수가 영인 경우에도 명시적으로 보호한 기록은 남는다.
choose_summaries 함수의 입력 검사. 여유분은 영 이상이고 전체 예산보다 작아야 한다. 이 조건이 깨졌을 때 임의의 기준으로 계속 계산하지 않고 오류를 낸다. 실제 기록 크기에는 지침과 도구 정의 등이 더해질 수 있지만, 이 프로그램은 전달받은 메시지 본문만 계산한다.
후보 선택 반복문. 원래 순서대로 구간을 확인하므로 오래된 후보부터 선택한다. 이미 정리 기준 안에 들어왔다면 반복을 끝낸다. 미리 작성한 요약문이 없거나 비어 있으면 그 구간을 건너뛴다. 원문보다 요약문이 길면 절감이 없으므로 선택하지 않는다. 최소 개수의 구간을 찾는 최적화가 아니라 이해하기 쉬운 순서 규칙이다.
예제 기록과 요약문. 첫 기록과 결정 기록은 명시적으로 보호한다. 마지막 두 기록도 위치에 따라 보호된다. 따라서 후보는 2~3번과 5~6번이다. 6번 기록의 “수정 빈 입력과”라는 표현은 정리되지 않은 원문을 흉내 낸다. 계산기는 문법을 교정하지 않으며, 사람이 의미를 확인한 뒤 요약문을 승인해야 한다.
검증과 출력. 낱말 수, 빈 입력, 선택 구간, 최종 크기, 요약문이 없는 경우를 검사한다. 특히 요약문이 없으면 크기가 그대로 남는지 확인한다. 선택된 두 요약문이 원문의 의미를 충분히 보존하는지는 별도의 내용 검토 대상이다. 예를 들어 두 번째 요약문에는 원문에 명확히 없는 “남은 작업”이 들어 있다. 그대로 승인하지 말고 실제 검증 결과와 남은 일을 구체적으로 적어 고쳐야 한다.
실행 결과
터미널에서 다음 명령을 실행한다.
python3 main.py
예상 출력은 다음과 같다. 앞의 검증 코드는 이 값들이 나오는지 프로그램 안에서도 확인한다. 실행 후에는 소스의 변경 차이도 검토해 보호 조건이나 검증 코드가 의도하지 않게 바뀌지 않았는지 확인한다.
검증: 통과
기록 수: 8
낱말 수: 56
정리 전 추정 글자 수: 272
정리 기준: 200 (예산 260 - 여유분 60)
보호 기록: 1, 4, 7, 8
요약 후보: 2~3, 절감 49
요약 후보: 5~6, 절감 44
정리 후 예상 글자 수: 179
판정: 기준 이내
첫 후보의 원문 추정치는 73이고 요약문은 24이므로 49를 줄인다. 그때 남는 값은 223으로 정리 기준보다 크다. 두 번째 후보에서 44를 더 줄이면 179가 되어 선택을 멈춘다. “기준 이내”는 이 프로그램의 입력 자료와 추정식에 대한 판정이며, 실제 AI 도구에 보낼 수 있다는 보장은 아니다.
실무에서 자주 틀리는 것
낱말 수를 실제 토큰 수로 표시한다
다음 코드는 실행되지만 변수 이름이 계산 결과의 의미를 잘못 설명한다.
text = "빈 입력을 확인한다"
token_count = len(text.split())
print(token_count)
낱말 수와 글자 수 추정치를 분리해 이름을 붙인다. 실제 토큰 수가 필요하면 사용 환경에서 지원하는 공식 확인 방법을 별도로 조사한다.
text = "빈 입력을 확인한다"
word_count = len(text.split())
estimated_chars = word_count * 4 + max(word_count - 1, 0)
print(word_count, estimated_chars)
요약문이 차지하는 크기를 빼먹는다
원문을 줄였다는 이유로 원문 크기 전체를 절감량으로 잡으면 남은 공간을 과대평가한다.
total = 272
original_size = 73
after = total - original_size
print(after)
대체할 요약문을 포함해 계산한다. 기록의 제목이나 출처를 추가한다면 그 내용도 같은 기준으로 계산해야 한다.
total = 272
original_size = 73
summary_size = 24
after = total - original_size + summary_size
print(after)
오래된 기록을 조건 없이 지운다
앞부분에는 최초 요구나 변경 금지 조건이 들어 있을 수 있다. 위치만 보고 잘라 내면 짧아져도 재현성이 나빠진다.
records = ["출력 유지", "원인 탐색", "최근 검증"]
remaining = records[1:]
print(remaining)
보호 대상과 검토 대상을 구분한다. 다음 코드는 검토할 후보를 고를 뿐 삭제를 실행하지 않는다. 완성 프로그램은 여기에 최근 기록 보호와 연속 구간 선택을 더한다.
records = ["출력 유지", "원인 탐색", "최근 검증"]
protected_indexes = {0, 2}
candidates = [
text for index, text in enumerate(records)
if index not in protected_indexes
]
print(candidates)
정리 기준을 이미 넘었다는 사실을 숨긴다
계산값을 기준에 맞춰 잘라 표시하면 실제로 줄이지 않은 기록까지 줄인 것처럼 보인다.
estimated = 272
target = 200
reported = min(estimated, target)
print(reported)
추정치는 유지하고 초과 여부를 별도로 알린다. 더 줄일 수 없다면 새 세션용 인계 메모를 만들거나 필요한 원문 범위를 다시 선택한다.
estimated = 272
target = 200
print(estimated)
print("추가 정리 필요" if estimated > target else "기준 이내")
한눈에 보기
| 상황 | 남길 것 | 할 일 |
|---|---|---|
| 같은 목표를 계속 해결한다 | 현재 조건과 최근 검증 | 지나간 탐색 과정의 요약을 검토한다 |
| 작업 목표가 바뀐다 | 현재 상태와 인계 메모 | 새 세션에서 파일 상태를 대조한다 |
| 큰 파일을 참고해야 한다 | 관련 범위와 호출 관계 | 부족한 정의를 확인하면서 범위를 넓힌다 |
| 요청을 반복하고 있다 | 실패 입력과 완료 조건 | 검증 가능한 변경 단위로 요청을 묶는다 |
| 사용량 제한 안내가 나온다 | 변경 내용과 미완료 항목 | 반복 호출을 멈추고 재개 조건을 확인한다 |
| 예산 안으로 들어왔다 | 추정식과 보호 규칙 | 요약의 의미와 실제 실행 결과를 따로 검토한다 |
연습 문제
- 최근 보호 기록 수를 세 개로 바꾸면 어떤 구간이 선택되고 예상 크기는 얼마가 되는지 계산하라. 변경 후 프로그램을 실행해 확인하라.
- 예산을 400, 여유분을 60으로 바꾸면 후보 선택 결과가 어떻게 달라지는지 설명하라. 기존 검증문에서 어떤 기대값을 바꿔야 하는지도 적어라.
- 5~6번 요약문에서 원문으로 확인할 수 없는 내용을 제거하라. 수정한 요약문의 낱말 수와 최종 예상 크기를 계산하고 관련 검증문을 고쳐라.
- 사용량 제한 안내를 받은 상황에서 새 세션을 여는 것만으로 해결되지 않는 이유를 설명하고, 다음 작업자가 받을 인계 항목 다섯 가지를 적어라.
정답과 해설
- 최근 세 기록인 6~8번이 보호된다. 후보는 2~3번과 5번 단독 구간이다. 예제 요약문에는 5번 단독 구간의 항목이 없으므로 2~3번만 선택한다. 예상 크기는 223이고 추가 정리가 필요하다. 보호 범위를 바꾸면 요약문 사전의 구간도 다시 검토해야 한다.
- 정리 기준은 340이고 원래 추정치는 272이므로 선택 결과는 빈 목록이다. 최종 크기는 272다. 선택 구간 검증과 최종 크기·기준 검증을 이 값에 맞게 바꾼다. 요약문이 없는 경우의 검증은 원문 크기를 유지한다는 점에서 그대로 성립한다.
- 예를 들어 “변경을 선택하고 두 입력을 검증했다”로 고칠 수 있다. 낱말은 다섯 개이고 추정치는 24로 기존과 같으므로 최종 예상 크기도 179다. 수치 검증은 유지되지만 요약문 자체는 원문과 대조한다. 실제 인계에서는 두 입력이 빈 입력과 정상 입력이었다는 사실과 검증 결과도 구체적으로 보완하는 편이 낫다.
- 세션의 맥락 범위와 서비스 이용 한도는 서로 다른 제약이기 때문이다. 인계에는 목표, 유지할 조건, 현재 변경, 검증 방법과 결과, 미완료 항목을 남긴다. 재개하는 사람은 이 메모를 현재 파일 및 변경 차이와 대조한다.
맥락 예산 계산기는 정리할 후보를 보여 주지만 무엇이 사실인지 판정하지 않는다. 짧아진 기록에서도 조건과 검증 근거를 복원할 수 있어야 한다. 다음 장에서는 이렇게 정리한 작업 상태를 바탕으로 작성자와 검토자의 역할을 나누고, 서로의 파일 변경이 섞이지 않도록 작업 공간을 분리한다.