.agents/specs/gate-issue-index-owner-key.md and tests/scripts/test_agent_record.py both assert, in prose, that appending a dashed row after an owned row for the same issue "raises the unowned count and reds the UNOWNED_HIGH_WATER ratchet". It does not, whenever any spec lists that issue under ## Owed — which is most of the index.
The mechanism
scripts/check-agent-record.py:2034:
if row_id is None and number not in owed:
unowned.append(number)
owed_issues() globs .agents/specs/*.md and collects every #N inside a ## Owed section. An owed issue never enters the unowned population, so no dashed row for it can move the ratchet in either direction.
Measured on row/GATE-ISSUE-INDEX-OWNER-KEY at f366a3ac6
- 328 owed issue numbers.
- 621 index rows, of which 226 carry BOTH an owning row ID and an issue number some spec also lists under
## Owed. Those 226 are exactly the rows for which the ownership-losing append is silent.
- 97 dashed rows, 64 of them owed. The ratchet's population is the remaining 33, which is
UNOWNED_HIGH_WATER.
Appending | [#168](https://github.com/mudler/vllm.cpp/issues/168) | — | PROBE ROW | bug | to the REAL index — #168 is already owned by BACKEND-CUDA-SM110 at :26 and is also under a spec's ## Owed:
| run |
result |
this branch's check-agent-record.py |
rc 0, agent record OK: ENGINE=170 MODEL=377 ... — silent |
| unowned count with the probe row present |
33, unchanged, against UNOWNED_HIGH_WATER 33 |
origin/main's check-agent-record.py at 6354755ba, run from inside this worktree |
rc 1, issue #168 listed twice — the OLD number-only key, not the ratchet |
The contrast case shows the owed set is the discriminator and not the dash. The same probe row for #618, an issue no spec owes, reds this branch's checker: 34 rows name no owner, above the recorded 33: #618.
The index was restored byte-for-byte, sha256 4e80b8ba32333ac2589c9b616719f95eece6dd8a53e978e89bb09e8838fe9fbe before and after, with git status --porcelain empty.
This may be an acceptable trade, and the false sentence is the certain defect
AGENTS.md states the obligation as "Every index row names an owning row ID, or names a spec that lists the issue under ## Owed". An owed issue IS owned, so exempting it from the unowned count is the rule working as written, and #1042 already tracks the separate problem that the ## Owed scrape is too loose.
What is missing is narrower than the count: nothing notices when a row that NAMED an owner is followed by a dashed row for the same issue. That is an ownership record moving backwards, and under the pair key (number, row_id) the two rows are different keys, so both stand and neither checker speaks.
What a guard has to decide
Ordering. The index is append-only, so "dashed row after owned row" is only visible as a sequence, and a guard has to say whether (N, dash) after (N, owner) is a regression to refuse or a legal de-adoption to record. Either way it is a checker semantic change and needs its own row, spec, red-before test or mutation, and green-after evidence.
Found by the fresh review of #1744 and reproduced independently before filing. Not repaired in that flow because it is a second checker semantic in a change that owes one. Owned as debt under ## Owed in .agents/specs/gate-issue-index-owner-key.md.
Refs #1745, #1042.
.agents/specs/gate-issue-index-owner-key.mdandtests/scripts/test_agent_record.pyboth assert, in prose, that appending a dashed row after an owned row for the same issue "raises the unowned count and reds theUNOWNED_HIGH_WATERratchet". It does not, whenever any spec lists that issue under## Owed— which is most of the index.The mechanism
scripts/check-agent-record.py:2034:owed_issues()globs.agents/specs/*.mdand collects every#Ninside a## Owedsection. An owed issue never enters theunownedpopulation, so no dashed row for it can move the ratchet in either direction.Measured on
row/GATE-ISSUE-INDEX-OWNER-KEYatf366a3ac6## Owed. Those 226 are exactly the rows for which the ownership-losing append is silent.UNOWNED_HIGH_WATER.Appending
| [#168](https://github.com/mudler/vllm.cpp/issues/168) | — | PROBE ROW | bug |to the REAL index — #168 is already owned byBACKEND-CUDA-SM110at:26and is also under a spec's## Owed:check-agent-record.pyagent record OK: ENGINE=170 MODEL=377 ...— silentUNOWNED_HIGH_WATER33origin/main'scheck-agent-record.pyat6354755ba, run from inside this worktreeissue #168 listed twice— the OLD number-only key, not the ratchetThe contrast case shows the owed set is the discriminator and not the dash. The same probe row for
#618, an issue no spec owes, reds this branch's checker:34 rows name no owner, above the recorded 33: #618.The index was restored byte-for-byte, sha256
4e80b8ba32333ac2589c9b616719f95eece6dd8a53e978e89bb09e8838fe9fbebefore and after, withgit status --porcelainempty.This may be an acceptable trade, and the false sentence is the certain defect
AGENTS.mdstates the obligation as "Every index row names an owning row ID, or names a spec that lists the issue under## Owed". An owed issue IS owned, so exempting it from the unowned count is the rule working as written, and #1042 already tracks the separate problem that the## Owedscrape is too loose.What is missing is narrower than the count: nothing notices when a row that NAMED an owner is followed by a dashed row for the same issue. That is an ownership record moving backwards, and under the pair key
(number, row_id)the two rows are different keys, so both stand and neither checker speaks.What a guard has to decide
Ordering. The index is append-only, so "dashed row after owned row" is only visible as a sequence, and a guard has to say whether
(N, dash)after(N, owner)is a regression to refuse or a legal de-adoption to record. Either way it is a checker semantic change and needs its own row, spec, red-before test or mutation, and green-after evidence.Found by the fresh review of #1744 and reproduced independently before filing. Not repaired in that flow because it is a second checker semantic in a change that owes one. Owned as debt under
## Owedin.agents/specs/gate-issue-index-owner-key.md.Refs #1745, #1042.