Skip to content

mail templates: a hole an author places in a template body may not be encoded for the context it lands in (reach not measured; detail withheld under the disclosure ruling) #25082

Closed

Description

@objectstack-fleet

Ruled: 6335348115 · letter F1 A2 / F2 B3 · 2026-10-22T07:33Z

Filing gate ①, the security exception ("may harm the reader of an output": measure reach first). Filed by the domain:services PM seat, seat 1 (seat post #6021, session_011TdZ8GjixNZFLz1xJD9zzK). The source is the contract review of PR #25076 (#25061). That review judged this reading outside the PR's stated bound and not a ground against it. ⛔ Not a claim. Unlabelled and ungraded, for triage.

Disclosure: the maintainer's ruling recorded on #9387 (5323310017) applies. This card records only that the reading exists, where it lives, and the governing rule. ⛔ No probe, value or template sample goes on this card, its PR or any comment. The seat holds the detail privately.

Reader, and what they do: triage grades and routes this card. The location is the two mail template renderers, which read as the domain:services lane. Whoever takes it measures reach FIRST: which hole placements authored rows actually use, and what a value becomes in each.

Where it lives (origin/main 2b1382a5b3)

Governing rule

The maintainer's ruling 3C on #25040 (6308462370) says each outlet escapes by context. The two renderers meet it for the contexts their changesets name. Triage decides whether 3C also reaches the other placements an author can write. The remedy direction is triage's call: authoring guidance, a per-context encoder, or restricting which holes may sit in which context (as the built-in auth templates' pin already does for their own raw holes).

Dedupe

Two MCP search_issues queries returned 0 hits and 1 hit (closed, not this). A positive control returned #25061. The exact terms name the class, so the seat holds them privately. New.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    [Decision] 模板占位符的放置限制:邮件模板一半的拒收放在哪里,以及两个无保存时机的渲染导出

    domain:services seat 2 (seat post #21118) · os-bill · session_01UnHcTADjeg3VwxF21QHj7W · 2026-10-22T06:29Z · Thread-read: 6334219164

    Release: session_01UnHcTADjeg3VwxF21QHj7W · Cause: the read-only measuring pass (6334219164) met the forks its dispatch named as stop conditions. Two of them have axes that disagree, and one route moves half the work to another lane · Goes to: needs-user-decision. This write's label stroke clears the assignee. The reserved branch claude/issue-25082-template-hole-placement has no commits.

    ⛔ 披露(#9387 5323310017):本决策只写抽象层,不写放置样例、取值或具体哪几类上下文被错误编码。细节由席位私下持有。

    一句话问题: 分诊已定方向:渲染器无法按其位置正确编码的占位符,在模板保存或注册时拒收。通知模板(数据行)一半没有分叉,可直接做。邮件模板一半可以作为元数据写(defineStack 的 emailTemplates),拒收放在 spec 的 schema、lint 的写作规则,还是 plugin-email 的运行时门禁,四轴不同向。另有两个渲染导出可以绕过任何保存时机,要不要退役。

    背景(只读实测 6334219164;席位已在 origin/main 复核关键引用)

    • 前提成立: 两个渲染器(service-messaging 的 template-renderer.ts,plugin-email 的 template-engine.ts)对 html 面上的每个占位符都用同一种编码。元素文本与带引号的属性值是对的,其余放置不是。
    • 可达性为零(可测范围内):
      • 本仓 45 个模板体、228 个占位符,生产模板 0 个在两类上下文之外;
      • objectstack-ai/hotcrm 76 个模板体、116 个占位符,全部在元素文本里;
      • 没有任何 html 或 mjml 的通知模板行。
      • objectstack-ai/cloud 与生产库未测(本账号不可见)。
    • 两半的门不同:
      • 通知模板是平台对象 sys_notification_template 的数据行。所有写入口都经引擎保存,可在 beforeInsert / beforeUpdate 判,返回现有的 VALIDATION_FAILED / 400,不新造错误码。
      • 邮件模板是元数据:stack.zod.ts:778 的 emailTemplates,email-template.zod.ts:195 的 bodyHtml: z.string(),无放置约束。入口有代码包构建(defineStack、os validate/build),也有运行时元数据保存。
    • 无保存时机的门: plugin-email/src/index.ts:88 导出 renderTemplate,service-messaging/src/index.ts:92-93 导出 renderNotification、interpolate。它们直接收模板体,不经任何保存。本仓(测试之外)与 hotcrm 的使用方都是 0,npm 外部依赖未测。
    • 车道: packages/lint 按锚定例外归 domain:spec,packages/spec 归 domain:spec,plugin-email 归本车道。

    Governing text

    The maintainer's ruling 3C (6308462370 on #25040): each outlet escapes by context. Triage's answer on this card (6332255183): 3C reaches every placement an author can write; the remedy is a placement restriction at save or registration (the built-in auth templates' pin shape), not a per-context encoder and not guidance alone; it ships patch with its BREAKING banner and ADR-0087 disposition. docs/adr: no ADR rules on hole placement (searched below).

    是否改协议: 取决于 F1。A1 收窄 spec 的 bodyHtml(Metadata-protocol: narrowed,至少 minor,归 spec 车道);A2、A3 不改 spec。

    前提(复核命令)

    • 邮件模板可作元数据写:git grep -n "emailTemplates:" origin/main -- packages/spec/src/stack.zod.ts,预期 :778。git grep -n "bodyHtml:" origin/main -- packages/spec/src/system/email-template.zod.ts,预期 :195 且为 z.string()。
    • lint 运行时门已映射该类型:git grep -n "email_template" origin/main -- packages/lint/src/runtime-gate.ts,预期 :189。阳性对照:git grep -n "CLI_AND_RUNTIME" origin/main -- packages/lint/src/authoring-rules.ts 必中。
    • 两个导出:git grep -n "renderTemplate\|renderNotification\|interpolate" origin/main -- packages/plugins/plugin-email/src/index.ts packages/services/service-messaging/src/index.ts,预期 3 行。

    F1 选项:邮件模板一半的拒收放在哪里

    选项 做什么 客户可感知后果 工作量
    A1 spec schema 收紧 bodyHtml 上加 superRefine 代码作者在 defineStack 时即报错。已存的违规环境模板在每次发送时失败(加载器 safeParse 抛错,邮件通道按可重试处理,最终进死信)。v18 迁移的模板提升步骤会被它挡住 spec 车道 · 1 PR · minor + ADR-0087 D3 条目
    A2 lint 写作规则(错误级) authoring-rules.ts 新条目,surfaces: CLI_AND_RUNTIME,运行时类型 email_template os validate/build/lint 与运行时发布(ACTIVE 保存)都响亮拒收,返回现有的 422 INVALID_METADATA。已存模板继续服务,下次发布时被判(差分门)。草稿不判 spec 车道(lint)· 1 PR · patch
    A3 plugin-email 运行时门禁 registerAuthoringGate('email_template', …) 只在运行时元数据保存时拒收。代码包作者(hotcrm、showcase、内置模板)永远不经过它 本车道 · 1 PR · patch

    业务含义直译:

    • A1:把规则写进契约本身,最严,但已有的违规模板会在发信时才暴露。
    • A2:用平台已有的「写作规则」那张表,写代码时和发布时都拦,已有的模板不受影响直到下次发布。
    • A3:只拦运行时在线编辑,代码包里的模板拦不到。

    F2 选项:两个无保存时机的渲染导出

    选项 做什么 后果 工作量
    B1 保留,写进文档 文档写明直接传模板体的调用方自负放置 限制看不到这扇门 最小
    B3 退役两个纯渲染导出 ADR-0087 runtime-export-retired,BREAKING。保留 setTemplateLoader(插件自己的接线点) 零已知使用方。外部 npm 依赖未测 services · 1 PR

    (B2「在导出函数里渲染时判」不推荐:发信晚失败,且与保存时机方向不符。)

    四轴(业务立场)

    • 实际业务需求: 任何选项都拒收 0 个已测生产模板。代码作者走 CLI,不走元数据保存门,所以 A3 永远拦不到他们,A1、A2 能拦到。两个导出零已知使用方。
    • 项目长远合理性: A2 落在平台已有的单一写作规则表上,规则只有一份,CLI 与运行时同一判定。A1 把渲染器专属的 HTML 上下文判断写进 spec 契约,且让已存违规项在发送时故障。A3 是单槽、仅运行时的第二条路径。B3 删掉无人使用、限制看不到的门。
    • 防 AI 写错: A1 最强,在 defineEmailTemplateDefinition 处即抛错。A2 在 os validate/build 与发布时响亮拒收,符合「publish 时响亮拒绝」。A3 对代码作者沉默。B3 优于 B1。
    • 创业阶段不扩散: 三者都不加 CI check:* 门。A2 用现有表,不新增机制。A1 带 spec 车道工作与迁移条目。B3 是立即退役零消费能力。

    推荐:A2 + B3,B3 另立一卡

    • 只看①得出的终态: 平台的写作期语义检查只有一处(写作规则表),CLI 与运行时发布共用同一判定。邮件模板的放置规则住在那里,通知模板的同一规则住在其数据门。没有第二条可绕过的渲染入口。
    • 自检行: 只看①选 A2;②③④ 是否翻转:③ 偏 A1,但 A2 已满足「发布时响亮拒绝」,不足以翻转;②④ 不翻转。
    • 置信缺口: 生产环境里的已存邮件模板与通知模板行未测。若有违规项,A2 下它们继续服务,下次发布时才被拒;A1 下会在发送时失败。
    • 不取 A1: 已存违规项变成发信故障,代价落在未测的生产数据上。
    • 不取 A3: 拦不到代码作者,而已测的全部模板都来自代码。
    • B3 另立一卡: 退役导出是独立的 BREAKING 动作,不应拖住放置限制。它也不阻塞本卡:两扇门零已知使用方。

    裁后执行段(席位提议的执行参数,请同笔裁定)

    • 分类严格度(F3): 严格按上下文判,外加内置模板钉子的原样规则(原样占位符只许作为声明为 url 的变量直接置于双引号 href 内)。这会拒收 5 个非生产模板体(文档示例 2、dogfood 夹具 1、spec 转换夹具 2),由本次构建改正。hotcrm 0,内置模板 0。四轴同向。
    • 已存行(F4): 通知模板行按合并后记录判(先例:channel_renders_template 规则),违规行编辑即冻结,不影响读取与投递。可测范围内受影响行为 0,不设迁移;若出现生产读数,再呈。
    • 若选 A2:
      • 通知模板一半由本席派发(service-messaging)。
      • 邮件模板一半是 lint 规则,归 domain:spec,本席立 spec 车道子卡并写 Blocked-by 关系。
      • 两半共用一个判定的位置(packages/formula 归 domain:engine,或各自实现)由子卡首测决定。
      • 本卡在两半都落地后关闭。
    • 若选 A1: 同上,但邮件一半是 spec schema 收紧。changeset 按 Metadata-protocol: narrowed,并带 ADR-0087 D3 条目,子卡归 spec 车道。
    • 若选 A3: 两半都由本席在一个 PR 内做,patch。PR 正文写明代码作者不受此门约束。
    • B3: 本席另立 services 卡,runtime-export-retired 处置,不阻塞本卡。
    • 两半都要: 一次 CONTRACT_REVIEW_TIER 评审再入队(收窄)。

    os-decision-facets

    • ① 项目长远合理性:A2 落在已有的单一写作规则表,CLI 与运行时同一判定;A1 把渲染器专属判断写进契约并让已存项发信故障;A3 是第二条仅运行时路径。
    • ② 实际业务拉动:任一选项拒收的已测生产模板数为 0;已测模板全部来自代码作者(只有 A1、A2 拦得到);两个导出零已知使用方。
    • ③ 防 AI 犯错:A1 最强(定义时抛错),A2 次之(构建与发布时响亮拒收),A3 对代码作者沉默。
    • ④ 创业阶段不扩散:无新增 CI 门;A2 无新机制;B3 立即退役零消费能力。
      Prior rulings read: email template, hole placement, escape by context, authoring rule → docs/adr 0 hits ruling on hole placement (ADR-0012 names an escape hatch only); ruling 3C 6308462370 on cloud 测试发现(框架部分):注册接口的邮箱存在性、邮箱验证只能全开或全关、展示型字段原样存储 HTML(细节按披露裁定隐去) #25040; thread: triage's answer 6332255183

    Related: the readings 6334219164; claim 6333863118; the seat's question 6331052089; #25040 (ruling 3C); #25061 / PR #25076 (the source of this card).


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #384 item 2 · letter F1 A2 / F2 B3 · maintainer 「同意」 2026-10-22T07:33Z

    Director seat, summon #47 continuation 2, session_01TQvbE2ENCniJr1ffCzbPc6 (os-bill, writing through the relay). Presented in this session's chat as batch #384 item 2, from the domain:services seat 2 decision 6334342274, the read-only measurement 6334219164 and triage's answer 6332255183; the maintainer answered 「同意」. ⛔ Disclosure (#9387, 5323310017): abstract only; no placement sample, value or template goes here. The director's delta re-checked on origin/main b6e87070: emailTemplates is a stack key (packages/spec/src/stack.zod.ts:778); bodyHtml is z.string() with no placement constraint (packages/spec/src/system/email-template.zod.ts:195); the lint runtime gate already maps email_template (packages/lint/src/runtime-gate.ts:189) and the authoring-rule table carries 28 CLI_AND_RUNTIME rules, so A2 is one more row in an existing table; the two body-taking render exports exist (plugin-email/src/index.ts:88, service-messaging/src/index.ts:92-93). Thread read to its end at this write: 6334342274 is the newest comment.

    Governing text: the maintainer's ruling 3C on #25040 (6308462370: every outlet that renders a text field into HTML escapes by context); triage's reading on this card (6332255183: 3C reaches every placement an author can write; the remedy is a placement restriction at save or registration, not a per-context encoder and not guidance alone); the #25105 ruling A on changesets (a non-protocol narrowing ships patch with its BREAKING banner and ADR-0087 disposition); ADR-0087 (runtime-export-retired, for B3); the standing line 「暂时不考虑 v19,协议的调整原则上也是尽快,不考虑退役版本。」 (no staged window for B3).

    What the ruling binds

    F1 — letter A2: the email half is an error-tier authoring rule.

    1. One entry in packages/lint/src/authoring-rules.ts with surfaces: CLI_AND_RUNTIME, runtime type email_template: os validate / os build / os lint and the runtime publish gate (ACTIVE saves) refuse a hole the renderer cannot encode for its placement, with the existing 422 INVALID_METADATA, naming the placement and the supported ones. Stored items keep serving and are judged at their next publish; drafts are not judged. This half lives in domain:spec (lint, by the lane table's anchoring exception); domain:services seat 2 files that sub-card, and this card closes only when both halves have landed.
    2. The notification half (data rows of the notification template object) is dispatched by domain:services seat 2: a judge beside service-messaging's hole grammar plus a save hook on the object (beforeInsert / beforeUpdate, the existing VALIDATION_FAILED / 400; failed rows on import and bulk update). No new error code at any door. Where the dependency edges allow one shared judge (lint and plugin-email) it is shared; service-messaging keeps its own; the sub-card's first measurement decides the placement of the shared code.
    3. F3, classification: context-strict, plus the built-in auth templates' raw-hole shape for everyone (a raw hole only as a declared url-typed variable inside a double-quoted href). The build corrects the five non-production bodies this refuses (two docs examples, one dogfood fixture, two spec conversion fixtures); hotcrm 0, built-ins 0.
    4. F4, stored rows: a notification row is judged on the merged record (the object's channel_renders_template rule is the precedent); a refused row freezes on its next edit and keeps rendering and delivering. Email items keep serving until their next publish (A2's own property). Measured affected population 0; no migration. A production reading, if one is obtained, comes back as its own card.
    5. Not taken: A1 (a spec refine makes every stored violating item fail at send and blocks the v18 template promotion — the cost lands on unmeasured production data; spec-lane minor plus a conversion entry); A3 (a runtime-only gate that code-package authors never pass through, while every measured template comes from code).

    F2 — letter B3: the body-taking render exports are retired.
    6. domain:services seat 2 files one card retiring the two exports that take a template body with no save moment (renderTemplate in plugin-email, renderNotification in service-messaging) under ADR-0087 runtime-export-retired, BREAKING, at once — no staged window, under the standing line above. setTemplateLoader stays (the plugin's own wiring point). Whether interpolate goes with them is that card's first measurement (consumers: zero in-tree outside tests, zero in hotcrm, npm dependants unmeasured). It does not block this card.
    7. Not taken: B1 (a documented door the restriction cannot see); B2 (a render-time judge that fails late, at send).

    Changeset and review (both halves): patch with the BREAKING banner and ADR-0087 disposition (#25105 A); Metadata-protocol: none under A2; a CONTRACT_REVIEW_TIER review before the queue (a narrowing of what an administrator can author).

    Effort of the chosen letters (the card's column): notification half domain:services · 1 PR; email half domain:spec (lint) · 1 PR · patch; B3 domain:services · 1 PR; no named precedent. Confidence gap carried: objectstack-ai/cloud and production rows are unmeasured; under A2 a stored violating item keeps serving until its next publish.

    State: needs-user-decision → pm:queue (domain:services, p2, security, area:api). domain:services seat 2 (seat post #21118) re-claims for the notification half (the reserved branch claude/issue-25082-template-hole-placement has no commits), files the spec-lane sub-card and the B3 retirement card.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Pointer · domain:services seat 2 (seat post #21118) · os-bill · session_01UnHcTADjeg3VwxF21QHj7W · 2026-10-22T08:17Z · executing ruling 6335348115 · ⛔ Not a claim.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: card thread · domain:services seat 1 (seat post #6021, project run by the Sales account) · p2 · security · the notification half of this card (ruling 6335348115, item 2) · 2026-10-22T16:16Z
    Session: session_01ApJv4hDHQ6M1JprNZFKzAW
    Account: os-sales (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-iydt23 (the harness-pinned branch for this session; it names no issue, so the Duplicate Fix Guard's branch-name hint will not match — this claim is the identity record)
    Worktree: the session's own container checkout (one task per container)
    Domain: domain:services
    Seat: domain:services#1 (seat post #6021)
    File surface (read on origin/main e58bd0e3e; stop on a breach and explain it in the report): packages/services/service-messaging/src/ — a placement judge beside the renderer's hole grammar in template-renderer.ts, the save hooks on sys_notification_template (beforeInsert / beforeUpdate, judged over the merged record), their binding in messaging-service-plugin.ts, the object's docblock in objects/notification-template.object.ts, and their tests; one patch changeset for @objectstack/service-messaging. ⛔ Not plugin-email, packages/lint, packages/formula or packages/spec (the email half is #25189).
    Container & model: M, card thread (in-session executor), model: default tier (dispatch-gates.mjs --tier: "no path-derived mandate"), effort: xhigh (security); a CONTRACT_REVIEW_TIER review of record before the queue (a narrowing of what an administrator can author)
    Clause-②: no (narrowing)
    Metadata-protocol: none
    Basis for the Clause-② line: a save-time refusal narrows what an administrator can store in a sys_notification_template row (data, not metadata); no accept set or public surface widens. The ruling's changeset line: patch with the BREAKING banner and its ADR-0087 disposition (#25105 A).
    Responsibility: withheld under the disclosure ruling (#9387, 5323310017); the ruling 6335348115 names the remedy side as service-messaging's own judge plus a save hook on the notification template object.
    Ruling-ref: 6335348115
    Thread-read: 6336133895
    Serial constraints cleared: none of the 10 open PRs touches packages/services/service-messaging/** (each PR's file list read this act). The email half (#25189, PR #25212, draft, not on origin/main) carries its own judge in packages/formula; this half keeps its own per ruling item 2 and uses the same placement vocabulary. #25190 (B3, retiring renderNotification) follows this card and is not blocked by it.
    Resume-from: none (the newest pointer 6336133895 names no commits on the reserved branch).


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 25082,
    "status": "done",
    "branch": "claude/project-thread-iydt23",
    "pr": "#25258",
    "session": "session_01ApJv4hDHQ6M1JprNZFKzAW",
    "premise_still_valid": true,
    "summary": "The notification half of ruling 6335348115 (items 2 to 4). service-messaging gets its own placement judge (template-hole-placement.ts), reading holes through the renderer's own token and a placement table re-derived from the renderer's encoder: element text and quoted plain-text attribute values are supported, every other placement is refused, context-strict over every reading a parser can give the body (fork at noscript and at text-element start tags once a select or frameset is open; foreign content never left). beforeInsert / beforeUpdate hooks on sys_notification_template (priority 30, bound in MessagingServicePlugin.init, unbound in destroy) refuse an html or mjml body with a refused hole, judged over the merged record, with the existing 400 VALIDATION_FAILED at body / invalid_value; a stored violating row is frozen on its next edit and keeps rendering and delivering, no migration, no new error code. Changeset: patch with the BREAKING banner and ADR-0087 not-required (no-migration-prescription).",
    "tests": "pnpm --filter @objectstack/service-messaging test: Test Files 58 passed (58), Tests 722 passed (722). New: src/template-hole-placement.test.ts 74/74 (every class, the readings, grammar and span parity with renderNotification); src/objects/notification-template-placement.integration.test.ts 20/20 on real ObjectQL + SqlDriver through ObjectStackProtocolImplementation, mapDataError and runImport (REST door 400, import failed row, bulk update failed record, predicate update writes no row, stored row frozen then repaired, still read/deleted/rendered, plugin binds on a booted kernel and unbinds on destroy). pnpm --filter @objectstack/service-messaging typecheck: exit 0. ESLint over the 7 changed source files: exit 0. Ablation: none run (no previously tested behaviour changed; the new pins are positive/negative twins on the same path, e.g. the plugin test inserts the same row refused before destroy and stored after it).",
    "gates": "local subset at head 4ca18be: dispatch-gates --commands derived 70; all 70 recorded with exit codes captured before any pipe; --ran: 70 derived, 70 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). check:doc-authoring was red on its first run (the plugin's missing-engine warning string carried a tracker id), fixed in 4ca18be and re-run exit 0. check:dual-build-cjs-loads and check:i18n answered exit 3 (prerequisite: no dist) until the dogfood closure build, then exit 0. CI on 5d129db: CI workflow success (Build Core, Test Core 1-6/6); Lint & Type Check failure on two lanes: Doc/skill authoring guard (the same tracker-id string, fixed in 4ca18be) and Issue citations (PREREQUISITE NOT MET: probeBoard could not read the allocation frontier; locally the same gate read the board and resolved all 5 citations). CI on 4ca18be, every check-run completed: Lint & Repo Gates success (all lanes, Doc/skill authoring guard and Issue citations included), TypeScript Type Check success (workspace, source gates, consumer gates, debt ledger), Lint · ESLint success, Build Core success, Test Core success (1-6/6), Check Changeset success, Check PR Size success, Governed Surface Queue Guard success, Dogfood Regression Gate success (the sharded dogfood jobs skip on PRs), the claim / single-writer / closing-keyword guards success; opt-in harnesses skipped.",
    "dogfood_battery": "4ca18be6 · os-verify-lock: VERDICT command-exit 0 (held 17m07s) · Test Files 288 passed | 3 skipped (291) · Tests 2411 passed | 18 skipped (2429) · no failures. Closure built first under the lock (turbo build --filter='@objectstack/dogfood^...', VERDICT command-exit 0). An earlier attempt before the closure build failed to resolve package entries and is not a reading.",
    "mcp_calls": "9 — reads only: issue_read x3, pull_request_read x2 (get_check_runs), get_job_logs x3, actions_list x1. No MCP write tool.",
    "api_writes": "5 — all through scripts/pm: label-write.mjs on #25082 (add pm:dispatched, remove pm:queue, assign os-sales: the dispatch atom); post-stamped.mjs claim comment on #25082; fleet-write pr_create (POST /pulls draft + POST /issues/25258/assignees os-sales); fleet-write pr_request_reviewers (POST /pulls/25258/requested_reviewers os-sales); post-stamped.mjs this report comment on #25082. git push is not counted.",
    "deviations": [
    "pr_request_reviewers is a write beyond the three-write budget: the project's session instructions ask for os-sales as reviewer and assignee; both went through the relay (assignees on pr_create, reviewers on pr_request_reviewers), not MCP.",
    "The branch is the harness-pinned claude/project-thread-iydt23, not claude/issue-25082-; the claim comment and the PR body say so.",
    "A first dogfood attempt was started on 5d129db and stopped when the head moved; a second attempt on 4ca18be ran before the closure build and is not a reading. The battery above is the one valid run on the final head."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "class: review note on an unmerged PR (not a filed class) · reach: none on main; PR #25212 is a draft · evidence: the email half's judge in PR #25212 models fewer parser readings than this half in two classes (where foreign content ends, and text-element start tags the tree builder may ignore), so its accepted set can be wider than a parser's reading; class names only, under the disclosure ruling · carrier: #25189 (spec lane, PR #25212) · noted, not filed"
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:services seat 1 (seat post #6021) · os-sales · session_016g7nYP9wdNx1GDa5XDr7Uy · 2026-10-22T18:23Z

    reading value
    PR #25258 MERGED through the queue (ACCEPT 6347615221, contract review 6347584087)
    origin/main carries 284e04810a

    State: the card closed completed through the PR; this stroke clears pm:dispatched and the assignee. The draft email half's parity note stands on the ACCEPT (owed by whichever half lands second).


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingdomain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedpriority:p2Medium: important, M3security

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions