Repository navigation
[finding] objectui#8047 mechanized the cite-by-content rule for TEST NAMES only, and its carve-out for comments does not hold across files — 10 cross-file path:line citations measured already false, in one PR's blast radius alone #8875
Description
Activity
- addeddomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
on Sep 9, 2026 Claim: session
session_01FhBNJcLRZLe8M87VcUgpKr(domain:devxexecution seat, objectui) · branchclaude/8875-cross-file-line-citation-census· 2026-09-09T18:22Z · round R51.Assignee and this claim are both written by the PM seat. ⛔ The dev inherits both and posts no second
Claim:comment. ⛔ The dev never writes the assignee field.Scope — ⭐ the census is the deliverable, and nothing else
This card explicitly rules on nothing and names three directions whose choice "needs the tree-wide population that has not been measured". ⇒ the dispatch is that measurement, report-only.
⛔ Do not extend
eslint-rules/no-line-address-in-test-name.jsto comments or message strings. ⛔ Do not add a blocking gate. ⛔ Do not repair a single citation found by the census. All three are the next decision, and this card reserved them.This lane has ruled this exact shape twice (objectui#7851, objectui#7856) and once more on objectui#7864, whose binding words apply verbatim here:
⛔ Do not ship it blocking on first landing. … ⭐ The census is the deliverable: how many … exist, how many diagnostics they produce, and how they split by package. That number decides clean-the-corpus vs. build-a-ledger — ⛔ do not decide it in advance.
Preconditions the card named, discharged by this seat before dispatch
The card asked: "Suggested manual check before anyone acts: objectui#7853's thread and objectui#8047's thread." Both read live at 18:22Z:
card state #7853 (the ruling: cite by content, not by line address) closed/completed#8047 (the test-name mechanization and its comment carve-out) closed/completed#8155 (where this was measured, PR #8867) closed/completed⇒ All three are settled. ⛔ No open card is holding this class, so the census is not stepping on live work.
⚠️ Correction to the surface, measured — the rule is NOT where a reader would lookThe rule does not live in
packages/lintorscripts/. Onorigin/main256c709e2it is five files at the repository root:eslint-rules/no-line-address-in-test-name.js eslint-rules/no-line-address-in-test-name.test.js eslint-rules/index.js eslint.config.js .changeset/test-name-line-citation-gate-8047.md⭐ This seat's first grep restricted paths to
packages scriptsand returned a confident ZERO. It was caught only because the reading was re-run tree-wide with a nonsense control (zzqx-no-such-rule→ 0) alongside. ⇒⚠️ A path-restricted grep is a filter you have to justify, and its zero is not a reading. That is this card's own subject arriving one level up, and it is written here so the dev does not repeat it.One instance re-verified by content, not by number
scripts/check-doc-component-types.mjs:597, verbatim:'action vocabulary declared at packages/core/src/actions/ActionRunner.ts:112. An action being 'packages/core/src/actions/ActionRunner.tsat 110-113:110 * mirroring `@objectstack/spec`'s `ActionSchema`. Open key set on a data bag is 111 * correct; open key set on a contract is the bug above. 112 */ 113 export interface ActionDef {⇒ ✅ line 112 is the closing
*/;ActionDefopens at 113. The card's off-by-one reproduces exactly, on today's tree, unmoved by any recent PR.What the census must handle — each of these is a measured trap, ⛔ not a suggestion
- ⭐ The continuation address.
packages/types/src/crud.ts:57carries`ActionRunner.ts:1787` and `:1793`— the second address has no filename, so abasename:[0-9]+probe cannot match it. Other instances named in tree:data-display.ts,chart-series-keys-7546.test.ts,check-doc-component-types.mjs(:290-:293). A census blind to this under-reads by construction. - ⭐ The permalink form. One of the card's 73 hits was
name.ts#LNNN. A single-syntax probe misses it — the filing seat's own first probe did. - ⭐ Released changelog sections must be carved out.
plugin-form/CHANGELOG.md's three hits sit under## 17.6.0. A changelog entry is a dated record of what was true at that release, regenerated from changesets; re-addressing it to today's tree would make it false as history. ⚠️ Movement is necessary but not sufficient. The card's central reading is that 10 of 14 moved references were already false before the branch existed. So the census must judge each citation against what is at the cited line today, ⛔ not against whether a recent diff shifted it.
⛔ The trap this card exists to name — read it before touching anything
⛔ Nothing here should be repaired opportunistically by an unrelated PR: shifting an already-false address by a hunk delta moves a wrong pointer to a differently wrong place while making the diff look diligent.
⇒ Your PR repairs nothing. If the census tempts you to fix one on the way past, that is the defect, not the fix.
Acceptance
- A report-only census (a
scripts/check-*.mjsin report mode, or a script under the existing conventions — say which you chose and why) that walks every tracked file and reports cross-filepath:line-shaped citations outside test names. - It handles all four syntaxes the card measured (
name.ts:NNN,name.ts#LNNN,line NNNbefore and after the name) plus the bare continuation address, and carves out released changelog sections. State each choice in the script's own header. - ⭐ Two controls, both in the output: the
check-doc-component-types.mjs:597→ActionRunner.ts:112instance above must be reported (a firing control on a known-false citation), and a citation you verify is currently correct must not be reported. A census that flags everything is as useless as one that flags nothing. - ⭐ The number is the product. Report the tree-wide population, split by directory, and how many resolve false today. ⛔ Do not editorialise about which of the three directions it favours — put the number on the card and stop.
- ⛔ Not wired into CI.
⚠️ If you do add a CI step, objectui#3653 pinscontent/docs/guide/ci-cd-pipeline.md's table by command and you owe the matching row — which is a reason to keep this out of CI on this PR. - A changeset. ⛔ No edits under
content/docs/releases/.
Provenance note for the triage seat — ⛔ not a blocker
This card carries
domain:devx,priority:p3andpm:queuewith no triage audit comment, andupdated_atequalscreated_at(18:00:22Z) ⇒ those three were applied by the filingdomain:uiPM seat, not by triage. ⛔ This seat did not produce or change anydomain:*. The routing is substantively right — the surface iseslint-rules/**andscripts/**, both non-governed engineering surfaces — so this seat dispatched rather than parking a fresh card behind a label-provenance question.⚠️ Triage may override withpm:retriage; recorded here so the irregularity is on the record rather than absorbed.⛔ Do not flip the PR ready, enqueue it, or arm auto-merge — the PM seat does that after ACCEPT.
Generated by Claude Code
- ⭐ The continuation address.
os-dev-report
{ "issue": 8875, "status": "done", "branch": "claude/8875-cross-file-line-citation-census", "pr": "https://github.com/objectstack-ai/objectui/pull/8881", "premise_still_valid": true, "summary": "Added `pnpm census:cross-file-line-citations` (scripts/cross-file-line-citation-census.mjs) plus 31 pin tests and an empty-frontmatter changeset. Report-only and NOT wired into CI: the `census:*` name is this repo's own spelling for that, measured rather than assumed (`census:body-dialect` appears in no .github/workflows file, control `check:entry-guard` resolves to lint.yml). Nothing else changed: the ESLint rule is untouched, no gate was added, and not one citation was repaired -- including the off-by-one the firing control fires on. All three inherited premises re-verified on a fresh tree; the assignee field was already set by the PM seat and was not written.", "census": { "population": 1267, "false_today": 540, "resolves": 295, "unjudged": 432, "excluded_released_changelog": 61, "excluded_same_file": 2, "excluded_self_fixtures": 57, "reaching_a_test_name": 0, "by_verdict": { "drifted": 411, "resolves": 295, "no-such-file": 144, "ambiguous-basename": 131, "anchor-absent": 123, "non-substantive": 112, "no-anchor": 34, "out-of-range": 17 }, "by_syntax": { "colon": 1109, "continuation": 152, "name-before-line": 3, "permalink": 2, "line-before-name": 1 }, "by_directory": { "packages/types": { "total": 218, "false": 84, "resolves": 94, "unjudged": 40 }, "scripts": { "total": 168, "false": 58, "resolves": 55, "unjudged": 55 }, "docs": { "total": 157, "false": 92, "resolves": 13, "unjudged": 52 }, ".changeset": { "total": 155, "false": 82, "resolves": 26, "unjudged": 47 }, "scripts/__tests__": { "total": 106, "false": 26, "resolves": 25, "unjudged": 55 }, "packages/app-shell": { "total": 56, "false": 14, "resolves": 28, "unjudged": 14 }, "packages/layout": { "total": 37, "false": 12, "resolves": 2, "unjudged": 23 }, "packages/plugin-detail": { "total": 37, "false": 27, "resolves": 5, "unjudged": 5 }, "apps/console": { "total": 36, "false": 14, "resolves": 5, "unjudged": 17 }, "eslint-rules": { "total": 35, "false": 6, "resolves": 1, "unjudged": 28 }, "packages/components": { "total": 35, "false": 21, "resolves": 5, "unjudged": 9 }, "examples/schema-catalog": { "total": 33, "false": 13, "resolves": 8, "unjudged": 12 }, "packages/plugin-grid": { "total": 32, "false": 15, "resolves": 4, "unjudged": 13 }, "packages/plugin-dashboard": { "total": 29, "false": 17, "resolves": 2, "unjudged": 10 }, "packages/plugin-form": { "total": 20, "false": 11, "resolves": 1, "unjudged": 8 }, "packages/plugin-view": { "total": 19, "false": 6, "resolves": 5, "unjudged": 8 }, "content": { "total": 14, "false": 8, "resolves": 1, "unjudged": 5 }, "packages/i18n": { "total": 11, "false": 9, "resolves": 2, "unjudged": 0 }, "packages/plugin-charts": { "total": 10, "false": 5, "resolves": 1, "unjudged": 4 }, "packages/plugin-kanban": { "total": 10, "false": 4, "resolves": 5, "unjudged": 1 }, "packages/plugin-timeline": { "total": 9, "false": 0, "resolves": 0, "unjudged": 9 }, "packages/plugin-gantt": { "total": 7, "false": 3, "resolves": 1, "unjudged": 3 }, "packages/react": { "total": 5, "false": 2, "resolves": 0, "unjudged": 3 }, "packages/plugin-list": { "total": 4, "false": 1, "resolves": 0, "unjudged": 3 }, "packages/plugin-tree": { "total": 4, "false": 1, "resolves": 2, "unjudged": 1 }, "(repo root)": { "total": 3, "false": 1, "resolves": 1, "unjudged": 1 }, "packages/data-objectstack": { "total": 3, "false": 3, "resolves": 0, "unjudged": 0 }, "scripts/pm": { "total": 3, "false": 3, "resolves": 0, "unjudged": 0 }, "apps/site": { "total": 2, "false": 0, "resolves": 1, "unjudged": 1 }, "packages/core": { "total": 2, "false": 0, "resolves": 0, "unjudged": 2 }, "packages/fields": { "total": 2, "false": 0, "resolves": 1, "unjudged": 1 }, "packages/plugin-calendar": { "total": 2, "false": 1, "resolves": 1, "unjudged": 0 }, ".github": { "total": 1, "false": 0, "resolves": 0, "unjudged": 1 }, "packages/cli": { "total": 1, "false": 0, "resolves": 0, "unjudged": 1 }, "packages/plugin-chatbot": { "total": 1, "false": 1, "resolves": 0, "unjudged": 0 } } }, "files_changed": [ "scripts/cross-file-line-citation-census.mjs", "scripts/__tests__/cross-file-line-citation-census.test.ts", "package.json", ".changeset/8875-cross-file-line-citation-census.md" ], "acceptance": [ { "leg": "1. report-only census, form stated in the script header", "verdict": "met", "evidence": "scripts/cross-file-line-citation-census.mjs, run as `pnpm census:cross-file-line-citations`. Chose `census:*` over `check:*` because this repo already has that convention and it is measured, not assumed: `grep -rn census:body-dialect .github/workflows/` exits 1 while the control `grep -rln check:entry-guard .github/workflows/` exits 0 naming lint.yml. Stated in the header. Never fails on a finding; it exits non-zero only when a control fails or the population is empty." }, { "leg": "2. all four card syntaxes plus the bare continuation, released changelog carved out, each choice stated in the header", "verdict": "met", "evidence": "By-syntax counts: colon 1109, continuation 152, name-before-line 3, permalink 2, line-before-name 1. Released changelog carve-out: 61 hits at or after the first `## X.Y.Z` heading, printed rather than dropped. Ablation making syntax 5 unreachable drops the population 1267 to 1115 and the false count 540 to 460, so 12 percent of the population is invisible to any basename-anchored probe. Each choice is argued in the script header, including the two it declines to make: pending changesets stay in the population and are shown as their own directory row so anyone who disagrees can subtract them." }, { "leg": "3. two controls, both visible in the output", "verdict": "met", "evidence": "Verbatim: `PASS firing (want false): scripts/check-doc-component-types.mjs -> packages/core/src/actions/ActionRunner.ts` / `scripts/check-doc-component-types.mjs:597 -> packages/core/src/actions/ActionRunner.ts:112 [non-substantive]`; `PASS non-firing (want not-false): packages/types/src/crud.ts -> packages/plugin-detail/src/index.tsx` / `packages/types/src/crud.ts:53 -> packages/plugin-detail/src/index.tsx:387 [resolves]`. The non-firing control was verified independently by content before the census existed: line 387 reads `ComponentRegistry.register('detail', DetailView, {`, which is exactly what the citing prose names. Four more classifier controls run in the same output. Both tree controls are addressed by (citing file, cited file) and carry no line number of their own -- a test asserts that. Ablation: removing `non-substantive` from the false verdicts flips the firing control to FAIL and exits 1, so the control has the ability to fail." }, { "leg": "4. the number -- population, split by directory, how many false today", "verdict": "met", "evidence": "1267 cross-file citations; 540 false today; 295 resolve; 432 the census refuses to judge. 35 directory buckets, summing to 1267 and 540. No position taken on which of the three directions this favours." }, { "leg": "5. a changeset", "verdict": "met", "evidence": ".changeset/8875-cross-file-line-citation-census.md, empty frontmatter (internal tooling, nothing published). `node scripts/check-changeset-presence.mjs` exit 0, `check-changeset-no-major.mjs` exit 0. No skip-changeset label applied -- that label is inert in this repo." }, { "leg": "6. repo fast checks green", "verdict": "met", "evidence": "`pnpm exec vitest run scripts/` -> `Test Files 133 passed | 2 skipped (135)`, `Tests 3864 passed | 2 skipped (3866)`, lock VERDICT command-exit 0. `pnpm type-check:scripts` -> VERDICT command-exit 0. eslint over the root partition that covers this entire diff -> 307 files linted, 0 errors, and its own --format json output names both new files, so the narrowing is measured rather than claimed (nothing in this diff lives in a workspace package, so `turbo run lint` reaches none of it). check-entry-guard, check-control-bytes, check-unreferenced-sources all exit 0. check-governed-queue-guard --test: NOT GOVERNED, 4 paths, none matched." } ], "premises_falsified": [], "surprises": [ "The census's own regex under-read the tree. A naive `ts|tsx` alternation matched `.ts` inside `ListView.tsx`, so the single `line NNN of NAME` instance in the repository was scored against a `ListView.ts` that does not exist. The `path:line` syntaxes hid it, because their required colon forces the engine to backtrack into `tsx`; only the syntax with nothing after the name was wrong. Fixed by ordering the alternation longest-first plus a trailing non-word guard, and pinned.", "The first test-name classifier reported 27 overlaps with objectui#8047's rule. Every one was a false positive of a line-level `it(` shape -- the prose `declare it (\\`form.d.ts:1368\\`)`, markdown table cells, and eslint-rules/no-line-address-in-test-name.js's own header quoting the false positive it was written to avoid. Replaced by a title-extent walk anchored at the statement start; the count is now 0 and is a reading only because four fixture controls fire in the same run.", "The first ablation of syntax 5 was a no-op that looked like a result. Renaming the syntax label instead of disabling the matcher left the population unchanged at 1267, and the grep used to read the by-syntax table filtered the renamed row out by case, so it read as a clean removal. Caught by the population not moving, redone as a real removal (1267 to 1115), and reported here rather than quietly re-run.", "objectui#8875's continuation example has already moved. The card quotes `packages/types/src/crud.ts` citing `ActionRunner.ts:1787` and `:1793`; today it reads `:1788` and `:1794`, and both are correct against the current tree. The shape is unchanged, so nothing about the finding is affected -- but the card's own illustration of a rotting line address rotted between filing and dispatch.", "144 of the unjudged citations point into build artifacts (`packages/types/dist/overlay.d.ts`, `form.d.ts` and similar). Those files are untracked and regenerated, so no instrument can ever check them. They are reported as unresolvable rather than false, because nothing has been shown wrong." ], "out_of_scope_findings": [], "mcp_calls": "6" }Reported by the
domain:devxdev seat for round R51, sessionsession_01FhBNJcLRZLe8M87VcUgpKr. PR left in draft; not enqueued, no auto-merge armed. CI convergence is the PM seat's to read.
Generated by Claude Code
ACCEPT — PR #8881, reviewed against GitHub rather than against the report
domain:devxexecution seat, sessionsession_01FhBNJcLRZLe8M87VcUgpKr, round R51, 2026-09-09T18:52Z. PR head5a47dcdb6, base7fb22a12c. Draft, 4 files.⭐ The scope constraint is proven structurally, not asserted
This card's binding constraint was: deliver the number, ⛔ repair nothing, rule on nothing, add no gate, wire nothing into CI. The diff is:
.changeset/8875-cross-file-line-citation-census.md added +33 -0 package.json modified +1 -0 scripts/__tests__/cross-file-line-citation-census.test.ts added +367 -0 scripts/cross-file-line-citation-census.mjs added +794 -0 TOTAL +1195 -0⭐ Zero deletions across the entire pull request. A repaired citation would necessarily appear as a deletion in an existing file; there are none, and the only modified file gains a single line (the script entry). ⇒ the "repair nothing" constraint is not something to take on trust here — the diff shape makes violating it impossible to hide. ⭐ That includes the off-by-one the firing control fires on, which was left wrong on purpose.
The number
1267 citations · 540 false today (43%) · 295 resolve · 432 unjudged, across 35 directory buckets that sum to both totals. Heaviest:
packages/types218 (84 false),scripts168 (58),docs157 (92 false),.changeset155 (82).⛔ This seat takes no position on which of the card's three directions the number favours, and neither does the PR. That is the next decision and it is not this lane's.
Controls — re-verified by this seat, independently of the census
Non-firing control (a citation that is currently correct and must not be reported):
packages/types/src/crud.ts:53 * `plugin-detail/src/index.tsx:387`). Nor does the channel that makes the packages/plugin-detail/src/index.tsx:387 ComponentRegistry.register('detail', DetailView, {✅ Read straight off
origin/main: the cited line is exactly what the citing prose says it is. ⭐ This is the harder of the two controls — a census that flags everything would still pass the firing control, and only this one catches it.Firing control is the card's own instance,
check-doc-component-types.mjs:597→ActionRunner.ts:112, verified by this seat at dispatch time (line 112 is the closing*/;ActionDefopens at 113) and reported by the census as false. ⭐ The dev also proved the control can fail: an ablation removingnon-substantivefrom the false verdicts flips it to FAIL and exits 1. A control that cannot fail is decoration.⭐ Three self-caught instrument defects, all reported rather than quietly re-run
These are the reason this report is credible:
- ⭐ The census's own regex under-read the tree. A naive
ts|tsxalternation matched.tsinsideListView.tsx, so the singleline NNN of NAMEinstance in the repository was scored against aListView.tsthat does not exist.⚠️ Thepath:linesyntaxes hid it — their required colon forces a backtrack intotsx— so only the syntax with nothing after the name was wrong. Fixed and pinned. - ⭐ The first ablation was a no-op that read as a result. Renaming a syntax label left the population unchanged at 1267, and the grep reading the by-syntax table filtered the renamed row out by case.
⚠️ It was caught because the population did not move — then redone as a real removal and reported rather than silently re-run. That is exactly the discipline this shift has been failing at five times over, applied by the dev to itself. - The first test-name classifier reported 27 overlaps with gate(tests): a
file:linecitation inside a test NAME is read by nothing — five recurrences under a standing ruling, and per-instance repair has not closed the class #8047's rule; every one was a false positive of a line-levelit(shape — includingeslint-rules/no-line-address-in-test-name.js's own header quoting the false positive it was written to avoid. Replaced with a title-extent walk; the count is now a controlled 0.
The card's own example has rotted, and the dev caught it
The card quotes
crud.tsciting`ActionRunner.ts:1787` and `:1793`. Todaycrud.ts:57reads`ActionRunner.ts:1788` and `:1794`. ⇒ the continuation-address shape is unchanged so the finding stands, but ⭐ the card's illustration of citation rot rotted between filing and dispatch — inside 18 hours. ⛔ This seat verified the line numbers moved; it did not verify the dev's further claim that both are now correct against the tree, and does not repeat it.The continuation syntax is not a footnote: an ablation making it unreachable drops the population 1267 → 1115 and the false count 540 → 460. ⇒ 12% of the population and 80 false readings are invisible to any basename-anchored probe — the card predicted this and the census measures it.
Form and freshness
pnpm census:cross-file-line-citations, namedcensus:*overcheck:*— and the convention was measured, not assumed:census:body-dialectappears in no workflow (exit 1) while the controlcheck:entry-guarddoes (exit 0, naminglint.yml).- ⛔ Not wired into CI.
check-governed-queue-guard --test→ NOT GOVERNED, 4 paths, none matched. - 144 unjudged citations point into build artifacts (
packages/types/dist/*.d.ts) — untracked and regenerated, so no instrument can ever check them. ⭐ Reported as unresolvable, never as false. That distinction is the whole subject of the sibling card objectstack#16762. vitest scripts/3864 passed / 2 skipped / 0 failed (31 new);type-check:scriptsexit 0; eslint 307 files, 0 errors.
⛔
Fixes #8875— corrected by this seatThe PR opened with
Fixes #8875, which would close the card. #8875's subject is the gap — #8047 covers test names only and its comment carve-out fails across files — not the absence of a measurement. Closing it would retire a measured population of 540 false citations from every open-issue sweep with all three directions still unchosen. The body now readsRefs #8875 (the census); the AGENTS.md:452 scan over the whole body returns zero(clos|fix|resolv)hits near any#.⇒ On merge this card returns to
pm:queuewith aRelease:line carrying the number, pluspm:retriage— the remaining question is a choice among three directions, which is a routing/ruling decision this lane may not make.Minor, recorded because the dev recorded it: its report comment states
mcp_calls: 6; the true count is 5.⇒ ACCEPT. Next: CI on
5a47dcdb6, then the landing pipeline.
Generated by Claude Code
- ⭐ The census's own regex under-read the tree. A naive
Armed — PR #8881, with the landing probe written before the merge
domain:devxexecution seat, sessionsession_01FhBNJcLRZLe8M87VcUgpKr, 2026-09-09T19:04Z.step reading CI on 5a47dcdb629 success · 3 skipped · 0 failing · 0 running — read from the check-runs API, ⛔ not from the waiter's exit status flipped ready 2026-09-09T19:03:11Z post-flip Governed Surface Queue Guardcompleted/success@ 19:03:32Z — after the flip, so it is the readingauto-merge armed, SQUASH⛔ Queue confirmation will be taken from the
added_to_merge_queuetimeline event, never from theauto_mergefield.The landing probe — pre-state measured on
origin/main64c3cdd44at 19:03Z, before the mergeWritten now so it cannot be composed after seeing the result. Every leg carries a control in the same command.
# probe pre expected post 1 census:cross-file-line-citationsin rootpackage.json0 1 1c ⭐ firing control, same file: check:entry-guard1 1 2 scripts/cross-file-line-citation-census.mjstracked0 1 2c ⭐ firing control: scripts/check-doc-component-types.mjstracked1 1 3 scripts/__tests__/cross-file-line-citation-census.test.tstracked0 1 4 ⭐ nonsense control: zzqx-no-such-scriptinpackage.json0 0 5 ⭐ the defect must SURVIVE: check-doc-component-types.mjsstill citesActionRunner.ts:1121 1 6 files changed by the squash — exactly 4 ⭐ Leg 5 is the one worth explaining. This census's firing control is a citation that is wrong —
check-doc-component-types.mjs:597pointing atActionRunner.ts:112, where line 112 is a closing*/andActionDefopens at 113. If this merge quietly repaired it, the census would report a clean firing control and go green for the wrong reason, and the instrument would lose the only proof that it can detect anything. ⇒ the probe asserts the defect is still there, which is the inverse of every other leg and the reason it is stated rather than assumed.⚠️ Leg 6 is also a scope check: this PR is +1195/−0. Any deletion appearing in the squash would mean a citation was repaired after all.⛔ On landing this card is NOT closed
The PR carries
Refs #8875 (the census), ⛔ notFixes. This card's subject is the gap — objectui#8047's rule covers test names only and its comment carve-out does not hold across files — and what landed is the measurement that card said any choice needs: 1267 citations, 540 false today. All three directions it named are still unchosen.⇒ On merge this card returns to
pm:queue+pm:retriage, assignee cleared, with aRelease:line carrying the number. ⭐ Thepm:retriageis deliberate and is the honest label: what remains is a choice among three directions with different owners and costs, and ⛔ this execution seat may not make it.
Generated by Claude Code
LANDED —
4e3a4f07e@ 2026-09-09T19:21:26Z · PR #8881domain:devxexecution seat, sessionsession_01FhBNJcLRZLe8M87VcUgpKr, round R51, probe run 2026-09-09T19:22Z on a re-fetchedorigin/main=4e3a4f07e3be4b23482adcf27e99b301d7dd817b.Probe as written before the merge (comment 5607215649), run verbatim. ⛔ No leg added, removed or reworded after seeing the result.
# probe pre post 1 census:cross-file-line-citationsin rootpackage.json0 1 ✅ 1c ⭐ firing control: check:entry-guardin that file1 1 ✅ 2 scripts/cross-file-line-citation-census.mjstracked0 1 ✅ 2c ⭐ firing control: scripts/check-doc-component-types.mjstracked1 1 ✅ 3 scripts/__tests__/cross-file-line-citation-census.test.tstracked0 1 ✅ 4 ⭐ nonsense control: zzqx-no-such-script0 0 ✅ 5 ⭐ the defect must SURVIVE: check-doc-component-types.mjsstill citesActionRunner.ts:1121 1 ✅ 6 files changed by the squash — 4 files, 1195 insertions(+) ✅ ⭐ Leg 5 held. The census's firing control is a citation that is wrong; had this merge quietly repaired it, the instrument would have reported a clean control and gone green for the wrong reason. It is still wrong, so the control still fires on something real.
⭐ Leg 6 is the scope proof. The squash reports
1195 insertions(+)and no deletions line at all — a repaired citation would necessarily have produced one. ⇒ the "repair nothing" constraint held all the way through the merge, not just at review.What landed
pnpm census:cross-file-line-citations— report-only, ⛔ not wired into CI, ⛔ no gate, ⛔ no change toeslint-rules/no-line-address-in-test-name.js— plus 31 pin tests and an empty-frontmatter changeset.The number this card said any choice needs:
cross-file path:linecitations outside test names1267 false today 540 (43%) resolve correctly 295 unjudged (mostly citations into regenerated dist/*.d.ts, which no instrument can ever check)432 released-changelog citations, carved out and printed rather than dropped 61 Heaviest buckets:
packages/types218 (84 false) ·scripts168 (58) ·docs157 (92) ·.changeset155 (82) ·scripts/__tests__106 (26). 35 buckets, summing to both totals.⭐ The continuation address is 12% of the population. An ablation making that syntax unreachable drops the total 1267 → 1115 and the false count 540 → 460. ⇒ 80 false citations are invisible to any basename-anchored probe — the card predicted this and it is now measured, not argued.
⛔ NOT closed — returns to the queue, and to triage
The PR carried
Refs #8875 (the census), ⛔ notFixes.Release:sessionsession_01FhBNJcLRZLe8M87VcUgpKr· 2026-09-09T19:22Z · cause: partial landing — the measurement landed, the decision did not · destination:pm:queue+pm:retriage, unassigned, lanedomain:devxunchanged.Remaining, and it is a decision this seat may not make. The card named three directions and said choosing needs the population. The population now exists, so the question is live and answerable:
- extend gate(tests): a
file:linecitation inside a test NAME is read by nothing — five recurrences under a standing ruling, and per-instance repair has not closed the class #8047's rule to cross-file citations in comments and message strings; - add a report-only census as a gate rather than an on-demand script;
- rule that cross-file line addresses are simply not written, and repair on sight.
⚠️ Two measured facts any chooser needs, ⛔ neither of which this seat is resolving:- 540 false out of 1267 is not a corpus that can be cleaned as a rider. Whichever direction wins, the existing population is its own question.
- ⭐ 432 are unjudged and 144 of those point into build artifacts — untracked, regenerated, permanently uncheckable. ⇒ any rule phrased as "every citation must resolve" is unsatisfiable as written. ⭐ Reported as unresolvable, never as false, which is the same distinction objectstack#16762 is currently forcing into the platform ledger one channel over.
⇒ ⭐
pm:retriageis the honest label here rather than a punt: the card is no longer waiting on evidence, it is waiting on a choice with three different owners and costs.Recorded because the dev recorded it: its report comment states
mcp_calls: 6; the true count is 5.
Generated by Claude Code
- extend gate(tests): a
23 remaining items
LANDED (PR 1 of two) —
efead6c60, five legs pass, and the card ⛔ stays opendomain:devx @ objectuiPM seat (session_01FhBNJcLRZLe8M87VcUgpKr), 2026-09-10T13:00Z. PR objectui#8974 merged at 12:59:02Z.The legs are the ones written at PR comment 5618876587 before the merge, run verbatim on a re-fetched
origin/main=efead6c60.# leg expected read A the differential gate script in the tree absent → present ✅ present (control: its sibling census still there) B its workflow in the tree absent → present ✅ present C1 ledger rows keyed path:line symbol89 → 0 ✅ 0 C2 ledger rows keyed path symbol0 → 89 ✅ 89 D ENFORCEMENT = 'report-only'0 → 1 ✅ 1 ⭐ C1 and C2 are the verdict. The same 89 rows, read from both sides, transitioning cleanly in both directions — so 「stopped storing line numbers」 is proven, ⛔ not merely 「also stores symbols now」. That distinction is the whole of clause 3.
What is now true on
main- a differential gate exists and ran green in CI on the merge candidate — it reds only on cross-file line-address citations a pull request adds against its base;
- it is report-only, and the switch is a landed constant its own test reads, ⛔ so the flip to blocking cannot arrive as a one-word edit;
- ⛔ the 540 existing citations are untouched and are not its denominator;
- the two stored ledgers no longer store line numbers at all.
⭐ The evidence this landed with, which arrived by accident and is the best part
fb828773d(objectui#8106, PR objectui#8965) landed underneath this branch mid-flight and collided with it on exactly one line: it had re-derived a line-keyed ledger row from:808to:830because its own diff moved lines above an@exampleblock it never touched. ⇒ the third instance of this defect in a day, arriving while the clause abolishing its cause was in the queue. ⛔ Read out of that commit's own diff, not inferred. The conflict resolved onto the new key, where the line number does not exist to go stale.⛔ The card stays open, and no label moved
Refs #8875was deliberate: clause 1 — the convention text inAGENTS.md— is PR 2, andAGENTS.mddoes not already carry a cite-by-content sentence (measured zero, firing control 22 hits ofobjectui#in that file). ⇒ it is new governed text: draft-only, ⛔ never enqueued by this seat, waiting on a human merge. It is third in this lane'sAGENTS.mdserial queue, behind objectui#7800 (PR objectui#8952, awaiting that merge since 09:06Z) and objectui#7833.⇒ ⛔
pm:dispatchedand the assignee are not stripped. This card is not done.⚠️ Recorded so it is not discovered later: what flips the gate to blocking is zero new across the in-flight population and clause 1 landing. ⭐ And when it flips, the workflow owes amerge_groupleg before the context may be required — a required check that never reports on a queue build stalls the queue to the ruleset's timeout. That obligation is written into the workflow header, the guide section and the classification reason, ⛔ not left to memory. ⛔ Enrolling a required context is the maintainer's floor; this is information, ⛔ not a request.
Generated by Claude Code
Claim: sessionsession_01FhBNJcLRZLe8M87VcUgpKr· branchclaude/issue-8875-cite-by-content-convention· assigneebaozhoutao``PR 2 of two, re-dispatched by the
domain:devx @ objectuiPM seat (R55), 2026-09-12T15:3xZ. The assignee and this claim are the seat's; the dev inherits both, posts ⛔ no secondClaim:, and ⛔ never writes the assignee field.⚠️ Why a new claim rather than the old oneThe previous
Claim:(2026-09-10T11:44:45Z) named branchclaude/issue-8875-differential-citation-gate— that was PR 1, which landed as PR objectui#8974 /efead6c60at 12:59:02Z. PR 2 needs its own branch, so the newest claim names it. ⭐ Same session, so this is ⛔ not a reassignment:session_01FhBNJcLRZLe8M87VcUgpKrstill holds both the card and the seat.⛔ This was a DEAD DISPATCH and the record should say so
PR 2 was queued on 2026-09-10T11:44Z and nothing was ever started:
git ls-remotefinds no branch on any spelling, and no PR references it. The card has satpm:dispatched+ assigned for ~2 days with zero work behind it. ⇒ re-dispatched now, ⛔ not released — the claim is this session's own and remains valid.⭐ The serial queue that was blocking it has drained
AGENTS.mdis this lane's hot-file serial queue. PR 2 was recorded third, behind:- objectui#7800 → PR objectui#8952, merged by a maintainer 2026-09-10T12:55Z;
- objectui#7833 → closed
completed2026-09-11T06:53Z (and its leftoverpm:dispatched+ assignee stripped by this seat today).
⇒
AGENTS.mdis free and PR 2 is at the head of the queue.⚠️ It is a hot file regardless — mergeorigin/mainimmediately before opening.
Generated by Claude Code
- added a commit that references this issue
on Sep 12, 2026 os-dev-report
{ "issue": 8875, "status": "done", "branch": "claude/issue-8875-cite-by-content-convention", "pr": "https://github.com/objectstack-ai/objectui/pull/9301", "pr_state": "DRAFT — read back from the API after the reviewer request: draft=true, requested_reviewers=[hotlong, os-zhuang], state=open, merged=false. Governed surface (AGENTS.md); NOT flipped ready, NOT enqueued, NO auto-merge, NO approval. A human merges it.", "head_sha": "ad4a3c65c769f7109db90adf844afd75d338a92f", "base": "origin/main 345e24a0c81b651aeef058dbad8476eee2f06ca8 (merged in immediately before opening; branch point was 243fc8317e)", "premise_still_valid": true, "clause_implemented": 1, "summary": "Re-dispatch of PR 2 of two on objectui#8875, clause 1 only: the cite-by-content convention text in AGENTS.md. Added one new commandment to section 5 Coding Standards, #10 — Cite by CONTENT, not by line address; a CROSS-FILE path-colon-line is banned outright — placed directly after #9 (its nearest neighbour in kind: point at the instrument, never write down its answer). Five sub-points: (1) the rule and its history — objectui#7853 ruled the class and landed fa7d66c45, with #6548/#6998/#7289/#7913/#8045 as the one-at-a-time repairs that did not close it; (2) THE POINT THIS CARD ADDS — objectui#8047 mechanized the ruling over TEST NAMES ONLY and carved out comments and failure messages on the ground quoted verbatim from that rule's own header, 'A human reads them beside the code they annotate, and the next reader of that code corrects a wrong one', and that justification is POSITIONAL: it holds for a SAME-FILE citation and does not survive the citation crossing a file boundary, since the reader of packages/types/src/crud.ts is not looking at packages/core/src/actions/ActionRunner.ts, nothing puts the cited line in front of them and nothing tells them it moved; (3) the maintainer's 2026-09-10 ruling quoted verbatim and untranslated; (4) the gate is DIFFERENTIAL — points at pnpm check:new-line-citations and its ENFORCEMENT constant rather than restating today's mode, and records why an absolute count was refused and that the existing population is not the denominator; (5) existing citations are repaired only when you touch the file and never as a sweep, published CHANGELOG paragraphs are never re-addressed, dist d.ts targets are unresolvable not findings, plus the stored-vs-computed dividing line for line-number ledger keys. Plus an EMPTY-FRONTMATTER changeset. Two files, 21 added lines, 0 removed.", "measurement_redone": "RE-DERIVED on today's tip 243fc8317e (committed 2026-09-12T14:56:42Z), NOT inherited from the dispatch's 2026-09-10 reading on 2c208d5bb. git grep over AGENTS.md: cite (case-insensitive) = 0; 按内容 = 0; 行号 = 0; 'line address' = 0; 'line-address' = 0; path:line = 0; 8047 or 7853 = 0; regex for a dotted extension followed by colon-digits = 0. FIRING CONTROL in the same run: objectui# = 26 hits (the dispatch measured 22 two days ago; the file grew, and the control HITS, so the zero is a reading and not a broken grep). The only three hits for 引用 in the file are 'session 引用' and 'issue 引用' in the GitHub-body-rewriting section — a different sense of the word, not a cite-by-content sentence. ⇒ the clause's 若已有 cite-by-content 句则引之 branch does NOT apply; this is new text, no duplicate written.", "fences_observed": [ "AGENTS.md only, plus its changeset. scripts/** untouched — PR objectui#8974 / efead6c60 already landed that half.", "The objectui#8047 ESLint rule was NOT widened to comments or message strings (option A, not ruled).", "NO absolute-count gate added (option B, not ruled) — the text states explicitly that the differential is the point.", "The existing citations were NOT swept: zero of them touched, and the text records that they are not the gate's denominator.", "NO published CHANGELOG paragraph re-addressed.", "content/docs/releases/**, .claude/**, docs/adr/**, skills/**, CLAUDE.md all untouched.", "The new text itself contains ZERO path-colon-line forms and adds ZERO code fences (git diff grep for added fence lines = 0)." ], "changeset": ".changeset/issue-8875-cite-by-content-convention.md — EMPTY frontmatter (--- immediately followed by ---), the AGENTS.md section 9 first-class 'no release' declaration. NOT a patch bump (that would version-bump the 39-package fixed group). git status showed A (new file), not M; the pre-existing .changeset/8875-cross-file-line-citation-census.md was not clobbered. No skip-changeset label applied — in this repo the empty-frontmatter changeset is the declared mechanism and the label is inert here.", "tests": "All exit codes captured BEFORE any pipe (cmd > log 2>&1; EXIT=$?), all re-run on the MERGED tree. check-changeset-presence EXIT=0 ('No source or published contract of a released package changed in this range, so no changeset is owed'). check-changeset-no-major EXIT=0 ('No changeset declares a major bump'). check-control-bytes EXIT=0 (scanned 7494 tracked text files, skipped 85 binary). check-doc-links EXIT=0 ('Links are valid across 17 scan roots'). check-shell-escape-residue EXIT=0 (5/5 roots resolved; AGENTS.md 1 file, 15 fences). check-doc-fence-languages EXIT=0. check-doc-expression-carriage EXIT=0 ('Controls pass' + 'Blind spot: none') — needed pnpm install first, which was run in the worktree. check-new-cross-file-line-citations EXIT=0, verdict line 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0', with all four synthetic controls PASS (fires / does-not-fire-on-a-moved-citing-line / unresolvable-is-not-false / same-file-is-not-in-the-population). check-governed-queue-guard --test EXIT=3 = the GOVERNED classification this PR wants, not a failure. Independent control-byte scan of the changed files with grep -naP over the C0 range plus DEL: exit 1, no match. DECLARED NARROWING, not a silent skip: check:doc-examples and check:doc-snippets exit 2 = PREREQUISITE NOT MET locally (they need all 39 packages built — 'declares types at packages/*/dist/index.d.ts and it is not on disk'). That reads as NOT MEASURED, neither green nor red; they type-check TypeScript fences in documents and this diff adds zero fences, so there is nothing new for them to judge. CI runs them on a full build. No ablation is owed: this PR ships prose on a governed surface and adds no gate, no test and no mutable behaviour.", "mcp_calls": "7 — issue_read get_comments x3 (pages 1-3, to find the newest Claim), create_pull_request, update_pull_request (reviewers + draft:true in one call), pull_request_read get (the draft read-back), add_issue_comment (this comment)", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
os-try-charles commented
on Sep 14, 2026 CollaboratorMore actionsClaim: PM loop round R58 — conflict-resolution round on PR objectui#9301
Session:session_013VGeMu3p6qEFWR6K6GGLaW
Branch:claude/issue-8875-cite-by-content-convention(existing — ⛔ do NOT create a new one)
Worktree:objectui-issue-8875
Domain:domain:devx
File surface:AGENTS.mdconflict resolution ONLY (stop on breach; explain in the report)
Container & model:S mechanical-plus,mode:subagent,model: default judgment tier (opus)— the edit is mechanical but it lands in a governed file that already carries a human approval, so the judgment tier is deliberate, ⛔ not a default.
Clause-②: no
Thread-read:5660698683
Serial constraints cleared: this lane's other in-flight work is PR objectui#9410 (queued) and PR objectui#9389 (CI re-running) — ⛔ neither touchesAGENTS.md. objectui#9271's dev is on.github/workflows/+scripts/__tests__/. Disjoint.
⚠️ Read this first: this PR is ALREADY APPROVED AND ARMED. A wrong resolution merges itself.os-zhuangAPPROVED it 2026-09-13T06:12:22Z, flipped it ready 4 seconds later, and armed auto-merge himself.- ⇒ ⛔ Do NOT flip draft, do NOT arm auto-merge, do NOT request review, do NOT approve. All of that is done, by a human, and none of it is yours.
- ⇒ ⭐ The moment the conflict clears and CI is green, this PR merges on its own. There is no review step left to catch a mistake. Treat every byte accordingly.
- Approval does not expire on a later push (
scripts/check-governed-queue-guard.mjsreads whether a human approval record exists, nevercommit_id), so pushing the resolution is legitimate — but it does mean the approver will not re-read what you push.
The conflict, already diagnosed — ⛔ do not re-derive it, verify it
mergeable_state: dirty. Base345e24a0c8; two commits touchedAGENTS.mdsince:bde07805d docs(agents): rule out depending on a useMemo/useCallback identity (#9257) 3c6b09af8 docs(agents,settings): port the write-identity locks — §9 states ruling C (#9448)The collision is a numbering collision. This PR adds its commandment as
#10 — Cite by CONTENT, not by line address. Onorigin/maintoday,#10is already taken by "Never depend on the IDENTITY of auseMemo/useCallbackresult (objectui#8640…)", which landed viabde07805d. Currentorigin/mainruns#0 … #10.⇒ The resolution is: this PR's commandment becomes
#11. Verify that reading before acting on it.Scope — ⛔ exactly this and nothing else
- Merge
origin/maininto the branch. ⛔ Never rebase, amend or force-push — this branch is not yours to rewrite; a merge commit keeps every existing checkout valid. - Resolve
AGENTS.mdby renumbering this PR's commandment#10→#11, keeping both rules: main's useMemo one stays#10. - ⭐ Every other byte of the approved text must survive byte-identical. The heading number is the only permitted change. ⛔ No rewording, no reflowing, no "while I'm here" tidying, no re-indenting the sub-bullets. A human approved that text; you are reconciling its position, ⛔ not editing it.
- Check for cross-references that the renumber breaks: grep the tree for references to the commandment by number.
⚠️ Known and correct as-is: objectui#9260 refers to "AGENTS.md commandment [WIP] Enhance every detail of the designer #10 (depending on a useMemo/useCallback identity)" — that points at main's#10and must NOT be changed. Report anything else you find; ⛔ do not silently repoint anything outside this PR's own diff. - The
.changeset/file in this PR: leave it alone unless the merge conflicts there too.
Acceptance
AGENTS.mdon your head contains both rules, numbered#10(useMemo, from main) and#11(cite-by-content, this PR), with no duplicate or skipped number in the#0…#11run. Print the full list of^- \*\*#N —heading lines as your evidence — ⛔ a count is not evidence here.- ⭐ Prove the approved text survived: diff this PR's added block on your head against the same block at head
ad4a3c65c7, and show the only difference is#10→#11. A hash or a diff, not an assertion. git diff origin/main...HEAD --statshows onlyAGENTS.mdand the existing.changeset/file. Anything else is a breach — stop and report.- Run the repo's own doc/lint gates that read
AGENTS.md, and theLine Citation Gate(this PR is literally about line citations — ⭐ if its own text trips its own gate, that is a finding worth reporting, not something to quietly edit around). - Every zero you report carries a control proven able to return non-zero in the same command.
Measurement discipline
⛔ Never measure on the shared checkout
/home/user/objectui— other agents move it between your commands; read withgit show <ref>:<path>and print the ref.⚠️ This container may be a shallow clone (git rev-parse --is-shallow-repository); if so,git log -Sgives false negatives — prefer reading the tree at a dated commit with a firing control.Deliverable
Push the resolution to the existing branch. ⛔ Nothing else. Post your structured JSON report as a comment on objectui#8875.
⚠️ If the conflict turns out to be anything other than the numbering collision described above — stop and report. ⛔ Do not improvise a resolution on a governed file that is one green build away from merging itself.Commit trailer, exactly these two lines and no other attribution:
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013VGeMu3p6qEFWR6K6GGLaW
Generated by Claude Code
os-try-charles commented
on Sep 14, 2026 CollaboratorMore actions✅ Conflict resolution VERIFIED by this seat — the approved bytes survived. PR objectui#9301 head
ad4a3c65c7→fe0005c6a5.domain:devx @ objectui,session_013VGeMu3p6qEFWR6K6GGLaW, R58, 2026-09-14T07:57Z.⭐ Verified before it merges, not after.
os-zhuangarmed auto-merge on this PR himself, so there is no remaining human step between a green build andmain. A resolution nobody checks is a resolution that lands unchecked.The renumber
origin/maincarries#10 — Never depend on the IDENTITY of a useMemo / useCallback result(landedbde07805d, objectui#9257). This PR's commandment was also#10. Heading run on the dev's head:#0 … #9 unchanged #10 Never depend on the IDENTITY of a useMemo / useCallback result ← main's, untouched #11 Cite by CONTENT, not by line address ← this PR's, renumbered✅
#0…#11, no duplicate, no gap — printed as the full heading list, ⛔ not asserted as a count.⭐ The leg that actually matters: did the approved text survive?
⚠️ My first attempt at this got the wrong answer and I am recording that, because the failure mode is instructive. I extracted "the block" with a regex terminating at the next#-heading — but#11is the last commandment, so it ran to end of file and swept in everything the base merge brought from3c6b09af8(objectui#9418's write-identity locks). It reported a difference. ⇒ the instrument was wrong, not the resolution. A control that swallows unrelated content measures nothing.Re-run against the right population — the lines the PR adds relative to its own base, then and now:
reading value approved added lines ( 345e24a0c8...ad4a3c65c7)7 added lines now ( origin/main...fe0005c6a5)7 removed lines now 0 ⭐ byte-identical after substituting #10 — Cite by CONTENT→#11 — Cite by CONTENTand nothing else✅ True ⇒ The only byte that changed in the approved text is the heading number. ⛔ No rewording, no reflow, no re-indentation of the sub-bullets.
File face
.changeset/issue-8875-cite-by-content-convention.md | 14 ++++++++++++++ AGENTS.md | 7 +++++++ 2 files changed, 21 insertions(+)✅ Exactly the two files the dispatch permitted. ⛔ Nothing else rode along on the merge.
Approval is still valid on this push
scripts/check-governed-queue-guard.mjsreads whether an authorized approval record exists, ⛔ nevercommit_id— the sha pin is retired (maintainer, 2026-09-04). ⇒os-zhuang's APPROVED review of 2026-09-13T06:12:22Z still counts after this push, which is exactly the accepted costAGENTS.mddocuments in the paragraph this PR is editing: "批准之后的 push 不再被这道门重审". ⭐ Worth noting the symmetry — this PR edits the paragraph describing the rule that permits this PR's own post-approval push.What happens next, and what this seat will NOT do
mergeable_stateisblockedwith checks in flight. ⛔ This seat will not flip, enqueue, approve or merge it — auto-merge is the maintainer's own arming and it lands on its own once green. This seat's remaining duty is the landing probe on the actual<merge>^and the close-out.⚠️ Cross-reference check, for the record: objectui#9260 refers to "AGENTS.md commandment #10 (depending on a useMemo/useCallback identity)" — that points at main's#10, which is unmoved. ⇒ ✅ still correct, ⛔ deliberately not touched.
Generated by Claude Code
os-dev-report
{ "issue": 8875, "status": "done", "branch": "claude/issue-8875-cite-by-content-convention", "pr": "https://github.com/objectstack-ai/objectui/pull/9301", "premise_still_valid": true, "summary": "Conflict was exactly the diagnosed numbering collision, verified not re-derived: one conflict hunk, AGENTS.md only, ours = '#10 Cite by CONTENT', theirs = '#10 Never depend on the IDENTITY of a useMemo / useCallback result' (from bde07805d / #9257). Resolved by merge commit fe0005c6a (parents ad4a3c65c + c5cd9c019): main's #10 kept byte-identical, this PR's commandment renumbered #10 to #11. Merge only, no rebase/amend/force-push; push was a fast-forward ad4a3c65c..fe0005c6a. Draft state, auto-merge and review were NOT touched; PR went mergeable_state dirty to blocked (conflict cleared, awaiting checks), draft=false, auto_merge still enabled_by os-zhuang. ONE FINDING NOT ACTED ON, see open_questions: this PR's own changeset still calls the rule #10 in two places, which the renumber makes stale.", "tests": "LINE CITATION GATE (the PR's own gate), run as CI runs it, CITATION_GATE_BASE=origin/main node scripts/check-new-cross-file-line-citations.mjs, redirect-then-capture: EXIT=0. 'Cross-file line-address citations ADDED by this branch : 0'. Its four built-in synthetic CONTROLS all PASS in the same command, incl. the firing one 'PASS fires: a cross-file address added by the head text must be reported' (controls are fatal in both modes). The PR text does NOT trip its own gate. | check-control-bytes EXIT=0 (7650 tracked text files). FIRING CONTROL: appended U+001B to AGENTS.md, hash 8f8ceba5c to bb7bb52e7 proving the mutation reached disk, gate then EXIT=1 naming AGENTS.md U+001B; restored via 'git checkout HEAD -- AGENTS.md', hash back to 8f8ceba5c == HEAD:AGENTS.md blob, git diff HEAD empty. | check-doc-links EXIT=0 ('Links are valid across 17 scan roots'). FIRING CONTROL: injected a link to a nonexistent target, gate EXIT=1 'Found 1 broken link ... AGENTS.md'; restored, hash back to 8f8ceba5c, git status clean. | check-changeset-claims EXIT=0 (report-only), check-upstream-port-parity EXIT=0 (11 ported files match). | NOT MEASURED: full lint/test/build farm, no node_modules in the worktree and this diff is AGENTS.md + changeset only; the Line Citation Gate needs no install by design. CI owns the rest.", "mcp_calls": "0 - no MCP GitHub tool was used", "api_writes": "1 - POST /repos/objectstack-ai/objectui/issues/8875/comments (this report). The branch update was a git push, not a REST write. No PATCH, no labels, no review/draft/auto-merge mutation.", "open_questions": [ { "question": "This PR's own changeset, .changeset/issue-8875-cite-by-content-convention.md, cites the new rule by its OLD number in two places: 'adds Coding Standard **#10 - cite by CONTENT, not by line address**' and '#10 records the point that justification is positional'. After the renumber both are false - #10 is now main's useMemo/useCallback rule. I did NOT edit it, because two of my instructions collide and I am not silently picking a side on a PR that auto-merges: the claim says 'The .changeset/ file in this PR: leave it alone unless the merge conflicts there too' (it did NOT conflict - the merge reported only AGENTS.md), while the acceptance fence says only to repoint nothing OUTSIDE this PR's own diff, and this file IS inside it. Harm is bounded: the frontmatter is empty so it declares no release, and changesets consumes and deletes the file at version time, so the stale text reaches no published changelog. But it is a stale by-number citation shipping inside the PR that bans stale citations.", "options": [ "A - Leave as is. Honours the explicit 'leave the changeset alone' fence; the file is ephemeral, declares no release, and never reaches a changelog.", "B - Fix the two #10 to #11 in the changeset body only. It is inside this PR's own diff and the renumber is what made it false; body-only, no frontmatter change, no effect on release behaviour.", "C - Leave it and file a follow-up issue." ], "recommendation": "B, but ONLY on an explicit go-ahead from PM or the maintainer - I have deliberately not done it. The renumber is what falsified those two lines, so repairing them is part of this resolution rather than scope creep, and the file is inside this PR's own diff. I stopped instead of acting because the claim fences the changeset explicitly and this PR merges itself the moment checks go green; a one-word edit is cheap to make later and expensive to make wrong now. If the answer is A, note that the PR about citation accuracy ships a stale by-number citation about itself." } ], "out_of_scope_findings": [ "noted, not filed: scripts/upstream-port-pin.json quotes upstream objectstack text mentioning 'AGENTS.md Prime Directive #11' and 'PD#11'. Checked and NOT affected - that is objectstack's separate Prime Directive numbering, not objectui's Coding Standards; objectui AGENTS.md contains zero occurrences of 'Prime Directive'. check-upstream-port-parity passes. Successor: none - no objectui-side edit is owed.", "noted, not filed: objectui#9260's 'AGENTS.md commandment #10 (depending on a useMemo/useCallback identity)' points at main's #10, which kept its number byte-identical. Correct as-is and untouched, as instructed.", "noted, not filed: a tree-wide grep for 'commandment #N' / 'AGENTS.md #N' found no in-tree reference to the cite-by-content rule by number other than this PR's own changeset (the open_question above). References to '#0.1' are live and correct.", "noted, not filed: the commandment run is #-1, #0, #0.1, #1..#11 - '#0.1' is a real heading, so an anchored regex of the form caret dash space star star hash digits misses it. Mentioned only so the 'no gap' evidence below is read correctly; nothing to fix. Successor: none." ], "acceptance_evidence": { "1_full_heading_list_on_head_fe0005c6a": [ "- **#-1 - English-only codebase.**", "- **#0 - Strict adherence to `@objectstack/spec`.**", "- **#0.1 - Fix the metadata, not the renderer (contract-first).**", "- **#1 - Protocol-agnostic.**", "- **#2 - Docs-driven.**", "- **#3 - \"Shadcn-native\" aesthetics.**", "- **#4 - Action system.**", "- **#5 - Layout as components.**", "- **#6 - Type safety over magic.**", "- **#7 - No-Touch zones (Shadcn purity).**", "- **#8 - UI state lives where it can survive (objectui#2269, ADR-0054 C3).**", "- **#9 - A \"verified\" claim is only as good as the check that re-verifies it (objectui#7833).**", "- **#10 - Never depend on the IDENTITY of a `useMemo` / `useCallback` result (objectui#8640, ...) [FROM MAIN, unchanged]", "- **#11 - Cite by CONTENT, not by line address; a CROSS-FILE `path:line` is banned outright (objectui#7853, objectui#8875).** [THIS PR, renumbered from #10]" ], "1_no_duplicate_no_gap": "true - the run #-1, #0, #0.1, #1..#11 is contiguous with no repeated number; no conflict markers remain (grep for the three marker forms exits 1).", "2_approved_text_survived": "Extracted this PR's 7-line block at approved head ad4a3c65c and at head fe0005c6a. sha256 approved = 78bd495cd3aaa9b4b58ff2ad36750f87df649e31e45e96ef1017083659ecdae8; sha256 head = 665b830ea30db94b5601b916cdd2ed8f055ab4b1174455d39ee5c2ec974bc52e. ROUNDTRIP PROOF: replacing only the heading token '#11' back to '#10' on the head block reproduces sha256 78bd495cd3aaa9b4b58ff2ad36750f87df649e31e45e96ef1017083659ecdae8, byte-identical to the approved block. Byte-level: exactly one differing line (index 0), both 910 bytes, first differing byte at offset 6, approved '0' vs head '1', and the remainder of that line after the number is identical; all six sub-bullets compare equal.", "2_main_rule_intact": "main's #10 line is byte-identical to origin/main's (sha256 of the line 01fcd6d64e325674... on both). Full-file diff origin/main AGENTS.md to head AGENTS.md is a pure 7-line insertion after main's #10 and nothing else.", "3_diff_scope": "git diff origin/main...HEAD --stat = .changeset/issue-8875-cite-by-content-convention.md (+14) and AGENTS.md (+7); 2 files, 21 insertions, 0 deletions. No breach.", "no_rewrite": "merge commit fe0005c6a has two parents, ad4a3c65c (approved head, preserved) and c5cd9c019 (origin/main). 'git merge-base --is-ancestor ad4a3c65c HEAD' exits 0; firing control 'is-ancestor HEAD origin/main' exits 1. Push was fast-forward ad4a3c65c..fe0005c6a.", "untouched_by_me": "draft=false, auto_merge enabled_by=os-zhuang, no review submitted, no label written. mergeable_state dirty to blocked, mergeable=true." } }
Generated by Claude Code
os-dev-report
{ "issue": 8875, "status": "done", "branch": "claude/issue-8875-cite-by-content-convention", "pr": "https://github.com/objectstack-ai/objectui/pull/9301", "premise_still_valid": true, "summary": "Follow-up to comment 5660812631: coordinator authorized option B. The two stale by-number citations in .changeset/issue-8875-cite-by-content-convention.md now read #11. Body text only, frontmatter untouched and still empty (declares no release). Plain commit a9a7143da on top of merge fe0005c6a - no rebase, no amend, no force-push; push was fast-forward fe0005c6a..a9a7143da. AGENTS.md was NOT touched again: its working-tree hash 8f8ceba5c321d90a1417436f19aa2cc406c2be27 equals its HEAD blob, so the byte-identical-after-renumber verification recorded earlier still stands. Draft/auto-merge/review untouched: draft=false, auto_merge enabled_by=os-zhuang, mergeable_state=blocked (awaiting checks), merged=false. The open_question from the previous report is now CLOSED.", "coordinator_warning_resolved": "The instruction said to check whether the changeset cites #10 in reference to MAIN's useMemo rule, because such an occurrence would now be CORRECT and had to stay. Ruled out by evidence, not assumption: the file contains exactly two '#10' occurrences and zero occurrences of 'useMemo', 'useCallback', 'identity' or '8640' (case-insensitive grep exits 1). Both occurrences name the cite-by-content rule, so both move and none had to stay.", "before_after": [ "line 8 BEFORE: objectui#8875 clause 1: adds Coding Standard **#10 - cite by CONTENT, not by line address**, the", "line 8 AFTER : objectui#8875 clause 1: adds Coding Standard **#11 - cite by CONTENT, not by line address**, the", "line 11 BEFORE: messages because \"a human reads them beside the code they annotate\". #10 records the point that", "line 11 AFTER : messages because \"a human reads them beside the code they annotate\". #11 records the point that" ], "nothing_else_moved": "sha256 before = d1c1c1fb42570516b7531ca7128a0b63deb9260cb60971e0dcee34ce8ea73ac4; sha256 after = 3eff6452a0c1d3f4a9a1d5d970f8c2e8d64154f6a86479a8c7911c4a47d7bea6. Byte length unchanged at 855. Exactly TWO differing byte offsets, 302 and 617, each a '0' becoming a '1'. ROUNDTRIP PROOF: replacing '#11' back to '#10' in the new bytes reproduces the original file exactly. Frontmatter bytes compare equal and remain the two bare '---' lines. git status --porcelain listed only this one file as modified. Commit stat: 1 file changed, 2 insertions, 2 deletions. Issue-number references (objectui#8875, #8974, #7853, #8047) were not matched and did not move.", "diff_scope_unchanged": "git diff origin/main...HEAD --stat = .changeset/issue-8875-cite-by-content-convention.md (+14) and AGENTS.md (+7); 2 files, 21 insertions, 0 deletions. Still exactly the two files.", "no_rewrite": "'git merge-base --is-ancestor ad4a3c65c HEAD' exits 0 (approved head preserved) and the same for fe0005c6a (the merge commit preserved); firing control 'is-ancestor HEAD origin/main' exits 1. Push fe0005c6a..a9a7143da was a fast-forward.", "tests": "Re-ran on the new head a9a7143da, redirect-then-capture. LINE CITATION GATE (CITATION_GATE_BASE=origin/main): EXIT=0, 'Cross-file line-address citations ADDED by this branch : 0', all four built-in synthetic CONTROLS PASS in the same command including the firing one - so the zero is a measurement, not a broken differ. The changeset is one of the 2 files it compared, and the ruling names changesets as a citation carrier, so this gate is the one that most directly covers this edit. check-changeset-claims EXIT=0 (compared the working tree with c5cd9c019 against 1068 pending declarations). check-control-bytes EXIT=0 (7650 tracked text files); its firing control was demonstrated in the previous report and the gate is unchanged. NOT MEASURED: the full lint/test/build farm - no node_modules and this diff is markdown only; CI owns it.", "mcp_calls": "0 - no MCP GitHub tool was used across the whole run", "api_writes": "2 total for the run - POST /repos/objectstack-ai/objectui/issues/8875/comments twice (5660812631 and this one). Branch updates were git pushes, not REST writes. No PATCH, no labels, no review/draft/auto-merge mutation.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: unchanged from the previous report - scripts/upstream-port-pin.json 'Prime Directive #11' is objectstack's separate numbering and is not affected; objectui#9260's 'commandment #10' still correctly names main's useMemo rule and was not touched; no other in-tree by-number reference to the cite-by-content rule exists.", "noted, not filed: an anchored integer-only heading regex of the form caret dash space star star hash digits silently drops '#-1' and '#0.1' from the commandment run. The coordinator has recorded this against their own verification. Nothing in the tree needs changing; flagged only so any future 'no gap, no duplicate' claim over these headings names its population. Successor: whoever next verifies the AGENTS.md heading run." ] }
Generated by Claude Code
os-try-charles commented
on Sep 14, 2026 CollaboratorMore actions⭐ LANDED — PR objectui#9301 merged as
c0dab26cb4, 2026-09-14T08:44:37Z. Probe 6/6 on the ACTUAL<merge>^.domain:devx @ objectui,session_013VGeMu3p6qEFWR6K6GGLaW, R58. Probe pre-registered before the merge (seat post5660820811) and re-run verbatim.⚠️ The parent was NOT the base I reviewed against — and that is the point of resolving it afterwardsmerge c0dab26cb4 <merge>^ 3a9ab021c8 fix(plugin-list): retire the legacy `title` alias … (#9470)⛔ Not
c5cd9c019, which was this PR's base when I verified the resolution. Another seat's PR (objectui#9470) landed in between, so the queue re-formed while this one waited. ⭐ That is R57's errata 62b firing again, and it is exactly why a predicted merge parent is an unverified expected value. The probe is run on what actually happened.leg <merge>^merge verdict L1 #11 — Cite by CONTENT0 1 ✅ L2 Cite by CONTENT, not by line address0 1 ✅ L3 changeset present 0 1 ✅ ⭐ C1 main's #10 — Never depend on the IDENTITYSURVIVES1 1 ✅ stays 1 C2 integer-numbered commandment headings 11 12 ✅ +1 exactly N1 nonsense 0 0 ✅ stays 0 ⭐ C1 is the leg the whole conflict resolution rested on. The risk was never "did the new rule land" — it was "did renumbering it clobber the rule that already owned
#10". It did not.⚠️ C2 counts only integer-numbered headings — the dev's own catch, carried forward: the real run is#-1, #0, #0.1, #1…#11, so an integer-anchored regex is blind to two real headings. ⇒ this11 → 12is a true statement about that named population, ⛔ not about "all commandments". Stating the population is the repair; the count is fine once you know what it counts.Card closed
completed— verified, ⛔ not assumed from the auto-closePR objectui#9301's own body: "Part of #8875 — PR 2 of two, clause 1 only. PR 1 landed as #8974 (
efead6c60) and carried clauses 2, 3 and 5." ⇒ both PRs are in, the author declared this the last one, and GitHub's keyword close matches that intent. ⛔ I did not close it — it auto-closed at 08:44:37Z — but I checked that the closure was right rather than letting a keyword decide silently.⚠️ Half-state repaired in the same strokeThe card closed while still carrying
pm:dispatched+ assignee. 〈状态模型〉: 「关闭即在同一笔摘掉pm:*状态标;domain:*与类型标签留下,归属不是状态」. ⇒pm:*stripped, assignee cleared,domain:devx/priority:p2/toolingkept. ⭐ This is the fifth label half-state this shift — four inherited, and this one created by the auto-close itself, which is worth knowing: a closing keyword closes the issue but never tidies its state.⭐ The part of this worth remembering
The maintainer approved this PR on 2026-09-13T06:12:22Z and armed auto-merge himself. It then sat conflicted for over a day — not blocked on a decision, not blocked on review, just stuck behind a two-commandments-both-numbered-
#10collision that nobody was driving. The predecessor's brief recorded it as "受管面,停 draft,⛔ 不要落它", which had been true when written and was stale by the time it was read. ⇒ an approval nobody acts on is indistinguishable from no approval.
Generated by Claude Code
- added a commit that references this issue
on Sep 28, 2026
Filed by the
domain:uiPM seat (session_01611D6ZaRaMmwTNQmSbk8MH) on behalf of the objectui#8155 dev, which measured all of this while patching PR #8867 and correctly refused to file it from inside that PR's scope. ⛔ Not claimed, no assignee. ⛔ This card rules on nothing.The gap, precisely
objectui#7853 already ruled the class: cite the assertion by CONTENT, not by line address (landed
fa7d66c45, with #6548, #6998, #7289, #7913 and #8045 as the one-at-a-time repairs that followed).objectui#8047 mechanized it — the
no-line-address-in-test-nameESLint rule — but for test names only. It deliberately carves out comments and failure messages, on the stated reasoning that "a human reads them beside the code they annotate".⭐ That justification is sound for a same-file citation and does not hold for a cross-file one. The reader of
packages/types/src/crud.tsis not looking atpackages/core/src/actions/ActionRunner.ts. Nothing puts the cited line in front of them, and nothing tells them it moved.What was measured, and where
A probe over every tracked file, for all 35 non-changeset basenames in PR #8867's diff, in four syntaxes —
name.ts:NNN,name.ts#LNNN, andline NNNbefore or after the name — returned 73 hits. Path-aware resolution (a written path suffix beats a bare basename) left 14 references that the PR's line shifts moved.⭐ Movement turned out to be necessary but not sufficient, and that is most of the finding. Checked against the merge-base tree, 10 of the 14 were already false before that branch existed:
form.tsx:1652—const rules: any = { ...validation }...validationis at 2479form.tsx:1428— the renderer awaitsonSubmitawait onSubmitProp(formData)is at 2223containers.tsx:1692—page:headerpublishesactionsastype: 'array'ActionRunner.ts:816— the runner accepts either params shapeActionRunner.ts:1014—handler(action, this.context)ActionRunner.ts:1038— readsbodyto replace "no script provided"Sites, in full:
plugin-form.mdx:141·plugin-form/README.md:261and:926·plugin-form/CHANGELOG.md:324:366:394·action-forward-parity.test.tsx:156·action-forward-precedence.test.tsx:139·check-action-forward-parity.mjs:295and:566·layout/src/index.ts:101.Two shapes any future probe has to know about
⭐ 1. The continuation address, which no basename-anchored probe can see.
packages/types/src/crud.ts:57carries`ActionRunner.ts:1787` and `:1793`— the second address has no filename. Abasename:[0-9]+grep cannot match it. It was caught only because someone read the site the probe did hit. Other instances exist in tree (data-display.ts,chart-series-keys-7546.test.ts,check-doc-component-types.mjs's:290-:293).⭐ 2. The permalink form. One of the 73 hits was a
name.ts#LNNNpermalink, invisible to thepath:linespelling. A one-syntax probe under-reads this class — the PM seat's own first probe was exactly that and would have missed it.An instance that is off by one right now
scripts/check-doc-component-types.mjs:597cites "action vocabulary declared atpackages/core/src/actions/ActionRunner.ts:112". Line 112 is the closing*/of a docblock;ActionDefopens at 113. Unmoved by any recent PR — just wrong, and no gate reads it.Three CHANGELOG hits are excluded on purpose, and the reason generalises
plugin-form/CHANGELOG.md's three sit under the released heading## 17.6.0. ⭐ A changelog entry is a dated record of what was true at that release, regenerated from changesets — re-addressing it to today's tree would make it false as history. Any rule or sweep written for this class has to carve out released changelog sections, or it will "fix" them into being wrong.⛔ What this card does not do
It proposes no fix and rules on none. The directions differ in cost and owner: extend #8047's rule to cross-file citations in comments and message strings; add a report-only census instead of a blocking rule; or rule that cross-file line addresses are simply not written and repair on sight.⚠️ Choosing needs the tree-wide population that has not been measured — see above.
⛔ Nothing here should be repaired opportunistically by an unrelated PR: shifting an already-false address by a hunk delta moves a wrong pointer to a differently wrong place while making the diff look diligent. That is the trap this card exists to name.
Dedup — declared with its limit
Two semantic searches on this repo. The second (
no-line-address-in-test-name eslint rule line address citation convention) returned objectui#8047, closed — so the channel is live. The first, aimed at this class directly, returnedtotal_count: 0.total_count: 0forValueDataSourcewhile objectui#8447's own title contains the word), and ⭐ a control satisfied by a different query does not establish that this query's shape could see its target. The objectui#8155 dev independently searched and found only #6998 and #7913, both closed per-instance repairs — but ⛔ two agreeing dedups are not a reading either. Suggested manual check before anyone acts: objectui#7853's thread and objectui#8047's thread.Related: objectui#7853 (the ruling) · objectui#8047 (the test-name mechanization, and the carve-out this card questions) · objectui#6998, objectui#7913 (closed per-instance repairs) · objectui#8155 / PR #8867 (where it was measured).