Red Before Green
The test exists before the feature does
Prompt compliance: Not tested yet
What it does
Makes it write a test that fails on purpose, run it, show you the failure, and only then build the thing.
When to use it
Any feature where “it seems to work” would otherwise be your only proof.
The prompt
CONTEXT
What I want: <one sentence>. The testing tool already in
this project: <name>.
RULES
- Step one is a test, and only a test. Stop after it.
- Run it and show me what it printed, proving it fails for
the right reason — because the feature is missing, not
because the test itself is broken.
- Only build it after I say go. You may not edit the test.
DONE MEANS
- The failing test says in its own name exactly what it is
checking.
- The failure is about the feature, not about setup.
- After you build it, the very same test passes, unchanged.
LAY IT OUT LIKE THIS
First reply: the test, the command, and the failing output.
Then the word WAITING.
Second reply, after I say go: the changed lines, the command,
and the passing output.Ways to use it
- If it cannot make the test fail first, the test checks nothing
- Keep the failing output with the change
- Do this for bugs too: make it break on demand, then fix it
Try a small example: clean up tags
Executable example: reproduced pass · October 4, 2026
Turn [" AI ", "ai", "", "Tools"] into ["ai", "tools"].
Trim spaces, lowercase tags, remove duplicates and drop blanks. An all-blank list must become an empty list.
- Write those two expected outcomes before changing the function.
- Write one named test for each outcome.
- Run them against the unfinished function: both fail with the wrong returned list.
- Freeze the test file. Keep its hash and failing output.
- Change only the function: the same two tests pass.
- Copy the function and frozen test into a fresh folder: both pass again.
Download the runnable example and evidence (ZIP)
Unzip it and run python3 reproduce.py. Python is required; no package install or API key.
The helper shows the intended failure, then the pass in separate fresh folders, and checks the saved file hashes.
Scope: a guided execution by Codex in ChatGPT Work, using Python 3.12.14 on Linux. The two cases passed; the prompt's separate-turn WAITING/approval behavior was not scored. This adds an executable example while the prompt-compliance test log remains unscored.
Open the evidence and technical limits
One attempt each for the original red, green and clean phases. The test SHA-256 is unchanged:
b56a34366a2ed3996788d9938e3179aa4eed3a7c48bc0f06c4ea3543cc80695d.
The clean rerun used a new folder on the same Python runtime. Other versions, non-string inputs, Unicode case-folding rules, full apps and security were not evaluated. The implementing agent performed the check; this is not an independent model comparison.
The frozen acceptance test
import unittest
from normalize_tags import normalize_tags
class TagNormalizationAcceptance(unittest.TestCase):
def test_trims_lowercases_deduplicates_and_drops_empty_tags(self):
self.assertEqual(normalize_tags([" AI ", "ai", "", "Tools"]), ["ai", "tools"])
def test_all_empty_tags_return_an_empty_list(self):
self.assertEqual(normalize_tags(["", " ", "\t"]), [])
if __name__ == "__main__":
unittest.main()
First run: two intended failures — exit 1
test_all_empty_tags_return_an_empty_list (test_normalize_tags.TagNormalizationAcceptance.test_all_empty_tags_return_an_empty_list) ... FAIL
test_trims_lowercases_deduplicates_and_drops_empty_tags (test_normalize_tags.TagNormalizationAcceptance.test_trims_lowercases_deduplicates_and_drops_empty_tags) ... FAIL
======================================================================
FAIL: test_all_empty_tags_return_an_empty_list (test_normalize_tags.TagNormalizationAcceptance.test_all_empty_tags_return_an_empty_list)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/workspace/scratch/763ddcfd142e/red-green-witness/test_normalize_tags.py", line 11, in test_all_empty_tags_return_an_empty_list
self.assertEqual(normalize_tags(["", " ", "\t"]), [])
AssertionError: Lists differ: ['', ' ', '\t'] != []
First list contains 3 additional elements.
First extra element 0:
''
- ['', ' ', '\t']
+ []
======================================================================
FAIL: test_trims_lowercases_deduplicates_and_drops_empty_tags (test_normalize_tags.TagNormalizationAcceptance.test_trims_lowercases_deduplicates_and_drops_empty_tags)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/workspace/scratch/763ddcfd142e/red-green-witness/test_normalize_tags.py", line 8, in test_trims_lowercases_deduplicates_and_drops_empty_tags
self.assertEqual(normalize_tags([" AI ", "ai", "", "Tools"]), ["ai", "tools"])
AssertionError: Lists differ: [' AI ', 'ai', '', 'Tools'] != ['ai', 'tools']
First differing element 0:
' AI '
'ai'
First list contains 2 additional elements.
First extra element 2:
''
- [' AI ', 'ai', '', 'Tools']
+ ['ai', 'tools']
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=2)
Only the function changed
--- scaffold/normalize_tags.py
+++ final/normalize_tags.py
@@ -1,3 +1,10 @@
def normalize_tags(tags):
- """Scaffold only: requested normalization is deliberately absent."""
- return tags
+ """Normalize string tags, retaining the first occurrence of each value."""
+ normalized = []
+ seen = set()
+ for tag in tags:
+ value = tag.strip().lower()
+ if value and value not in seen:
+ seen.add(value)
+ normalized.append(value)
+ return normalized
Same test: two passes — exit 0
test_all_empty_tags_return_an_empty_list (test_normalize_tags.TagNormalizationAcceptance.test_all_empty_tags_return_an_empty_list) ... ok
test_trims_lowercases_deduplicates_and_drops_empty_tags (test_normalize_tags.TagNormalizationAcceptance.test_trims_lowercases_deduplicates_and_drops_empty_tags) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Fresh folder: two passes — exit 0
test_all_empty_tags_return_an_empty_list (test_normalize_tags.TagNormalizationAcceptance.test_all_empty_tags_return_an_empty_list) ... ok
test_trims_lowercases_deduplicates_and_drops_empty_tags (test_normalize_tags.TagNormalizationAcceptance.test_trims_lowercases_deduplicates_and_drops_empty_tags) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Execution receipt, hashes and limits
{
"date": "2026-10-04",
"timezone": "America/New_York",
"phase": "reproduced pass",
"started_at": "2026-10-04T16:22:37.941225+00:00",
"command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest -v test_normalize_tags.py",
"exit_code": 1,
"test_sha256": "b56a34366a2ed3996788d9938e3179aa4eed3a7c48bc0f06c4ea3543cc80695d",
"scaffold_sha256": "7f54a14fa60e2cbafc69287d98ea9be5ade70262515251f27a6b1f4d006c6862",
"python": "3.12.14",
"os": "Linux",
"machine": "x86_64",
"tool": "Codex in ChatGPT Work",
"model": "GPT-6 (session identity; exact backend revision unavailable)",
"scope": "Guided execution demo; prompt WAITING/approval compliance not evaluated",
"finished_at": "2026-10-04T16:23:12.150206+00:00",
"red_exit_code": 1,
"green_exit_code": 0,
"clean_exit_code": 0,
"test_sha256_before": "b56a34366a2ed3996788d9938e3179aa4eed3a7c48bc0f06c4ea3543cc80695d",
"test_sha256_after": "b56a34366a2ed3996788d9938e3179aa4eed3a7c48bc0f06c4ea3543cc80695d",
"test_sha256_clean": "b56a34366a2ed3996788d9938e3179aa4eed3a7c48bc0f06c4ea3543cc80695d",
"implementation_sha256": "992d90b77608b3a0ea1ddcf75911be21dec4beb2c1e5c2ad85c3528acf47909c",
"clean_environment": "New temporary directory containing only implementation and frozen test; no cache; same installed Python runtime, not a different machine or container image.",
"attempts": {
"red": 1,
"green": 1,
"clean": 1
},
"limitations": [
"Two predeclared cases only; no property testing, non-string inputs, locale rules, full application or security assessment.",
"Guided execution by the implementing agent; not an independent fresh-session prompt benchmark.",
"No intervening user approval turn: prompt WAITING/approval behavior was not scored.",
"Same Python runtime in fresh folder; cross-version/platform reproducibility not tested."
],
"outputs": {
"red.txt": "fa4c489020c6b2909eb26f2feba376f133d15303110035f8eeb846ce8adb4710",
"green.txt": "23873b2548730f5477edcef7e3a3838b49cc107150ef864d59adcbf2a65ca5e8",
"clean.txt": "23873b2548730f5477edcef7e3a3838b49cc107150ef864d59adcbf2a65ca5e8",
"implementation.diff.txt": "0e79e3c71a00bc6e4855fc195f5b5327ade1cb0a698ab98789bf5cdaa241c08f"
}
}
Test log
Nobody has logged a run of this prompt yet. That means no date, no tool, no model and no result to show you, so treat it as a starting point and check what comes back.
When a run is logged it goes in a table here: the date, the tool and model it ran on, whether it worked, and what happened. Runs that fail get logged too.
The pass standard for this prompt: five criteria and an automatic-fail rule, written down on September 27, 2026, before any run.
Related words
- characterization test — A test that writes down what code does today, right or wrong, so you can tell later whether you broke it.
- eval-driven development — Writing the check before the feature, so you can tell whether a change actually made anything better.
- success criteria — The things you can actually watch happen that tell you the job is finished.