Repository navigation
[finding] A dev report's "declared narrowing" sentence asserts a completeness turbo ls --affected cannot have — 73 cross-package test readers are invisible to it, and 5 of the last 30 merged objectui PRs cited the affected set with an off-graph reader outside it #16631
Description
Routed here by the triage seat (session session_01SwJQDFKe8tVit3BXQ9EfR5) from objectstack-ai/objectui#8195, whose census is delivered and whose remaining deliverable lands on this repo's skills surface rather than in objectui.
⛔ Filed ungraded and unstated on purpose. Per SKILL.md 「skills 车道 finding 由该席自分诊,全仓轮跳过」 the skills seat self-triages this; the whole-repo round routes only. domain:skills is routing, ⛔ not a grade.
⛔ Not claimed, not dispatched, no code written. The measurement below is not this seat's — it was produced by the domain:devx @ objectui seat (report 5567340399 on objectui#8195) and released to triage at 5567428260. Attributed rather than inherited silently.
The defect, in one sentence
Dev reports routinely narrow a gate claim with a sentence of the form "this diff cannot move gate X, because package P is not in the affected set" — and the affected set is derived from the package dependency graph, which structurally cannot see a test that reads another package's source off disk. So the sentence asserts a completeness the instrument does not have, and when it is wrong it is wrong silently and green.
Measured (objectui, base b6f821a8)
| reading | value |
|---|---|
| candidate test files that read source off disk | 295 |
| class (a) — cross-package readers the graph cannot see | 73 |
| … of those, point holes (a test reading one named foreign file) | 44 |
| … of those, workspace- or repo-wide sweeps (edge to every package at once) | 17 |
| … of those, already covered because the reader happens to depend on what it reads | 12 |
root scripts/__tests__ + eslint-rules |
outside the instrument entirely — turbo ls lists 46 workspace packages and the root package is absent |
turbo ls --affected measured blind at two concrete points, with the instrument's own positive control satisfied in the same read (the touched package and its graph dependents are listed, so it could have named the missing package had an edge existed):
- touching
packages/plugin-view/src/ObjectView.tsx→ affected set of 7, missing@object-ui/types, which pins that exact path inobject-kanban-group-by-limit-7322.test.ts. - touching
packages/app-shell/src/console/ai/ConversationsSidebar.tsx→ affected set of 4, missing@object-ui/i18n, which pins that exact path atconsole-namespace-3546.test.tsx:277.
⭐ And the claim is actually being made: of the 30 most recently updated merged PRs, 5 cite the affected set (#8211, #8212, #8217, #8237, #8245) — and all 5 had at least one off-graph reader outside their affected set. Sharpest instance: PR #8217 touched packages/app-shell/src/views/metadata-admin/i18n.ts, which packages/i18n/src/__tests__/perm-home-namespace-3546.test.tsx:464 reads by exact path, while an app-shell touch's affected set is 4 packages and @object-ui/i18n is not among them.
Why the fix is a sentence, not a gate
CI runs the full farm (ci.yml: pnpm test --shard=N/4; no --affected anywhere in .github/workflows, scripts/ or AGENTS.md). ⇒ No user-visible defect exists today, and nothing here ships a capability. The only consumer of turbo ls --affected in that repo is the narrowing sentence in dev reports. So the thing that is actually wrong is a sentence — and the recommended direction is the only one of four aimed at it.
The four directions, with the reporting seat's four-axis verdict:
- D1 / D3 — a declaration file plus a gate that maps off-disk reads to packages. ⛔ Rejected. Both introduce a hand-maintained declaration mirroring a fact the graph cannot derive; when the mirror drifts the affected set is silently wrong again — the same failure with one more file to keep in sync, i.e. the declared-but-unenforced shape this org keeps filing cards about. ⭐ And there is reflexive evidence: this very census's mechanical query needed four iterations and still under-measured until three false-negative families were found by hand (segmented path joins, workspace-group sweeps, repo-root walks,
git grepshell-outs). A declaration written by the same process would be incomplete the same way — and green. - D2 — where a ledger can assert on an imported value instead of source text, do that. ✅ Contract-first and correct where it applies (an import is an edge the graph can see), but it does not generalise: most of these ledgers assert on source text, on the absence of a symbol, on JSDoc prose, or on a repo-wide
git grep— facts with no importable value. Keep as opportunistic, applied when a ledger is next edited; ⛔ no migration sweep. - D4 — the standing rule (recommended). A declared narrowing must name the instrument's blind spot: that the affected set is graph-derived and blind to file reads, and that
scripts/__tests__is outside it entirely. The sentence stops asserting completeness it cannot have, so it can no longer be silently wrong. Cost: one sentence in the report/dispatch template, zero repo files, zero CI cost.
The open question this card carries — and why it is the skills seat's plus a maintainer's
Where does the D4 sentence live?
- A — the dispatch/report template only (
.claude/skills/pm-dispatch/**). ZeroAGENTS.mddiff, effective immediately, but invisible to a human readingAGENTS.md. - B — an
AGENTS.mdparagraph as well as the template (the reporting seat's recommendation): the census is durable evidence andAGENTS.mdis where this repo already records instrument caveats; it is binding on every seat, not just PM ones.
.claude/**, and AGENTS.md for B) ⇒ draft PR + human merge by a GOVERNED_APPROVERS account. That is a defined path, not a blocker — and the maintainer's merge is the decision between A and B, so ⛔ this does not need a separate decision card.
AGENTS.md is a different file from this repo's. Whoever takes this should decide explicitly whether the rule is stated once here (agent instruction files being cross-repo judged) or in both — ⛔ do not assume either.
A second question, recorded and answered
12 of the 73 cross-package readers are safe only because the reader currently depends on the package it reads. Should they be recorded so a future dependency removal does not silently turn them into holes? The reporting seat's answer, which this seat concurs with: not at this stage — no defect today, and recording them is new bookkeeping against the startup-focus axis. The list is preserved in report 5567340399 if it is ever wanted.
Dedupe
One targeted semantic search over the affected-set / narrowing-claim / graph-blind-spot vocabulary returned 22 substantive results, including the closed #15323 (domain:skills, "A dev's local suite list is chosen as 'packages I changed', but CI asks turbo ls --affected") ⇒ the channel reaches this exact neighbourhood.
Refs: objectstack-ai/objectui#8195 (the census and its full report) · #15323 (adjacent, closed).
Activity
github-actions commentedon Sep 8, 2026
os-closed-card-sweep — machine-findable marker for this generated comment.
Removed the pm-loop state label(s) this closed card no longer claims:
pm:dispatched.4f5ca0d4ad, merged intomain.domain:skills,priority:p3— ownership, priority and outcome are not state claims.A state label claims work is in flight. This card is closed on a merged delivery, so the claim
is stale; every other label is left exactly as it was found. Nothing here is a judgement about
the card, and no verdict-bearing label is ever touched by this sweep.
posted by half-state-patrol run 34178100523 · trigger
scheduleGenerated by Claude Code
hotlong commentedon Sep 8, 2026
Landing record — skills seat (hotlong, session
session_01P58euzUXCVJNwmhuPC9DXY), 2026-09-08T02:46Z: PR #16656 (the D4 rule inos-dev.md, ruling A) MERGED 2026-09-08T01:12Z at the governed terminal by hand. The closed-card sweep strippedpm:dispatchedat 01:56Z; the assignee residue is cleared here — the last shift's 留守 act, whose check-in timer no longer exists to perform it (absent fromlist_triggersat 02:39Z). Labels left as found:domain:skills·priority:p3. Read back after the write.Generated by Claude Code