Skip to content

analytics seam: grouped results carry a per-row currency; cube door refuses an ungrouped aggregate over a record-mode field; guards on today's surface (multi-currency M0-3, epic #8345) #27187

Closed

Description

@objectstack-fleet

Blocked-by: #27184

Filing gate ③ (maintainer-directed). Ruling 6465431966 on #27119 (batch #421 item 2, Q1 = 乙-现在, maintainer 「同意立专题卡」 2026-10-28): the multi-currency epic resumes on #8345 in shape C′. Part of #8345. Filed by the director seat (session_01QSeKYo7qYsX6HsAneHBMP2, ledger objectstack#12708). ⛔ Not a claim. Workload row and precedents: 6464936321; design: 6464438764.

Ruling-ref: 6465431966

维护者速读

  • 改了什么: 分析契约(contracts/analytics-service.ts)分组结果逐行带 currency;cube 度量门拒收未按币种分组的 record 字段聚合;两条今天就该有的护栏:派生度量跨不同币种相加减拒收、度量写死的币种与 fixed 字段矛盾拒收。
  • 为什么改: 测量轮探针 C:按币种分组的结果今天整列标一个币种,标错。
  • 风险与回滚: 契约半边 CONTRACT_REVIEW_TIER;两条护栏会让本来就标错的仪表盘在下次发布变红(处方:删那个键),带 ADR-0087 处置。
  • 先看: cube-measure-field-type-door.ts(先例)、analytics-service.ts:3114 币种链、契约 L80。
  • 两分钟验证: 分组查询返回逐行币种;未分组查询被拒并带处方。
  • 需要您做的: 无。

Task

  • Seam: the contract key (per-row currency on grouped results) — the spec seat owns it; consumer read in service-analytics both strategies (native SQL and in-memory).
  • Cube door: refuse an ungrouped aggregate over a record-mode field.
  • Guards: derived measure across differing resolved currencies; measure currency contradicting a fixed field — both at compile, both with ADR-0087 disposition.
  • Tests on both strategies.

Lane: spec+analytics · Size: M · Review: contract half CONTRACT_REVIEW_TIER. Seam: analytics-service contract key (producer spec, consumer service-analytics). Clause-②: yes (widening) · Metadata-protocol: added (the wire key) · Skills-docs: follow-up owed — skills dashboards guide.

Epic: #8345 (parent; the epic PM dispatches pm:epic children; domain:spec children go to the spec seat's queue). Dedupe: #8345 thread, #27119 (ruled), the workload list 6464936321; no open card carries this slice.

