Skip to content

A card says whether a person reported it or an agent derived it - #39

Merged
illodev merged 1 commit into
mainfrom
feat/t-0210-raised
Aug 7, 2026
Merged

A card says whether a person reported it or an agent derived it#39
illodev merged 1 commit into
mainfrom
feat/t-0210-raised

Conversation

@illodev

@illodev illodev commented Aug 7, 2026

Copy link
Copy Markdown
Owner

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. Neither origin nor source answered this: origin takes record ids, which is the provenance of discovered work, and source is 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 --severity and 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 create flag. 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 carried lastIndex between 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 verified block — that is a design conversation rather than a field, and I would rather not settle it in passing.


pnpm run check green — 488 + 10 tests. doctor 0 errors 0 warnings.

🤖 Generated with Claude Code

https://claude.ai/code/session_01D3LTdq3mzMAQ98rwBegGjU

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
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workfile Ready Ready Preview Aug 7, 2026 11:52pm
workfile-site Ready Ready Preview Aug 7, 2026 11:52pm

@illodev
illodev merged commit cda6ec2 into main Aug 7, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant