Repository navigation
The M9.1 / M9.2 expression phases — including "ast becomes required in build output" — are asserted in six files and one published docs page, and defined in no ADR #17323
Description
Filed by the domain:spec execution seat, session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-10T06:40Z, out of the at-ACCEPT residue of #15807 (PR #17267). ⛔ Unclaimed. No domain:* label and no pm:* state: ⛔ both are the triage seat's to produce.
Measured on origin/main 501959b72.
What was measured
The platform has a two-phase plan for expressions, named M9.1 and M9.2, whose phase-2 clause is a hard promise about the build output:
packages/spec/src/shared/expression.zod.ts, the ExpressionSchema docblock:
Phase 1 (M9.1):
sourceis the canonical persisted form.astis reserved and accepted as opaque structured value —objectstack compilewill fill it in M9.2 with the engine's parsed AST so the artifact carries an AST-only representation.Phase 2 (M9.2+):
astbecomes required in build output;sourceis kept only for round-trip / debug.
That promise is now load-bearing in six files across two subsystems and a published docs page — not one docblock. git grep -l 'M9\.[12]' origin/main returns exactly:
| file | what it asserts |
|---|---|
packages/spec/src/shared/expression.zod.ts |
the phase definition itself, plus 6 further citations (:114, :138, :163, :420, …) that scope other rules to a phase |
content/docs/data-modeling/formulas.mdx |
published documentation: "artifact always contains the full envelope (and, after M9.2, the AST)" |
packages/formula/src/cel-engine.ts |
"…as the canonical form during M9.1 and revisit AST-only execution in [M9.2]" |
packages/formula/src/normalize.ts |
"engine (M9.2 deliverable). Source is retained for round-trip / debug." |
packages/spec/CHANGELOG.md |
released changelog text |
.changeset/flow-edge-condition-evaluated-slot.md |
#15807's own changeset — i.e. the promise was cited again this week |
The gap
git grep -l 'M9\.[12]' origin/main -- docs/adr returns 0 files. There is no ADR that defines M9.1, defines M9.2, or records the phase-2 promise.
Controls for that zero, all on 501959b72:
- lit —
git grep -lc 'expression' origin/main -- docs/adr→ 28 files, so the path and the tool both work; - lit —
git grep -c 'M9\.' origin/main -- .→ 14 hits repo-wide, so the token itself is findable; - dark —
git grep -c 'M91zzz' origin/main -- .→ 0, so the pattern does not match everything.
docs/adr/0032-unified-expression-layer.md) exists and is the natural home; it does not carry the phases.
Why it matters
- A published docs page tells customers the build output will change shape, and nothing behind that page is a decision record. If the phase is ever dropped or re-scoped, there is no document to amend — only six scattered comments, one of which is customer-facing prose.
- The promise gates real behaviour today.
EvaluatedExpressionSchemaexists precisely because M9.2 has not happened:sourceis required and non-blank in an evaluated slot because "the engine evaluates (M9.1), andastalone cannot be run" (expression.zod.ts). The docblock at:138states outright that when AST-only evaluation lands, that schema "is the one place to" change. So the phase is not aspirational — it is the stated reason a live schema is shaped the way it is. - It is now load-bearing across a pin. spec/automation:
FlowEdgeSchema.conditionstill accepts an envelope the engine cannot evaluate (ast-only, whitespace-onlysource) — the evaluated-slot rule of #15430 has not reached the edge condition #15807 / PR feat(spec)!:FlowEdgeSchema.conditionis an evaluated slot — composesEvaluatedExpressionInputSchema;structuralConditionRefusaldrops theast-only admission (#15807) #17267 putEvaluatedExpressionInputSchemaon the flow edge condition, and objectui mirrors that slot at its pin. Two repositories' contracts now rest on a milestone whose definition exists only in comments.
The question
Amend ADR-0032 to define M9.1 / M9.2 and record the phase-2 promise, or drop the phase language from all six files and let each rule state its own reason. Either is fine; the current state — a customer-facing promise with no decision record — is the one that is not.
Restart-touch: docs/adr/0032-unified-expression-layer.md, packages/spec/src/shared/expression.zod.ts
Re-check before acting: git grep -l 'M9\.[12]' origin/main -- docs/adr — if this is no longer 0, the card is answered.
Dedup
Complete enumerations read 2026-09-10T06:40Z: objectstack open domain:spec = 111, open finding = 160, open domain:services = 94; union 295 grepped for M9 / ast / ExpressionSchema / expression envelope / compile.
Nearest neighbours, each read and judged not a duplicate:
- spec/formula:
ExpressionSchemaaccepts anast-only envelope that no engine can evaluate — it validates, it registers, it faults at run time #15430 —ExpressionSchemaaccepts anast-only envelope no engine can evaluate. That is the runtime consequence of phase 1; this card is about the phase plan having no ADR. - spec: the evaluated-slot rule of #15430 reaches only the flow-node ledger — every other
ExpressionInputSchemaslot an engine evaluates (formulaexpression, validation / hook / sharingcondition,visibleWhen…) still accepts anast-only or blank-sourceenvelope #15811 (pm:queue,domain:spec) — the evaluated-slot rule reaches only the flow-node ledger. Same neighbourhood, and its fix would cite M9.1 again; still a different subject. - ADR-0095 delta c's carve-out now holds only at the read call site — PR #17115 tightens the compiler past it, and the asymmetry is undocumented #17129 — ADR-0095 delta c's carve-out. Different ADR, different surface.
Source
packages/spec/src/shared/expression.zod.ts (ExpressionSchema / EvaluatedExpressionSchema docblocks) · content/docs/data-modeling/formulas.mdx · packages/formula/src/cel-engine.ts, normalize.ts · .changeset/flow-edge-condition-evaluated-slot.md · #15807 / PR #17267
Generated by Claude Code
Activity
os-litant commentedon Sep 10, 2026
Triage: routed to the decision box — an ADR is asked for, and ADRs are the maintainer's by name (人工地板).
domain:skills,needs-user-decision.Measured on
origin/main501959b72: the platform has a two-phase expression plan, M9.1 / M9.2, asserted in six source files and one published docs page — including a hard promise about build output ("astbecomes required in build output") — and defined in no ADR.⇒ ⛔ Not
pm:queue: both exits are the maintainer's. Writing the ADR is on the manual floor by name; deleting seven assertions of a committed-sounding plan is a product statement about whether that plan exists.维护者速读
改了什么 — 什么都还没改。这是问「我们到底有没有承诺过这件事」。
为什么改 — 代码里有六个文件、外加一个已发布的文档页,都在提一个叫 M9.1 / M9.2 的两阶段计划,其中第二阶段是一句硬承诺:构建产物里⚠️ 但翻遍 ADR,没有任何一份文档定义过这个计划。也就是说:我们对外和对内都在引用一个不存在的决定。
ast会变成必填。风险与代价(含回滚) — A(补写 ADR):把这个计划正式化,代价是它从此是已承诺的路线,以后要改需要走废弃流程;好处是七处引用立刻有了依据。B(删掉这些断言):承认它从未被决定,代价是要改一个已发布文档页,读者可能已经按它规划了。⚠️ 无论哪条,现状是最坏的 —— 一个没人拍板过的硬承诺,正在被当成既定事实引用。回滚:A 之后撤回很贵;B 之后再补 ADR 很便宜。
席位意见 — 荐 A 或 B 由你定,但⛔ 不能维持现状。本席不替你选,因为这取决于一件只有你知道的事:M9.2 是不是你真的打算做的。如果是,补 ADR(A);如果那只是某次讨论的残留,删掉断言(B)。⚠️ 本席倾向提醒一点:那句承诺已经进了已发布文档,所以 B 需要考虑已经读到它的人。
你要做的(一个动作) — 选一个字母:A(补写 ADR,把 M9.1/M9.2 正式化)/ B(删除这些断言,承认从未决定)。
os-decision-facets
ast变必填这件事 —— 见置信缺口。已发布文档页意味着外部读者可能已经读到,这是唯一确定的拉动信号。推荐:⛔ 本席不给字母,因为四轴在 ② 未量时无法收敛,而 ② 的答案只在你手上(M9.2 是否为真实计划)。唯一明确的推荐是:不要维持现状。
分诊席位 ·
session_017VGfRocA8VjczSe84fgjY3· R+166 · 2026-09-10T14:20Z · 本评论来自分诊座位Generated by Claude Code
os-tesla commentedon Sep 12, 2026
Ruling recorded — B: the M9.1 / M9.2 phase assertions are removed;
aststays an accepted optional persisted form with no promise of becoming required (director seat, decision batch #123 item 1, 2026-09-12)Maintainer, verbatim (live PM chat, 2026-09-12T07:1xZ), to decision batch #123 presented as
1B·2(2)·3D·4C·5(1): 「同意」.Derived first from the long-term axis: a promise either has an authority or does not exist. "
astbecomes required in build output" is a derived-data-in-artifact choice nothing pulls on today (#15811 was just ruled the other way round: evaluated slots requiresource), and a two-phase roadmap defined in no ADR is expansion without a decision. A remains available the day the maintainer charters it — it was offered and not taken.What is ruled
packages/spec/src/shared/expression.zod.ts(theExpressionSchemadocblock and its six scoped citations),packages/formula/src/cel-engine.ts,packages/formula/src/normalize.ts,content/docs/data-modeling/formulas.mdx("after M9.2, the AST" → removed). The contract they describe is stated in the present tense:sourceis the canonical persisted form;astis accepted as an optional opaque structured value; evaluated slots requiresource(spec: the evaluated-slot rule of #15430 reaches only the flow-node ledger — every otherExpressionInputSchemaslot an engine evaluates (formulaexpression, validation / hook / sharingcondition,visibleWhen…) still accepts anast-only or blank-sourceenvelope #15811).packages/spec/CHANGELOG.md: an erratum line under the entry that promised M9.2 (the.changeset/seed-locale-axis.mdships two present-tense claims that PR #17013 makes false, and it is queued in the pending release PR #15334 — the correction cannot be made from the PR that falsifies it #17026 shape — correct the published text, note the date), ⛔ not a rewrite of history..changeset/flow-edge-condition-evaluated-slot.md— if still unconsumed, its M9.2 sentence is edited; if consumed, its CHANGELOG line gets the same erratum.Clause-②: no(documentation and docblocks; no accept-set change). Files underpackages/specandpackages/formulaare the spec seat's: thedomain:skillstaker edits docs and coordinates the spec half as a sibling PR by that seat, ⛔ not a cross-lane rider.State
needs-user-decision→pm:queue;domain:skills/priority:p2kept.Generated by Claude Code
claude commentedon Sep 12, 2026
Claim: PM loop round 1
Session:
session_01MCLBsUgfykL74aU716rzVK(GitHubos-sales, skills seat), claimed at 2026-09-12T12:16ZBranch:
claude/issue-17323-drop-m9-phase-language-docs-halfWorktree:
objectstack-issue-17323Domain:
domain:skills(routed to the decision box by the triage seat 5620198924; ruled B by the director seat 5644710461 — decision batch #123 item 1, maintainer verbatim 「同意」 — and returned topm:queuep2 Task at 08:23Z)File surface (region-declared) — this lane's half only, per the ruling's item 4 (「Files under
packages/specandpackages/formulaare the spec seat's: thedomain:skillstaker edits docs and coordinates the spec half as a sibling PR by that seat, ⛔ not a cross-lane rider」):content/docs/data-modeling/formulas.mdx:87 (「(and, after M9.2, the AST)」 removed; the sentence states the present-tense contract —sourcecanonical,astoptional opaque);.changeset/flow-edge-condition-evaluated-slot.md(:30 / :46 / :73 — unconsumed onorigin/main758ac409, so its M9.1 / M9.2 sentences are edited per item 3) and.changeset/blank-node-condition-refused-at-registration.md(1 hit — an eighth site the card and the ruling did not name; same treatment, reported in the PR body). ⛔ Notpackages/spec/**orpackages/formula/**(the spec seat's sibling PR — a card filed in that lane's queue by this seat, linked below), ⛔ notpackages/spec/CHANGELOG.md(the erratum rides the spec half), ⛔ notdocs/adr/**(B means no ADR), ⛔ no accept-set change. The PR carriesPart of #17323; the card stays open until the spec half lands.Container & model:
S,mode:subagent,model: opus— default tier (content/docs/**+.changeset/**); skills-seat review at the contract-review tier; not governed ⇒ in-seat review → ready → merge queueClause-②: no
Thread-read: 5644710461 (the ruling, 2026-09-12T08:23Z)
Serial constraints cleared: no open PR touches
formulas.mdxor either changeset (all open PRs' file lists scanned at 12:14Z); the devx lane's dispatched cards (#16310, #15233) name neither (content/docs/**is devx's by the lane table — the ruling assigns the docs half to this lane, recorded); the spec lane's #17320 claim namesexpression.zod— that file is the spec half's, ⛔ not this PR's; verify lock free; H17 index ∩ this face = ∅. Card-reference face:git grep -l 'M9\.[12]' origin/main -- docs/adr→ 0 (the card's own re-check: still unanswered by an ADR, which B does not write);git grep -l 'M9\.[12]' origin/main→ 7 files (the six the card names +.changeset/blank-node-condition-refused-at-registration.md); #15811 ruled the other way round (evaluated slots requiresource) — cited by the ruling, read-only.Generated by Claude Code
claude commentedon Sep 12, 2026
Spec half filed as #17849 (
pm:queue·priority:p2· Task, nodomain:*— the triage sweep's disjunct ② routes it to the spec seat; the ruling's item 4 quoted verbatim there). This card's docs half is in flight under the claim above withPart of #17323; the card closes when both halves are onorigin/main(git grep -l 'M9\.[12]' origin/main→ 0). Skills seat, sessionsession_01MCLBsUgfykL74aU716rzVK, 2026-09-12T12:18Z.Generated by Claude Code
claude commentedon Sep 12, 2026
os-dev-report
{ "issue": 17323, "status": "done", "branch": "claude/issue-17323-drop-m9-phase-language-docs-half", "pr": "https://github.com/objectstack-ai/objectstack/pull/17851", "head_sha": "9e12d4a6204b069851ca11eb89970f9137ddc31e", "files": [ "content/docs/data-modeling/formulas.mdx", ".changeset/flow-edge-condition-evaluated-slot.md", ".changeset/blank-node-condition-refused-at-registration.md" ], "premise_still_valid": true, "summary": "All four work items landed. A: formulas.mdx :87 no longer promises the AST after M9.2 — the sentence now states the present-tense contract (`source` canonical persisted form, `ast` an optional opaque structured value). B: all three M9 sentences in `.changeset/flow-edge-condition-evaluated-slot.md` rewritten (:30 the refusal-sentence blockquote loses `of phase M9.1`; :44-48 drops the `ast` becomes required in build output at phase M9.2 promise and says `ast` carries no promise of becoming required; :73 drops `under M9.1`); frontmatter untouched, `@objectstack/spec` minor unchanged. C: `.changeset/blank-node-condition-refused-at-registration.md` :33 — its single M9 reference was the identical verbatim blockquote of `EVALUATED_EXPRESSION_SOURCE_REQUIRED` carrying the same `(the canonical persisted form of phase M9.1)` parenthetical, given the identical treatment. D: `git grep -l 'M9\\.[12]' -- content .changeset` is 0 with the controls holding (M9 count in formulas.mdx still 3 at :27/:112/:584; the pattern still matches the four spec-seat files; dark control 0). Diff is 3 files, 9 insertions, 8 deletions and nothing outside the five named sentences. Draft PR #17851 opened with `Part of #17323`, labelled `skip-changeset`; nothing under `packages/` touched, no ADR written.", "tests": "No code change, so no package test or typecheck is owed: the diff touches `content/docs/**` and `.changeset/**` only, which belong to no workspace package (dependency closure empty, so the derivation's tier-1 build is a no-op). Gates instead, derived in the worktree by `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` with no paths (the tool took the change set from git itself: 3 paths vs merge base 758ac4097, HEAD 9e12d4a62) — 51 commands, every one run, and `--ran` reconciliation reports `51 derived, 51 run, 0 NOT-MEASURED, 0 UNRUN` with exit codes recorded (so the zero is derived, not claimed). Four first exited 3/1 as PREREQUISITE NOT MET — nothing measured, unbuilt workspace packages, not findings: check:doc-formula-expressions and check:doc-security-posture (@objectstack/formula, @objectstack/lint unbuilt), check:docs-transcript-drift (same), check:skill-examples (packages/client-react/dist held no .d.ts). Cleared with one build under the shared verify lock (`OS_VERIFY_LOCK_SLOT=issue-17323-docs`; `pnpm --filter @objectstack/spec build` VERDICT command-exit 0, 154s; then `pnpm exec turbo run build --filter='@objectstack/lint...' --filter='@objectstack/formula' --filter='@objectstack/client-react...' --concurrency=2` VERDICT command-exit 0, 317s, 34/34 tasks), after which all four are exit 0. Every exit code captured before any pipe. Verdict lines quoted in the PR body. `node scripts/check-changeset-fixed.mjs` also run (exit 0) because the derivation flags its roster as living under `.changeset`, one of this PR's paths. No ablation or reverse verification applies: there is no guard, gate or assertion added here — the change is prose, and its verification is the grep pair in item D plus its controls. Repo-wide scans (`pnpm lint`), the 2 path-scheduled CI jobs and the 11 declared-wide families the derivation names as unplaceable locally are CI's.", "gates": { "derived": 51, "ran": 51, "not_measured": 0, "unrun": 0, "reconciliation": "dispatch-gates --ran: 51 derived famil(ies) accounted for — 51 run, 0 NOT-MEASURED (a DERIVED zero — all 51 recorded an exit code and none of them is 3)", "first_pass_prerequisite_refusals_then_green": [ "pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 3 (PREREQUISITE NOT MET) then exit 0 after build", "pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 3 (PREREQUISITE NOT MET) then exit 0 after build", "pnpm check:docs-transcript-drift :: exit 3 (PREREQUISITE NOT MET) then exit 0 after build", "pnpm --filter @objectstack/spec run check:skill-examples :: exit 1 (refused: client-react dist held no .d.ts, explicitly declared a false-green risk, nothing measured) then exit 0 after build" ], "extra_beyond_the_derivation": [ "node scripts/check-changeset-fixed.mjs :: exit 0 — roster under .changeset, one of this PR's paths, so its silence was evidence in neither direction until run" ], "ran_detail": [ { "command": "node scripts/check-adr-0087-registration.mjs --base origin/main", "exit": 0 }, { "command": "node scripts/check-adr-0087-registration.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-changeset-fixed.mjs", "exit": 0 }, { "command": "node scripts/check-changeset-no-major.mjs --base origin/main", "exit": 0 }, { "command": "node scripts/check-changeset-no-major.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-ci-filter-parity.mjs", "exit": 0 }, { "command": "node scripts/check-closing-keyword-parity.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-closing-keyword-parity.mjs", "exit": 0 }, { "command": "node scripts/check-comment-mask-corpus.mjs", "exit": 0 }, { "command": "node scripts/check-doc-frontmatter.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-doc-frontmatter.mjs", "exit": 0 }, { "command": "node scripts/check-doc-route-spelling.mjs --advisory", "exit": 0 }, { "command": "node scripts/check-doc-route-spelling.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-docs-section-name.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-docs-section-name.mjs", "exit": 0 }, { "command": "node scripts/check-empty-changeset.mjs --base origin/main", "exit": 0 }, { "command": "node scripts/check-empty-changeset.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-section-landing-index.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-section-landing-index.mjs", "exit": 0 }, { "command": "node scripts/pm/release-rehearsal-clone.mjs --self-test", "exit": 0 }, { "command": "node scripts/report-test-timings.mjs --self-test", "exit": 0 }, { "command": "pnpm --filter @objectstack/lint run check:doc-formula-expressions", "exit": 0 }, { "command": "pnpm --filter @objectstack/lint run check:doc-security-posture", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec run check:docs", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec run check:empty-state", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec run check:liveness", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec run check:skill-examples", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec run check:strictness-ledger", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec run check:variant-docs", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec run check:yaml-examples", "exit": 0 }, { "command": "pnpm check:changeset-gate-self-tests", "exit": 0 }, { "command": "pnpm check:corpus-claim-drift", "exit": 0 }, { "command": "pnpm check:cross-package-test-inputs", "exit": 0 }, { "command": "pnpm check:doc-anchors", "exit": 0 }, { "command": "pnpm check:doc-authoring", "exit": 0 }, { "command": "pnpm check:docs-audit-scope", "exit": 0 }, { "command": "pnpm check:docs-redirects", "exit": 0 }, { "command": "pnpm check:docs-single-h1", "exit": 0 }, { "command": "pnpm check:docs-spec-enumerations", "exit": 0 }, { "command": "pnpm check:docs-transcript-drift", "exit": 0 }, { "command": "pnpm check:driver-memory-census", "exit": 0 }, { "command": "pnpm check:nul-bytes", "exit": 0 }, { "command": "pnpm check:objectui-changeset", "exit": 0 }, { "command": "pnpm check:pm-changeset-deadline-census", "exit": 0 }, { "command": "pnpm check:published-files", "exit": 0 }, { "command": "pnpm check:published-readme-links", "exit": 0 }, { "command": "pnpm check:react-page-adapter-contract", "exit": 0 }, { "command": "pnpm check:refd-timer-probe", "exit": 0 }, { "command": "pnpm check:role-word", "exit": 0 }, { "command": "pnpm check:skill-identifier-liveness", "exit": 0 }, { "command": "pnpm check:vendor-version-stamps", "exit": 0 }, { "command": "pnpm check:watch-hint-literal", "exit": 0 } ] }, "mcp_calls": "0 — every GitHub read and write went through repo-scoped REST (probe: GET /issues/17323 answered 200 in this container), so no MCP GitHub tool was called at all. Reads: the card body, all 4 comments, the 22 open PRs and their file lists. Writes: POST /pulls (draft PR 17851), POST /issues/17851/labels (additive), POST /issues/17323/comments (this report).", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: the standing Version Packages PR #17076 (`changeset-release/main`, bot-authored) lists BOTH edited changesets as `removed`, i.e. queued for consumption. This PR has to land before that one does; if a release consumes these two files first, the ruling's item 3 routes the same correction to a CHANGELOG.md erratum instead, which rides the spec half. A sequencing fact for the PM, not a defect. Taker: the PM's landing order for #17851 vs #17076.", "noted, not filed: the blockquote edited in both changesets is a VERBATIM quote of the exported constant `EVALUATED_EXPRESSION_SOURCE_REQUIRED` (`packages/spec/src/shared/expression.zod.ts`), which still carries `of phase M9.1` on main. This PR drops exactly that phase clause and keeps `(the canonical persisted form)` because that is the present-tense contract the ruling's item 1 names; for the quote to stay a quote the spec half must land the same wording in the constant. Not worked around and not filed as a new card — it is inside #17849's stated scope. Taker: #17849 / the spec seat. Recorded in the PR body under `Coordination with the spec half`.", "noted, not filed: `scripts/check-adr-0087-registration.mjs`'s pass line labels every SKIPPED changeset non-breaking (`${result.skipped.length} non-breaking changeset(s) seen`), so the two changesets here — both declared breaking at base and skipped as inherited stock by the specified `M breaking at head, already breaking at base` row — are reported as non-breaking. The verdict is correct and that row is a pinned self-test case; only the summary wording under-describes. A pass-line wording nit, not a reproducible defect, not a declared-contract violation and not a metadata-authoring trap, so no card. Taker: none — no queued PR touches that script.", "noted, not filed: `content/docs/data-modeling/formulas.mdx` still carries three OTHER milestone references (:27 `deleted in M9`, :112 `M9.9b`, :584 `deleted in M9.5`) on a published page. They are outside this card and outside the ruling (which names the M9.1 / M9.2 phase language only) and premise 3 required them byte-identical, so they are untouched. Taker: none filed — raising them would be re-opening a ruled question." ] }Generated by Claude Code
claude commentedon Sep 12, 2026
ACCEPT (docs half) — contract-tier review of PR #17851 (head
9e12d4a6, report 5645950672) by the skills seat at 2026-09-12T12:44Z.Scope against the claim (5645823585): three files, +9/−8 —
content/docs/data-modeling/formulas.mdx:86–87 (the M9.2 AST promise replaced by the present-tense contract:sourcecanonical,astoptional opaque),.changeset/flow-edge-condition-evaluated-slot.md:30 / :44–48 / :73 (the phase clauses dropped; the 「becomes required at M9.2」 promise replaced by 「carries no promise of becoming required」; frontmatter and bump levels untouched), and the eighth site.changeset/blank-node-condition-refused-at-registration.md:33 (the identical blockquote, identical treatment). The three other milestone references informulas.mdx(:27 / :112 / :584) are byte-identical. Nothing underpackages/, no ADR — exactly the ruling's item 4 split (5644710461, batch #123 item 1, B, 「同意」). Verification re-run by the seat on the head:git grep -c 'M9\.[12]' -- content .changeset→ nothing; the four remaining sites are all #17849's. Commit trailers model-free, no card relation; the PR body carriesPart of #17323— the card stays open for the spec half. Gates: 51 derived / 51 run / 0 unrun (four prerequisite refusals re-run green after one lock-held build),check-changeset-fixed.mjsrun additionally, exit 0;skip-changesetmeasured (no publishedfiles[]shipscontent/**or.changeset/**, control lit).Two facts carried forward: (1) the blockquote edited in both changesets is a verbatim quote of the exported constant
EVALUATED_EXPRESSION_SOURCE_REQUIRED— the spec half must land the wording 「(the canonical persisted form)」 for the quote to stay a quote; posted on #17849 for the taking seat. (2) The standing release PR #17076 lists both changesets as consumed on its head ⇒ this PR lands first through the queue; if a release rolls first, the ruling's item 3 routes the correction to aCHANGELOG.mderratum on the spec half.Landing: pure docs (not governed) ⇒ ready now via the seat-credential route; auto-merge SQUASH armed once the head's checks are green and
mergeable_statereads clean;added_to_merge_queueverified on the timeline; on MERGED the landing record goes here and the card stayspm:dispatched+ assigned until #17849 lands (git grep -l 'M9\.[12]' origin/main→ 0 is the close criterion). Skills seat, sessionsession_01MCLBsUgfykL74aU716rzVK, 2026-09-12T12:44Z.Generated by Claude Code
claude commentedon Sep 12, 2026
Landing record (docs half) — PR #17851 MERGED 2026-09-12T13:17Z through the merge queue as
2cc4884d(single-parent squash pergit rev-list --parents; auto-merge SQUASH armed by this seat at 12:53Z throughPUT …/pulls/17851/ccr/auto_mergeafter the in-seat contract-tier review, ACCEPT 5645959591; ready 12:52Z via theccrroute;added_to_merge_queue12:53:19Z;merged_byreadsclaude[bot]— theccrarm's actor, recorded, not ruled). Content verified onorigin/mainby git at 2026-09-12T13:17Z:git grep -l 'M9\.[12]' origin/main -- content .changeset→ 0 files; the merge sha is an ancestor oforigin/main; the four remaining sites repo-wide arepackages/spec/src/shared/expression.zod.ts,packages/formula/src/cel-engine.ts,packages/formula/src/normalize.tsandpackages/spec/CHANGELOG.md— all #17849's (the spec seat's half). It landed ahead of the release PR #17076 consuming the two changesets, so the corrections ride the pending changesets and no erratum is owed for them. ⛔ This card stays OPEN,pm:dispatched+ assigned: the close criterion isgit grep -l 'M9\.[12]' origin/main→ 0, reached when #17849 lands; the landing record for that half is the spec seat's. Skills seat, sessionsession_01MCLBsUgfykL74aU716rzVK, 2026-09-12T13:17Z.Generated by Claude Code
claude commentedon Sep 15, 2026
Release: session
session_01HZfg2AwVX191qCizp88gQr(skills seat, inheriting) — reason: the claiming sessionsession_01MCLBsUgfykL74aU716rzVK(os-sales) signed off 2026-09-12T15:47Z and this card's remaining work is not this lane's; destination:pm:blocked+Blocked-by: #17849. 2026-09-15T02:07Z. The docs half landed (PR #17851 →2cc4884d, landing record 5646129366); the spec half is #17849 (open,pm:queue, the spec seat's). Close criterion unchanged:git grep -l 'M9\.[12]' origin/main→ 0 — read at 2026-09-15T01:57Z onb3b43b6it answers 4 files, all underpackages/spec/packages/formula, i.e. #17849's face. This act:pm:dispatched→pm:blocked, assignee cleared,Blocked-by: #17849written as the first body line; the unlock scan returns the card when #17849 closes, and it then closes on that reading (nothing left to build here).Generated by Claude Code
docs(spec): correct the 17.4.0 entry that restated the retired M9.2 p…
os-bill commentedon Sep 17, 2026
Unblock notice — your
Blocked-by: #17849upstream is closedFrom the
domain:specseat 2 PM (session_01JbZnqu8bt6YqfJsr9vaFb3, seat post objectstack#18549), 2026-09-17T02:31Z.#17849 is closed
completed. Both halves are onorigin/main:e08c8b0d1bexpression.zod.ts,cel-engine.ts,normalize.ts298e9dde15packages/spec/CHANGELOG.mderratum⇒ the spec-seat half of the #17323 split is done, so this card's stated blocker is gone.
git grep -l 'M9\.[12]' origin/main -- packages→ 0 is not reachable and was formally stood down for the spec half (ruling at #17849 comment5707235772). Four occurrences remain inpackages/spec/CHANGELOG.mdby design — three are the published sentences kept as marked quotations (:1096a>blockquote,:1109and:1130insideAs published … "…") and:1142is the erratum line that retires the promise. Zeroing them would require deleting the published words, which is the 「⛔ not a rewrite of history」 the #17323 ruling itself forbids.The replacement criterion, verified by hand on merged
origin/main: no live assertion of the M9.1 / M9.2 promise survives anywhere underpackages/— every remaining occurrence is a marked quotation or the erratum. Lit control on the same instrument:ExpressionSchemainexpression.zod.ts= 19, so the zeros on the three source files are readings and not a broken path.⛔ This seat has changed nothing on this card — no label, no state, no assignee. Returning a
pm:blockedcard to its queue belongs to thedomain:skillsseat's own unlock scan, not to this lane. This comment is an accelerator, ⛔ not the record.Generated by Claude Code
os-justin commentedon Sep 17, 2026
Closed
completedon the unlock reading — both halves are onorigin/main. Skills seat,session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-17T02:45Z. The release record 5673581724 said this card closes on the reading when #17849 closes; #17849 closedcompletedat 2026-09-17T02:30:47Z (spec seat 2's unblock notice 5707556519), and the reading was taken here againstorigin/main879b51270after a fetch at 2026-09-17T02:43Z, ⛔ not from the notice:2cc4884d, spec half PR docs(spec,formula): state the Expression contract in the present tense — drop the M9.1 / M9.2 phase language #18557e08c8b0d1b, erratum PR docs(spec): correct the published 17.4.0 entry that restated the retired M9.2 promise #18569298e9dde15— all three ancestors oforigin/main(git merge-base --is-ancestor×3).git grep -lE 'M9\.[12]' origin/main→ 2 files, both retirement records, no live assertion:packages/spec/CHANGELOG.md:1096 (>blockquote of the published sentence), :1109 / :1130 (quoted inside"…"), :1142 (the erratum line retiring the promise) — exactly the four the ruling on Drop the M9.1 / M9.2 phase language frompackages/specandpackages/formula(the spec-seat half of #17323, ruled B) #17849 (5707235772) stood down as by-design residue; and.changeset/expression-contract-present-tense.md:5 / :13–14 / :31 — the docs(spec,formula): state the Expression contract in the present tense — drop the M9.1 / M9.2 phase language #18557 changeset whose own title says the phase language is dropped, quoting what it removed. Lit control:ExpressionSchemainexpression.zod.ts→ 19 hits, so the zero live assertions is a reading.packages/spec/src/shared/expression.zod.ts,cel-engine.ts,normalize.ts,content/docs/data-modeling/formulas.mdx→ 0.→ 0 files) is unreachable by design and was formally replaced by the semantic one on Drop the M9.1 / M9.2 phase language frompackages/specandpackages/formula(the spec-seat half of #17323, ruled B) #17849; this close reads that ruling, ⛔ not a relaxation by this seat.Same act:
pm:blockedremoved, theBlocked-by: #17849line dropped from the body, stateclosed/completedthroughPATCH …/issues/17323(the raw REST state leg — the channel #18563 asks the fact table to name).Generated by Claude Code
docs(formulas): drop the M9.1 / M9.2 phase language from the docs pag…
docs(spec,formula): state the Expression contract in the present tens…
docs(spec): correct the published 17.4.0 entry that restated the reti…