You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Decision] Is an API key an agent under ADR-0090 D10 rule 4, or a non-agent tool? Today it is classed human and audits as its owner — split out of #17022 #18335
Split out of #17022 by the triage seat (#6015, session_01UXnFshug1c4AVcjrqPy4jq, R+238) answering that card's pm:retriage. The reasoning and the full measurement table are in that card's comment; this card carries only the door that was split off, plus the question that made it separable.
Measured (origin/main, this act)
reading
result
agent channel in packages/core/src/security/assemble-execution-context.ts
oauth?.clientId only — :293, consumed at :316 (principalKind) and :317 (onBehalfOf)
keyId / apiKey / api_key in that file
0 — controls userId9, onBehalfOf4 fire ⇒ discriminating probe
principalKind in api-key.ts + resolve-authz-context.ts
0 — control: same term reads 7 in assemble-execution-context.ts, 9 in its test, same directory
⇒ An API-key caller is not classed as an agent anywhere. It carries no principalKind from its own path and falls through the :316 ternary to 'human' — so its writes audit as a human's own, and no ADR-0090 D10 dual attribution is even attempted for it.
⛔ This is not the same defect as #17022. There the agent exists and has nowhere to record its identity; here the principal is never classed as an agent at all. Different upstream, different files, different fix — which is why it is a separate card.
Why it is a decision and not execution
ADR-0090 D10 rule 4 says 「every write records performed_by (agent) + on_behalf_of (user) + run id」. Whether an API key is an agent acting on behalf of its owner or a service principal in its own right changes who the audit row blames and what the permission model grants — ⛔ the tree does not answer it, and it sits on the 安全/权限边界 floor.
维护者速读
事情。 平台有两种"不是人在按键"的调用方式:一种是 MCP 的 OAuth 客户端(AI 代理),另一种是 API key。审计日志要求记下"谁代谁干的"。OAuth 那一路的修复已经在 #17022 上,这张卡只问 API key 这一路。
现状(实测)。 API key 调进来时,系统根本不把它当成代理 —— 它被当作"人"记账,写进审计日志的就是钥匙主人本人,看不出这是一把钥匙自动跑的。
Governing text: ADR-0090 D10 agent rule 4(逐字「Dual attribution: every write records performed_by (agent) + on_behalf_of (user) + run id」)· 维护者 2026-08-04 创业阶段聚焦指示 · SKILL.md 人工地板「安全/权限边界」条。
Sequencing
Blocked-by: #17022 — either answer needs that card's carrier landed first: under B it is the field to populate; under A the ADR sentence being amended is the same one #17022's follow-up docs PR touches, and ⛔ two cards must not edit docs/adr/0090-*.md in parallel (#17189 already collided there once).
Dedup words: API key agent principal · principalKind service · ADR-0090 D10 rule 4 · dual attribution keyId · resolve-authz-context principalKind
Blocked-by: #17022
Split out of #17022 by the triage seat (#6015,
session_01UXnFshug1c4AVcjrqPy4jq, R+238) answering that card'spm:retriage. The reasoning and the full measurement table are in that card's comment; this card carries only the door that was split off, plus the question that made it separable.Measured (
origin/main, this act)packages/core/src/security/assemble-execution-context.tsoauth?.clientIdonly —:293, consumed at:316(principalKind) and:317(onBehalfOf)keyId/apiKey/api_keyin that fileuserId9,onBehalfOf4 fire ⇒ discriminating probeprincipalKindinapi-key.ts+resolve-authz-context.tsassemble-execution-context.ts, 9 in its test, same directory⇒ An API-key caller is not classed as an agent anywhere. It carries no
principalKindfrom its own path and falls through the:316ternary to'human'— so its writes audit as a human's own, and no ADR-0090 D10 dual attribution is even attempted for it.⛔ This is not the same defect as #17022. There the agent exists and has nowhere to record its identity; here the principal is never classed as an agent at all. Different upstream, different files, different fix — which is why it is a separate card.
Why it is a decision and not execution
ADR-0090 D10 rule 4 says 「every write records
performed_by(agent) +on_behalf_of(user) + run id」. Whether an API key is an agent acting on behalf of its owner or a service principal in its own right changes who the audit row blames and what the permission model grants — ⛔ the tree does not answer it, and it sits on the 安全/权限边界 floor.维护者速读
事情。 平台有两种"不是人在按键"的调用方式:一种是 MCP 的 OAuth 客户端(AI 代理),另一种是 API key。审计日志要求记下"谁代谁干的"。OAuth 那一路的修复已经在 #17022 上,这张卡只问 API key 这一路。
现状(实测)。 API key 调进来时,系统根本不把它当成代理 —— 它被当作"人"记账,写进审计日志的就是钥匙主人本人,看不出这是一把钥匙自动跑的。
问题。 一把 API key 到底算什么?
席位推荐:A。 三条理由:今天没有任何人提出过要按 API key 区分审计(零实测拉动);创业阶段默认不扩散能力面;而 B 会把"钥匙"变成权限模型里的新主体类别,那是比审计大得多的一件事。⛔ 但这是安全/权限边界,所以不代裁。
你要做的:回一个字母 —— A 或 B。
四棱分析
sys_audit_logrecordsuser_id/actor= the delegator and nothing names the client, so ADR-0090 D10 rule 4 「dual attribution: performed_by (agent) + on_behalf_of (user) + run id」 has no writer #17022 的成因是维护者对 MCP 的表态(「MCP 集成人类的身份,只需要在审计日志中记录这是 AI 代替人类执行」),逐字只点名 MCP,⛔ 未提 API key。⇒ B 是推定的需求面。sys_audit_logrecordsuser_id/actor= the delegator and nothing names the client, so ADR-0090 D10 rule 4 「dual attribution: performed_by (agent) + on_behalf_of (user) + run id」 has no writer #17022 这一族卡存在的原因。⛔ A 不是"什么都不做"。合议:① ④ 指向 A,② 倾向 A,③ 中性但给 A 附一个强制交付物。 ⛔ 安全/权限边界在人工地板上 ⇒ 呈报,⛔ 不代裁。
Governing text: ADR-0090 D10
agentrule 4(逐字「Dual attribution: every write recordsperformed_by(agent) +on_behalf_of(user) + run id」)· 维护者 2026-08-04 创业阶段聚焦指示 · SKILL.md 人工地板「安全/权限边界」条。Sequencing
Blocked-by: #17022— either answer needs that card's carrier landed first: under B it is the field to populate; under A the ADR sentence being amended is the same one #17022's follow-up docs PR touches, and ⛔ two cards must not editdocs/adr/0090-*.mdin parallel (#17189 already collided there once).Dedup words:
API key agent principal·principalKind service·ADR-0090 D10 rule 4·dual attribution keyId·resolve-authz-context principalKindGenerated by Claude Code