Repository navigation
docs: expressions/architecture guides teach text.value for expressions — switch all 23 occurrences to content, the ruled sole evaluation channel (objectstack#13670 option 2) #7015
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Aug 31, 2026 - addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removed
on Sep 1, 2026 🔒 Claimed —
domain:uiexecution seat (objectui)- Session:
session_012wwHa4aaFybxXrfmfHioDM - Branch:
claude/issue-7015-expressions-docs-content - Build tier: opus (
⚠️ Fable 5 quota exhausted; standing maintainer exemption 2026-08-13 「fable 如果用完了,可以用 opus」 lowers the build tier only)
Not clause ②, and that is why it was selected this round. The card states zero spec change — this edits authored prose in
content/docs/guide/**and changes nothing about what the platform accepts or refuses. NoCONTRACT_REVIEW_TIERis owed, so the exhausted quota cannot strand it.Selected as time-sensitive, not merely ripe. This card is the prerequisite half of the ordering constraint in its own body: objectui#4795's second ruled half will legitimately reject
text.value, and if that gate lands first it reddens the platform's own 23 examples. Dispatching this ahead of the gate is the whole point of the constraint.Domain label added. The card carried
documentation+pm:queuewith no domain label;content/docs/guide/expressions.mdteachingtextschema authoring is squarely this seat's surface, so I labelled itdomain:uirather than leaving it un-routed.⚠️ Also recording the small trap in the body for the implementer: the census says the 23 occurrences are "concentrated in" two files — concentrated in ≠ only in. The census gets re-measured against the whole authored corpus, not those two files.
Generated by Claude Code
- Session:
os-dev-report
{ "issue": 7015, "status": "done", "branch": "claude/issue-7015-expressions-docs-content", "pr": "https://github.com/objectstack-ai/objectui/pull/7114", "premise_still_valid": true, "files_changed": [ "content/docs/guide/expressions.md", "content/docs/guide/architecture.md", "content/docs/guide/schema-rendering.md", "content/docs/guide/dashboard-filters.md", "content/docs/blocks/block-schema.mdx", ".changeset/7015-text-expression-content-channel.md" ], "census_before": { "ruled_scope_text_nodes_with_expression_in_value": 29, "by_file": { "content/docs/guide/expressions.md": 20, "content/docs/guide/architecture.md": 3, "content/docs/guide/schema-rendering.md": 3, "content/docs/blocks/block-schema.mdx": 2, "content/docs/guide/dashboard-filters.md": 1 }, "total_raw_hits_in_content_docs": 35, "note": "The card's 23 is exactly expressions.md (20) + architecture.md (3) — the two files it names. 'Concentrated in' was not 'only in': three further files carry six more." }, "census_after": { "ruled_scope_text_nodes_with_expression_in_value": 0, "content_with_expression_lines": 33, "note": "33 = the 29 ruled + the 4 typeless judgment-call fragments." }, "occurrences_fixed": 29, "occurrences_excluded_with_reasons": [ "expressions.md:388 — type 'progress', not a text node. Excluded as an unruled behaviour edit. Also outside the carriage map, so it likely renders a literal too.", "expressions.md:453 — type 'input', not a text node. Same reasoning.", "skills/ — 7 hits, ALL correct as written and destructive to change: schema-expressions.md and page-builder.md use text+value as DELIBERATE counter-examples teaching this exact rule, each paired with its correct 'content' fix; the remainder are 'statistic', which genuinely declares a value carriage row. Zero files under skills/ touched.", "packages/plugin-dashboard/README.md — type 'metric-card', non-text. Reported in issue 7115.", "packages/react/README.md — type 'input', non-text. Reported in issue 7115.", "README.md (root) x4 — type 'stat-card', non-text AND registered nowhere. Different defect class; filed as issue 7115.", "packages/react/CHANGELOG.md — generated release artifact, never hand-edited.", "packages/**/src/** — source and tests that deliberately exercise the broken spelling (they pin the defect).", "schema-rendering.md:34 — text node whose value holds NO expression; renders correctly via the fallback. Out of scope by the card's own rule.", "examples/schema-catalog/.../javascript-editor.json — FALSE POSITIVE: the ${name} is JavaScript template-literal source inside a code-editor widget's sample content, not an ObjectUI expression." ], "changeset_grade_and_gate_verdict": "EMPTY frontmatter (not patch, not major). Gate verdict, verbatim: 'No source or published contract of a released package changed in this range, so no changeset is owed.' exit 0 — i.e. the gate says a changeset was NOT OWED at all, since 0 of the changed files are published package source. Included anyway as an explicit statement of release intent, a first-class form per AGENTS.md. check-changeset-no-major exit 0.", "gates": [ { "name": "check-doc-snippet-types", "exit": 0, "verdict": "green", "raw": "Every covered documentation snippet compiles against the built types. Semantic phase: 272 of 272 block(s) judged, 0 failed. Self-controls fired: sentinel produced 1 diagnostic (TS2305), undeclared produced 1 diagnostic (TS2307), resolution resolved to packages/types/dist/index.d.ts." }, { "name": "check-doc-snippet-types (FIRST attempt, unbuilt tree)", "exit": 2, "verdict": "NOT_MEASURED", "raw": "PRECONDITION NOT MET (exit 2) — The snippet program was NOT run: the packages it resolves against are not built. Resolved by building the 21-package closure (turbo: 32 successful, 32 total), then re-running for the green above." }, { "name": "check-doc-component-types", "exit": 0, "verdict": "green", "raw": "Every documented component type is registered. 185 doc files, 1068 code blocks, 900 type literals — counts byte-identical to the pre-edit baseline, confirming no type literal moved." }, { "name": "check-doc-fence-languages", "exit": 0, "verdict": "green", "raw": "every TypeScript block in 224 document(s) is fenced ts/tsx/typescript" }, { "name": "check-doc-links", "exit": 0, "verdict": "green", "raw": "Links are valid across 17 scan roots." }, { "name": "check-control-bytes", "exit": 0, "verdict": "green", "raw": "OK (scanned 5893 tracked text file(s); skipped 85 binary)." }, { "name": "check-changeset-presence", "exit": 0, "verdict": "green", "raw": "No source or published contract of a released package changed in this range, so no changeset is owed." }, { "name": "check-changeset-no-major", "exit": 0, "verdict": "green", "raw": "No changeset declares a major bump." }, { "name": "vitest: 6 gate suites (doc-component-types, doc-fence-languages, doc-links, changeset-presence, changeset-no-major, control-bytes)", "exit": 0, "verdict": "green", "raw": "Test Files 6 passed (6) / Tests 266 passed (266). Root-relative invocation via pnpm exec vitest run, under the shared verify lock (VERDICT command-exit 0)." } ], "controls_used": [ "Zero-hit control: the after-census zero for text-node value-with-expression is reported beside the SAME query in the SAME run still returning 2 live hits (expressions.md:388 progress, :453 input). The query is demonstrably not dead.", "Positive control on the injected text: content-with-expression counted 33 lines post-edit (29 ruled + 4 typeless), matching the predicted total exactly.", "stat-card zero-registration control: the sweep returning 0 registrations for 'stat-card' was paired with 'statistic', which returned a real registration at statistic.tsx:64.", "Gate self-controls: check-doc-snippet-types printed its own sentinel (TS2305) and undeclared (TS2307) controls firing, proving the harness can detect errors rather than vacuously passing.", "Baseline control: check-doc-component-types / fence-languages / control-bytes were each run BEFORE the edits and were green, so the post-edit greens are differential, not first-sightings.", "On-disk mutation proof: every replacement batch was verified by git diff --stat plus a per-file grep count of the INJECTED text, never by the editing tool's exit code.", "Tooling control: an early ripgrep sweep used 'rg -ril', where -r is ripgrep's --replace, not 'recursive' — it silently rewrote matched text to 'il' in the output. Caught and re-run with -l; noted because the mangled output was superficially readable." ], "assumptions_falsified": [ "FALSIFIED — the count is 29 in ruled scope, not 23, across 5 files not 2. The 23 is reproducible as exactly expressions.md (20) + architecture.md (3); schema-rendering.md (3), block-schema.mdx (2) and dashboard-filters.md (1) were missed by the original census.", "FALSIFIED — not every hit is a text node. Of 35 raw hits in content/docs: 29 are declared type text, 2 are non-text (progress, input), and 4 declare NO type at all. The typeless class was not anticipated by either zone.", "FALSIFIED — this is NOT purely prose. 3 of the 29 in-scope edits live in COMPILED snippets: architecture.md:151 (tsx) and block-schema.mdx:306/311 (ts, inside a 'const cardBlock: BlockSchema' annotation). All five touched files are gate-COVERED by check-doc-snippet-types. Risk resolved to nil because all three reach BaseSchema, whose [key: string]: any index signature accepts both spellings identically — then measured green.", "FALSIFIED — the dispatch instruction that this docs card OWES an empty-frontmatter changeset. The gate's own verdict is that no changeset is owed at all, because 0 changed files are published package source. One was added anyway as a statement of intent, but the instruction's premise was wrong.", "CONFIRMED (premise) — the card's premise holds exactly. text.tsx:51 renders {schema.content || schema.value}, so value IS read back but never evaluated, putting the literal ${...} on screen. content is evaluated unconditionally with no type gate at all." ], "open_questions": [ { "question": "The 4 TYPELESS fragments in expressions.md Best Practices (lines 591/596/619/624) declare no type, so they fall outside the ruling's literal wording ('on type: text nodes'), yet both halves of both correct/incorrect pairs used value as the carriage. I fixed them, ISOLATED in commit 39d3eb151 so the decision is reversible in one command.", "options": [ "A — keep them (current state): the carriage map answers the empty set for an ABSENT type, so value evaluated for nothing there; the 'correct' half of each pair was teaching a non-working spelling. content is right whatever type a reader substitutes, since its evaluation leg has no type gate.", "B — revert commit 39d3eb151 to hold strict ruling scope, and let a follow-up card adjudicate the typeless class." ], "recommendation": "A, because the fix is behaviourally free (docs-only, and content is universally evaluated) while B knowingly leaves 4 occurrences that objectui#4795's second ruled half would legitimately redden — which is the exact ordering-constraint harm this card exists to prevent. But it IS a scope judgment, so it is quarantined in its own commit for a one-command revert." }, { "question": "Does the ordering constraint still hold as stated? The card says objectui#4795's build-time rejection must not land first or it reddens the platform's own examples.", "options": [ "A — the constraint is now discharged for content/docs: text-node value-with-expression is 0 there.", "B — it is NOT fully discharged repo-wide: 2 non-text occurrences (progress, input) and the package/root READMEs still carry ${...} in keys outside the carriage map, and would redden a strict gate." ], "recommendation": "B is the accurate reading and the PM should route it. This card discharged the text-node half only; the non-text carriage question is unruled and was deliberately not touched. Filed the README half as issue 7115." } ], "out_of_scope_findings": [ "filed as #7115: the root README's flagship dashboard example teaches `stat-card`, registered nowhere (4 occurrences), and the root README.md sits outside EVERY doc gate's scan surface (which is content/docs plus packages/NAME/README.md) — so the most-read authored file in the repo is the one teaching surface no gate reads. Includes the metric-card / input README observations." ], "mcp_calls": 7 }
Generated by Claude Code
🟢 LANDED — closing as completed
PR #7114 merged to
mainas71d83a6b1at2026-09-01T02:15:08Z:
"docs: teachcontentas text's expression channel, notvalue(29 occurrences, not 23)".Seat state cleared:
pm:dispatchedremoved, assignee cleared.Landing verified by mutual control on the landed tree
The subject and the deliberately-retained residue serve as each other's control, so neither number rests on a query nobody checked:
probe, content/docsbefore ( 03380aa14)after ( 71d83a6b1)"content"holding an expression — subject0 30 "value"holding an expression — residue32 2 Both moved in the predicted direction, by the predicted magnitude, in the same query. The surviving 2 are exactly
expressions.md'sprogressandinputnodes — non-text, deliberately untouched, and now routed on #7115. A zero on one row would have been ambiguous; the pair is not.⇒ The ruled deliverable is complete: no authored
textnode undercontent/docscarries an expression invalue.⭐ The card's census was low, and finding that was worth more than the fix
The card said 23, "concentrated in" two files. The real ruled scope was 29 across five files — and the implementer showed why the 23 was wrong rather than merely replacing it: it reproduces exactly as
expressions.md(20) +architecture.md(3), identifying it as a two-file census rather than a miscount.schema-rendering.md(3),block-schema.mdx(2) anddashboard-filters.md(1) had simply never been looked at.⚠️ "Concentrated in" is not "only in". That phrase now reads, on this lane, as a flag that the census was scoped rather than exhaustive.Three PM assumptions falsified, one of them a plain error of mine
- The count — 29, not 23; five files, not two.
- "Docs-only, therefore prose" — three of the 29 edits live in compiled
ts/tsxsnippets undercheck-doc-snippet-types. The risk resolved to nil (both spellings reachBaseSchema's[key: string]: anyindex signature), but it was measured, not assumed, and the gate is green in CI. - ⛔ My changeset instruction was wrong. I said this card owed an empty-frontmatter changeset. The gate's verdict: "No source or published contract of a released package changed in this range, so no changeset is owed." One was included anyway as an explicit statement of release intent, which is a first-class form here. I later gave the opposite wrong answer on finding(app-shell):
PALETTE_EXCLUSIONS['app:launcher']says "the app shell renders it, not a page" — PR #7091 makes that clause false #7092 — so the standing rule is now simply: run the gate and quote its verdict; never predict it.
Scope discipline: the highest-value edit was one not made
The 7 hits under the published skills surface were left untouched.
schema-expressions.mdandpage-builder.mdusetext+valueas deliberate counter-examples teaching this exact rule, each paired with its correctcontentfix. A mechanical sweep would have destroyed the lesson and reported a clean census — success-shaped, and wrong.⚠️ What this card did NOT dischargeThe ordering constraint against objectui#4795's gate is satisfied only for
textnodes undercontent/docs. Still outstanding, and routed on #7115: the two non-textin-corpus occurrences, the rootREADME.md(which teachesstat-card, registered nowhere, and sits outside every doc gate's scan surface), and theplugin-dashboard/reactREADMEs. The underlying fork — carriage rows for non-texttypes, or stop authoring expressions in those keys — is unruled and is the maintainer's.
Generated by Claude Code
- added a commit that references this issue
on Sep 1, 2026 - added a commit that references this issue
on Sep 28, 2026
Provenance: maintainer ruling 2026-08-31 (director seat summon #7, decision batch #17, verbatim 「同意」 on objectstack#13670's corrected recommendation, option 2). Ruling record: objectstack#13670 comment 5478581056. Filed by the director seat, session
session_01KGtaLpkW1mycWgkbSb3H6t.The ruled facts
text's intended evaluation channel iscontent, solely.content: "${…}"evaluates today (its own memo leg);value: "${…}"renders the literal (no carriage row, and none will be added — ruled).type: "text"with${…}invalueacross the authored corpus, concentrated incontent/docs/guide/expressions.mdandarchitecture.md(census recorded on objectstack#13670; counts from PR feat(react): evaluate the spec-declared expression-bindable text keys #6981's discussion).The change
Switch every one of the 23 occurrences from
"value": "…${…}…"to"content": "…${…}…". Mechanical; each example then works as taught, zero spec change.objectui#4795's second ruled half (build-time rejection of
${…}outside the carriage map) will legitimately rejecttext.value— this docs fix must land BEFORE or in the same stroke as that gate, or the gate reddens the platform's own 23 examples.Not this card
text: ['value']carriage row — ⛔ ruled out.TextSchema.valuefallback spelling itself — separate ADR-0049 enforce-or-remove card (filed alongside this one).