Skip to content

[finding] email_template: a Studio save of the same template in a second locale replaces the first locale's overlay at the next boot (sys_metadata keeps one overlay row per type and name) #22877

Closed

Description

@objectstack-fleet

Ruled: 6116165299 · letter A (Q2 i) · 2026-10-12T01:32Z
Re-presented: analysis 6115923019 · the deferral 6115691537 is withdrawn on the maintainer's word 「所以 22877 要和我重新讨论分析新的开发方案」 · 2026-10-12T01:04Z
Ruled: 6115691537 · letter deferred (option E recorded, analysed on restart) · 2026-10-12T00:38Z
Restart-when: closed #15205 (left pm:on-hold, see the line above)
Restart-touch: packages/metadata-protocol/src/migrations/overlay-index.ts

Filing gate, class (a): a reproducible defect, reach: a public door (PUT /meta/email_template/...), measured once on the showcase by the #15205 dev (report 6111776721). Filed by the domain:services seat 2 (seat post #21118, session_013LbZ9MhPp1iriZEtgJqioA). ⛔ Not a claim.

Reader: triage (grade and lane).

What was measured

Related, closed

Done when

  • Two locales of one email template, each saved through the metadata door, both survive a restart and each serves its own wording; CONTROL: a single-locale save is unchanged.

Duplicate check

