You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
conditionalFormatting on the object-view node has a SECOND read on the author-reachable kanban path — the #5097 host-surface exemption is narrower for this one key #5248
Found while implementing the ruled exemption on #5097. Filed unassigned, not claiming. No code change was made for it — #5097's ruling preserves the status quo either way (nothing declared, nothing removed).
What was measured
Measured on main at e03dfa5ea (and identical at #5097's base 9fbb9b52f).
The #5097 ruling exempts 27 keys read off the object-view node as HOST-COMPOSITION surface. Its stated basis is measured reachability: the renderListView delegation branch in packages/plugin-view/src/ObjectView.tsx is entered only when a host supplies the prop, and the registered renderer ObjectViewRenderer (packages/plugin-view/src/index.tsx:58) does not, so the schema-registration path documented to authors cannot reach those keys.
That basis holds for 26 of the 27. It is narrower for conditionalFormatting, which has a second read site outside the delegation branch:
packages/plugin-view/src/ObjectView.tsx:1094 — inside the host-only renderListView branch, with its 30 neighbours.
packages/plugin-view/src/ObjectView.tsx:768 — inside generateViewSchema's kanban branch, as the last fallback of kanbanConditionalFormatting (kanbanCfg.conditionalFormatting ?? activeView?.conditionalFormatting ?? (schema as any).conditionalFormatting), forwarded to the emitted object-kanban node.
The kanban branch is on the author-reachable path: renderContent delegates to renderListView only when the prop is present; otherwise, for a non-grid view type, it calls generateViewSchema(currentViewType) and hands the result to SchemaRenderer. That is exactly what ObjectViewRenderer does. So an author who registers an object-view node with a kanban view type and a top-level conditionalFormatting rule does get an effect today.
conditionalFormatting is not a declared member of ObjectViewSchema (derived from packages/types/src/objectql.ts + BaseSchema: 42 declared members, conditionalFormatting is not among them), and it is not in the object-view registry inputs (packages/plugin-view/src/index.tsx:71-86), so nothing on the authoring surface offers it and nothing rejects it — BaseSchema's index signature means tsc is silent too.
The question
One key is honoured on the authored path while being recorded as host surface. Three ways out, and it shapes the public contract, so it wants a ruling rather than a guess:
Declare conditionalFormatting on ObjectViewSchema (and add it to the object-view registry inputs) — it does something on the author's path, so the "declaring it would promise a surface that does nothing" argument does not apply to it.
Keep it exempt and narrow the kanban read — drop the (schema as any).conditionalFormatting fallback at :768 so the key is genuinely host-only, and let kanban conditional formatting be authored where it is declared. This changes behaviour for any document relying on the top-level rule, so it needs the usual liveness check first.
The exemption block added by #5097 names this asymmetry in full and points here, so a later sweep meets a statement rather than a flat claim. See packages/plugin-view/src/ObjectView.tsx (OBJECT_VIEW_HOST_COMPOSITION_KEYS), section "The one asymmetry".
Triage: escalating to the decision inbox — one key (conditionalFormatting) is honoured on the author-reachable kanban path while recorded as host-only surface; all three ways out shape the public contract, and the #5097 ruling is the neighbouring decision this must stay consistent with. Typed Task.
Measured business pull — unknown: option 2 needs the liveness check the card names (does any authored document rely on top-level conditionalFormatting reaching kanban?).
Startup scope discipline — option 2 (drop the (schema as any).conditionalFormatting fallback at ObjectView.tsx:768) removes surface rather than declaring-and-maintaining it, consistent with the finding: 没有门禁核对包内 README 的自包导入名 vs 真实导出面 —— #5002 家族 7 个包的漂移全靠人工巡查发现(附已验证的检查器原型) #5043 family direction; option 1 adds a declared key whose only demand today is one fallback read.
Recommendation: 2, gated on the liveness check coming back empty — narrow the kanban read so the key is genuinely host-only. If liveness finds real authored usage, switch to 1 (declare it: it demonstrably does something for authors, so the "promises a dead surface" objection does not apply).
Claim: PM loop round 17
Session: session_01RV6yuVCxymHYE16PL9vQkE
Branch: claude/issue-5248-conditional-formatting-kanban-read
Worktree: objectui-issue-5248
Domain: repo:objectui (execution seat)
File surface: packages/plugin-view/src/ObjectView.tsx (the (schema as any).conditionalFormatting fallback around :768 and the OBJECT_VIEW_HOST_COMPOSITION_KEYS note), plus tests under packages/plugin-view. If the liveness check fires the Option 1 branch, the surface additionally covers ObjectViewSchema in packages/types and the object-view registry inputs — declare that in your report the moment you know. ⛔ OUT: packages/cli/** (#5127), packages/plugin-grid/src/ObjectGrid.tsx (#5148), console top bar + packages/app-shell/** (#5287), packages/components/** (#5125) — all in flight this round.
Container & model: S–M, mode:subagent, model: opus — the edit is small either way; the liveness check decides which edit, and it is the judgement.
Clause-②: branch-dependent, and you must state which applies in the PR. Option 2 narrows — a key stops being honoured on the author path, restoring declared = enforced; that is no. Option 1 declares a new authorable key, which widens the accepted set; that is yes. Both branches are pre-ruled, so this does not change where the card goes — but it changes what the PR body must say.
Serial constraints cleared: packages/plugin-view/src/ObjectView.tsx is free — I checked the two cards that held it. #5102 is closed, via PR5274 (merged 2026-08-18 23:45Z); #5097's PR5252 (the 27-key host-surface exemption you are amending) is merged. Rebase on current main and re-read :768 — the line will have moved.
Zone 1 — RULED, and both branches are pre-ruled. Do not escalate.
Maintainer, 2026-08-19, verbatim 「全部接受」, recorded on this card:
Ruling: Option 2, gated on the liveness check; if liveness finds real usage, Option 1
First step of the dispatched work is the liveness check: does any authored document rely on a top-level conditionalFormatting reaching the kanban branch via the (schema as any).conditionalFormatting fallback at ObjectView.tsx:768?
Liveness finds real authored usage → Option 1: declare conditionalFormatting on ObjectViewSchema and add it to the object-view registry inputs (it demonstrably does something on the author path, so it is not a dead-surface promise).
Either way, report which branch fired and the evidence. Option 3 (record the asymmetry and keep both) is rejected — a ruled exemption with a known counter-example decays.
⛔ Do not implement Option 3. "Record the asymmetry and keep both reads" is the comfortable middle and it is explicitly rejected: it leaves a ruled exemption standing next to a known counter-example, which is how the exemption stops meaning anything.
Zone 2 — the liveness check IS the first deliverable, and the ruling's expectation is not evidence
The ruling says "(expected)" about the empty result. That is a prediction, not a reading. Treat it as something to falsify:
Search authored documents — content/docs/**, skills/**, examples/**, package READMEs, and any in-repo fixture or catalog schema — for a top-levelconditionalFormatting on an object-view node reaching the kanban branch. Distinguish that from conditionalFormatting nested where it is already declared; only the top-level-on-object-view case fires this fallback.
A zero is not a reading until you counter-probe it with a term you know is present in the same corpus, through the same method. The counter-probe has already earned its keep twice on neighbouring cards this session — once when the probe and its control were both empty because the package was not installed, once when a wrong filename returned a void zero.
A top-level conditionalFormatting on an object-view node no longer reaches the kanban branch. This is the change; it must fail before your edit.
The host-supplied renderListView delegation path still carries it. ⛔ Do not narrow that too — the key stays host surface, it just stops being author-reachable.
The other 26 keys in OBJECT_VIEW_HOST_COMPOSITION_KEYS are untouched.
Option 1 branch:
The key parses on ObjectViewSchema and appears in the object-view registry inputs.
⚠️And it must survive the save gate. A key declared in registry inputs but rejected by the spec's strictObject is the preview-works / save-refuses trap — measured on ObjectGrid 用 (schema as any) 读的 4 个键不在 GRID_QUERY_INPUTS 里 —— #4648 要消除的「渲染器读得到、声明面否认」在这些键上仍然存在 #5091 (registry-inputs-spec-parity.test.ts fails on exactly this). Check parity before you commit; if the spec refuses the key, that is a fork — stop and report, do not declare it one-sidedly.
Reverse-verify: restore the file, keep the tests, predict which go red before running, report predicted vs observed. State per leg whether a build artifact sits between your edit and the thing under test (plugin-view consumes @object-ui/core and @object-ui/types through dist).
Gates
Derive from your diff (scripts/pm/dispatch-gates.mjs is objectstack-only). Run vitest from the repo root — the reason is not that a package-scoped run is refused (17 packages own a standalone vitest.config.ts, plugin-view among them, and are not refused) but that a package-scoped run uses a different config than CI does, so its green is not CI's green. Changeset required (@object-ui/plugin-view, plus @object-ui/types on the Option 1 branch); patch or minor, ⛔ never major.
⛔ Do not background a long check and end your turn. ⛔ No exhaustive paginated API sweeps.
Deliver
Draft PR against main, first body line Fixes #5248. State which branch fired in the first paragraph of the PR body, with the evidence. Push the branch early. Return the JSON report and post it as a comment whose first line is the literal <!-- os-dev-report --> marker.
{
"issue": 5248,
"status": "done",
"branch": "claude/issue-5248-conditional-formatting-kanban-read",
"pr": "https://github.com/objectstack-ai/objectui/pull/5336",
"premise_still_valid": true,
"summary": "OPTION 2 FIRED. The liveness check came back empty, so the `(schema as any).conditionalFormatting` fallback was dropped from `generateViewSchema`'s kanban branch (packages/plugin-view/src/ObjectView.tsx) — the key is now genuinely host-only and the #5097 exemption's stated basis holds for all 27 keys. Evidence, each zero paired with a counter-probe through the same method on the same corpus: objectui content/docs+skills+examples+apps has `conditionalFormatting` in exactly 2 files (plugin-grid.mdx, on `object-grid`'s DECLARED key; skills/objectui/guides/schema-expressions.md, on a `list-view` node) — controls `object-view` → 5 files, `groupByField` → 1 file; objectstack authors no `object-view` node at all (2 prose mentions repo-wide) against controls `object-form` → 54 files and `object-grid` → 19 files, and its only real authored `conditionalFormatting` (examples/app-showcase/src/ui/views/field-zoo.view.ts:61) is a VIEW-level rule on a grid view, i.e. the `activeView` link this PR keeps. Structural cross-check: no file in either repo carries both an object-view NODE and the key — the 7 files carrying both mentions are declarations, the code under change, its pin test, app-shell's host (which builds its object-view node WITHOUT the key and reads the key into the delegated list-view node), and prose. The `OBJECT_VIEW_HOST_COMPOSITION_KEYS` 'one asymmetry' note is rewritten as RESOLVED with that evidence; the host `renderListView` delegation is NOT narrowed and its forwarding is pinned.",
"tests": "All measured at HEAD 6325ef257 (clean tree), vitest run from the repo ROOT (CI's config). `pnpm exec vitest run packages/plugin-view/` → Test Files 17 passed (17), Tests 180 passed (180). `pnpm exec turbo run type-check --filter=@object-ui/plugin-view --concurrency=2` → Tasks: 16 successful, 16 total (package-scoped `pnpm type-check` alone fails with TS2307 'Cannot find module @object-ui/*' — unbuilt workspace dists, pre-existing on untouched files, not a regression; turbo builds the closure first). eslint on the 3 changed source files → 0 errors, 65 warnings, all `no-explicit-any` of the same kind the neighbouring mapFlatten test already carries. `pnpm run check:control-bytes` → OK (4726 tracked text files); `check-changeset-presence.mjs` → OK (1 changeset); `check-changeset-no-major.mjs` → OK. REVERSE VERIFICATION, predicted before running: restore ObjectView.tsx to origin/main, keep both test files → predicted 4 red / 13 green, naming them (new file: 'a TOP-LEVEL rule … does not reach the kanban node', 'a top-level key does not fill in for a view that declares none'; pin: 'NO exempt key is read outside the fence', '`conditionalFormatting` in particular is no longer read outside the fence'). OBSERVED: exactly those four — `Tests 4 failed | 13 passed (17)` — no surprises, no direction reversal. Restoration leg: `Test Files 2 passed (2) / Tests 17 passed (17)`. BUILD ARTIFACT PER LEG: none on either leg, and no rebuild was owed — the repo-root vitest config aliases every `@object-ui/*` specifier straight at `packages/*/src` (vitest.config.mts:244-285, incl. core/types/react), no package in the worktree had a `dist/` at test time, the edited file is in the package under test and imported relatively, and the pin test reads ObjectView.tsx from disk at import. The red leg landing exactly on the predicted four is itself the proof the mutation reached the tests rather than a stale artefact.",
"open_questions": [],
"out_of_scope_findings": []
}
Draft PR: #5336 — first body line Fixes #5248, first paragraph states the branch that fired. Changeset: @object-ui/plugin-viewminor. Reported at draft-PR time per the 2026-08-10 ruling; CI convergence is the PM's to read.
Activity
os-support-ai commentedon Aug 18, 2026
Triage: escalating to the decision inbox — one key (
conditionalFormatting) is honoured on the author-reachable kanban path while recorded as host-only surface; all three ways out shape the public contract, and the #5097 ruling is the neighbouring decision this must stay consistent with. Typed Task.Four-prism:
(schema as any)从 object-view 节点读 31 个键转发给 renderListView,其中 27 个不是 ObjectViewSchema 声明成员 —— #5091 在 ObjectView 上的同形实例 #5097 exemption's stated basis (host-only reachability) is false for exactly this key; option 3 keeps a ruled exemption with a known counter-example.conditionalFormattingreaching kanban?).(schema as any)读的 4 个键不在GRID_QUERY_INPUTS里 —— #4648 要消除的「渲染器读得到、声明面否认」在这些键上仍然存在 #5091 exist to close; in either direction the surfaces must agree.(schema as any).conditionalFormattingfallback atObjectView.tsx:768) removes surface rather than declaring-and-maintaining it, consistent with the finding: 没有门禁核对包内 README 的自包导入名 vs 真实导出面 —— #5002 家族 7 个包的漂移全靠人工巡查发现(附已验证的检查器原型) #5043 family direction; option 1 adds a declared key whose only demand today is one fallback read.Recommendation: 2, gated on the liveness check coming back empty — narrow the kanban read so the key is genuinely host-only. If liveness finds real authored usage, switch to 1 (declare it: it demonstrably does something for authors, so the "promises a dead surface" objection does not apply).
Generated by Claude Code
os-support-ai commentedon Aug 19, 2026
Claim: PM loop round 17
Session:
session_01RV6yuVCxymHYE16PL9vQkEBranch:
claude/issue-5248-conditional-formatting-kanban-readWorktree:
objectui-issue-5248Domain:
repo:objectui(execution seat)File surface:
packages/plugin-view/src/ObjectView.tsx(the(schema as any).conditionalFormattingfallback around:768and theOBJECT_VIEW_HOST_COMPOSITION_KEYSnote), plus tests underpackages/plugin-view. If the liveness check fires the Option 1 branch, the surface additionally coversObjectViewSchemainpackages/typesand theobject-viewregistryinputs— declare that in your report the moment you know. ⛔ OUT:packages/cli/**(#5127),packages/plugin-grid/src/ObjectGrid.tsx(#5148), console top bar +packages/app-shell/**(#5287),packages/components/**(#5125) — all in flight this round.Container & model:
S–M,mode:subagent,model: opus— the edit is small either way; the liveness check decides which edit, and it is the judgement.Clause-②: branch-dependent, and you must state which applies in the PR. Option 2 narrows — a key stops being honoured on the author path, restoring
declared = enforced; that isno. Option 1 declares a new authorable key, which widens the accepted set; that isyes. Both branches are pre-ruled, so this does not change where the card goes — but it changes what the PR body must say.Serial constraints cleared:
packages/plugin-view/src/ObjectView.tsxis free — I checked the two cards that held it. #5102 is closed, via PR5274 (merged 2026-08-18 23:45Z); #5097's PR5252 (the 27-key host-surface exemption you are amending) is merged. Rebase on currentmainand re-read:768— the line will have moved.Zone 1 — RULED, and both branches are pre-ruled. Do not escalate.
Maintainer, 2026-08-19, verbatim 「全部接受」, recorded on this card:
⛔ Do not implement Option 3. "Record the asymmetry and keep both reads" is the comfortable middle and it is explicitly rejected: it leaves a ruled exemption standing next to a known counter-example, which is how the exemption stops meaning anything.
Zone 2 — the liveness check IS the first deliverable, and the ruling's expectation is not evidence
The ruling says "(expected)" about the empty result. That is a prediction, not a reading. Treat it as something to falsify:
content/docs/**,skills/**,examples/**, package READMEs, and any in-repo fixture or catalog schema — for a top-levelconditionalFormattingon anobject-viewnode reaching the kanban branch. Distinguish that fromconditionalFormattingnested where it is already declared; only the top-level-on-object-viewcase fires this fallback.(schema as any)从 object-view 节点读 31 个键转发给 renderListView,其中 27 个不是 ObjectViewSchema 声明成员 —— #5091 在 ObjectView 上的同形实例 #5097 pattern you are amending.Tests
Option 2 branch:
conditionalFormattingon anobject-viewnode no longer reaches the kanban branch. This is the change; it must fail before your edit.renderListViewdelegation path still carries it. ⛔ Do not narrow that too — the key stays host surface, it just stops being author-reachable.OBJECT_VIEW_HOST_COMPOSITION_KEYSare untouched.Option 1 branch:
ObjectViewSchemaand appears in theobject-viewregistryinputs.inputsbut rejected by the spec'sstrictObjectis the preview-works / save-refuses trap — measured on ObjectGrid 用(schema as any)读的 4 个键不在GRID_QUERY_INPUTS里 —— #4648 要消除的「渲染器读得到、声明面否认」在这些键上仍然存在 #5091 (registry-inputs-spec-parity.test.tsfails on exactly this). Check parity before you commit; if the spec refuses the key, that is a fork — stop and report, do not declare it one-sidedly.Reverse-verify: restore the file, keep the tests, predict which go red before running, report predicted vs observed. State per leg whether a build artifact sits between your edit and the thing under test (
plugin-viewconsumes@object-ui/coreand@object-ui/typesthroughdist).Gates
Derive from your diff (
scripts/pm/dispatch-gates.mjsis objectstack-only). Run vitest from the repo root — the reason is not that a package-scoped run is refused (17 packages own a standalonevitest.config.ts,plugin-viewamong them, and are not refused) but that a package-scoped run uses a different config than CI does, so its green is not CI's green. Changeset required (@object-ui/plugin-view, plus@object-ui/typeson the Option 1 branch);patchorminor, ⛔ nevermajor.⛔ Do not background a long check and end your turn. ⛔ No exhaustive paginated API sweeps.
Deliver
Draft PR against
main, first body lineFixes #5248. State which branch fired in the first paragraph of the PR body, with the evidence. Push the branch early. Return the JSON report and post it as a comment whose first line is the literal<!-- os-dev-report -->marker.Generated by Claude Code
fix(plugin-view): a top-level conditionalFormatting no longer reaches…
os-support-ai commentedon Aug 19, 2026
{ "issue": 5248, "status": "done", "branch": "claude/issue-5248-conditional-formatting-kanban-read", "pr": "https://github.com/objectstack-ai/objectui/pull/5336", "premise_still_valid": true, "summary": "OPTION 2 FIRED. The liveness check came back empty, so the `(schema as any).conditionalFormatting` fallback was dropped from `generateViewSchema`'s kanban branch (packages/plugin-view/src/ObjectView.tsx) — the key is now genuinely host-only and the #5097 exemption's stated basis holds for all 27 keys. Evidence, each zero paired with a counter-probe through the same method on the same corpus: objectui content/docs+skills+examples+apps has `conditionalFormatting` in exactly 2 files (plugin-grid.mdx, on `object-grid`'s DECLARED key; skills/objectui/guides/schema-expressions.md, on a `list-view` node) — controls `object-view` → 5 files, `groupByField` → 1 file; objectstack authors no `object-view` node at all (2 prose mentions repo-wide) against controls `object-form` → 54 files and `object-grid` → 19 files, and its only real authored `conditionalFormatting` (examples/app-showcase/src/ui/views/field-zoo.view.ts:61) is a VIEW-level rule on a grid view, i.e. the `activeView` link this PR keeps. Structural cross-check: no file in either repo carries both an object-view NODE and the key — the 7 files carrying both mentions are declarations, the code under change, its pin test, app-shell's host (which builds its object-view node WITHOUT the key and reads the key into the delegated list-view node), and prose. The `OBJECT_VIEW_HOST_COMPOSITION_KEYS` 'one asymmetry' note is rewritten as RESOLVED with that evidence; the host `renderListView` delegation is NOT narrowed and its forwarding is pinned.", "tests": "All measured at HEAD 6325ef257 (clean tree), vitest run from the repo ROOT (CI's config). `pnpm exec vitest run packages/plugin-view/` → Test Files 17 passed (17), Tests 180 passed (180). `pnpm exec turbo run type-check --filter=@object-ui/plugin-view --concurrency=2` → Tasks: 16 successful, 16 total (package-scoped `pnpm type-check` alone fails with TS2307 'Cannot find module @object-ui/*' — unbuilt workspace dists, pre-existing on untouched files, not a regression; turbo builds the closure first). eslint on the 3 changed source files → 0 errors, 65 warnings, all `no-explicit-any` of the same kind the neighbouring mapFlatten test already carries. `pnpm run check:control-bytes` → OK (4726 tracked text files); `check-changeset-presence.mjs` → OK (1 changeset); `check-changeset-no-major.mjs` → OK. REVERSE VERIFICATION, predicted before running: restore ObjectView.tsx to origin/main, keep both test files → predicted 4 red / 13 green, naming them (new file: 'a TOP-LEVEL rule … does not reach the kanban node', 'a top-level key does not fill in for a view that declares none'; pin: 'NO exempt key is read outside the fence', '`conditionalFormatting` in particular is no longer read outside the fence'). OBSERVED: exactly those four — `Tests 4 failed | 13 passed (17)` — no surprises, no direction reversal. Restoration leg: `Test Files 2 passed (2) / Tests 17 passed (17)`. BUILD ARTIFACT PER LEG: none on either leg, and no rebuild was owed — the repo-root vitest config aliases every `@object-ui/*` specifier straight at `packages/*/src` (vitest.config.mts:244-285, incl. core/types/react), no package in the worktree had a `dist/` at test time, the edited file is in the package under test and imported relatively, and the pin test reads ObjectView.tsx from disk at import. The red leg landing exactly on the predicted four is itself the proof the mutation reached the tests rather than a stale artefact.", "open_questions": [], "out_of_scope_findings": [] }Draft PR: #5336 — first body line
Fixes #5248, first paragraph states the branch that fired. Changeset:@object-ui/plugin-viewminor. Reported at draft-PR time per the 2026-08-10 ruling; CI convergence is the PM's to read.Generated by Claude Code
fix(plugin-view): a top-level conditionalFormatting no longer reaches…