Skip to content

ConnectorActionDescriptor declares nothing about whether an action reads or writes, so the platform cannot count what a connector_action did #4395

Closed

Description

@os-zhuang

Package: @objectstack/spec (packages/spec/src/integration/connector-descriptor.ts)
Found while wiring #4354's per-run summaries into connector_action.

The gap

ConnectorActionDescriptor describes an action's shape and nothing about its effect:

export interface ConnectorActionDescriptor {
  readonly key: string;
  readonly label: string;
  readonly description?: string;
  readonly inputSchema?: Record<string, unknown>;
  readonly outputSchema?: Record<string, unknown>;
}

So crm.push_opportunity and crm.lookup_account are indistinguishable to the runtime. Nothing in the authorable Connector schema fills this in either — registerConnector reads actions for dispatch only.

Why it matters now

#4354 makes every flow run report selected / acted, and selected > 0 AND acted = 0 over consecutive runs is the broken-sweep alert. For a connector_action the platform has to pick one of three answers, and two of them are wrong:

That is correct but weaker than it needs to be. A connector-driven flow currently contributes no signal at all: it can neither confirm work happened nor be flagged for doing none. Every ObjectStack app whose automation runs through connectors is in that blind spot.

Proposal

Let the action declare its effect, and let the runtime count it:

export interface ConnectorActionDescriptor {
  readonly key: string;
  readonly label: string;
  readonly description?: string;
  readonly inputSchema?: Record<string, unknown>;
  readonly outputSchema?: Record<string, unknown>;
  /**
   * What the action does upstream. `read` never mutates; `write` does.
   * Absent keeps today's behaviour — the run reports the effect as uncountable.
   */
  readonly effect?: 'read' | 'write';
}

Then connector_action reports acted: 1 for a successful write, acted: 0 for a read, and falls back to unmeasuredEffect only when the connector declared nothing. Optional on purpose: existing connectors keep working and lose nothing, and declaring it is a strict improvement rather than a migration.

Worth considering alongside it: a count rather than a boolean, for bulk actions that report how many upstream records they touched (outputSchema often already carries one). That can follow — the read/write split is the part that unblocks the alert.

Note the ADR-0076 D12 angle: this is a machine-readable surface that is currently silent rather than wrong, which is the right failure. The proposal is to let it be accurate.

Related: #4354 (the summaries this feeds), #4347 (the silent-failure class both exist to surface).

Activity

  1. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 2, 2026
  2. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    裁决(PM 代决,维护者可否决):按提案落地 —— ConnectorActionDescriptor 增加可选 effect?: 'read' | 'write':声明 write → acted:1,声明 read → acted:0,不声明 → 维持 unmeasuredEffect: true 现状。

    两轴理由:

    count 型效果(bulk 场景)暂不做,待真实需求。已入队待派。


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 3, 2026
  4. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    分诊级别建议:给 ConnectorActionDescriptor 增加 reads/writes 声明面是新契约词表,创业阶段聚焦原则下需要真实业务拉动佐证与维护者拍板——建议摘 pm:queue 换 needs-user-decision 进决策箱。交分诊座位定夺。背景:维护者 2026-08-06 拍板 spec 车道缩盘方案,见 #5837。


    Generated by Claude Code

  5. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 6, 2026
  6. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    标签落实(维护者 2026-08-06 指示,session_01LeEfA7CFwbJb7JJmXm2KM3):按 08-06 降级建议执行 pm:queue → needs-user-decision——ConnectorActionDescriptor 增加 reads/writes 声明面属新契约词表,创业阶段聚焦原则下需真实业务拉动佐证与拍板。


    Generated by Claude Code

  7. claude commented on Aug 7, 2026

    @claude
    Contributor

    队列管家通知:本单的 PR #6160 于 06:20:22Z 被移出合并队列 —— 新签名,⛔ 未重投。

    签名:ESLint job 的 step 34 Spec type-alias convention gate (ADR-0122):

    ADR-0122: 1 type-alias convention violation(s) in packages/spec.
      integration/connector.zod.ts — ConnectorActionEffect
        `ConnectorActionEffect` names the PARSED state of `ConnectorActionEffectSchema`,
        but ADR-0122 reserves the bare name for the AUTHOR state.
    

    判读:时序碰撞,不是回归。 该门禁由 #6072(ADR-0122 第一期防回流门)引入、05:35Z 才落地,而本 PR 分支上的 ConnectorActionEffect 写在那之前 ⇒ 本 PR 是新门禁上线后第一批撞上它的新增类型。

    需要一处代码改动(⛔ 不在队列管家授权面):加一行 export type ConnectorActionEffectParsed = z.infer<typeof ConnectorActionEffectSchema>;,或(若 z.input/z.infer 同型)在 type-alias-convention.pin.test.ts 钉住。完整签名、日志归档与门禁原文处方见 PR #6160 上的拦截评论。


    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

    domain:specDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpm:queueReady for the PM dispatch loop

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions