The Issue Was Closed. Nobody Implemented It.

Issue #330 was closed as done, the release index said shipped in v2.72, and the status report agreed. The feature did not exist. A closed ticket is a claim somebody once made, not a property of the code.

The Issue Was Closed. Nobody Implemented It.

Issue #330 asked for extra render layers in the EXR export. It was closed as done. The internal release index said "#330 already shipped in v2.72." The status report repeated it. Three records, one story, no dissent.

The feature did not exist. The shadow layer the reporter asked for was computed by the shader on every frame and never written to the file. The export the ticket was about had never once produced the thing the ticket asked for.

Nobody lied. That is the part worth staring at. Every record faithfully copied the record above it. The claim simply outlived its own truth, and it was doing fine until someone opened the file.

Operating Conditions

The project is a fractal renderer, largely built by agents under a written doctrine. The EXR exporter writes render layers as named channels: an ExrLayerOptions struct decides which layers exist, and a channel-writing block does the work. Issue #330 asked for more layers in that export. In the comments, the reporter got specific about one of them: a shadow layer, shadowFactors for six lights, rgba32f.

Around the code sits the usual bookkeeping. A memory index that records what shipped in which release. A queue cache the agents consult before picking up work. Status reports assembled on top of both. Derived records, every one of them. Convenient, fast, and none of them compiles.

The ticket had been closed for a while. The index said v2.72. Ask the system anything about #330 and every layer of it answered, without hesitation: shipped.

Then I told the agent: "read and understand 330 again. Make sure to review all the comments and verify that they are all addressed."

Failure Modes

The re-read was not clever. That is what makes it worth describing. The agent went through the ticket comment by comment, and for each thing requested, looked for the code that did it. Most items checked out. Then it reached the reporter's shadow layer and went hunting for shadowFactors in the export path.

The shader computes it. Six lights, exactly as described. Every frame, the values exist on the GPU. Then the frame ends and they die there. The ExrLayerOptions struct has no shadow entry. The channel-writing block never mentions it. Between "computed" and "written to the EXR," the feature simply is not.

So: gh issue reopen 330. The remaining work went into a fresh ticket, #545, where it cannot hide under a months-old checkmark.

Now trace the claim backward, because the interesting failure is the provenance chain. "Shipped in v2.72" did not start as a lie. It started as a line in a memory index, most likely an agent summarizing a session in which export layers were touched and #330 came up. Plausible, at the time. The queue cache copied the line, minus the hedging around it. The status report cited the cache, now with a version number attached, which reads as precision. Three hops. Each hop stripped context and added confidence. By the third copy, "probably covered by the v2.72 export work" had hardened into "shipped in v2.72." And no copy along the way involved opening the exporter or re-reading the reporter's last comment.

Derived records inherit errors. Worse, they launder them. A guess in an index looks exactly like a fact in an index, and the moment a second system quotes it, the guess has a citation.

Root Cause

"Closed" is a workflow state. One click sets it. Nothing in the click reads the diff, greps for the channel name, or holds the reporter's list up against the code. We treat the label as a property of the software, and it is not. It is a property of the ticket. A closed ticket is a claim somebody once made, timestamped, and claims go stale the moment the code and the claim diverge.

The bookkeeping made it worse in one specific way: none of the derived records had an invalidation path. Code changes; nothing flips the index line back. An entry that says "shipped" says it forever, with the same confidence on day one and day four hundred. A cache with no invalidation is not a record. It is a rumor with uptime.

And the chain had no step where anyone was responsible for touching ground truth. The index trusted the session summary. The cache trusted the index. The report trusted the cache. I trusted the report. Four layers of trust. Zero layers of looking.

Proposed Fix

The audit that caught this has three steps, and none of them require talent.

Re-read the original request. Not the summary. Not the title. Not the index entry. The reporter's words, every comment, the last comment most carefully, because the last comment is where the real scope usually lands. Summaries are where requirements go to lose their details.

List every distinct request in the ticket. #330 was not one feature. It was a list of layers, and each layer is its own claim to verify. "Mostly done" is how a missing feature hides inside a closed ticket: four items ship, and the fifth rides out on their credibility.

Point at the line. For each item on the list, name the file and the line that satisfies it. Not "the export work covered this." The struct field. The channel write. If you can point, it is done. If you cannot point, it is not done, whatever the label says, and the honest move is gh issue reopen.

That is the whole method. The receipt for "addressed" is the code and the reporter's comments in agreement. Everything else, index, cache, dashboard, status report, is directions to where a receipt might be. Use derived records to find things. Never accept one as proof of things.

System Status

#330 is open again and says so honestly. #545 carries the shadow layer as live work with a clean history. The index line got corrected, but the correction is not the point, because the next stale line is already forming somewhere. The standing rule is the point: any record that cannot be recomputed from the code is a lead, not a fact.

The shader still computes shadowFactors on every frame, as it has all along. It is patient. It will be there when the exporter finally learns to write it, which is more than I can say for my confidence in dashboards.

Your turn. Pick the last ticket an agent closed for you, or the oldest closed ticket you still quietly rely on. Open the original request. List what it actually asked for, item by item. Then point at the lines. On which item does your finger come down on nothing?

Further Reading

No comments yet