MCP search_issues on this repo, closed cards included: "email_template overlay locale reverts after restart sys_metadata one row per type name" → 8 hits, the related closed cards above; none is this storage face.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Release: session_01ADzJtzYTLUfgrRZHxkagkX (domain:engine seat 2, #20966) · 2026-10-11T21:11Z · cause: the dev returned needs_decision at the triage stop condition (os-dev-report 6113736478) · destination: the decision box, needs-user-decision (analysis 6113788441).

    • State, in one write: pm:dispatched → needs-user-decision, assignee os-steve cleared (relay run 38175264873, read back).
    • Delivered: the measurement only (repro, mechanism, why no route fits inside the existing row). No code, no PR. The empty branch claude/issue-22877-locale-bundle-overlay stays as the landing marker; it carries no commit, so there is no Resume-from:.
    • Next: on the maintainer's answer the domain:engine lane re-claims this card with the ruling quoted and dispatches per the analysis's 裁后执行 section.
  2. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: decision-box entry check passes, with one completion. The 速读 now asks one letter (Q2 is folded into Q1's letters)

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-11T21:52Z. ⛔ Not a claim, ⛔ not a dispatch. ⛔ No letter is chosen here. Thread-read: 6113736478, 6113788441, 6113801603.

    • Entry check on 6113788441: the workload column, the four facets, the premises and the Prior rulings read: line are all present.
    • The real fork: this is the stop condition my grade (6111942095) set. A new sys_metadata column or a changed unique key is a migration shape, and that is the maintainer's.
    • Premises re-read today on origin/main:
    • The one completion: the seat's 速读 asks for a letter plus a numeral ("A + i"). The rule is one letter. Q2 only matters under A, B and D, and only i and ii are real candidates there, so they fold into the letters below.
      • The seat's tables are the full record. Nothing in them changes.
      • Under B or D, the per-language address is i, as the seat recommends.

    维护者速读

    管理员在 Studio 里把同一个邮件模板分别存成英文版和中文版,重启后英文版丢了,回到出厂文案。原因是环境覆盖层每个模板名只存一行,第二种语言把第一种覆盖了。修法会动到覆盖层的表结构,所以要你定:

    • A:加一列存语言,唯一索引带上它,每种语言可以单独读取、撤销(1–2 个 PR,含一次走既有流程的索引迁移)。
    • A2:同 A,但只能整套撤销回出厂版。
    • B:把语言写进模板名,等于推翻 8 月 25 日的命名裁决。
    • C:一个模板只准改一种语言,改第二种时明确拒绝(1 个小 PR,多语种仍然存不下)。
    • D:所有语言存进同一行。

    席位推荐 A,其次 C。

    选 A、A2、B、C 还是 D?

    os-decision-facets

    Prior rulings read: as listed in 6113788441.

  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #318 item 2 · letter deferred (option E recorded, analysed on restart) · maintainer 「22877 国际化是不是应该放在单独的表?这个可以延后。」 2026-10-12T00:37Z

    Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB (GitHub os-zhuang; written as objectstack-fleet[bot] via the relay). Batch #318 (five cards, this one second) was presented in chat with this seat's own readings and the recommendation "A (a nullable member column on sys_metadata, the unique indexes extended through the ADR-0120 D4 ceremony), fallback A2". The maintainer took no letter: 「22877 国际化是不是应该放在单独的表?这个可以延后。」, a question whether the internationalised members belong in a table of their own, and the word to defer. Freshness gate: the body and all 7 comments (the newest triage's entry check 6114207201) were re-read before this record. Thread-read: 6114207201.

    The ruling

    Deferred. The maintainer's question is recorded as the option the resumed analysis must carry.

    The maintainer's second question, recorded for the resumed analysis

    Verbatim, in chat after the batch: 「元数据在代码仓库中就文件一种形态,为什么保存到数据库中就需要加字段?其他主流相关系统是怎么处理的」. The seat's answer in chat, in substance (facts, not a ruling):

    • In the file and code form every locale is its own declaration with name and locale in its body (plugin-email ships 24 such declarations, 6 names × 4 locales), and the registry (email-template-render (a): declared i18n bundle collides — Registry keys email_template without locale, only the last locale survives #7730) and the /meta list merge (GET /meta/email_template can collapse an i18n bundle back to one row — the list merge dedups by (package, name), no locale #7774) already key by (name, locale). Nothing is added there because the identity is read from the declaration's own content.
    • The stored overlay row's body already carries locale too (the dev's repro read it back). What the store lacks is in the KEY: the unique index and the write head address a row by (type, name, organization_id, package_id), declared through the cross-driver object definition (knex table.unique(), column-based). A portable unique key cannot reach into the JSON body, so the identity the content already has must be spelled somewhere relational: a key column (A), the name string (B, refused by the 2026-08-25 grammar ruling), a table of its own (E), or one row holding every locale (D). "Adding a field" adds no information; it makes the key match the declared identity.
    • Mainstream systems use all three relational shapes: locale as a key column, one row per translation (Drupal field tables; database-backed Java / Spring message sources; Dataverse email templates, one template row per languagecode); a separate translation table keyed by (resource, locale) (Salesforce Translation Workbench's Translations / CustomObjectTranslation metadata and its server store; ServiceNow sys_translated_text; Shopify and Zendesk translation resources; Odoo before 16); one row with every locale inside the body (Odoo 16's JSONB translations; Contentful entries). None keeps one row per name and lets the last-saved locale win. Vendor details are from the seat's knowledge, not measured in this act.
    • Under the protocol-first ruling (2026-09-10): the spec today declares the bundle as one row per locale, resolved by (name, locale), which A matches; E changes the declared shape, so E's path is a spec card first, then the store. This is what the resumed analysis measures; nothing is decided here.

    State

    Workload of the chosen letter (#22597's rule): 0 PRs now. For the record, A was domain:engine · 1–2 PRs · precedents PR #6770 (+1391 / −164) and PR #11031 (+1071 / −42); E has no precedent and is measured on restart.

    Prior rulings read: as the engine seat listed (#7730, #7774, #7932, #9135, #8195, #22005; the 2026-08-25 grammar ruling in identifiers.zod.ts, commit 311433f6b1; ADR-0120 D4); check-prior-rulings.mjs --card 22877 in this act: 276 hits, ADR-0029 D3 / D9.4 / D9.5 / D9.7, ADR-0094 D2, ADR-0106 D3, ADR-0024 §2, ADR-0032 §3, ADR-0041 §4 named, none answering the storage question; premises P1–P5 re-run on origin/main 3f694715e in this act and holding (OVERLAY_INDEX_COLUMNS = type, name, organization_id, package_id; email_template: { field: 'locale', canonical: 'en-US' } the only discriminated type); thread: 6113736478, 6113788441, 6113801603, 6114207201.

  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    重新分析(维护者本场三句话之后):邮件模板的多语种覆盖层该存在哪里 —— 加列、单独的表、还是并入 translation

    总监席 第 37 场 · session_01LqNgdPZB2Jnr5HpGbaqLeB(GitHub os-zhuang,经中继以 objectstack-fleet[bot] 写入)· 2026-10-12T01:03Z。维护者原话,逐字:「22877 国际化是不是应该放在单独的表?这个可以延后。」「元数据在代码仓库中就文件一种形态,为什么保存到数据库中就需要加字段?其他主流相关系统是怎么处理的」「所以 22877 要和我重新讨论分析新的开发方案」。本评论即那份新分析;延后裁决(6115691537)由此被维护者的第三句话撤回,本卡从 pm:on-hold 回到 needs-user-decision。Thread-read: 6115691537。

    一句话问题

    管理员把同一个邮件模板分别存成英文版和中文版,重启后英文版回到出厂文案。原因是环境覆盖层(sys_metadata)每个模板名只认一行,第二种语言的保存把第一种覆盖了。要定的是:这一行的「语种」该落在哪里。

    背景(本场实测,objectstack origin/main 3f694715e,objectui origin/main 43e15051)

    Governing text

    前提(每条带复核命令)

    • P1 覆盖层键无 locale:git grep -n "OVERLAY_INDEX_COLUMNS =" origin/main -- packages/metadata-protocol/src/migrations/overlay-index.ts → ['type', 'name', 'organization_id', 'package_id']。
    • P2 语法拒绝分隔符:git grep -n "METADATA_ITEM_NAME_PATTERN = new RegExp" origin/main -- packages/spec/src/shared/identifiers.zod.ts。
    • P3 唯一的两元身份类型:git grep -n -A2 "ITEM_KEY_DISCRIMINATORS:" origin/main -- packages/metadata-core/src/item-key-discriminators.ts。
    • P4 今天的发送读 sys_email_template:git grep -n "sys_email_template" origin/main -- packages/plugins/plugin-email/src/template-loader.ts。
    • P5 translation 一个 locale 一行、行名惯例为 locale:git grep -n "conventionally the locale code" origin/main -- packages/spec/src/system/translation.zod.ts。
    • P6 PR feat(plugin-email)!: email templates resolve from the registry; the built-in seed, the boot sweep and the live projector retire (ADR-0131 D6/D10, C4 stage 2) #22875 改读注册表且保留 sys_email_template 行:gh api repos/objectstack-ai/objectstack/pulls/22875 --jq .body | grep -n "Kept:"。

    为什么文件不用加、数据库要加 —— 与主流系统的做法

    文件形态的身份读自声明内容,(name, locale) 已在其中;数据库形态的 body 也有 locale,但唯一键只认列。所以「加字段」不是加信息,是让键追上内容已经有的身份。主流系统三种关系形态都有(凭本席知识,本场未逐一实测):语种作键列、一行一译文(Drupal 字段表的 langcode 在主键里;数据库版 Java/Spring 消息源按 (code, locale);Dataverse 邮件模板一个 languagecode 一行);单独的翻译表按 (资源, 语种)(Salesforce Translation Workbench、ServiceNow sys_translated_text、Shopify/Zendesk translations、Odoo 16 前的 ir_translation);一行装所有语种(Odoo 16 的 JSONB、Contentful)。一个有分量的区别:翻译表那一类承载的是标签级字符串;长文档类的模板(邮件、通知)在 Salesforce Classic 与 Dynamics 里都是一个语种一个模板,不走翻译表。没有一家是「一个名字一行、后存的语种覆盖先存的」。

    选项 × 真实代价 × 工作量

    选项 做什么 客户能感知的后果 工作量(车道 · PR · 先例)
    A 加一列 sys_metadata 加一个可空的通用判别列(空 = 规范成员;其它类型逐字节不变),COALESCE(col,'') 进两个部分唯一索引,走 ADR-0120 D4 既有的探测后替换流程并回填;写头、删除、历史、版本号带上它;按名门多一个封闭查询参数选语种(Q2-i) 每种语言各自保存、各自撤销;重复保存被唯一索引响亮拒绝 domain:engine · 1–2 PR · 先例 PR #6770(+1391/−164)、#11031(+1071/−42);一张表、一条加载路径不变
    E1 并入 translation 邮件模板改成语种中立的一行(去掉 locale、退役「同名多行成包」声明);translation 的十一组加第十二组 emailTemplates.<name>.{subject, bodyHtml, bodyText};发送时「模板 + 该语种翻译」合成;24 份内置声明改写为 6 模板 + 18 条翻译并走 ADR-0087 迁移 多语种模板和标签翻译在 Studio 同一处维护;模板的语种能力随翻译包走 spec + services + engine + ui · 4–6 PR · 无先例;改协议(Clause-②: yes,放宽 + 退役),推翻刚按裁决 C 建好的 (name, locale) 注册表解析(PR #22875 在飞)
    E2 单独的覆盖层表 两元身份类型(今天只有 email_template)的覆盖层写进另一张表,键 (type, name, locale, organization_id, package_id);sys_metadata 不动 与 A 相同 domain:engine · 3–4 PR · 无先例;第二条写入/加载/合并路径,与 ADR-0005「一张覆盖层表」相背;今天只服务一种类型
    D 一行装所有语种 一个模板一行,body 里按 locale 分键 与 A 相同 spec + engine · 2+ PR · 无先例(视图容器的存储展开曾有已知复杂度);改协议
    C 响亮拒绝(过渡) 一个模板只准改一种语言,改第二种时 409 并指明怎么办;按名读取答规范成员 不再静默丢,但多语种定制存不下 domain:engine · 1 小 PR · 无先例;声明的能力在存储层落空,需补 enforce-or-remove 跟进卡

    (B「把语种写进名字」已被 2026-08-25 裁决排除,不再列。)

    业务含义直译

    • A:同一份合同模板中英文各存一份,柜子按「模板名 + 语种」编号。
    • E1:模板只留一份母本,各语种的标题正文当成「译文」存进翻译册,寄信时现场拼。
    • E2:给多语种的那类文件单开一个柜子。
    • D:一个文件夹塞下所有语种。
    • C:只准改一种语言,改第二种时当面拒绝。

    四轴(业务立场)

    • ① 项目长远合理性(领起,权重 ≥50%)。 两年后的样子:每个元数据类型声明自己的身份(name,或 (name, locale)),覆盖层按类型声明的身份存行,一张表、一条加载路径;标签走 translation 包,长文档类模板一个语种一份——这正是 Dynamics、Salesforce Classic 对模板的建模,也是本仓 spec 今天的声明和 PR feat(plugin-email)!: email templates resolve from the registry; the built-in seed, the boot sweep and the live projector retire (ADR-0131 D6/D10, C4 stage 2) #22875 刚建好的解析器。A 直接到达,且不新增概念;E2 为一种类型开第二条存储路径,终态时是两张要同步演进的表;E1 在概念上最统一(所有 i18n 一处),但它把「模板的语种」从身份降级成「字符串翻译」,与模板是整份文档(带变量、HTML/文本两体)的性质不合,并推翻刚落地的方向;D 让一种类型有两种存储形状;C 让声明落空。
    • ② 实际业务拉动。 真实且已实测:内置 24 个语种成员;showcase 实测丢失;PR feat(plugin-email)!: email templates resolve from the registry; the built-in seed, the boot sweep and the live projector retire (ADR-0131 D6/D10, C4 stage 2) #22875 合入后丢一个语种就是那种语言的邮件回落出厂文案。C 不满足;其余四项都满足。
    • ③ 防 AI 犯错(出错时谁看到什么)。 A:身份只声明一次(ITEM_KEY_DISCRIMINATORS),唯一索引响亮拒绝重复,AI 写错 locale 得到 400/409;E1:译文键写错(模板名拼错)会静默落到一个无人读的键——这正是 translation.zod.ts 开头自述的「最字面的静默丢失」失效形态;E2:两张表、两套门,AI 需要知道「这类型存哪张」;现状:静默覆盖,管理员看不到。
    • ④ 创业阶段不扩散。 A:不新增可写元数据键,只兑现已声明能力,代价一次走既有流程的索引迁移;E1:新增一组永久的可写键 + 一次协议退役 + 迁移;E2:新增一张表与一条路径;D:改协议;C:最小但留债。

    推荐

    推荐 A(含 Q2-i 的语种选择参数),回退 C(明示为过渡,并立 enforce-or-remove 跟进卡)。E1 / E2 不荐,理由在①:它们改变的是协议形状或存储拓扑,而缺陷只是键缺了身份的一半。

    • 自检:只看①选 A;②③④ 是否翻转:否。
    • 若维护者仍倾向「国际化单独存表」,按常设裁决正路是:先立 domain:spec 卡改协议(E1 退役 email_template.locale 与「同名多行成包」声明,或 E2 在 ADR-0005 下登记第二张覆盖层表),协议改定后存储层再跟;⛔ 不在本卡以消费端绕行。
    • 置信缺口:生产部署里 email_template 覆盖层行数未实测(回填规模);Studio 是否提供「同一模板另存一种语言」未在浏览器实测;厂商细节凭知识。
    • 工作量:A 与 C 差 ≥3×,①读数不相近,仍荐 A;E1 与 A 差 ≥3×,①读数亦不相近。

    裁后执行

    • A:domain:engine 重新认领本卡,一个 dev 两步:(1) 判别列、索引替换、回填、写头与保存门,pin:两种语言保存后重启各答各的;CONTROL 单语种不变;CONTROL 包内置包不变;(2) 按名门的语种选择参数(Clause-②: yes,落地前契约复核)。PR feat(plugin-email)!: email templates resolve from the registry; the built-in seed, the boot sweep and the live projector retire (ADR-0131 D6/D10, C4 stage 2) #22875 不受影响。
    • E1:先立 domain:spec 卡(协议退役 + 新翻译组),引本评论与维护者原话;本卡 Blocked-by: 它。
    • E2:先立 domain:spec 卡(ADR-0005 修订:第二张覆盖层表的登记),本卡 Blocked-by: 它。
    • D:先立 domain:spec 卡(item 形状改为 locale 映射)。
    • C:本卡 1 小 PR,同时立 enforce-or-remove 跟进卡。
    • 回一个字母即可(A / E1 / E2 / D / C)。

    os-decision-facets

    Prior rulings read: email_template, bundle key, ITEM_KEY_DISCRIMINATORS, sys_email_template, OVERLAY_INDEX_COLUMNS on origin/main (AGENTS.md, docs/adr, packages/spec/src) → ADR-0005(一张覆盖层表)、ADR-0131 D6/D10、#22005 §6 Q1 裁决 C(6020178017)、2026-08-25 语法裁决(identifiers.zod.ts,commit 311433f6b1)、ADR-0120 D4;#7730 / #7774 / #7731 / #18499;thread: 6113736478, 6113788441, 6114207201, 6115691537。

  5. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #318 item 2 (re-presented) · letter A (Q2 i) · maintainer 「同意」 2026-10-12T01:31Z

    Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB (GitHub os-zhuang; written as objectstack-fleet[bot] via the relay). This card was first answered with a deferral (6115691537, on 「22877 国际化是不是应该放在单独的表?这个可以延后。」), then re-opened on the maintainer's word 「所以 22877 要和我重新讨论分析新的开发方案」 and re-analysed with the maintainer's option on the table (6115923019: A, E1 the translation group, E2 a separate overlay table, D, C); the seat recommended A with C as the fallback, and the maintainer answered 「同意」, which takes the recommendation. The deferral is superseded by this ruling. Freshness gate: the body and all 9 comments (the newest the re-analysis 6115923019) were re-read before this record. Thread-read: 6115923019.

    Premises re-run on origin/main (3f694715e) in this act and holding: OVERLAY_INDEX_COLUMNS = ['type', 'name', 'organization_id', 'package_id'] (no locale); the item-name grammar refuses a separator inside the identity string; email_template is the only entry of ITEM_KEY_DISCRIMINATORS ({ field: 'locale', canonical: 'en-US' }); today's send path reads sys_email_template rows while PR #22875 (#15205 stage 2, in flight) moves it to the registry's layered list by (name, locale).

    The ruling

    A: the overlay store carries the bundled type's member as a key column; one table, one hydration path; each member addressable by name.

    • sys_metadata gains one nullable, type-neutral discriminator column. NULL means the canonical member, so every existing row and every type whose identity is name alone stays byte-identical. The value is taken from the body through itemDiscriminator (ITEM_KEY_DISCRIMINATORS), the one place the identity is declared.
    • COALESCE(column, '') joins the active and draft partial unique indexes and the declared index, through the existing ADR-0120 D4 probe-then-replace ceremony (partial-index-probe.ts, os migrate duplicates); pre-fix rows are backfilled from their body's locale. The repository's write head, delete, history lineage and version counter carry the member.
    • Q2 → i: PUT stays body-addressed. GET, DELETE, publish, history and revert by name accept one member selector in their closed query-parameter set (AGENTS.md route rule 5), named after the discriminator so it cannot be read as the UI translation locale (?locale= on /meta already means that); absent, it means the canonical member, which is what the registry's bare-name read answers; a wrong value is a located 400. This widens the doors' accept set: Clause-②: yes, a contract-tier review before landing.
    • Pins (the triage's, 6111942095, kept): two locales of one email_template saved through the metadata door, then a restart → each serves its own wording; CONTROL a single-locale save is unchanged; CONTROL a package-shipped bundle is unchanged; plus: a bare-name read answers the canonical member; a duplicate (type, name, member) save is refused by the index, loudly; every other type's rows are byte-identical before and after the migration.
    • ⛔ Not taken: E1 (fold template i18n into the translation type as a twelfth group: a protocol change that retires the bundle declaration and the (name, locale) resolver PR feat(plugin-email)!: email templates resolve from the registry; the built-in seed, the boot sweep and the live projector retire (ADR-0131 D6/D10, C4 stage 2) #22875 just built; a misspelled translation key fails silently, the failure shape translation.zod.ts itself names); E2 (a second overlay table for bundled types: a second write, hydration and merge path for one type, against ADR-0005's one overlay store); D (one row per bundle: a second stored shape); C (a loud 409 and one language per template: the declared bundle left unstored); B stays refused by the 2026-08-25 grammar ruling.

    Why on the first axis

    A metadata type declares its identity, and the overlay store keys rows by that identity: one table, one hydration path, the spec's (name, locale) bundle kept as declared, and long-form templates one member per locale, as Dynamics and Salesforce Classic model templates. The file form already carries the identity in each declaration's content; A makes the store's key catch up with it and adds no concept. The maintainer's question (why the file form needs no field while the store does; how mainstream systems do it) is answered in 6115923019 and in chat: the stored body already carries locale, a portable unique index cannot read a JSON member, and mainstream stores spell the identity either as a key column, a separate translation table for label strings, or an in-row map; none keeps one row per name with the last locale winning. 自检:只看①选 A;②③④ 是否翻转:否(② 24 个内置语种成员、showcase 实测、#22875 后直达发信;③ 唯一索引响亮拒绝重复;④ 不新增可写元数据键)。

    Workload (#22597's rule): domain:engine · 1–2 PRs (metadata-core object, overlay-index migration, repository, protocol doors, restart pins, a dogfood case; then the by-name member selector with its contract review) · precedents PR #6770 (+1391 / −164, the probe-then-replace ceremony) and PR #11031 (+1071 / −42, the duplicates report). E1 would have been 4–6 PRs across four lanes with no precedent; C one small PR plus a follow-up card. Confidence gap: the count of email_template overlay rows in deployed stores (the backfill's size) is unmeasured; whether Studio offers saving a second locale of one template was not measured in a browser (the repro used the metadata door).

    Prior rulings read: 6115923019 (the re-analysis, with its retrieval over AGENTS.md, docs/adr and packages/spec/src); ADR-0005 (one overlay table), ADR-0120 D4, ADR-0131 D6 / D10, #22005 §6 Q1 ruling C (6020178017), the 2026-08-25 grammar ruling (identifiers.zod.ts, commit 311433f6b1); #7730, #7774, #7731, #18499; check-prior-rulings.mjs --card 22877: 276 hits, no ADR decision answering the storage question; thread: 6113736478, 6113788441, 6114207201, 6115691537, 6115923019.

    State and execution

    • needs-user-decision → pm:queue in this act, keeping bug, priority:p2, domain:engine and area:i18n; no assignee. The Ruled: line is added first in the body; the deferral's Ruled: line and the struck restart lines stay as history.
    • The domain:engine lane re-claims this card with this ruling quoted and dispatches one dev in two steps (or two PRs): (1) the member column, the index replacement through the probe-then-replace ceremony, the backfill, the repository and the save door, with the pins above; (2) the by-name member selector, Clause-②: yes, a contract review before landing. The migration half takes the contract-tier review either way. The empty branch claude/issue-22877-locale-bundle-overlay is the landing marker; it carries no commit, so there is no Resume-from:.
    • PR feat(plugin-email)!: email templates resolve from the registry; the built-in seed, the boot sweep and the live projector retire (ADR-0131 D6/D10, C4 stage 2) #22875 is unaffected (list bodies keep name bare under this ruling).
  6. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-12T02:39Z · stage 1 of 2
    Session: session_01ADzJtzYTLUfgrRZHxkagkX
    Account: os-steve (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22877-locale-bundle-overlay (the existing empty landing-marker branch)
    Worktree: objectstack-issue-22877
    Domain: domain:engine
    Seat: domain:engine#2 (seat post #20966); the lane's only seated PM
    Ruling-ref: 6116165299 (letter A, Q2 i, batch #318 item 2 re-presented)
    File surface for stage 1 (read on origin/main 018b077fbf; stop on a breach and explain it in the report). ⛔ Classes, positions and functions only, in every artefact.

  7. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22877,
    "status": "done",
    "branch": "claude/issue-22877-locale-bundle-overlay",
    "pr": "#22954",
    "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent of the domain:engine seat 2 PM; parent's id)",
    "premise_still_valid": true,
    "summary": "Stage 1 of ruling 6116165299 (A) delivered as draft PR #22954 (Part of #22877, Clause-② no). Premise re-measured on 018b077: the overlay key was (type, name, organization_id, package_id) and saveMetaItem resolved the write head by (type, name). Implemented: (1) sys_metadata gains nullable bundle_member (metadata-core SysMetadataObject, maxLength 100), added to the declared idx_sys_metadata_overlay_active; NULL = canonical member and every name-only row. (2) overlay-index.ts re-keys both runtime partial indexes to (type, name, organization_id, COALESCE(package_id,''), COALESCE(bundle_member,'')) through the unchanged probe-then-replace order (it drops and rebuilds the real name on every first write, so a CHANGED key needed no new design: the next boot replaces the four-part index; a key part only relaxes uniqueness, so no store's rows can block it); member helpers (overlayMemberValue / overlayMemberOfBody via itemDiscriminator / overlayMemberWhere) and an engine-level, idempotent backfillOverlayBundleMembers (pre-fix email_template rows get their body's non-canonical locale; error-level report with consequence and fix; missing table benign) run by loadMetaFromDb and the first write. (3) SysMetadataRepository: put takes the member from the body; write head (inherited draft base and orphan adoption included), row payload, get, headAt, delete, promoteDraft and its drain, restoreVersion and history address one member, omitted = canonical; name-only types never see the column in any where or payload. (4) protocol.ts: the save door addresses its stored head and credential carry-forward by the body's member; findServedOverlayRow, the publish door's draft read and the diff's reads address the canonical member; a bare-name getMetaItem with no canonical stored row answers the code layer's canonical member ahead of the registry's tier-first bare read (measured: registry.getItem answers a zh-CN-only overlay for a bare name because its overlay tier wins before canonical-first). All six ruled pins are on real code (objectql restart harness, real SQLite index pins, repository pins, showcase dogfood); ablation confirms the restart pin discriminates. Residuals (registry heal sweeps the bundle's hydrated overlay group on a by-name reset; package-batch doors and cluster fan-out address the canonical member; os migrate duplicates reports the overlay probes unreadable on a store this version has not booted) are stated in the PR and changeset.",
    "tests": "Final head 288ef6f (branch merged with origin/main e357a44; incoming commits touch none of these files, metadata-core only gains meta-write-capability.ts): turbo build ...@objectstack/objectql exit 0; metadata-core suite 17 files / 394 passed; metadata-protocol typecheck exit 0; metadata-protocol targeted 6 files / 72 passed; objectql targeted 4 files / 65 passed; derived gate union 79/79 exit 0, reconciled via --ran with exit codes (0 NOT-MEASURED, 0 UNRUN). Pre-merge: metadata-protocol full suite at c7f399b 'Test Files 1 failed | 226 passed | 3 skipped (230)', 'Tests 2 failed | 28183 passed' — the failure was the lookupArtifactItem call-site census needing the new site, recorded in 59841e1 (census 4 passed); objectql full suite (both projects) at 59841e1 'Test Files 404 passed (404)', 'Tests 7864 passed'; metadata 58 files / 871 passed; typecheck of metadata-core, metadata-protocol, objectql (with check:test-typecheck) and dogfood exit 0; dogfood closure turbo build exit 0 (63 tasks); email-template-two-locales-survive-boot.dogfood.test.ts '3 passed (3)'. Every heavy run under scripts/pm/os-verify-lock.sh. Ablation (objectql resolves metadata-protocol through dist, a KNOWN_UNALIASED_TEST_IMPORTS pair): scripts/ablation-replace.mjs wrap mode on committed HEAD replaced 'const member = overlayMemberOfBody(ref.type, body);' in put with an expression undefined at runtime carrying marker __ABLATION_22877_MEMBER_DROPPED — anchor 1→0, marker 0→1, blob 314afe10d8→a28c0832a6; metadata-protocol rebuilt exit 0; ablation-dist-preflight (present) exit 0; environment-overlay-email-locale-restart.test.ts '3 failed | 3 passed (6)' — two-locale restart pin, bare-name canonical pin and by-name reset pin red, both CONTROLs (single-locale, package bundle) and the backfill case green, the predicted direction. Restore: blob back to 314afe10d8, git diff HEAD empty, JS rebuilt, ablation-dist-preflight --absent exit 0, file '6 passed (6)'. The restore build's DTS step failed transiently (my own gate runner was rebuilding metadata-core's dist at that moment); the JS leg and the absence preflight are what the run read, and every later build (turbo) was green.",
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "3 REST writes in 2 relay dispatches (objectstack-fleet[bot]): POST /repos/objectstack-ai/objectstack/pulls (draft #22954) + POST /repos//issues/22954/assignees (os-steve), one pr_create action, run 38206947497, body read back byte-identical (10537 sent = 10537 stored); POST /repos//issues/22877/comments (this os-dev-report, scripts/pm/post-stamped.mjs). Not REST: git push of the branch (fast-forward of the landing marker, then WIP commits and one merge commit). Zero label writes (none named by the dispatch; a changeset is present, so no skip-changeset). REST reads with the session's gh: GET issues/22877, its comments, pulls/22954.",
    "open_questions": [
    {
    "question": "Release sequencing between stage 1 and stage 2. With stage 1 alone, a by-name DELETE, publish, history or revert with no selector addresses the en-US member: a non-en-US member's overlay is edited by a PUT naming its locale and served by the list and the send path, but it cannot be reset or have its DRAFT published by name until stage 2's selector lands (a pre-fix zh-CN-only overlay row, once backfilled, is no longer removed by a bare DELETE, which answers 'No customization overlay found').",
    "options": [
    "A — land stage 1 when green and dispatch stage 2 next, both in one release (no published window where a non-en-US draft is unpublishable by name)",
    "B — land stage 1 and let stage 2 follow in a later release (the window ships; the changeset states it)",
    "C — hold stage 1 until stage 2 is ready and land them together"
    ],
    "recommendation": "A: stage 1 fixes the measured data loss now, and keeping both stages in one release closes the by-name reach window without holding the fix."
    },
    {
    "question": "The ruling says the version counter 'carries the member'. Implemented: one lineage counter per (org, type, name), shared by the bundle, with history and restoreVersion filtered by member, because sys_metadata_history declares unique (organization_id, type, name, version) and a per-member counter would mint colliding versions under it. Keep it, or re-key the history index too?",
    "options": [
    "A — keep the shared counter (each version names one snapshot; revert to another member's version answers 404 VERSION_NOT_FOUND); no history-table change",
    "B — per-member counter plus a re-key of the history unique index (a second index ceremony on a second table, and a history member column)"
    ],
    "recommendation": "A: it meets what the counter is for (rollback addresses one snapshot) with no second migration; B buys monotonic per-member numbers only."
    }
    ],
    "out_of_scope_findings": [
    "carrier: stage 2 PR of #22877 (member-addressed DELETE) · noted, not filed — registry.removeRuntimeShadow (objectql registry.ts) sweeps a bundle's whole hydrated overlay group, a premise ('the overlay layer is keyed by name alone') this PR retires: a by-name reset of the en-US member drops the zh-CN REGISTRY entry until the next boot, while its row stays and the list and send path keep serving it (pinned in the reset case).",
    "carrier: stage 2 PR of #22877 · noted, not filed — package-batch doors (publishPackageDrafts, discardPackageDrafts, revertCommit commit items) and the cluster mutation fan-out (applyRemoteMetadataMutation) carry no member and address the canonical member; before this PR two members' drafts could not coexist, so their prior behaviour is unchanged.",
    "carrier: 承接者:无 · noted in PR acceptance notes, not filed — packages/drivers/driver-sql/src/sql-driver-overlay-index-drift.test.ts keeps a hand-written four-part overlay index fixture; it tests the drift detector's COALESCE key-part reading and imports nothing changed here, so it stays valid."
    ],
    "gates": [
    {
    "command": "node scripts/check-adr-0087-registration.mjs --base origin/main",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-adr-0087-registration.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-changeset-no-major.mjs --base origin/main",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-changeset-no-major.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-ci-filter-parity.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-closing-keyword-parity.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-closing-keyword-parity.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-comment-mask-adoption.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-comment-mask-adoption.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-comment-mask-corpus.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-dts-emitted.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-empty-changeset.mjs --base origin/main",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-empty-changeset.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-engine-split-ratio.mjs --days 90",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-engine-split-ratio.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-issue-citations.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-keyed-text-bounds.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-keyed-text-bounds.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-platform-object-tenancy-census.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-platform-object-tenancy-census.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-plugin-teardown-shape.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-plugin-teardown-shape.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-registry-log-declared.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-registry-log-declared.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-rest-log-spy-declared.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-rest-log-spy-declared.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-scripts-symbol-anchors.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-scripts-symbol-anchors.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-system-context-census.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-system-context-census.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-undeclared-dep-imports.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/check-undeclared-dep-imports.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/docs-audit/check-affected-docs.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/docs-audit/check-drift-comment.mjs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/pm/release-rehearsal-clone.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "node scripts/release-pending-publish.mjs --self-test",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm --filter @objectstack/spec run check:duration-unit-keys",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm --filter @objectstack/spec run check:empty-state",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm --filter @objectstack/spec run check:liveness",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm --filter @objectstack/spec run check:strictness-ledger",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm --filter @objectstack/spec run check:variant-docs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:agent-test-spelling",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:bash32-floor",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:changeset-gate-self-tests",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:cli-command-ids",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:cross-package-test-inputs",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:dispatcher-error-vocabulary",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:doc-authoring",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:driver-memory-census",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:dts-closure",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:dual-build-cjs-loads",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:durability-log-level",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:engine-double-contract",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:entry-guard",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:error-status-conformance",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:filter-alias-parity",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:gitlink-declared",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:issue-citations",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:lean-entry-closure",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:logger-receiver-detach",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:nul-bytes",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:objectql-double-limit",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:objectui-changeset",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:org-identifier",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:page-declaration-shape",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:parse-guard",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:pm-changeset-deadline-census",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:pnpm-filter-targets",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:published-files",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:query-options-erasure",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:refd-timer-probe",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:slot-lookup",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:sourcemap-no-sources-content",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:test-source-alias",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:tier-file-adoption",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:type-check-coverage",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:type-check-debt",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:watch-hint-literal",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "pnpm check:where-matcher",
    "exit": 0,
    "head": "288ef6fb69"
    },
    {
    "command": "bash scripts/pm/os-verify-lock.sh -c "pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2" (full suite, c7f399b)",
    "exit": 1,
    "note": "1 failed file (lookupArtifactItem call-site census needed the new site recorded) | 226 passed | 3 skipped; 28183 tests passed. Fixed in 59841e1, census re-run 4 passed (exit 0)"
    },
    {
    "command": "bash scripts/pm/os-verify-lock.sh -c "pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2" (full suite, both projects, 59841e1)",
    "exit": 0,
    "note": "Test Files 404 passed, Tests 7864 passed"
    },
    {
    "command": "pnpm --filter @objectstack/metadata exec vitest run --maxWorkers=2 (139a2cb)",
    "exit": 0,
    "note": "58 files, 871 tests passed"
    },
    {
    "command": "typecheck metadata-core / metadata-protocol / objectql (incl. check:test-typecheck) / dogfood (139a2cb)",
    "exit": 0
    },
    {
    "command": "pnpm turbo run build --filter='@objectstack/dogfood^...' --concurrency=2 (139a2cb)",
    "exit": 0,
    "note": "63 tasks, 27 cached"
    },
    {
    "command": "pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/email-template-two-locales-survive-boot.dogfood.test.ts (139a2cb)",
    "exit": 0,
    "note": "3 passed (3), real showcase + SQLite file, real sendTemplate per locale, cold boot"
    },
    {
    "command": "pnpm turbo run build --filter='...@objectstack/objectql' --concurrency=2 (288ef6f)",
    "exit": 0
    },
    {
    "command": "pnpm --filter @objectstack/metadata-core exec vitest run --maxWorkers=2 (288ef6f)",
    "exit": 0,
    "note": "17 files, 394 tests"
    },
    {
    "command": "pnpm --filter @objectstack/metadata-protocol run typecheck (288ef6f)",
    "exit": 0
    },
    {
    "command": "metadata-protocol targeted: overlay-index, sys-metadata-repository.bundle-member, runtime-index-preflight, lookup-artifact-item-call-sites, i18n-bundle-list-merge, item-name-every-door (288ef6f)",
    "exit": 0,
    "note": "6 files, 72 tests"
    },
    {
    "command": "objectql targeted: environment-overlay-email-locale-restart, environment-overlay-five-types, engine-security-catalog-package-door, registry-i18n-bundle-key (288ef6f)",
    "exit": 0,
    "note": "4 files, 65 tests"
    },
    {
    "command": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran2.txt (288ef6f)",
    "exit": 0,
    "note": "79 derived, 79 run, 0 NOT-MEASURED (derived from recorded exit codes), 0 UNRUN"
    },
    {
    "command": "ablation (scripts/ablation-replace.mjs wrap + ablation-dist-preflight, under os-verify-lock)",
    "exit": 0,
    "note": "mutated leg: restart pin file 3 failed | 3 passed (red as predicted); restored leg: 6 passed"
    }
    ],
    "line_budget": "1580 — PR #22954 additions 1515 + deletions 65 (generated included; 14 files)",
    "deviations": [
    "Version counter kept per (org, type, name), not per member (see open question 2): the history table's declared unique (organization_id, type, name, version) forbids per-member numbering without a second index ceremony; history and restoreVersion carry the member instead.",
    "History rows carry no member column: a history row's member is read off its body (a tombstone's off the row it removed via previous_checksum) through the same overlayMemberOfBody; sys-metadata-history.object.ts untouched, so the claimed file surface held.",
    "Ruling premise partly measured false: 'absent, it means the canonical member, which is what the registry's bare-name read answers' — registry.getItem answers a non-canonical overlay when only that member is overlaid (its overlay tier wins before canonical-first, pinned as '#7730 bare-name reads answer the same layer'). Implemented the operative half (absent = canonical member) in protocol getMetaItem (canonical stored row, else the code layer's canonical member via lookupArtifactItem, else the registry as before) rather than editing objectql registry.ts, which is outside the claimed surface. Conflict named, not silently resolved.",
    "Files beyond the four claimed production files are tests and one gate ledger only: two objectql harnesses gained the bundle_member field (the engine refuses an undeclared where field), the lookupArtifactItem call-site census gained one row, runtime-index-preflight.test.ts fixture gained the column, scripts/engine-double-contract.pinned.json gained 3 rows via the gate's own --write. No other production file touched.",
    "Merged origin/main (e357a44) into the branch before opening the PR (AGENTS.md multi-agent §10); scoped re-check run on the merged head.",
    "The worktree was attached to the pre-existing local branch ref left by the first dev (at 45e206e, no commits) and fast-forwarded to origin/main 018b077, instead of creating it with -b; nothing older was merged.",
    "Lock-discipline slip: one early metadata-protocol tsc --noEmit ran outside os-verify-lock; every later build, test and typecheck went through it.",
    "Commits carry the model-free trailer pair AGENTS.md prescribes (Claude-Session + Co-authored-by: Claude) instead of the harness reminder's model-named Co-Authored-By (the reminder yields to the repo's own rule)."
    ],
    "files_changed": [
    ".changeset/22877-overlay-locale-member.md",
    "packages/metadata-core/src/objects/sys-metadata.object.ts",
    "packages/metadata-protocol/src/migrations/overlay-index.ts",
    "packages/metadata-protocol/src/migrations/overlay-index.test.ts",
    "packages/metadata-protocol/src/migrations/runtime-index-preflight.test.ts",
    "packages/metadata-protocol/src/protocol.ts",
    "packages/metadata-protocol/src/protocol.lookup-artifact-item-call-sites.test.ts",
    "packages/metadata-protocol/src/sys-metadata-repository.ts",
    "packages/metadata-protocol/src/sys-metadata-repository.bundle-member.test.ts",
    "packages/objectql/src/environment-overlay-email-locale-restart.test.ts",
    "packages/objectql/src/environment-overlay-five-types.test.ts",
    "packages/objectql/src/engine-security-catalog-package-door.test.ts",
    "packages/qa/dogfood/test/email-template-two-locales-survive-boot.dogfood.test.ts",
    "scripts/engine-double-contract.pinned.json"
    ]
    }


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat answers to stage 1's open questions (PR #22954) · domain:engine#2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T05:17Z

    Report 6118202838 (stage 1, PR #22954, Part of #22877). Both questions are execution parameters inside ruling 6116165299, so the seat answers them here and does not take them to the decision box. The maintainer's veto window applies as usual.

    • Q1, the release sequencing of stage 1 and stage 2: A. Stage 1 lands when green and contract-reviewed, and stage 2 is dispatched next. Stage 1 fixes the measured data loss (both languages survive a restart), so holding it buys nothing. The window between the two is stated in stage 1's changeset: a non-canonical member cannot yet be reset or published by name. This seat runs no release, so "one release for both" is the aim, not a promise; the changeset carries the window either way.
    • Q2, the version counter: A, one lineage counter per (organization, type, name) shared by the bundle; history and revert filtered by member. Measured: sys_metadata_history declares unique (organization_id, type, name, version), so a per-member counter would mint colliding versions unless that index were re-keyed too, a second migration the ruling did not ask for. With the shared counter each version still names exactly one snapshot, and a revert to another member's version answers 404 VERSION_NOT_FOUND. What the ruling protects is that a version carries its member: it addresses one member's snapshot and never a sibling's. Under A it does, and the only visible difference is non-consecutive version numbers within one member. Recorded as the seat's reading of "version counter carries the member", not as a change to the ruling.
    • A premise half-false, recorded. The ruling's "absent means the canonical member, which is what the registry's bare-name read answers" does not hold in the registry: SchemaRegistry.getItem answers a non-canonical overlay when only that member is overlaid, because its overlay tier wins before canonical-first. Stage 1 implements the operative half (absent means canonical) at the protocol's getMetaItem and leaves objectql's registry untouched, as the claim required.
    • Carried to stage 2 (to be claimed after stage 1 lands), each to be measured there:
      1. the registry's bare-name read of a discriminated type resolving the canonical member, which closes the half-false premise above;
      2. registry.removeRuntimeShadow sweeping a bundle's whole hydrated overlay group on a by-name reset (report finding 1);
      3. the package-batch doors (publishPackageDrafts, discardPackageDrafts, revertCommit items) and the cluster mutation fan-out, which carry no member (finding 2);
      4. the by-name member selector itself (Clause-②: yes, packages/rest cross-lane), as ruled.
  9. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22877,
    "status": "done",
    "branch": "claude/issue-22877-locale-bundle-overlay",
    "pr": "#22954",
    "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent of the domain:engine seat 2 PM; parent's id)",
    "round": "patch round 1",
    "new_head": "f21b6f9d24",
    "premise_still_valid": true,
    "summary": "Patch round 1 on PR #22954, new head f21b6f9. Three CI reds, all this PR's, fixed in three commits; no rebase, amend or force-push; origin/main still merges cleanly, so no merge commit was needed. (1) Test Core (1/6), the operatorFacingErrorText census. I KEPT the new call in overlay-index.ts (backfillOverlayBundleMembers' failure detail) and added the row plus a pin, rather than removing the call. Reason: the backfill reads and writes through the engine, and no enumerated site can report its failure. Dropping the helper would leave either the composed envelope sentence (losing the dialect's words, e.g. a missing column) or an uncut message, and the helper is the one cut. Row: overlay-index.ts calls 1, sentinelPin raw-exec-operator-detail-16657.test.ts. Pin: in that file's [#21418] block, the read leg (find, synthetic bound statement) and the write leg (update binds the row id, and the id IS the sentinel). Both assert the sentinel reaches neither result.detail nor the error report, the dialect words survive, and the fault really carried the sentinel. Commit a9f79a3. (2) Type Check consumer gates, check:i18n drift. Measured as this PR's: main e357a44 was green on that job, and the drift is the 4 bundle_member keys only. Regenerated with node scripts/check-i18n-bundles.mjs --write, committed alone as 10f3b68 (7 generated platform-objects files, +22). check:i18n then exits 0. (3) Test Core (3/6), cli duplicates.integration.test.ts. On a sys_metadata table that predates the member column, the overlay pre-flight answered 'unreadable'. Now overlay-index.ts owns two more statements, buildOverlayMemberPresenceSql and buildOverlayDuplicateProbeSqlWithoutMember. The latter groups by the other key parts and projects bundle_member_key as ''. runtime-index-preflight.ts runProbe uses the member-less statement when the column-presence read is refused, and reports the statement that actually ran as the entry's duplicateSql. The report document's keys are unchanged; the test was not weakened. The changeset paragraph and the preflight test moved from 'unreadable' to 'listed, every row the empty member'. Commit f21b6f9. The PR body is now stale in places; see deviations for the edits the seat should make.",
    "fix_chosen": {
    "census": "kept the call; row + sentinel pin (not removal): the engine-level backfill has no enumerated reporting site, and the helper is the one cut",
    "i18n": "regenerated with the repo's command, own commit 10f3b68",
    "duplicates_preflight": "member-less listing on a pre-column table (every row the empty member, what the column will hold), statements owned by overlay-index.ts, chosen in runtime-index-preflight.ts"
    },
    "tests": "Ran under os-verify-lock unless stated, exit codes captured before any pipe. types test:repo 11 passed; types local 754 passed; platform-objects 1083 passed. metadata-protocol: build, typecheck, src/migrations/ 232 passed. cli duplicates*, both tiers: 6 files, 37 passed, including the integration file that was red on 10f3b68. Full packages build exit 0. Gate union on f21b6f9: 81 derived + 11 declared WIDE-population families + check:i18n-coverage / i18n-walk-parity / app-nav-i18n + types test:repo = 96 commands, 96 exit 0 (check:dual-build-cjs-loads now measured: 66 packages). --ran reconciliation: 81 of 81 run, 0 NOT-MEASURED, 0 UNRUN. Before/after for each fix: the census pin and duplicates.integration were red in CI on the old heads (the PM's readings) and are green here; check:i18n exited 1 before the regeneration and 0 after.",
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "1 REST write: POST /repos//issues/22877/comments (this os-dev-report, scripts/pm/post-stamped.mjs, relay). Not REST: git push of the branch (3 commits). REST reads with the session's gh: check-runs for the PR heads and recent main commits, pulls/22954.",
    "open_questions": [],
    "out_of_scope_findings": [],
    "gates": [
    "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
    "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
    "node scripts/check-changeset-no-major.mjs --self-test :: exit 0",
    "node scripts/check-ci-filter-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-corpus.mjs :: exit 0",
    "node scripts/check-dts-emitted.mjs --self-test :: exit 0",
    "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
    "node scripts/check-empty-changeset.mjs --self-test :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --days 90 :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --self-test :: exit 0",
    "node scripts/check-issue-citations.mjs :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0",
    "node scripts/check-registry-log-declared.mjs :: exit 0",
    "node scripts/check-registry-log-declared.mjs --self-test :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0",
    "node scripts/check-scripts-symbol-anchors.mjs :: exit 0",
    "node scripts/check-scripts-symbol-anchors.mjs --self-test :: exit 0",
    "node scripts/check-system-context-census.mjs :: exit 0",
    "node scripts/check-system-context-census.mjs --self-test :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0",
    "node scripts/docs-audit/check-affected-docs.mjs :: exit 0",
    "node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
    "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
    "node scripts/release-pending-publish.mjs --self-test :: exit 0",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
    "pnpm --filter @objectstack/spec run check:empty-state :: exit 0",
    "pnpm --filter @objectstack/spec run check:liveness :: exit 0",
    "pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0",
    "pnpm --filter @objectstack/spec run check:variant-docs :: exit 0",
    "pnpm check:agent-test-spelling :: exit 0",
    "pnpm check:bash32-floor :: exit 0",
    "pnpm check:changeset-gate-self-tests :: exit 0",
    "pnpm check:cli-command-ids :: exit 0",
    "pnpm check:cross-package-test-inputs :: exit 0",
    "pnpm check:dispatcher-error-vocabulary :: exit 0",
    "pnpm check:doc-authoring :: exit 0",
    "pnpm check:driver-memory-census :: exit 0",
    "pnpm check:dts-closure :: exit 0",
    "pnpm check:dual-build-cjs-loads :: exit 0",
    "pnpm check:durability-log-level :: exit 0",
    "pnpm check:engine-double-contract :: exit 0",
    "pnpm check:entry-guard :: exit 0",
    "pnpm check:error-status-conformance :: exit 0",
    "pnpm check:filter-alias-parity :: exit 0",
    "pnpm check:gitlink-declared :: exit 0",
    "pnpm check:i18n :: exit 0",
    "pnpm check:i18n-stale-fill :: exit 0",
    "pnpm check:issue-citations :: exit 0",
    "pnpm check:lean-entry-closure :: exit 0",
    "pnpm check:logger-receiver-detach :: exit 0",
    "pnpm check:nul-bytes :: exit 0",
    "pnpm check:objectql-double-limit :: exit 0",
    "pnpm check:objectui-changeset :: exit 0",
    "pnpm check:org-identifier :: exit 0",
    "pnpm check:page-declaration-shape :: exit 0",
    "pnpm check:parse-guard :: exit 0",
    "pnpm check:pm-changeset-deadline-census :: exit 0",
    "pnpm check:pnpm-filter-targets :: exit 0",
    "pnpm check:published-files :: exit 0",
    "pnpm check:query-options-erasure :: exit 0",
    "pnpm check:refd-timer-probe :: exit 0",
    "pnpm check:slot-lookup :: exit 0",
    "pnpm check:sourcemap-no-sources-content :: exit 0",
    "pnpm check:test-source-alias :: exit 0",
    "pnpm check:tier-file-adoption :: exit 0",
    "pnpm check:type-check-coverage :: exit 0",
    "pnpm check:type-check-debt :: exit 0",
    "pnpm check:watch-hint-literal :: exit 0",
    "pnpm check:where-matcher :: exit 0",
    "pnpm check:init-service-contract :: exit 0",
    "pnpm check:live-db-isolation :: exit 0",
    "pnpm check:meta-type-normalized :: exit 0",
    "pnpm check:optional-error-sink :: exit 0",
    "pnpm check:resume-authority-declared :: exit 0",
    "pnpm check:route-envelope :: exit 0",
    "pnpm check:runner-env-posture :: exit 0",
    "pnpm check:settings-bind-window :: exit 0",
    "pnpm check:startup-registry-verdict :: exit 0",
    "pnpm check:verify-stand-in :: exit 0",
    "pnpm check:wildcard-fallthrough :: exit 0",
    "pnpm check:i18n-coverage :: exit 0",
    "pnpm check:i18n-walk-parity :: exit 0",
    "pnpm check:app-nav-i18n :: exit 0",
    "pnpm --filter @objectstack/types run test:repo :: exit 0",
    "bash scripts/pm/os-verify-lock.sh -c 'pnpm --filter @objectstack/types run test:repo' (a9f79a3 types census state, unchanged since) :: exit 0 (1 file, 11 passed)",
    "pnpm --filter @objectstack/types run test (local project) :: exit 0 (27 files, 754 passed)",
    "pnpm --filter @objectstack/types run typecheck :: exit 0",
    "pnpm --filter @objectstack/platform-objects exec vitest run (10f3b68) :: exit 0 (69 files, 1083 passed)",
    "pnpm exec turbo run build (check-i18n-bundles prerequisite closure, 10 filters) --concurrency=2 :: exit 0 (59 tasks)",
    "node scripts/check-i18n-bundles.mjs (before regeneration, a9f79a3) :: exit 1 (platform-objects DRIFTED (7))",
    "node scripts/check-i18n-bundles.mjs --write :: exit 0",
    "pnpm check:i18n (10f3b68) :: exit 0",
    "pnpm --filter @objectstack/metadata-protocol build (f21b6f9) :: exit 0",
    "pnpm --filter @objectstack/metadata-protocol run typecheck (f21b6f9) :: exit 0",
    "pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2 src/migrations/ (f21b6f9) :: exit 0 (11 passed | 3 skipped files, 232 passed)",
    "pnpm --filter @objectstack/metadata-protocol exec vitest run src/migrations/raw-exec-operator-detail-16657.test.ts src/migrations/overlay-index.test.ts (a9f79a3) :: exit 0 (2 files, 54 passed)",
    "pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 src/commands/migrate/duplicates (both tiers, f21b6f9) :: exit 0 (6 files, 37 passed; includes duplicates.integration.test.ts, red in CI on 10f3b68)",
    "pnpm exec turbo run build --filter='./packages/' --filter='./packages//*' --concurrency=2 (f21b6f9) :: exit 0 (72 tasks)",
    "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran (81 derived, exit-coded, f21b6f9) :: exit 0 (81 run, 0 NOT-MEASURED, 0 UNRUN)"
    ],
    "line_budget": "1823 — PR #22954 at f21b6f9: 1753 additions + 70 deletions, generated included, 24 files (this round 288ef6f..f21b6f9: +247 / -14 over 13 files, of which the 7 generated i18n files are +22)",
    "deviations": [
    "runtime-index-preflight.ts is a production file outside the claim's listed surface (overlay-index.ts, partial-index-probe.ts). I edited it rather than stopping: it is the metadata-protocol module that reads overlay-index's pre-flight statements (same package, same directory, engine lane, not packages/cli), the edit is one function (runProbe) plus a private table, and the statements themselves live in overlay-index.ts per that module's 'every probe statement comes from the migration that owns the index' rule. Named so the seat can rule on it.",
    "The member-less listing reads a pre-column store's rows as the empty member, so an email_template pair whose bodies name different locales could be reported there and then not block after the serving boot's backfill. That is the strict direction, as the PM prescribed.",
    "packages/types/src/driver-error-classification.callers.test.ts is a domain:cli file: one row added to the existing OPERATOR_TEXT_CALLERS list, the pre-declared class of edit the PM named.",
    "The regenerated zh-CN / ja-JP / es-ES bundles carry the English source text for the two new bundle_member keys (merge mode); they still need translating. check:i18n-coverage stays green (none new against its baseline).",
    "PR body edits owed (dev writes the body once; the seat writes later edits): in 'Deviations and residuals', replace the 'os migrate duplicates on a store this version has not booted yet ... unreadable' bullet with: 'On a store this version has not booted yet, the overlay pre-flight lists with every row read as the empty member (the member-less statement, owned by overlay-index.ts), so a duplicate that will block the rebuild is still reported; the entry's duplicateSql is the statement that ran.' Refresh 'Evidence' to cite head f21b6f9 and this round's runs. Add to 'Acceptance notes': the 7 regenerated platform-objects i18n bundles (node scripts/check-i18n-bundles.mjs --write), and the OPERATOR_TEXT_CALLERS row plus its sentinel pin.",
    "The worktree was recreated on the branch for this round (it had been removed after the first report) and removed again afterwards.",
    "types test:repo also ran inside the unlocked gate runner on f21b6f9 as a re-confirmation; the measurement of record is the locked run (the types census file is unchanged since a9f79a3)."
    ],
    "files_changed": [
    ".changeset/22877-overlay-locale-member.md",
    "packages/metadata-protocol/src/migrations/overlay-index.ts",
    "packages/metadata-protocol/src/migrations/runtime-index-preflight.ts",
    "packages/metadata-protocol/src/migrations/runtime-index-preflight.test.ts",
    "packages/metadata-protocol/src/migrations/raw-exec-operator-detail-16657.test.ts",
    "packages/types/src/driver-error-classification.callers.test.ts",
    "packages/platform-objects/src/apps/translations/en.objects.generated.ts (generated)",
    "packages/platform-objects/src/apps/translations/es-ES.objects.generated.ts (generated)",
    "packages/platform-objects/src/apps/translations/es-ES.source-hashes.generated.ts (generated)",
    "packages/platform-objects/src/apps/translations/ja-JP.objects.generated.ts (generated)",
    "packages/platform-objects/src/apps/translations/ja-JP.source-hashes.generated.ts (generated)",
    "packages/platform-objects/src/apps/translations/zh-CN.objects.generated.ts (generated)",
    "packages/platform-objects/src/apps/translations/zh-CN.source-hashes.generated.ts (generated)"
    ]
    }


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    patch round 2
    {
    "issue": 22877,
    "round": "patch round 2",
    "status": "done",
    "branch": "claude/issue-22877-locale-bundle-overlay",
    "pr": "#22954",
    "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent of the domain:engine seat 2 PM; parent's id)",
    "new_head": "4d6105d8ba",
    "merged_origin_main": "246edf5b39",
    "premise_still_valid": true,
    "summary": "Patch round 2 on PR #22954, new head 4d6105d. Two changeset commits: 8a092fa (both notes) and c3a7db0 (one wording correction, made as a new commit because amend is barred). Then one merge of origin/main 246edf5 (merge commit 4d6105d): no conflicts and no os-regen pending. The incoming changes to protocol.ts and sys-metadata-repository.ts are the allowOrgOverride → allowEnvironmentOverlay rename (#22874), in other regions, and the merged tree typechecks and tests green. Note 2 (stage-1 window) is written as asked. Note 1 (fallback dialect): I checked it against the code before writing, and its central claim does not hold, so the changeset states the verified behaviour instead. The review note says a second member's save is refused by the kept four-column declared UNIQUE. In the code, that index is declared unique 'global', so its key parts are the bare columns. Every row the metadata door writes stores organization_id NULL (ADR-0131 D6), and a UNIQUE key does not collide NULLs. This holds both for MySQL's direct index and for driver-sql's #11627 hash shadow: sql-driver.ts createHashShadowUniqueIndex uses CONCAT, and its docblock says 'an any-NULL tuple still conflicts with nothing'. Measured on SQLite, which has the same NULL-distinct UNIQUE semantics, against the four-column UNIQUE: two members of one template with organization_id NULL are both accepted; CONTROL, with a non-NULL organization the second member is refused 'UNIQUE constraint failed'. So on MySQL members coexist and no save is refused. What does hold as reviewed: the old index is kept under its name (syncDeclaredIndexes skips by name), and os migrate plan reports it as an index_mismatch with a destructive recreate_index (schema-drift.ts; its message names 'os migrate apply --allow-destructive'). A fresh store gets the five-column declaration. The changeset says exactly that, with the one-line remedy. Not measured on a live MySQL.",
    "tests": "Under os-verify-lock, on 4d6105d. Build of the cli and dogfood closures plus the i18n prerequisites: exit 0. metadata-protocol targeted: 15 passed | 3 skipped files, 268 passed. objectql restart pin and its siblings: 65 passed. cli duplicates, both tiers: 6 files, 37 passed. types test:repo: 11 passed. Typecheck of metadata-core, metadata-protocol, objectql, types, platform-objects and dogfood: exit 0 each. check:i18n exit 0. The three changeset gates exit 0. Gate union re-derived on the real diff (81 commands): 80 exit 0 on the first pass. check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET in a fresh worktree); after the full packages build (exit 0, all cached) it exits 0. --ran reconciliation: 81 of 81 run, 0 NOT-MEASURED, 0 UNRUN. origin/main has since moved to a2240c4; git merge-tree against it exits 0 (merges clean), so I made no second merge.",
    "mcp_calls": "0",
    "api_writes": "1 REST write: POST /repos//issues/22877/comments (this 'patch round 2' os-dev-report, via scripts/pm/post-stamped.mjs and the relay). Not REST: git push of the branch (2 changeset commits and 1 merge commit). No PR-body write.",
    "open_questions": [],
    "out_of_scope_findings": [],
    "gates": [
    "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
    "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
    "node scripts/check-changeset-no-major.mjs --self-test :: exit 0",
    "node scripts/check-ci-filter-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-corpus.mjs :: exit 0",
    "node scripts/check-dts-emitted.mjs --self-test :: exit 0",
    "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
    "node scripts/check-empty-changeset.mjs --self-test :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --days 90 :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --self-test :: exit 0",
    "node scripts/check-issue-citations.mjs :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0",
    "node scripts/check-registry-log-declared.mjs :: exit 0",
    "node scripts/check-registry-log-declared.mjs --self-test :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0",
    "node scripts/check-scripts-symbol-anchors.mjs :: exit 0",
    "node scripts/check-scripts-symbol-anchors.mjs --self-test :: exit 0",
    "node scripts/check-system-context-census.mjs :: exit 0",
    "node scripts/check-system-context-census.mjs --self-test :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0",
    "node scripts/docs-audit/check-affected-docs.mjs :: exit 0",
    "node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
    "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
    "node scripts/release-pending-publish.mjs --self-test :: exit 0",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
    "pnpm --filter @objectstack/spec run check:empty-state :: exit 0",
    "pnpm --filter @objectstack/spec run check:liveness :: exit 0",
    "pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0",
    "pnpm --filter @objectstack/spec run check:variant-docs :: exit 0",
    "pnpm check:agent-test-spelling :: exit 0",
    "pnpm check:bash32-floor :: exit 0",
    "pnpm check:changeset-gate-self-tests :: exit 0",
    "pnpm check:cli-command-ids :: exit 0",
    "pnpm check:cross-package-test-inputs :: exit 0",
    "pnpm check:dispatcher-error-vocabulary :: exit 0",
    "pnpm check:doc-authoring :: exit 0",
    "pnpm check:driver-memory-census :: exit 0",
    "pnpm check:dts-closure :: exit 0",
    "pnpm check:dual-build-cjs-loads :: exit 0",
    "pnpm check:durability-log-level :: exit 0",
    "pnpm check:engine-double-contract :: exit 0",
    "pnpm check:entry-guard :: exit 0",
    "pnpm check:error-status-conformance :: exit 0",
    "pnpm check:filter-alias-parity :: exit 0",
    "pnpm check:gitlink-declared :: exit 0",
    "pnpm check:i18n :: exit 0",
    "pnpm check:i18n-stale-fill :: exit 0",
    "pnpm check:issue-citations :: exit 0",
    "pnpm check:lean-entry-closure :: exit 0",
    "pnpm check:logger-receiver-detach :: exit 0",
    "pnpm check:nul-bytes :: exit 0",
    "pnpm check:objectql-double-limit :: exit 0",
    "pnpm check:objectui-changeset :: exit 0",
    "pnpm check:org-identifier :: exit 0",
    "pnpm check:page-declaration-shape :: exit 0",
    "pnpm check:parse-guard :: exit 0",
    "pnpm check:pm-changeset-deadline-census :: exit 0",
    "pnpm check:pnpm-filter-targets :: exit 0",
    "pnpm check:published-files :: exit 0",
    "pnpm check:query-options-erasure :: exit 0",
    "pnpm check:refd-timer-probe :: exit 0",
    "pnpm check:slot-lookup :: exit 0",
    "pnpm check:sourcemap-no-sources-content :: exit 0",
    "pnpm check:test-source-alias :: exit 0",
    "pnpm check:tier-file-adoption :: exit 0",
    "pnpm check:type-check-coverage :: exit 0",
    "pnpm check:type-check-debt :: exit 0",
    "pnpm check:watch-hint-literal :: exit 0",
    "pnpm check:where-matcher :: exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
    "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0 (no declared-breaking changeset)",
    "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
    "pnpm check:i18n :: exit 0",
    "os-verify-lock: pnpm exec turbo run build (cli + dogfood closures + i18n prerequisite packages) :: exit 0 (66 tasks)",
    "os-verify-lock: metadata-protocol vitest src/migrations/ + sys-metadata-repository.bundle-member + protocol.lookup-artifact-item-call-sites + protocol.i18n-bundle-list-merge + protocol.item-name-every-door :: exit 0 (15 passed | 3 skipped files, 268 passed)",
    "os-verify-lock: objectql vitest environment-overlay-email-locale-restart + environment-overlay-five-types + engine-security-catalog-package-door + registry-i18n-bundle-key :: exit 0 (4 files, 65 passed)",
    "os-verify-lock: cli vitest src/commands/migrate/duplicates (both tiers) :: exit 0 (6 files, 37 passed)",
    "os-verify-lock: pnpm --filter @objectstack/types run test:repo :: exit 0 (11 passed)",
    "os-verify-lock: typecheck metadata-core / metadata-protocol / objectql / types / platform-objects / dogfood :: exit 0 each",
    "os-verify-lock: pnpm exec turbo run build --filter='./packages/' --filter='./packages//' :: exit 0 (72 tasks, all cached)",
    "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran (exit-coded) :: exit 0 (81 derived, 81 run, 0 NOT-MEASURED, 0 UNRUN)",
    "node probe/old-index.mjs (scratch measurement, not committed) :: exit 0"
    ],
    "line_budget": "1825 — PR #22954 at 4d6105d: 1755 additions + 70 deletions, generated included, 24 files (this round: .changeset/22877-overlay-locale-member.md +3 / -1; the merge adds no PR-diff lines)",
    "deviations": [
    "Note 1 is not written as the review phrased it. The review says a second member's save is refused by the kept four-column UNIQUE on MySQL. Verified against driver-sql (key parts are bare columns under unique 'global'; the hash shadow uses CONCAT, which is NULL for any NULL part) and measured on SQLite's identical NULL-distinct semantics: environment-wide rows (organization_id NULL, the only rows the door writes since ADR-0131 D6) never collide under that index, so no save is refused there. The changeset instead says the index is kept, that it never constrained environment-wide rows, that languages coexist and no save is refused, that os migrate plan lists a destructive recreate_index, the remedy 'os migrate apply --allow-destructive', and that a fresh store gets the five-column declaration. The seat should check this reading against the review record; not measured on a live MySQL.",
    "Two changeset commits instead of one: c3a7db0 corrects 'reported at boot' to 'reported in the server log at the first metadata write' (ensureOverlayIndex runs at the first write), as a new commit because amend is barred.",
    "Merged origin/main 246edf5. main has since moved to a2240c4; it merges clean (merge-tree exit 0), so I did not merge a second time.",
    "check:dual-build-cjs-loads needed the full packages build in the fresh worktree (first pass exit 3, NOT MEASURED); re-run after the build: exit 0.",
    "Worktree recreated for this round and removed afterwards; the changeset gates and check:i18n ran outside the lock (they are check:
    scripts)."
    ],
    "files_changed": [
    ".changeset/22877-overlay-locale-member.md"
    ]
    }


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR #22954 at 4d6105d8ba (stage 1 of 2). Arming held on #22949's fix

    domain:engine seat 2 (#20966) · os-steve · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T08:02Z. Ruling 6116165299 (A, Q2 i) binds. The seat's answers are in 6118224899. Claim 6116768302. Reports: 6118202838, patch round 1 6119103318, patch round 2 6119963033. Checked on GitHub rather than taken from the reports. Classes, positions and functions only.

    • Form:
      • draft to main, assignee os-steve;
      • line 1 Part of #22877: stage 2 (the by-name selector) completes the card;
      • line 2 Clause-②: no, matching the claim and the changeset.
    • Scope:
      • 24 files, +1755 / −70, of which 7 are generated platform-objects translation bundles;
      • none governed;
      • nothing under content/docs/releases/;
      • runtime-index-preflight.ts (in lane, same package and directory) and one domain:cli census row with its pin in metadata-protocol are accepted deviations.
    • Fix, read in the diff:
      • sys_metadata gains a nullable member column, where NULL is canonical and name-only types stay byte-identical;
      • the declared index and both runtime partial indexes are re-keyed through the existing probe-then-replace ceremony, a strict relaxation, so no row already stored can block it;
      • an idempotent backfill gives pre-column rows the member their body names;
      • the repository and the save door address one member, taken from the body;
      • by-name doors with no selector address the canonical member;
      • the version counter stays shared, and no history or revert path reaches a sibling.
    • Patch rounds:
      • round 1 fixed the PR's three own CI reds: the caller census row and sentinel pin, the regenerated i18n bundles, and the os migrate duplicates pre-flight on a store that predates the column;
      • round 2 added the stage-2 window sentence and the verified fallback-dialect paragraph to the changeset, and merged main.
    • Evidence:
      • the ruling's pins on real code: two locales survive a restart; single-locale and package-bundle CONTROLs; a bare-name read answers the canonical member; a duplicate (type, name, member) is refused on real SQLite; other types are byte-identical;
      • the showcase dogfood on a real SQLite file;
      • an ablation of the write head reddened exactly the three member pins;
      • 81 derived gate commands, all exit 0.
    • CI on 4d6105d8ba: 42 runs, 35 success, 5 skipped, 2 failure. Both reds are only the timing gates: Test Core (6/6)'s drift step (ci: PR-time Test Core (6/6) reds on shard-timing-drift at 1.60–1.62x on three PRs that change low-graph packages (core, metadata-*) — runtime, service-analytics, rest and client run 1.4–2.4x their refreshed weights #22966) and the aggregator's suite-duration ceilings (ci: merge-queue Test Core reds on the new suite-duration ceiling — @objectstack/cloud-connection measured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since 1bd612bd6) #22949, ruled C2, fix PR ci: Test Core's two timing gates exit-grade on schedule alone (C2), with a 20s ceiling floor #22973).
    • Contract review:
      • PASS on f21b6f9d24 (6119363786);
      • delta PASS on 4d6105d8ba (on the PR), which supersedes the prior record's fallback-dialect sentences: metadata-door rows store no organization, and the four-column UNIQUE never collides NULLs, so on that dialect two members coexist and no save is refused;
      • the seat's own sentence that repeated the false reading is corrected in place.
    • Out-of-scope findings and carried items (Acceptance notes; none is a new filing class):
      • stage 2 carries removeRuntimeShadow's whole-group sweep, the cluster mutation's canonical re-read, and the package-batch doors;
      • the zh-CN / ja-JP / es-ES text for the two new keys is owed to the area:i18n lane;
      • ADR-0005's four-part key spelling is Tier H, the maintainer's hand, and is filed at landing, when it becomes false on main.

    Landing: held. Arming happens on the first head whose required contexts are all success, after PR #22973 lands. The dev merges main once at that point if it has moved, and the seat confirms that the net diff is unchanged before arming. Stage 2 (the selector, Clause-②: yes, packages/rest cross-lane) is claimed after this lands.

  12. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    patch round 3 (merge of main after #22973)
    {
    "issue": 22877,
    "round": "patch round 3 (merge of main after #22973)",
    "status": "done",
    "branch": "claude/issue-22877-locale-bundle-overlay",
    "pr": "#22954",
    "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent of the domain:engine seat 2 PM; parent's id)",
    "new_head": "4a1e80ae7c",
    "merged_origin_main": "eede467f3d",
    "eede467f3d_in_origin_main": "git merge-base --is-ancestor eede467 origin/main :: exit 0",
    "summary": "Merged origin/main eede467 (the #22949 timing-step fix, PR #22973) into the branch as 4a1e80a and pushed. No conflicts, no os-regen pending; the 5 incoming commits touch none of the PR's files. Net diff unchanged. Nothing else changed.",
    "diff_stat": "git diff origin/main...HEAD --stat :: 24 files changed, 1755 insertions(+), 70 deletions(-)",
    "gates": [
    "os-verify-lock: turbo build (cli + dogfood closures + i18n prerequisites) :: exit 0 (66 tasks, 54 cached)",
    "os-verify-lock: metadata-protocol targeted (src/migrations/, sys-metadata-repository.bundle-member, protocol.lookup-artifact-item-call-sites, protocol.i18n-bundle-list-merge, protocol.item-name-every-door) :: exit 0 (268 passed, 19 skipped)",
    "os-verify-lock: objectql environment-overlay-email-locale-restart + five-types + engine-security-catalog-package-door + registry-i18n-bundle-key :: exit 0 (65 passed)",
    "os-verify-lock: cli src/commands/migrate/duplicates, both tiers :: exit 0 (6 files, 37 passed)",
    "os-verify-lock: pnpm --filter @objectstack/types run test:repo :: exit 0 (11 passed)",
    "os-verify-lock: pnpm check:i18n :: exit 0",
    "os-verify-lock: typecheck metadata-core / metadata-protocol / objectql / types / platform-objects / dogfood :: exit 0 each"
    ],
    "line_budget": "1825 — 1755 additions + 70 deletions, 24 files (unchanged)",
    "mcp_calls": "0",
    "api_writes": "1 REST write: POST issues/22877/comments (this report, post-stamped via the relay). Not REST: git push of 1 merge commit.",
    "deviations": [
    "The worktree was recreated for this round and removed afterwards."
    ],
    "files_changed": []
    }


    Generated by Claude Code

  13. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Armed: PR #22954 at 4a1e80ae7c · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T09:02Z. The landing hold in the ACCEPT is lifted.

  14. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: stage 1, PR #22954 → 5677add93f · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T09:29Z

    • Merge: the merge queue merged PR fix(metadata-protocol): two locales of one email template survive a restart — sys_metadata overlay rows keyed by bundle member (#22877, stage 1) #22954 at 2026-10-12T09:28Z as 5677add93fd12ca6ff41a42f82b0448f9c5750fe, with one parent, 6a7eca6868. ACCEPT 6120204973. Contract reviews PASS: 6119363786 on f21b6f9d24, and the delta on 4d6105d8ba, which supersedes the fallback-dialect sentences. Arming note 6121085402.
    • On main at that commit: the squash carries the accepted change exactly. All 24 files carry hunks identical to the armed head 4a1e80ae7c (+1755 / −70).
    • What main now holds: two locales of one email_template saved through the metadata door are two sys_metadata rows (bundle_member), and both survive a restart. By-name doors with no selector address the en-US member.
    • Card: stays open. The PR read Part of #22877, and stage 2 (the by-name member selector) completes it. pm:dispatched and the assignee stay, for stage 2's claim.
    • Filed at landing, as the ACCEPT recorded: ADR-0005's present-tense overlay key (four parts) is now false on main. Card follows.
    • Carried to stage 2:
      • the selector;
      • the registry's bare read (SchemaRegistry.getItem's tier order);
      • removeRuntimeShadow's whole-group sweep;
      • the cluster mutation's canonical re-read;
      • the package-batch doors;
      • the untranslated bundle_member keys, owed to area:i18n.
  15. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-12T12:08Z · stage 2 of 2
    Session: session_01ADzJtzYTLUfgrRZHxkagkX
    Account: os-steve (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22877-member-selector (new: stage 1's branch merged as 5677add93f and is not reused)
    Worktree: objectstack-issue-22877-s2
    Domain: domain:engine
    Seat: domain:engine#2 (seat post #20966); the lane's only seated PM
    Ruling-ref: 6116165299 (letter A, Q2 i). Its workload line places both stages in domain:engine. Seat answers 6118224899; carried items in landing record 6121513183.
    File surface (read on origin/main 0ede0f8ab3; stop on a breach and explain it in the report). ⛔ Classes, positions and functions only, in every artefact.

  16. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22877,
    "status": "done",
    "branch": "claude/issue-22877-member-selector",
    "pr": "#23070",
    "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent of the domain:engine seat 2 PM; the parent's id)",
    "premise_still_valid": true,
    "summary": "Stage 2 of ruling 6116165299 (A, Q2 i) delivered as draft PR #23070 (Fixes #22877, Clause-② yes, head 2b882e6, +1375/-105, 14 files). The five by-name /meta doors (GET, DELETE, /history, /publish, /rollback) accept ONE bundle member through member (the stored column's concept, never locale). The protocol reads it once (resolveBundleMemberSelector: absent = canonical; a selector on a type with no discriminator, a non-string, a blank or a value over the column's 100 characters is a located 400 VALIDATION_ERROR). Each REST route now opens with a measured closed query set, and the four spec requests (Get/Delete/Publish/HistoryMetaItemRequest) gain an optional member; rollback has no declared request. The carried items are built: SchemaRegistry.getItem's bare-name read answers the canonical member across tiers; removeRuntimeShadow/removeOverlayEntry and the protocol heal address one member; publishPackageDrafts, discardPackageDrafts, revertCommit and the cluster fan-out (MetadataMutationEvent.member) carry it. The showcase dogfood found one defect in the first cut — a hydrated overlay of a member the package does not ship wears the bundle's artifact envelope, so the heal left it serving until restart — fixed (a member's shadow is lifted while the bundle ships any artifact) and pinned in the objectql harness with a versioned package. Measured absent-member answers: GET 404 (item undefined), DELETE reset:false, publish 404 NO_DRAFT, history events [], revert 404 VERSION_NOT_FOUND.",
    "tests": "All heavy runs under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0 each); exit codes captured before any pipe. objectql full: 'Test Files 407 passed (407)', 'Tests 7955 passed' (before the last registry commit 2b882e6); after it, the 13 objectql files naming removeRuntimeShadow/removeOverlayEntry/email_template '246 passed' and restart harness + registry bundle file '40 passed'. metadata-protocol full at 12b4b50: 'Test Files 228 passed | 3 skipped (231)', 'Tests 28196 passed | 19 skipped'. rest full at 00886e1 (the main merge touched no rest file): 'Test Files 279 passed (279)', 'Tests 5960 passed | 327 skipped'; after the merge 6 targeted rest files '141 passed'. spec protocol.test.ts + type-alias-convention.pin.test.ts '187 passed'. typecheck exit 0: spec, metadata-protocol, objectql (+check:test-typecheck), rest (+check:test-typecheck), dogfood. dogfood email-template-two-locales-survive-boot.dogfood.test.ts '4 passed (4)' after objectql rebuilt at 2b882e6 (also measures that the showcase's /meta item read is RestServer's route). eslint --no-inline-config --format json over the 11 changed .ts files: 11 linted, 0 errors, 0 warnings; population = eslint.config.mjs files ['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}'] minus NEVER_LINTED; no type-aware linting (no parserOptions.project), so untouched files' verdicts cannot move. Ablations (scripts/ablation-replace.mjs wrap mode on committed HEAD fdf01eb: anchor 1->0, blob changed, restored blob == HEAD, git diff HEAD empty; metadata-protocol rebuilt with ablation-dist-preflight present then --absent): (1) rollbackMetaItem member dropped (marker __ABLATION_22877_ROLLBACK_MEMBER_DROPPED): harness '1 failed | 17 passed', only the member-revert pin red ('No history row at version 2 ... (its canonical member)'), bare-name revert CONTROL green; restored '18 passed'. (2) registry tier order reverted (__ABLATION_22877_REGISTRY_TIER_ORDER, objectql src): '1 failed | 38 passed', only the bare-name canonical registry pin red (the harness's protocol-level bare-name pins stay green because getMetaItem answers the canonical artifact before the registry); restored '39 passed'. (3) heal member dropped: '3 failed | 15 passed' (DELETE by member, DELETE reverse, cluster member reset); restored '18 passed'. (4) batch publish member dropped: batch answered refused / NO_DRAFT 'No pending draft exists for email_template/acme.welcome — nothing to publish.'; batch discard member dropped: discard answered success while the zh-CN draft stayed; both restored, dist absent.",
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "3 REST writes in 2 relay dispatches (objectstack-fleet[bot]): POST /repos/objectstack-ai/objectstack/pulls (draft #23070) + POST /repos//issues/23070/assignees (os-steve) as one pr_create action, run 38273402759, body read back byte-identical (19409 sent = 19409 stored); POST /repos//issues/22877/comments (this os-dev-report, scripts/pm/post-stamped.mjs). Not REST: git push of the branch (the empty landing marker, then commits and one merge of main). Zero label writes (the dispatch forbade them). REST reads with the session's gh: issues/22877 and its comments, pulls/23070.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 (the runtime lane) · noted in the PR's acceptance notes, not filed — packages/runtime/src/domains/meta.ts (the runtime dispatcher's /meta item read) does not read ?member=: a host served by the dispatcher alone would answer GET ...?member=zh-CN with the canonical member, since that transport has no closed query set at all. Outside the claim's surface; not measured on a dispatcher-only host (the showcase is served by RestServer, measured by the dogfood case). dedupe words: dispatcher meta member selector; runtime domains meta query; member selector transport parity",
    "carrier: 承接者:无 · noted, not filed — GET /meta/_drafts and GET /packages/:id/commits keep their declared shapes and do not serve member (the ruling widened the doors' accept set, not these responses), so two drafts or plan items of one template in two languages read as two entries with the same type and name; Studio's DraftChangesPanel would fetch the canonical body for both (not measured in a browser). dedupe words: drafts list bundle member; commit timeline member; DraftChangesPanel locale",
    "carrier: 承接者:无 · noted — the by-name doors outside the ruling's list (/diff, /layers, /audit, /published, /references) stay canonical-only; the deprecated ?layers= spelling refuses ?member= with a 400 rather than answering the canonical member's layers.",
    "carrier: 承接者:无 · noted — the MetadataService (MetadataManager) keys a type's items by name alone, so for a bundle it holds one member (the last registered); getMetaItem and the registry heal now accept its answer only when it is the addressed member. Pre-existing; the service is unchanged.",
    "carrier: 承接者:无 · noted — the selector's VALUE refusal is raised by the protocol and rendered by the REST door's one error door (handleRouteError) in the flat position (body.code VALIDATION_ERROR, body.error the sentence), while the route's own recognition refusal of a misspelled name is nested (body.error.code); the existing split check:route-envelope ratchets repo-wide, same code on both."
    ],
    "gates": [
    "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
    "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
    "node scripts/check-changeset-no-major.mjs --self-test :: exit 0",
    "node scripts/check-ci-filter-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-corpus.mjs :: exit 0",
    "node scripts/check-dev-prereqs.mjs --self-test :: exit 0",
    "node scripts/check-doc-frontmatter.mjs :: exit 0",
    "node scripts/check-doc-frontmatter.mjs --self-test :: exit 0",
    "node scripts/check-doc-route-spelling.mjs --advisory :: exit 0",
    "node scripts/check-doc-route-spelling.mjs --self-test :: exit 0",
    "node scripts/check-docs-section-name.mjs :: exit 0",
    "node scripts/check-docs-section-name.mjs --self-test :: exit 0",
    "node scripts/check-dts-emitted.mjs --self-test :: exit 0",
    "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
    "node scripts/check-empty-changeset.mjs --self-test :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --days 90 :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --self-test :: exit 0",
    "node scripts/check-issue-citations.mjs :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0",
    "node scripts/check-registry-log-declared.mjs :: exit 0",
    "node scripts/check-registry-log-declared.mjs --self-test :: exit 0",
    "node scripts/check-rest-log-declared.mjs :: exit 0",
    "node scripts/check-rest-log-declared.mjs --self-test :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0",
    "node scripts/check-section-landing-index.mjs :: exit 0",
    "node scripts/check-section-landing-index.mjs --self-test :: exit 0",
    "node scripts/check-spec-docblock-symbol-anchors.mjs :: exit 0",
    "node scripts/check-spec-docblock-symbol-anchors.mjs --self-test :: exit 0",
    "node scripts/check-system-context-census.mjs :: exit 0",
    "node scripts/check-system-context-census.mjs --self-test :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0",
    "node scripts/docs-audit/check-affected-docs.mjs :: exit 0",
    "node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
    "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
    "node scripts/release-pending-publish.mjs --self-test :: exit 0",
    "pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0",
    "pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0",
    "pnpm --filter @objectstack/spec run check:api-surface :: exit 0",
    "pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0",
    "pnpm --filter @objectstack/spec run check:browser-reachable-entries :: exit 0",
    "pnpm --filter @objectstack/spec run check:docs :: exit 0",
    "pnpm --filter @objectstack/spec run check:dual-source-exports :: exit 0",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
    "pnpm --filter @objectstack/spec run check:empty-state :: exit 0",
    "pnpm --filter @objectstack/spec run check:entry-nameability :: exit 0",
    "pnpm --filter @objectstack/spec run check:export-origins :: exit 0",
    "pnpm --filter @objectstack/spec run check:exported-any :: exit 0",
    "pnpm --filter @objectstack/spec run check:generated :: exit 0",
    "pnpm --filter @objectstack/spec run check:liveness :: exit 0",
    "pnpm --filter @objectstack/spec run check:llms-txt :: exit 0",
    "pnpm --filter @objectstack/spec run check:objectui-pin-citations :: exit 0",
    "pnpm --filter @objectstack/spec run check:skill-examples :: exit 0",
    "pnpm --filter @objectstack/spec run check:skill-refs :: exit 0",
    "pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0",
    "pnpm --filter @objectstack/spec run check:variant-docs :: exit 0",
    "pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0",
    "pnpm check:authz-resolver :: exit 0",
    "pnpm check:changeset-gate-self-tests :: exit 0",
    "pnpm check:corpus-claim-drift :: exit 0",
    "pnpm check:cross-package-test-inputs :: exit 0",
    "pnpm check:dispatcher-error-vocabulary :: exit 0",
    "pnpm check:doc-anchors :: exit 0",
    "pnpm check:doc-authoring :: exit 0",
    "pnpm check:docs-audit-scope :: exit 0",
    "pnpm check:docs-redirects :: exit 0",
    "pnpm check:docs-single-h1 :: exit 0",
    "pnpm check:docs-spec-enumerations :: exit 0",
    "pnpm check:docs-transcript-drift :: exit 0",
    "pnpm check:driver-memory-census :: exit 0",
    "pnpm check:dts-closure :: exit 0",
    "pnpm check:dual-build-cjs-loads :: exit 0",
    "pnpm check:durability-log-level :: exit 0",
    "pnpm check:engine-double-contract :: exit 0",
    "pnpm check:error-status-conformance :: exit 0",
    "pnpm check:filter-alias-parity :: exit 0",
    "pnpm check:gitlink-declared :: exit 0",
    "pnpm check:issue-citations :: exit 0",
    "pnpm check:lean-entry-closure :: exit 0",
    "pnpm check:logger-receiver-detach :: exit 0",
    "pnpm check:merge-driver :: exit 0",
    "pnpm check:nul-bytes :: exit 0",
    "pnpm check:objectql-double-limit :: exit 0",
    "pnpm check:objectui-changeset :: exit 0",
    "pnpm check:org-identifier :: exit 0",
    "pnpm check:page-declaration-shape :: exit 0",
    "pnpm check:pm-changeset-deadline-census :: exit 0",
    "pnpm check:pm-prior-rulings :: exit 0",
    "pnpm check:published-files :: exit 0",
    "pnpm check:published-readme-links :: exit 0",
    "pnpm check:query-options-erasure :: exit 0",
    "pnpm check:quick-reference-counts :: exit 0",
    "pnpm check:react-page-adapter-contract :: exit 0",
    "pnpm check:refd-timer-probe :: exit 0",
    "pnpm check:role-word :: exit 0",
    "pnpm check:route-envelope :: exit 0",
    "pnpm check:skill-identifier-liveness :: exit 0",
    "pnpm check:slot-lookup :: exit 0",
    "pnpm check:sourcemap-no-sources-content :: exit 0",
    "pnpm check:spec-parsed-alias :: exit 0",
    "pnpm check:test-source-alias :: exit 0",
    "pnpm check:tier-file-adoption :: exit 0",
    "pnpm check:type-check-coverage :: exit 0",
    "pnpm check:type-check-debt :: exit 0",
    "pnpm check:vendor-version-stamps :: exit 0",
    "pnpm check:watch-hint-literal :: exit 0",
    "pnpm check:where-matcher :: exit 0"
    ],
    "gates_reconciliation": "node scripts/pm/dispatch-gates.mjs --ran (exit codes recorded) at 2b882e6: 118 derived, 118 run, 0 NOT-MEASURED, 0 UNRUN; the lead list (86 at 0ede0f8) is a subset. An earlier round at 12b4b50 had check:skill-examples and check:dual-build-cjs-loads at exit 3 (PREREQUISITE NOT MET); after a full packages build (turbo 72 tasks, exit 0) both pass and the final round has them at exit 0.",
    "line_budget": "+1375 / -105 = 1480 changed lines in 14 files (PR #23070 as GitHub counts it); within the ruled 1-1.5k estimate (precedents PR #6770, PR #11031); under the 3,000-line Tier H threshold, no split.",
    "deviations": [
    "File surface: all edits are inside the claim's listed files, plus protocol.lookup-artifact-item-call-sites.test.ts (its census records the re-scoped artifact-lookup site and the definition's new member parameter) and two regenerated artifacts (packages/spec/authorable-surface/api.json, content/docs/references/api/protocol.mdx).",
    "removeRuntimeShadow with a named member keeps the artifact test at the level of the NAME (any member's artifact), not the member — found by the showcase dogfood (a hydrated overlay of an unshipped member wears the bundle's artifact envelope, so removeOverlayEntry refuses it as code); pinned in the objectql harness, whose package is now versioned so its artifacts carry the envelope.",
    "Response contracts unchanged by choice: the repository's draft headers and the stored commit plan carry member, and the protocol's listDrafts/listCommits serve their declared keys only (see out_of_scope_findings 2).",
    "No RollbackMetaItemRequestSchema was added: none exists in packages/spec, and the REST door calls rollbackMetaItem through a cast; the field was added only where the protocol request is declared.",
    "Test-suite heads: objectql full ran before the last registry commit (then targeted reruns at 2b882e6); rest full ran pre-merge at 00886e1 (the merge touched no rest file; targeted rest reruns after); metadata-protocol full at the merge 12b4b50. CI runs the full set on the PR.",
    "Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer; AGENTS.md (the user's instruction, enforced by the pre-push hook) requires the model-free trailer pair and the session-URL footer, so those were used.",
    "PR body line 3 states what widens (the dispatch asked for a line saying what widens after the Clause-② line)."
    ],
    "files_changed": [
    ".changeset/22877-member-selector.md",
    "content/docs/references/api/protocol.mdx",
    "packages/metadata-protocol/src/protocol.bundle-member-selector.test.ts",
    "packages/metadata-protocol/src/protocol.lookup-artifact-item-call-sites.test.ts",
    "packages/metadata-protocol/src/protocol.ts",
    "packages/metadata-protocol/src/sys-metadata-repository.ts",
    "packages/objectql/src/environment-overlay-email-locale-restart.test.ts",
    "packages/objectql/src/registry-i18n-bundle-key.test.ts",
    "packages/objectql/src/registry.ts",
    "packages/qa/dogfood/test/email-template-two-locales-survive-boot.dogfood.test.ts",
    "packages/rest/src/rest-server-meta-member-selector.test.ts",
    "packages/rest/src/rest-server.ts",
    "packages/spec/authorable-surface/api.json",
    "packages/spec/src/api/protocol.zod.ts"
    ]
    }

  17. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat note: PR #23070's contract review is FAIL on 2b882e6774, and patch round 1 is asked · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T16:13Z

    This concerns report 6127796890 (stage 2). The record is 6128093700 on the PR. The seat re-read its blocking finding.

    Blocking, in ②. @objectstack/objectql is graded patch. But the exported SchemaRegistry gains an optional member argument on public methods, and the WHICH LEVEL rule (batch #35 on #15294) grades an additive widening at least minor. The PR body's Widens: line also omits three additive items:

    • MetadataMutationEvent.member;
    • listDrafts' member header;
    • the registry methods' argument.

    The dev is asked to fix the changeset level and the PR body. No code change is asked. A delta contract review then runs on the new head.

    Holding at this head, per the record's ①:

    • the name member (the discriminator field is locale, the forbidden one);
    • the five closed query sets, re-measured from each handler's read points;
    • the four located 400s;
    • the four spec request fields, with the regenerated surface;
    • the registry's canonical bare read;
    • removeRuntimeShadow at name level;
    • the package-batch doors and the cluster event;
    • the answers for an absent member.

    Follow-ups, filed at this PR's ACCEPT (the out-of-scope findings, two families):

    1. The member selector's transport parity:
      • the runtime dispatcher's /meta item GET neither declares a closed set nor forwards ?member=;
      • PUT /meta/:type/:name declares no closed set, so ?member= there is dropped silently;
      • the remaining by-name doors (/diff, /layers, /audit, /published, /references) have no closed sets either.
    2. The drafts and commits lists, and Studio and client member addressing: two drafts of one name in two languages read as identical entries.
  18. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22877,
    "status": "done",
    "round": "patch round 1",
    "branch": "claude/issue-22877-member-selector",
    "pr": "#23070",
    "new_head": "2c055c088f",
    "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent of the domain:engine seat 2 PM; the parent's id)",
    "premise_still_valid": true,
    "summary": "Patch round 1 on PR #23070 answers contract review 6128093700 (FAIL on 2b882e6). The new head is 2c055c0: one fast-forward commit on 2b882e6, with no rebase, amend, force-push or main merge. The PR is not conflicting: GitHub answered mergeable true, state blocked, on this head's first read, and unknown on a later read while it recomputed. (1) The blocking ② finding is fixed in .changeset/22877-member-selector.md. @objectstack/objectql goes from patch to minor. The changeset gains a section, 'For code that uses these packages directly', which says what a consumer can now pass or read: SchemaRegistry's optional last argument member on getItem, getArtifactItem, removeRuntimeShadow and removeOverlayEntry, including what each answers and getItem's bare-name canonical answer; the optional MetadataMutationEvent.member and the ClusterMetadataMutationPayload that carries it; and the optional member on SysMetadataRepository.listDrafts entries, which GET /meta/_drafts does not serve. (2) The PR body's Widens: line was NOT patched by this dev. .claude/agents/os-dev.md says the dev writes the PR body once, at pr_create, never PATCHes it, and names later edits in its report for the seat to write. That conflicts with the round's instruction ('the PR body update through the relay'), and the role file wins. The replacement body is ready, see deviations. (3) CI: no shard has gone red on either head. On 2b882e6, Test Core 1/6 and 5/6 concluded success; 2/6, 3/6, 4/6 and 6/6 were cancelled by this round's push, none red. On 2c055c0, at this report: Test Core 1/6, 5/6 and 6/6 success; 2/6, 3/6 and 4/6 in_progress; every other check success or skipped (Lint & Repo Gates, TypeScript Type Check, Build Core, Check Changeset, Governed Surface Queue Guard included). Code is unchanged, so no test was re-run.",
    "fix_chosen": {
    "changeset_level": "@objectstack/objectql: patch -> minor (an additive widening of SchemaRegistry, which the package index exports; the WHICH LEVEL rule grades it at least minor)",
    "changeset_text": "a section naming each additive public surface and what a consumer can pass or read: SchemaRegistry's member argument (four methods), MetadataMutationEvent.member, and the SysMetadataRepository.listDrafts member header",
    "pr_body": "prepared, not written (role-file rule); see deviations"
    },
    "tests": "No code changed this round, so no suite or ablation was re-run; round 0's records stand (os-dev-report 6127796890). Gate union re-derived on the new head: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 2c055c0 gives 118 commands, the same set as round 0; all 118 exit 0. Reconciled with --ran (exit codes recorded): '118 derived, 118 run, 0 NOT-MEASURED, 0 UNRUN'. The changeset gates are included: check-changeset-no-major --base origin/main and --self-test, check-empty-changeset, check-adr-0087-registration, check:pm-changeset-deadline-census, check:changeset-gate-self-tests. The worktree was recreated, with pnpm install --frozen-lockfile and a full packages build under the lock (turbo, 72 tasks, exit 0, cache-replayed), so the dist-reading gates read built output. CI 'Check Changeset' is success on 2c055c0.",
    "ci": {
    "head_2c055c088f": "Test Core (1/6), (5/6) and (6/6) success; (2/6), (3/6) and (4/6) in_progress at this report; every other check success, or skipped (Console Pin Gate, Temporal Conformance, Dogfood Verify CLI, Packed-tarball smoke, the Dogfood Regression Gate matrix shard)",
    "head_2b882e6774": "Test Core (1/6) and (5/6) success; (2/6), (3/6), (4/6) and (6/6) cancelled by this round's push; nothing red"
    },
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "1 REST write: POST /repos//issues/22877/comments (this os-dev-report, scripts/pm/post-stamped.mjs, through the relay). Not REST: git push of one fast-forward commit (2b882e6..2c055c0). No PR-body PATCH (see deviations), no label writes. REST reads with the session's gh: comment 6128093700, check-runs on both heads, pulls/23070.",
    "open_questions": [],
    "out_of_scope_findings": [
    "The review's escalations are the seat's to file, as the round said, and none was built here: the runtime dispatcher's ?member=, the remaining by-name doors' closed sets (PUT included), the drafts and commits lists with Studio and the client SDK, and the envelope graft that makes isCodeArtifactBody misread an unshipped member's overlay."
    ],
    "gates": [
    "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
    "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
    "node scripts/check-changeset-no-major.mjs --self-test :: exit 0",
    "node scripts/check-ci-filter-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-corpus.mjs :: exit 0",
    "node scripts/check-dev-prereqs.mjs --self-test :: exit 0",
    "node scripts/check-doc-frontmatter.mjs :: exit 0",
    "node scripts/check-doc-frontmatter.mjs --self-test :: exit 0",
    "node scripts/check-doc-route-spelling.mjs --advisory :: exit 0",
    "node scripts/check-doc-route-spelling.mjs --self-test :: exit 0",
    "node scripts/check-docs-section-name.mjs :: exit 0",
    "node scripts/check-docs-section-name.mjs --self-test :: exit 0",
    "node scripts/check-dts-emitted.mjs --self-test :: exit 0",
    "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
    "node scripts/check-empty-changeset.mjs --self-test :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --days 90 :: exit 0",
    "node scripts/check-engine-split-ratio.mjs --self-test :: exit 0",
    "node scripts/check-issue-citations.mjs :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs :: exit 0",
    "node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs :: exit 0",
    "node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0",
    "node scripts/check-registry-log-declared.mjs :: exit 0",
    "node scripts/check-registry-log-declared.mjs --self-test :: exit 0",
    "node scripts/check-rest-log-declared.mjs :: exit 0",
    "node scripts/check-rest-log-declared.mjs --self-test :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs :: exit 0",
    "node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0",
    "node scripts/check-section-landing-index.mjs :: exit 0",
    "node scripts/check-section-landing-index.mjs --self-test :: exit 0",
    "node scripts/check-spec-docblock-symbol-anchors.mjs :: exit 0",
    "node scripts/check-spec-docblock-symbol-anchors.mjs --self-test :: exit 0",
    "node scripts/check-system-context-census.mjs :: exit 0",
    "node scripts/check-system-context-census.mjs --self-test :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs :: exit 0",
    "node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0",
    "node scripts/docs-audit/check-affected-docs.mjs :: exit 0",
    "node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
    "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
    "node scripts/release-pending-publish.mjs --self-test :: exit 0",
    "pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0",
    "pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0",
    "pnpm --filter @objectstack/spec run check:api-surface :: exit 0",
    "pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0",
    "pnpm --filter @objectstack/spec run check:browser-reachable-entries :: exit 0",
    "pnpm --filter @objectstack/spec run check:docs :: exit 0",
    "pnpm --filter @objectstack/spec run check:dual-source-exports :: exit 0",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
    "pnpm --filter @objectstack/spec run check:empty-state :: exit 0",
    "pnpm --filter @objectstack/spec run check:entry-nameability :: exit 0",
    "pnpm --filter @objectstack/spec run check:export-origins :: exit 0",
    "pnpm --filter @objectstack/spec run check:exported-any :: exit 0",
    "pnpm --filter @objectstack/spec run check:generated :: exit 0",
    "pnpm --filter @objectstack/spec run check:liveness :: exit 0",
    "pnpm --filter @objectstack/spec run check:llms-txt :: exit 0",
    "pnpm --filter @objectstack/spec run check:objectui-pin-citations :: exit 0",
    "pnpm --filter @objectstack/spec run check:skill-examples :: exit 0",
    "pnpm --filter @objectstack/spec run check:skill-refs :: exit 0",
    "pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0",
    "pnpm --filter @objectstack/spec run check:variant-docs :: exit 0",
    "pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0",
    "pnpm check:authz-resolver :: exit 0",
    "pnpm check:changeset-gate-self-tests :: exit 0",
    "pnpm check:corpus-claim-drift :: exit 0",
    "pnpm check:cross-package-test-inputs :: exit 0",
    "pnpm check:dispatcher-error-vocabulary :: exit 0",
    "pnpm check:doc-anchors :: exit 0",
    "pnpm check:doc-authoring :: exit 0",
    "pnpm check:docs-audit-scope :: exit 0",
    "pnpm check:docs-redirects :: exit 0",
    "pnpm check:docs-single-h1 :: exit 0",
    "pnpm check:docs-spec-enumerations :: exit 0",
    "pnpm check:docs-transcript-drift :: exit 0",
    "pnpm check:driver-memory-census :: exit 0",
    "pnpm check:dts-closure :: exit 0",
    "pnpm check:dual-build-cjs-loads :: exit 0",
    "pnpm check:durability-log-level :: exit 0",
    "pnpm check:engine-double-contract :: exit 0",
    "pnpm check:error-status-conformance :: exit 0",
    "pnpm check:filter-alias-parity :: exit 0",
    "pnpm check:gitlink-declared :: exit 0",
    "pnpm check:issue-citations :: exit 0",
    "pnpm check:lean-entry-closure :: exit 0",
    "pnpm check:logger-receiver-detach :: exit 0",
    "pnpm check:merge-driver :: exit 0",
    "pnpm check:nul-bytes :: exit 0",
    "pnpm check:objectql-double-limit :: exit 0",
    "pnpm check:objectui-changeset :: exit 0",
    "pnpm check:org-identifier :: exit 0",
    "pnpm check:page-declaration-shape :: exit 0",
    "pnpm check:pm-changeset-deadline-census :: exit 0",
    "pnpm check:pm-prior-rulings :: exit 0",
    "pnpm check:published-files :: exit 0",
    "pnpm check:published-readme-links :: exit 0",
    "pnpm check:query-options-erasure :: exit 0",
    "pnpm check:quick-reference-counts :: exit 0",
    "pnpm check:react-page-adapter-contract :: exit 0",
    "pnpm check:refd-timer-probe :: exit 0",
    "pnpm check:role-word :: exit 0",
    "pnpm check:route-envelope :: exit 0",
    "pnpm check:skill-identifier-liveness :: exit 0",
    "pnpm check:slot-lookup :: exit 0",
    "pnpm check:sourcemap-no-sources-content :: exit 0",
    "pnpm check:spec-parsed-alias :: exit 0",
    "pnpm check:test-source-alias :: exit 0",
    "pnpm check:tier-file-adoption :: exit 0",
    "pnpm check:type-check-coverage :: exit 0",
    "pnpm check:type-check-debt :: exit 0",
    "pnpm check:vendor-version-stamps :: exit 0",
    "pnpm check:watch-hint-literal :: exit 0",
    "pnpm check:where-matcher :: exit 0"
    ],
    "line_budget": "This round: 1 file, +11/-1 against 2b882e6 (.changeset/22877-member-selector.md). The PR on 2c055c0 against its merge-base: 14 files, +1385/-105 = 1490 changed lines, still under the 3,000-line Tier H threshold.",
    "deviations": [
    "PR body not edited by the dev. .claude/agents/os-dev.md: 'PR 正文 dev 只写一次,在开 PR 那一笔,⛔ 不 PATCH;事后要改的报告点名改法,席位代写。' The round asked for 'the PR body update through the relay', and the role file wins on a conflict. For the seat to write, two edits, prepared in full at the scratch path below. (a) Replace line 3 with: 'Widens: the accept set of the five by-name /meta doors (GET, DELETE, /history, /publish, /rollback on /meta/:type/:name) by one query parameter, member, and the four protocol requests behind them (GetMetaItemRequest, DeleteMetaItemRequest, PublishMetaItemRequest, HistoryMetaItemRequest) by one optional field, member; and three exported surfaces, each by one optional member: the last argument of SchemaRegistry.getItem, getArtifactItem, removeRuntimeShadow and removeOverlayEntry (@objectstack/objectql), the MetadataMutationEvent field (@objectstack/metadata-protocol, also carried on the ClusterMetadataMutationPayload a peer accepts), and the header on each SysMetadataRepository.listDrafts entry.' Lines 1 and 2 are unchanged. (b) Optional, from the review's ① 3: under 'The value refusal's envelope', add the bullet 'The ?layers= plus ?member= refusal is raised by the GET handler itself, not by the protocol. It is thrown into the same handleRouteError, so it is flat too; that is the handler's only pre-existing shape for a 400 of its own, so it mints no new dialect.' The full body with both edits, built from the stored body (contains no less-than character), is at /tmp/claude-0/-home-user-objectstack/99494cdf-a0fd-56b5-adae-98900c5dd071/scratchpad/issue-22877b/s2/r1/pr-body-r1.md. Its evidence section still describes head 2b882e6, where every code-bearing measurement was taken.",
    "The worktree removed after round 0 was recreated at ../objectstack-issue-22877-s2 on the existing local branch, which matched origin at 2b882e6."
    ],
    "files_changed": [
    ".changeset/22877-member-selector.md"
    ]
    }

  19. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR #23070 at 2c055c088f (stage 2 of 2) · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T16:55Z

    Basis:

    • the maintainer's ruling 6116165299 (A, Q2 i) binds;
    • the seat answers 6118224899;
    • stage 1's landing record 6121513183;
    • claim 6123966682;
    • reports 6127796890 and 6128562834 (patch round 1).

    Everything below was checked on GitHub, not taken from the reports. Classes, positions and functions only.

    Landing: prechecks pass:

    • every check is green;
    • merge-tree is clean against origin/main;
    • not governed;
    • 1,490 lines.

    The PR is readied and armed through the relay in this act. When it merges, Fixes #22877 closes the card.

  20. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: stage 2, PR #23070 → 038d4c9588 · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T17:25Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:i18nThe customer's own language, across UI, metadata and notificationsbugSomething isn't workingdomain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they landpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions