Open
Labels
domain:serverDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestneeds-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PRBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PRpriority:p3
Description
repo:cloud#3 · os-warren · session_01JQwxbZqfEd7pcckjz3pGqn
Filing gate: ② a finding from a dispatched card. cloud#3665 (Enterprise P2 item 4) lists "report run" among the events an enterprise SIEM must receive. Its dev measured at pin 6ed533f that no framework writer records it (report cloud#3665 comment 6731925007). The cloud lane does not dispatch it; triage routes it.
维护者速读
- 问题:运行报表不留审计记录,安全审查问"谁导出/查看了哪张报表"时答不上来。
- 要做:报表执行时写一行审计(谁、哪张报表、过滤条件的字段名、行数、时间),不记数据值。
- 需要你做的:无,分诊定车道。
Evidence (pin 6ed533f)
read-audit.tsrecords record views only; thesys_audit_log.actionenum has no report value; no writer on the report execution path. Seam: specsys_audit_log.action→ runtime consumer none.
Work
- Add an action value for a report run and write one row per run on the report execution path: principal, report name, filter field names (not values), row count, outcome.
- Keep it to one row per run, as the export door's run-level row does (feat(audit): every data export writes one run-level
sys_audit_logrow, and theexportaction comes back with its writer #31000).
Done when
- Running a report leaves exactly one
sys_audit_logrow with the report name, filter fields and row count; a refused run writes none or an outcome row, as decided; tests pin it.
Dedupe: repo:objectstack-ai/objectstack is:issue "report run audit" → none.
Related: cloud#3665, cloud#4018, objectstack#31000.
Metadata
Metadata
Assignees
Labels
domain:serverDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestneeds-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PRBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PRpriority:p3
Activity
objectstack-fleet commentedon Nov 9, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage:
domain:server· p3 ·pm:queue· 2026-11-09T04:56Z⛔ Not a claim.
domain:server. A report-run audit row is written by plugin-audit or the analytics writer: who, which report, filter field names, row count, time, and never data values. Per [Decision]repo:cloudis used in two senses: 6 open cards are the cloud PM's whole (withdomain:cloud), 20 are objectstack-lane work that cloud asked for. Which one does the label mean? #31154 A it carries an objectstack lane and cites the cloud consumer; norepo:cloud. The consumer is cloud#3665 (SIEM).Generated by Claude Code
objectstack-fleet commentedon Nov 9, 2026
domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM
Claim: PM loop round 15 · 2026-11-09T06:29Z
Session:
session_01ADHkmSnFAgPUKAz3xraGoJ(card thread, dev) · seatsession_01ADHkmQKZzp4DLtqiCkZZRMAccount:
os-steveBranch:
claude/project-thread-r06jvvWorktree:
objectstack-issue-31797Domain:
domain:serverSeat:
domain:server#2File surface:
packages/plugins/plugin-audit/src/**and its tests, the report door's file only to call the writer, i18n bundles if needed, root.changeset/. ⛔ Nopackages/spec/**without the seat re-scoping, noui/**Container & model: S,
mode:thread,model: default tier,effort: mediumClause-②: yes (widening: a new
sys_audit_log.actionvalue)Metadata-protocol: none
Responsibility: finding of cloud#3665 (report cloud#3665 comment 6731925007), filed by repo:cloud#3
Thread-read: none
Premise: holds as filed, read at claim on
origin/mainad622d30: thesys_audit_logaction options have no report value, and the export door's run-level row (data-export-audit.ts) is the only run-level writerSerial constraints cleared: none; no other in-flight card on this seat touches
plugin-auditScope: Fixes #31797. One run of a report writes exactly one
sys_audit_logrow: the principal, the report name, the filter field names (never values), the row count and the outcome, following the export door's run-level precedent. Order:/mnt/project-files/server-seat2/standard-order.md+/mnt/project-files/server-seat2/31797-delta.md. Summons: the maintainer's 「server 任务很多,你应该跟进并发5」 (project chat, 2026-11-09T02:28Z).objectstack-fleet commentedon Nov 9, 2026
domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM
待裁 · 「运行报表写审计」在服务端没有可挂的入口 · 2026-11-09T06:31Z
一句话问题: 卡要求每次运行报表写一行审计,并记下报表名。但 main 上报表是在浏览器里拼出来的,服务端只看到一次次数据集查询,既拿不到报表名,也分不清这次查询是报表发的还是仪表盘发的。
背景
cloud#3665(企业版 SIEM)要求收到「报表运行」事件,cloud 车道据此开了本卡。卡线程第 0 步实测(树
ad622d30,读数/mnt/project-files/server-seat2/31797-step0.md):/reports这一族 REST 接口已随旧报表栈退役(retire the saved-report stack —sys_saved_report/sys_report_schedule,/api/v1/reports,client.reports,IReportService, thereportscapability and@objectstack/plugin-reports(zero consumers; not thereportmetadata kind) #20102,packages/rest/src/rest-server.ts约 L2142、L5000)。没有任何服务方法负责运行已保存的报表,MCP/AI 也没有报表工具。ui/packages/plugin-report/src/DatasetReportRenderer.tsx每个展示块各发一次POST /analytics/dataset/query {datasetName, selection}(packages/rest/src/analytics-routes.tsL111)。报表名不进服务端。打开一张报表会发出多次查询,仪表盘部件也走同一个接口。所以卡面的证据(「报表执行路径上没有写入方」)属实,原因是这条路径根本不存在。
Governing text
packages/plugins/plugin-audit/src/data-export-audit.ts:导出接口写一行运行级审计(feat(audit): every data export writes one run-levelsys_audit_logrow, and theexportaction comes back with its writer #31000),这是本卡要沿用的先例。请求在开始读取前被拒绝时不写;读取开始后失败的,写一行outcome: failed。packages/plugins/plugin-audit/src/read-audit.ts:记录读取审计是按对象在安装时开启的封闭名单,没有全局开关。sys_audit_log.action的取值只定义在plugin-audit/src/objects/sys-audit-log.object.ts,spec 里没有镜像枚举。协议声明:
Clause-②: yes (widening)(新增一个 action 取值),Metadata-protocol: none。前提复核:
git grep -n "_retiredReportsServiceProvider" origin/main -- packages/rest/src/rest-server.ts有命中;git grep -n "queryDataset" origin/main -- ui/packages/plugin-report/src/DatasetReportRenderer.tsx有命中。选项
report_run审计;前端渲染器改走这个接口report字段,带了就记审计POST /analytics/dataset/query写一行dataset_query,记录调用者、数据集名、所选维度和指标名、过滤字段名(不记值)、行数和结果。按导出接口的先例与写入方式实现,并像记录读取审计一样按数据集在安装时开启analytics-routes.ts· 1 PR;先例 #31000(导出)、read-audit(按对象开启)业务含义直译:
os-decision-facets
① 项目长远合理性:C 记录服务端实际执行的读取,每一行都是权威事实;A 要把报表执行搬回服务端,等于部分撤回 #20102 的退役方向;B 把客户端自报的名字写进审计。
② 实际业务拉动:cloud#3665 的企业 SIEM 要求收到报表事件;本席没有读到它是否必须精确到报表名(置信缺口)。
③ 防 AI 犯错:C 的 action 按记录内容命名,不会被误读成「报表运行」;B 的名字可以被省略或伪造。
④ 创业阶段不扩散:C 新增一个 action 取值和一个按数据集开启的名单;A 新增一条路由和一次 ADR,是永久义务。
Prior rulings read:
report,#20102,read-audit,opt-in,export auditin plugin-audit / rest-server / ADR index → #20102 (saved-report stack retired), #31000 (export run-level row), read-audit's per-object opt-in header.席位推荐
推荐 C。理由有三:一,审计要记服务端真正执行、真正交出去的数据,C 的每一行都是服务端的权威事实,B 的报表名可以伪造;二,C 只动本车道两个包,沿用 #31000 和 read-audit 两个现成先例,不新增路由,也不改前端;三,按数据集开启,默认不写,日志量不会因为仪表盘刷新而暴涨。如果 SIEM 的要求必须精确到报表名,就另立一张 A 的 ADR 卡交维护者,不放在这张 p3 里做。C 的 action 取值按它记录的内容命名为
dataset_query,不叫report_run:审计字段宁可窄,也不能名不副实。在裁定之前,卡线程不写任何代码。
objectstack-fleet commentedon Nov 9, 2026
domain:server#2 · os-steve · session_01ADHkmSnFAgPUKAz3xraGoJ
os-dev-report
{ "issue": 31797, "status": "needs_decision", "branch": "claude/project-thread-r06jvv", "pr": null, "session": "session_01ADHkmSnFAgPUKAz3xraGoJ", "premise_still_valid": false, "summary": "Step 0 only, no code. On origin/main ad622d30 there is no server-side report execution path: the saved-report /reports REST family and its service were retired (#20102; rest-server.ts ~L2142 retired provider slot, ~L5000), no service method runs a saved report, and no MCP or AI tool runs one. A report runs in the browser: ui/packages/plugin-report/src/DatasetReportRenderer.tsx posts POST /analytics/dataset/query {datasetName, selection} once per presentation (table, matrix, chart, each joined block, drill drawer, re-reads). The report name never reaches the server, and the door cannot tell a report's query from a dashboard widget's, so 'one row per report run naming the report' has no seam. The card's evidence holds (no writer), but because the path does not exist. Readings: /mnt/project-files/server-seat2/31797-step0.md. Seat decision analysis: issuecomment-6733834629.", "tests": "none: needs_decision before any code (standard order step 10)", "gates": "none run: no diff", "dogfood_battery": "n/a — no diff", "mcp_calls": "3 — mcp__github__issue_read (get, get_comments x2); no write tools", "api_writes": "1 — this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/31797/comments via post-stamped relay)", "files_changed": [], "line_budget": "n/a — no diff", "deviations": [ "Delta ruling 3 assumed the export door writes an outcome row for refusals; it does not. data-export-audit.ts writes NO row for a refusal before reading and one outcome:failed row only after reading began. Whichever option is ruled, the card thread would follow the precedent as it is: refused = no row, failed-after-start = one failed row." ], "seat_rulings_read": { "ruling_1_spec_mirror": "sys_audit_log.action options live only in plugin-audit/src/objects/sys-audit-log.object.ts L423ff; packages/spec carries no mirror enum, only the ADR-0087 registry entry migrations/entries/semantic/17.audit-log-action-enum-retired.ts. No spec change needed for a new value.", "ruling_2_paths": "none on main (see summary)." }, "open_questions": [ { "question": "Where does the report-run audit row sit, given main has no server-side report execution path?", "options": [ "A — new server-side report run door (server loads the report, compiles block selections, writes one report_run row with the authoritative name; renderer switches to it). Root fix; L; new REST route + ui/** + reopens the #20102 retirement direction; ADR, maintainer.", "B — optional report key on the dataset-query body, audited when present. M; ui/** + REST body widening; client-asserted name, N rows per view. Not recommended.", "C — one dataset_query row per POST /analytics/dataset/query (principal, dataset, selection names, filter field names via summarizeExportFilter, row count, outcome), export seam, per-dataset opt-in. S-M; plugin-audit + analytics-routes.ts; no report name.", "D — premise false: close and hand back to cloud#3665; report audit waits for A." ], "recommendation": "C, as the seat's analysis also recommends (named dataset_query, opt-in per dataset); A only as its own ADR card if the report name is required." } ], "security_findings": "none", "out_of_scope_findings": [] }Stamped 2026-11-09T06:33Z.
Generated by Claude Code