A card says whether a person reported it or an agent derived it - #39
Merged
Conversation
T-0210. Asked where one of eight cards came from, the record could not answer: the commit message that filed them was read, the grouping of its paragraphs was taken as evidence the card was the agent's own, and that was wrong — it was item six of a list the owner had written out. `raised: reported | derived`, on every surface that creates a card. Neither `origin` nor `source` answered this: `origin` takes record ids, which is the provenance of *discovered* work, and `source` is a path checked on disk, so a report made in conversation had nowhere to go. Two values, and the smallness is the decision — more than two and nobody picks correctly, while this is the distinction that changes what you do with the card. No default. A card filed without it is a card nobody has classified, and a value the tool invented would be the same wrong answer this was filed about. The rule is bounded by date, which the card left open. Warning on every card carrying none meant 223 in this repository on the day the field shipped, and backfilling is not available — guessing which were reported reproduces the error that prompted the card. A date rather than a config value: a project does not choose when a field appeared in the package it installed, and a knob would only be used to switch the rule off, which `--severity` and the baseline already do with a record of the decision. Two existing guards caught what a new card field needs beyond itself: reserving it against being declared an axis, and reaching it from a `card create` flag. Both were failing tests rather than things I remembered. T-0224 rides along, and the rule it asked for found what the card did not know: there were six more copies of the anchored-quantifier shape, and one of them — `\n+$` in the frontmatter reader — runs over a record *body*, which nothing caps. Half a million newlines followed by one other character is O(N²) bounded only by the disk. CodeQL never reported it; it reported the copy whose taint it could follow. The five slug helpers keep the shape and are allowlisted with the bound that makes them safe — a title is refused past 80 characters — rather than because they look fine. The rule caught two faults of its own on the way: it reported the comment explaining the shape, and its `g` matcher carried `lastIndex` between files so the staleness half silently skipped whichever file followed a match. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3LTdq3mzMAQ98rwBegGjU
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two cards. The first is a protocol field; the second is a lint rule that found something the card that asked for it did not know about.
T-0210 — nothing said whether a person asked for the card
Asked where one of eight cards came from, the record could not answer. The commit message that filed them was read, the grouping of its paragraphs was taken as evidence the card was the agent's own, and that was wrong — it was item six of a list the owner had written out. The inference was wrong and the record could not correct it, because it did not carry the fact.
raised: reported | derived, on every surface that creates a card. Neitheroriginnorsourceanswered this:origintakes record ids, which is the provenance of discovered work, andsourceis a repository path checked on disk, so a report made in conversation had nowhere to go.Two values, and the smallness is deliberate — more than two and nobody picks correctly, while this is the distinction that changes what you do: a reported card is a commitment to somebody, a derived one is a proposal that costs nothing to discard. No default: a card filed without it is one nobody classified, and a value the tool invented would be the same wrong answer this was filed about.
The date bound is the part the card left open
Warning on every card carrying none meant 223 warnings in this repository on the day the field shipped, which would teach everyone to ignore the rule. Backfilling is not available either — guessing which were reported reproduces the exact error that prompted the card. So the rule speaks about cards filed from the day it could be answered and says nothing about the ones that could not.
A date rather than a config value: a project does not get to choose when a field appeared in the package it installed, and a knob here would only be used to switch the rule off — which
--severityand the baseline already do, per project, with a record of the decision.Tested against a card dated past the cutoff rather than by waiting for the clock, which is the only way to test a date boundary without owning time.
Two existing guards caught what a new card field needs
Reserving it against being declared an axis, and reaching it from a
card createflag. Both were failing tests, not things I remembered — which is what they are for.T-0224 — the rule found a seventh copy that mattered
The card said "nothing stops the sixth copy." Writing the rule found there were already six more, and one of them was not like the others:
replace(/\n+$/, "")in the frontmatter reader runs over a record body, which nothing caps — unlike a title, refused past 80 characters on write. Half a million newlines followed by one other character is O(N²) bounded only by the disk. Fixed with a linear strip.CodeQL never reported it. It reported the one copy whose taint it could follow from a declared value, which is why fixing what was reported would have left the rest.
The five slug helpers keep the shape and are allowlisted with the bound that makes them safe — the 80-character title cap is the argument — rather than because they look fine. Take the cap away and they are the next finding, which the allowlist says out loud. The allowlist also fails when an entry stops applying, so it cannot rot into a list of names.
The rule caught two faults of its own
It reported the comment that explains the shape — a rule that reports prose teaches people to stop reading it — and its
g-flagged matcher carriedlastIndexbetween files, so the staleness half silently skipped whichever file followed a match. Both are fixed and both mutation-proven, along with a seventh copy in an unbounded file and a stale allowlist entry.Still open
T-0209, the other half of the provenance pair, is not in here. Its card asks for model and reasoning budget recorded alongside the actor, and says it should be designed together with T-0186's
verifiedblock — that is a design conversation rather than a field, and I would rather not settle it in passing.pnpm run checkgreen — 488 + 10 tests.doctor0 errors 0 warnings.🤖 Generated with Claude Code
https://claude.ai/code/session_01D3LTdq3mzMAQ98rwBegGjU