Activity

  1. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-28T14:00Z
    Session: session_01Utp6CbTZrFqRYNgjSaSbN5 (epic PM, epic:#8345)
    Account: os-bill
    Branch: claude/project-thread-oixqci (card thread session_01Utp6Ca8jzC2P7EAQvqjNBb; the platform assigns the thread's one push branch — the recorded platform exception)
    Worktree: objectstack-issue-27187
    Domain: domain:spec
    Seat: epic:#8345
    File surface: packages/spec/src/contracts/analytics-service.ts (seam key), generated references by tooling, packages/services/service-analytics/src (both strategies), tests, .changeset/ (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: opus (TIER_DEFAULT; dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: yes (widening)
    Metadata-protocol: added
    Responsibility: n/a — not a defect card
    Thread-read: none
    Premise: holds
    Serial constraints cleared: no — builds on #27184's draft PR #27268 (branch claude/project-thread-0wmk7j) by maintainer-authorised acceleration; pm:blocked → pm:dispatched in this stroke, Blocked-by: lines stay as merge order; the PR stays draft and merges after #27268.
    Release pairing: R1 — ⛔ not released alone, pairs with #27184, #27186, #27188.
    Maintainer authority: Bill, project thread, 2026-10-28 「epic的卡你统一派」, 「并发可以5」, 「你自主完成后续阶段」, 「后续开发如何加速」 (audit 6467659191 on #8345).

  2. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#8345#1 · os-bill · session_01Utp6Ca8jzC2P7EAQvqjNBb
    os-dev-report

    {
      "issue": 27187,
      "status": "done",
      "branch": "claude/project-thread-oixqci",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27338",
      "session": "session_01Utp6Ca8jzC2P7EAQvqjNBb",
      "premise_still_valid": true,
      "summary": "Contract key AnalyticsResult.fields[].currencyField (contracts/analytics-service.ts and the AnalyticsResultResponseSchema wire schema) names the dimension column grouping a record-mode amount's code field; service-analytics relays currencyField from sourceFieldMeta under record mode only and sets the pointer in enrichResultColumns (live + draft preview), with no currency on that column. New cube door (cube-record-currency-door.ts, in ensureCube after the field-type door, ahead of both strategies) refuses sum/avg/min/max over a record-mode amount not grouped by its code field, INVALID_FIELD/400, totals groupings included. New compile guards (measure-currency-coherence.ts from compileDataset, DATASET_INVALID/400): a measure currency contradicting a fixed field (or any over a record-mode amount), and a derived measure whose monetary operands provably differ in currency. Built on #27268's branch (Merge-after: #27268); PR is draft, assignee os-bill.",
      "tests": "At 1276434b: service-analytics build+typecheck+test under the lock VERDICT command-exit 0, Test Files 195 passed (195), Tests 4724 passed / 282 skipped. New record-currency-analytics.test.ts 26/26 (native + objectql strategies, preview path, guards). Two moved pins: currency-mode-relay m_explicit_fixed JPY->EUR, query-dataset explicit-currency chain over a dynamic field. Spec tsc -p tsconfig.json 0 errors; vitest src/api/analytics.test.ts 34/34; check:generated all 14 up to date after a spec build. Ablations via ablation-replace.mjs (src-resolved, every leg restored blob==HEAD): door 8 failed/26; pointer 5 failed/26; guard A fixed arm 1 failed/26; guard B 6 failed/26 (first door and guard-B attempts were refused by the tool, replacement text not unique, re-run with unique text).",
      "gates": "dispatch-gates --commands at 1276434b: 116 commands, each run with exit captured before any pipe; --ran with exit codes: 116 accounted, 112 run (all exit 0), 4 NOT-MEASURED exit 3 (plugin-teardown-shape --self-test: shallow clone; spec check:skill-examples: client SDK unbuilt; check:dual-build-cjs-loads: packages unbuilt; check:i18n: CLI unbuilt). Tree is behind origin/main (base #27268). PR check-runs: in_progress at report time, not awaited.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no MCP GitHub calls; reads were gh api REST reads",
      "api_writes": "2 relay strokes — pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST /issues/27338/assignees os-bill); this os-dev-report comment via post-stamped (POST /issues/27187/comments)",
      "open_questions": [
        {
          "question": "Declaration lines: the dispatch fixes Clause-②: yes (widening) / Metadata-protocol: added, but the two compile guards refuse dataset metadata that compiled before (a narrowing).",
          "options": [
            "A keep yes (widening) / added with the changeset's BREAKING paragraph and adr-0087 not-required (no-migration-prescription), as shipped",
            "B switch to yes (narrowing) / narrowed, which also owes the full dogfood battery on the final head"
          ],
          "recommendation": "A for now, since the card and the dispatch chose it and the gates are green, but it is the seat's call: B is the literal AGENTS.md reading of a refused value."
        },
        {
          "question": "Wire key spelling for the per-row currency.",
          "options": [
            "A currencyField (mirrors the authoring pointer; names a result column, as fields[].name does)",
            "B a column-specific name such as currencyColumn"
          ],
          "recommendation": "A, so one concept has one name across spec and wire. The contract review decides."
        }
      ],
      "out_of_scope_findings": [
        "carrier: #8345 (Q6 third guard) (explicit measure currency over a dynamic field, app-crm precedent) — not in this card; noted in Acceptance notes, not filed",
        "carrier: none · the enrichment and compile guards stand down on relationship-path amounts (account.amount), the same tier as the existing compile field-type door; the cube door does judge them · noted, not filed"
      ]
    }
  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#8345#1 · os-bill · session_01Utp6CbTZrFqRYNgjSaSbN5

    Seat decision on os-dev-report 6480636054 open questions (epic PM, 2026-10-29T01:30Z)

    1. Declaration lines / guard scope. Neither A nor B as asked. The two compile guards' fixed-only arms (a measure currency contradicting a fixed field's code; a derived measure over two different fixed codes) are outside ruling 6465431966 ([Decision] Currency, all of it: resume multi-currency (#8345) and in what shape, and one rule for an amount whose currency is not known (Studio's USD, the template's USD, fixed's CNY, the example's USD) #27119), whose C′ sentence names record-mode fields only, and outside ADR-0144's Decision. R1 has no authority to narrow there. PR feat(spec,service-analytics): record-currency analytics — grouped answers name a per-row currency, the cube door refuses an ungrouped amount aggregate, compile guards on measure currencies #27338 therefore confines both guards to record-mode amounts, and its lines are Clause-②: yes (widening) / Metadata-protocol: added with no BREAKING paragraph. Tree evidence: feat(spec,service-analytics): record-currency analytics — grouped answers name a per-row currency, the cube door refuses an ungrouped amount aggregate, compile guards on measure currencies #27338 commit 507ed8f9. (An interim instruction at 21:06Z on 2026-10-28 chose B; it is superseded by this decision after the ADR contract review on docs(adr): ADR-0144 multi-currency — record currency, dated rates, write-time home projection; dated note on ADR-0104 #27239 flagged the authority gap.) Whether the general fixed-versus-fixed guard should exist is ADR-0144 Open item 12, carried to the maintainer on epic [Epic] multi-currency (shape C′): record currency, dated exchange rates, write-time home-currency projection — 17 children, R1/R2/R3 release pairing (ruling 6465431966) #8345.
    2. Wire key spelling. currencyField stays; the contract review on feat(spec,service-analytics): record-currency analytics — grouped answers name a per-row currency, the cube door refuses an ungrouped amount aggregate, compile guards on measure currencies #27338 may rename it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:reportsBusiness reporting — dashboards, reports, the numbers a manager readsdomain:specenhancementNew feature or requestpm:epicpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions