본문으로 건너뛰기
cccskills
무료GitHub에 공개한국어 소개

Review testdata changes

컴파일러 테스트 출력 차이가 코드 변경의 의도와 맞는지 검토하는 방법을 안내합니다. 사용자에게 보이는 진단과 내부 출력을 나눠 살피고, 숨은 회귀를 찾으며 자동 갱신 뒤 테스트를 확인하는 절차를 다룹니다.

원문원문 설명 보기

Instructions for judging whether changes to file test output (`// CHECK:STDOUT:` and `// CHECK:STDERR:` lines) are correct, which changes are acceptable churn, and which are regressions in disguise.

carbon-language/carbon-lang스타 33,929(GitHub 33,929 + cccskills 0)

실행 점수 미검증

설치 방법 보기

이럴 때 유용합니다

  • 자동 갱신 뒤 출력 차이 검토
  • 진단 메시지 변경 근거 확인
  • 내부 출력 변경 원인 추적
  • 테스트 이름과 예상값 점검

한국어 소개

할 수 있는 일

이 스킬은 Carbon 도구 체인 테스트의 // CHECK:STDOUT: 및 // CHECK:STDERR: 행이 바뀐 경우 그 변경이 올바른지 판단하는 방법을 설명합니다. 자동 갱신 후 테스트가 통과해도 새 동작이 의도한 결과라는 뜻은 아닙니다. 각 변경의 원인을 설명할 수 있는지 확인하고, 사용자에게 보이는 진단인 표준 오류와 내부 표현인 표준 출력을 따로 검토합니다. 명령어, 형식, 제어 흐름 같은 구조적 변경은 각각 이유를 확인하고, 이름 변경이나 위치 번호 재정렬은 기계적인 변경인지 살펴봅니다. 진단 변경을 갱신 전에 세운 예상과 비교하고, 결과가 더 이상 바뀌지 않을 때까지 확인한 뒤 테스트 실행과 파일 이름 접두사도 점검합니다.

이럴 때 유용합니다

테스트 출력을 자동 갱신한 뒤 차이를 그대로 받아들여도 되는지 판단할 때 사용할 수 있습니다. 리팩터링 중 예상하지 못한 진단 변경이 있는지, 내부 출력의 변화가 코드 변경으로 설명되는지도 검토할 수 있습니다.

사용 예시

  • “이 테스트 출력 차이가 코드 변경의 의도와 맞는지 확인해 주세요.”
  • “표준 오류와 표준 출력의 변경을 나누고 설명되지 않는 차이를 찾아 주세요.”
  • “테스트 출력 갱신 후 확인할 항목을 정리해 주세요.”

주의 사항

// CHECK:STDOUT: 또는 // CHECK:STDERR: 행을 직접 편집해 차이를 맞추는 절차가 아닙니다. 검토에는 저장소의 테스트 갱신 절차와 테스트 실행이 포함됩니다.

이 소개문은 공개된 SKILL.md를 바탕으로 AI(OpenAI Codex)가 작성했습니다. 정확한 사양은 아래 원문을 확인하세요.

문서 점검

AI가 SKILL.md의 내용에서 주의가 필요한 작업과 도입 전제를 확인했습니다. 점수는 실제로 실행한 결과(실행 검증)만으로 매깁니다.

안전성전송·삭제·명령 실행 등을 명시하고 있는가
B일부 부족업데이트 도구가 이전 예상값을 덮어쓰므로 매번 차이를 확인하라고 안내합니다.
도입의 용이성필요한 도구나 API 키가 적고 적혀 있는가
B일부 부족저장소의 테스트 갱신 절차와 실행 환경을 사용하지만 설치 안내는 없습니다.

점수에는 넣지 않았습니다. 2026년 10월 26일 기준으로 AI(OpenAI Codex)가 판정했습니다. 참고용이므로 설치 전에 원문도 확인해 주세요.

평가가 다르다고 생각되면 재검토를 요청하기

어느 항목이 왜 다르다고 생각하는지 적어 주세요. 로그인은 필요 없습니다. SKILL.md와 대조해 평가를 다시 만들고 이곳에 반영합니다.

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

포함된 파일(1)

  • SKILL.md16.5 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Review testdata changes

<!-- Part of the Carbon Language project, under the Apache License v2.0 with LLVM Exceptions. See /LICENSE for license information. SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -->

Introduction

Most toolchain work moves file test output. ./toolchain/autoupdate_testdata.py rewrites the // CHECK:STDOUT: and // CHECK:STDERR: lines in toolchain/*/testdata/ to match current behavior, so after running it the tests pass again whether or not the new behavior is right. Deciding that the new output is the output you wanted is a separate, manual step, and it is the step this skill covers.

Three skills divide the work:

[!IMPORTANT] Never hand-edit // CHECK:STDOUT: or // CHECK:STDERR: lines. Everything below is about changing the code until the generated output is right, never about editing the output to match the code.

The rule that generates all the others

Every line of testdata churn must have a cause you can name. Not "it is similar to the other changes", not "the tests pass now" — an actual sentence saying which code change produced it and why that is the intended result.

A diff you cannot narrate is a diff you have not reviewed. Changes you cannot explain are where regressions hide, because a regression and an intended change look exactly alike once the autoupdater has written them down.

[!CAUTION] Autoupdating is destructive to your evidence. Once the autoupdater has run, the previous expectations are gone from the working copy. Read the diff after every autoupdate run, and if something changed for a reason you cannot name, fix the code before autoupdating again. Recovering the old expectations later means reverting and re-running.

STDERR and STDOUT are different kinds of evidence

Treat them separately; they have different standards of proof.

STDERR is user-visible behavior. These are the diagnostics a Carbon programmer sees. A change here is a change to the language implementation as users experience it, so each one needs an individual justification. For a refactoring, the expected STDERR diff is empty.

STDOUT is internal representation. SemIR dumps, parse trees, LLVM IR. Users never see it. Churn here is normal and often unavoidable, so the standard is not "no change" but "no change I cannot account for".

For a change that is supposed to preserve behavior, write the list of accepted STDERR changes down before you autoupdate, and keep it current. Order matters more than form: written first, the list is a prediction the diff can falsify; written afterwards, it is a description of whatever happened, and describes a regression exactly as well as an intended change.

The list does not have to be a deliverable. Scratch notes you never publish do the job, because the work is in committing to the list, not in presenting it. What a reader needs is not the list but its exceptions: diagnostics that changed without being predicted, and predictions that did not occur. Both are findings. The matches are not, and reporting them buries the two entries that matter.

Judging STDOUT churn

Sort each STDOUT change into mechanical or structural.

Mechanical churn

Expected, and cheap to accept in bulk once you have confirmed the pattern:

  • Renaming. An instruction, type, or scope prints under a new name.
  • Positional name renumbering. Names like %x.loc18_46.3 embed a line, column, and disambiguating index. Two different events move them:
    • Adding or removing an instruction at a location renumbers the rest, so a single removed instruction can show up as many changed lines in the same block. Confirm the cascade is a cascade before accepting it as one.
    • Adding or removing a diagnostic moves the source lines themselves, so the line component changes everywhere below it in the file. See Autoupdate to a fixed point.
  • Fingerprint-derived names. Mangled names and some scope names are derived from a hash of their inputs. If you changed a hashed input, these move. Confirm that each such difference is only the fingerprint, and not a fingerprint difference concealing a structural one.

[!TIP] Mechanical churn is usually wide and shallow: the same substitution, repeated across many files. If a "mechanical" pattern needs a different explanation in each file, it is not mechanical.

Structural churn

Each of these needs its own explanation:

  • Instructions appearing or disappearing.
  • Changed [concrete = ...], [symbolic = ...], or other constant-value annotations.
  • Changed types on existing instructions.
  • Changed control flow: new or removed blocks, changed branch targets.
  • Raw instruction ids renumbering in --dump-raw-sem-ir output when you did not intend to change the id layout.

Fewer instructions is not automatically better

A diff that removes instructions looks like an optimization. Whether it is one depends on what the changed function owes its caller, and two functions can produce the same shrinking diff for opposite reasons:

  • A function that only needs a constant value, but built instructions on the way to it, was doing wasted work. Dropping them and using the constant directly is correct, and the shorter output reflects that.
  • A function whose caller needs a non-canonical instruction can be made shorter the same way, by using the constant instead of creating an instruction of its own — and that is wrong. The instruction carries location information, and symbolic constant substitution operates on it; the constant value alone loses both.

The instruction count is identical evidence in both cases, so it cannot be the thing you judge. Decide what the function is required to produce; the count follows from that.

The same reasoning runs in reverse: a diff that adds instructions is not automatically a regression.

Judging STDERR churn

A diagnostic's authority depends on the file's prefix

The fail_ and todo_ prefixes (see Toolchain tests) say how much the recorded diagnostics are worth:

  • fail_... — the test should and does produce errors. The recorded diagnostic is the specification. Changing it is a user-visible behavior change and needs justification on its own merits.
  • fail_todo_... — the test produces errors (or crashes) but shouldn't, or produces the wrong errors. The recorded diagnostic is explicitly not the specification; the file exists to record that today's behavior is wrong. Changing it replaces one wrong answer with another. That is acceptable when you can say why the new message follows from your change and why it is no further from the intended eventual behavior — which, for many such files, is no diagnostic at all.
  • todo_fail_... — the test should produce errors but does not. Gaining a diagnostic here may be progress, not a regression. Either way the file must be renamed, since the framework requires a fail_ prefix on any file that errors: fail_... if it now produces the right error, fail_todo_... if the error is the wrong one. Both renames make the test pass, so record which case it is instead of letting the rename settle it.
  • todo_... — behavior is wrong but produces no errors, and shouldn't. Gaining a diagnostic here is a regression unless you can argue otherwise.

[!IMPORTANT] This is a reason to look at the filename before judging a diagnostic change, not a license to ignore todo_ files. "It was already broken" does not excuse making it differently broken for no reason.

Reclassifying tests

If your change moves a test between the states above, the prefix must move with it: when the test is fixed, when it starts failing, and when it starts failing differently. The correspondence between the fail_ prefix and whether compilation actually failed is enforced by the test framework, not by the autoupdater, so it surfaces when you run bazelisk test and not when you autoupdate. Autoupdating is not a substitute for running the tests.

Only that half of the name is checked. Nothing enforces todo_, so a file whose behavior you have just fixed can keep its todo_ prefix indefinitely and still pass. A missing fail_ stops the build; a stale todo_ is silent, and is yours to catch.

When a fix drops a file's prefix, also check that the file still belongs where it is and that its comments do not still describe the old broken behavior.

Vaguer diagnostics are a signal, not a verdict

When a diagnostic becomes less specific — a general "unsupported" message replacing one that named the problem — that usually means a code path stopped finding information it previously had. Sometimes that is correct: the information was misleading, and the old message was confidently wrong.

Do not accept it silently and do not reject it reflexively. Say which direction it moved and whether the new message is closer to or further from the eventual intended behavior.

Signals in the shape of the diff

Zero churn is a result

If you removed something you believed was doing work and no testdata moved, that is not a missing test run — it is the proof that the thing was a no-op. Say so explicitly; it is one of the strongest pieces of evidence a refactoring can produce.

The converse is also informative. If you expected a path to churn and it didn't, either your model of the code is wrong or that path is untested. Find out which, and consider adding a test before continuing.

Churn should be proportional to the change

  • Wide churn from a narrow change means your model of the code is wrong. Do not autoupdate over it. Find the structural mistake first.
  • Narrow churn from a sweeping change means the affected paths are probably untested.

Set a rough expectation for the size of the diff before you run the autoupdater, and treat a large mismatch in either direction as a finding.

Never make the diff smaller by weakening the test

Editing test input (the Carbon source, not the CHECK lines) to make a diff look better is a behavior change in disguise. Deleting a test that now produces awkward output is worse. If a test's input has to change, that is a separate, explicitly-justified change, not diff cleanup.

What the autoupdater will not fix for you

  • NOAUTOUPDATE files. Their expectations are maintained by hand. They fail under bazelisk test rather than being silently rewritten.
  • Hand-written C++ expectations, for example golden output asserted in a _test.cpp. When several assertions in one of these break together, often only the first failure is reported, so fixing it can reveal another. Re-run until clean rather than assuming one fix was the whole repair.
  • Golden files outside testdata/, and documentation that quotes compiler output.

Review loop

Run the autoupdater

Autoupdate everything, then read the diff a directory at a time. Passing no paths is the default and updates every file test in the toolchain:

./toolchain/autoupdate_testdata.py

Narrow the scope only while iterating on one subdirectory you know you are not done with, where each round would otherwise regenerate output you have already read:

./toolchain/autoupdate_testdata.py toolchain/check/testdata/SUBDIR/**/*

The globs are expanded by the shell; the script filters its arguments to .carbon files under a testdata/ directory.

[!TIP] If intermediate states crash on CARBON_CHECK failures, pass --non-fatal-checks so you can see the full set of downstream damage in one run instead of one crash at a time.

[!IMPORTANT] Return to the full scope before judging the diff. Whether churn is proportional to the change, and whether a change to one phase moved another phase's testdata, are only visible across everything.

Autoupdate to a fixed point

One pass is not always enough, because the autoupdater's output is part of its own input. // CHECK:STDERR: lines sit inline, immediately above the source line they describe, and the compiler reads them as comments in the file. Gaining or losing a diagnostic therefore moves every source line below it.

Within a single run, the compiler has already read the file as it was, so the two kinds of output end up in different states:

  • STDERR is correct after one pass. These lines locate themselves relatively, as [[@LINE+N]], and the autoupdater recomputes N as it places them.
  • STDOUT is stale after one pass. SemIR names like %x.loc18_46.3 embed an absolute line and column with no filename attached, and the autoupdater only remaps file.carbon:18-style references. Nothing rewrites the loc, so it still describes where the instruction was before the diagnostic lines moved it.

Running again compiles the shifted file and the names catch up. The diagnostic set does not change this time, so nothing shifts again and a third run is a no-op. Keep running the autoupdater until it stops changing files: one pass when the diagnostics held still, two when they didn't.

[!WARNING] The intermediate state is self-inconsistent, not just unfinished: its loc names describe a file layout that no longer exists. Keep reading the diff after every run — that rule does not change — but do not chase positional churn to a cause until the file has converged, and do not present the diff until then either.

The converging pass should be positional renumbering and nothing else. If it moves an instruction, a type, or a constant value, then something other than a loc name is sensitive to where lines fall in the file. Find out what before accepting it.

The file tests do catch a file left unconverged, since each test re-runs the autoupdate in memory and fails with Autoupdate would make changes to the file content when the result differs. But that arrives at bazelisk test time, after you have already read a diff that was describing a file which had moved out from under it.

Inspect the diff

Inspect the diagnostics first, since that is the acceptance criterion:

# STDERR-only view, with jj.
jj --no-pager diff --git 'glob:toolchain/*/testdata/**' \
  | grep -E '^[-+].*CHECK:STDERR'

# The same, with git.
git diff -- 'toolchain/*/testdata/*' \
  | grep -E '^[-+].*CHECK:STDERR'

For a structured view separating test input, STDERR, and STDOUT changes, use the helper from the Summarize testdata changes skill:

jj --no-pager diff --git 'glob:toolchain/*/testdata/**' \
  | python3 .agents/skills/summarize_testdata_changes/scripts/parse_diff.py

git diff -- 'toolchain/*/testdata/*' \
  | python3 .agents/skills/summarize_testdata_changes/scripts/parse_diff.py

The argument after the tool name is not interchangeable: glob:... is a jj fileset, -- ... is a git pathspec. --git and --no-pager are jj flags; git already emits this format and skips the pager when piped.

Run the tests

Then run the tests, which is what catches prefix mismatches and non-autoupdated expectations:

bazelisk test //toolchain/...

See the Bazel usage skill.

Checklist

Before presenting a testdata diff as finished:

  • The autoupdater was run until it made no further changes, so no loc name describes a stale line numbering.
  • The list of accepted STDERR changes was written before autoupdating, and every change either matches it or is reported as an exception.
  • Every STDOUT change is either an instance of a named mechanical pattern or has its own explanation.
  • Instructions that appeared or disappeared are justified by what the changed function owes its caller, not by the instruction count.
  • Files whose prefix no longer matches their behavior have been renamed.
  • No test input was changed, and no test was deleted, to make the diff smaller.
  • The size of the diff is proportional to the size of the change.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Accessing GitHub issues

무료요약 있음

명령줄의 `gh`로 GitHub 이슈 본문과 댓글을 읽기 전용으로 확인하는 방법을 안내합니다. 번호나 URL로 이슈를 찾고 다른 저장소를 지정하는 방법, 댓글이 많은 경우 JSON과 `jq`로 내용을 추출하는 방법을 다룹니다.

  • 이슈 본문과 댓글 읽기
  • URL로 이슈 내용 확인
  • 다른 저장소의 이슈 조회
carbon-language/carbon-lang3.4만2026년 10월 26일 업데이트

Agent tools

무료요약 있음

Carbon 저장소에서 일하는 AI 도우미가 전용 환경 도구로 파일을 읽고 검색하고 편집하는 규칙을 안내합니다. 임시 파일을 둘 위치와 삭제 시점, 사용자 지정 프로그램을 허용하는 경우도 설명합니다.

  • 정해진 도구로 Carbon 파일 검색
  • 파일 변경에 맞는 전용 도구 선택
  • 임시 파일 위치와 삭제 규칙 확인
carbon-language/carbon-lang3.4만2026년 10월 26일 업데이트

Bazel usage

무료요약 있음

Carbon 프로젝트에서 Bazelisk로 빌드, 테스트, 실행하는 기본 절차를 안내합니다. 대상을 지정한 검증, ASan 활성화, 시스템 의존성 변경 후 캐시 재생성도 다룹니다.

  • Carbon 코드 빌드
  • 변경 사항과 관련된 테스트 실행
  • Bazel로 빌드한 프로그램 실행
carbon-language/carbon-lang3.4만2026년 10월 26일 업데이트

Builtin functions

무료요약 있음

Carbon 컴파일러에 내장 함수를 추가하는 절차를 안내합니다. 함수 등록과 시그니처 검증부터 상수 평가, 런타임 호출의 LLVM IR 생성, Prelude 연결, 최소 Prelude를 이용한 개별 테스트까지 다룹니다.

  • 내장 함수 등록
  • 상수 평가 구현
  • LLVM IR 생성 추가
carbon-language/carbon-lang3.4만2026년 10월 26일 업데이트

Code style

무료요약 있음

Carbon 툴체인의 Bazel, C++, Carbon, Markdown, Python 파일 서식 기준을 안내합니다. 주석, 문서, 이름, 설계 원칙과 변경 내용을 설명하는 커밋 메시지 작성법도 다룹니다.

  • Carbon 코드와 관련 파일 서식 정리
  • 주석과 문서 검토
  • 이름이 실제 의미에 맞는지 확인
carbon-language/carbon-lang3.4만2026년 10월 26일 업데이트

Diagnostics

무료요약 있음

Carbon 도구 체인에서 오류와 경고 진단을 추가하거나 수정하는 방법을 안내합니다. 진단 종류 등록, 형식이 지정된 인수로 메시지 구성, 소스 위치에 라벨과 문맥 연결, 문구 규칙 및 테스트 범위 확인을 다룹니다.

  • 진단 메시지 추가
  • 소스 위치에 라벨 지정
  • 진단 문구 통일
carbon-language/carbon-lang3.4만2026년 10월 26일 업데이트

carbon-language의 스킬 모두 보기

이 스킬의 문제 신고