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
{{ message }}
Repository navigation
service-analytics: a dataset's currency guard compares a count that names an amount field, refusing an amount-per-row ratio as cross-currency (multi-currency, epic #8345) #28194
measureCurrencyResolver.resolvedOf (measure-currency-coherence.ts, the non-derived branch) resolves a measure's currency from fieldOf(m) without reading m.aggregate. DatasetMeasureSchema.field is allowed on a count (a count of non-null values; the guard's own test dataset declares priced_invoices: { aggregate: 'count', field: 'amount' }). Such a count therefore resolves to the amount's currency (record, or a fixed code), and guard 2 compares it with the other operand. A ratio of usd_total (fixed USD) over priced_invoices (a count over a record-mode or a differently-coded amount) is refused with DATASET_INVALID "amounts in different currencies", although one operand counts rows.
The other two readers already gate on AMOUNT_AGGREGATES and get the same count right: enrichResultColumns and the analytics cube door. Ruling 6486427200 on #8345 and ADR-0144 Open item 12's note both say "a count operand is not compared".
Responsibility: PR #27991 (#27579), which wrote the resolver.
Task
In resolvedOf's non-derived branch, resolve a currency only for an amount aggregate (the same AMOUNT_AGGREGATES set the cube door and enrichResultColumns use); a count with a field resolves to none.
Pin it: a ratio and a sum derived measure over an amount and a count with field compile; the existing refusals (two different fixed codes, a record amount against a fixed one) stay red. Ablate the new test.
Lane: server (@objectstack/service-analytics) · Size: S · Review: default. Declarations, for the card to confirm: Clause-②: yes (widening) (a refusal shrinks) · Metadata-protocol: none; patch changeset.
Epic: #8345. Dedupe: PR #28181 review record; no open card carries this.
Claim: PM loop round 4 · cross-lane · 2026-10-31T05:44Z
Session: session_01L9qibz8HEj53Wx2uphTo2o (seat; implementation by card thread session session_01L9qibyimd4GfDwsijRiftT, mode:thread)
Account: os-tesla (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/project-thread-5zv5e6 (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-28194
Domain: domain:server (the card keeps its lane; dispatched by ui seat 3)
Seat: domain:ui#3
File surface: packages/services/service-analytics/src/measure-currency-coherence.ts (gate the non-derived branch on AMOUNT_AGGREGATES imported from cube-record-currency-door.ts), packages/services/service-analytics/src/analytics-service.ts (enrichResultColumns non-record arm, same gate; seat ruling), their tests, one root changeset (stop on breach; explain in the report)
Container & model: S, mode:thread, model: default (dispatch-gates --tier re-run on the actual diff), effort: high
Clause-②: yes (widening: two refusals shrink; card's own declaration, re-judged on the diff)
Metadata-protocol: none
Responsibility: PR #27991 (#27579), which wrote the resolver
Thread-read: none
Premise: re-measured by the card thread on main69c39b16 before this claim (premise holds)
Serial constraints cleared: server seat 2 answered "No objection: take both" on #28284 (6539522584) and holds no overlapping work; server seat 1 was notified on #6367 and raised no objection within the 20-minute window. ui seat 3 siblings share no file with this card.
{
"issue": 28194,
"status": "done",
"branch": "claude/project-thread-5zv5e6",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28360",
"session": "session_01L9qibyimd4GfDwsijRiftT",
"premise_still_valid": true,
"summary": "measureCurrencyResolver.resolvedOf's non-derived branch now resolves a currency only for an amount aggregate, through the existing AMOUNT_AGGREGATES export of cube-record-currency-door.ts (no copy, nothing moved), so a count over an amount field or with its own currency is never a guard-2 operand. Per the seat's ruling, enrichResultColumns' fixed/tenant arm takes the same gate, so a count over a fixed or tenant-currency amount carries no currency on its column. Premise measured on main 69c39b16 before the fix: ratio(usd_total, priced_invoices) refused DATASET_INVALID; a count with a currency key reached monetaryOperands through the same branch (closed by the same gate, pinned).",
"tests": "head 85afc7ba. record-currency-analytics.test.ts: 8 new tests; on the unfixed source 6 failed | 54 passed (60) (expected 'EUR' to be undefined; expected the refusal message to be undefined); with the fix 60 passed (60). Ablation 1 via scripts/ablation-replace.mjs on measure-currency-coherence.ts (resolver gate forced true, anchor 1 -> 0, blob 985caf62 -> e563f99c): 3 failed | 57 passed, the three accepted-derived tests; restored blob == HEAD, git diff HEAD empty. Ablation 2 on analytics-service.ts (column gate removed, blob 0ea0b0f3 -> 624524bf): 3 failed | 57 passed, the three count-column tests; restored, git diff HEAD empty. Tests import src relatively, no dist build involved. pnpm --filter @objectstack/service-analytics test: Test Files 200 passed (200), Tests 4814 passed | 282 skipped; typecheck tsc --noEmit exit 0 (os-verify-lock VERDICT command-exit 0).",
"gates": "dispatch-gates --commands at 85afc7ba (4 paths vs merge base 69c39b16): 62 derived; 61 exit 0; pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (needs every package dist; only the service-analytics closure was built) = NOT MEASURED, declared narrowing, CI Lint and Repo Gates runs it. check-plugin-teardown-shape --self-test first exit 3 on the shallow clone (pinned fixture commit absent), exit 0 after fetching that commit. --ran reconciliation: 62 derived accounted for, 61 run, 1 NOT-MEASURED, 0 UNRUN. PR check-runs: in_progress at report time.",
"line_budget": "114 changed lines (+107 / -7), under the 3000 human-merge threshold",
"files_changed": [
".changeset/28194-count-is-not-an-amount.md",
"packages/services/service-analytics/src/measure-currency-coherence.ts",
"packages/services/service-analytics/src/analytics-service.ts",
"packages/services/service-analytics/src/__tests__/record-currency-analytics.test.ts"
],
"deviations": [
"analytics-service.ts (enrichResultColumns) is outside the card's own task list; folded in by the seat's ruling and named in the claim's file surface",
"main checkout detached to host the worktree on the platform-designated branch (worktree path objectstack-28194, not objectstack-issue-28194)",
"one shallow-clone fetch of a pinned self-test fixture commit"
],
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "4 — mcp__github__issue_read (get x1, get_comments x2) and ToolSearch load; 0 writes",
"api_writes": "2 — relay pr_create (objectstack-ai/objectstack#28360), relay comment os-dev-report on #28194; plus 1 git push",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed: an author-declared currency on a count still labels that count's column (unchanged behaviour, not judged by the card or the ruling)"
]
}
Activity
objectstack-fleet commentedon Oct 31, 2026
domain:ui#3 · os-tesla · session_01L9qibz8HEj53Wx2uphTo2o
Claim: PM loop round 4 · cross-lane · 2026-10-31T05:44Z
Session:
session_01L9qibz8HEj53Wx2uphTo2o(seat; implementation by card thread sessionsession_01L9qibyimd4GfDwsijRiftT,mode:thread)Account:
os-tesla(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-5zv5e6(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-28194Domain:
domain:server(the card keeps its lane; dispatched by ui seat 3)Seat:
domain:ui#3File surface:
packages/services/service-analytics/src/measure-currency-coherence.ts(gate the non-derived branch onAMOUNT_AGGREGATESimported fromcube-record-currency-door.ts),packages/services/service-analytics/src/analytics-service.ts(enrichResultColumnsnon-record arm, same gate; seat ruling), their tests, one root changeset (stop on breach; explain in the report)Container & model:
S,mode:thread,model: default(dispatch-gates --tierre-run on the actual diff),effort: highClause-②: yes (widening: two refusals shrink; card's own declaration, re-judged on the diff)
Metadata-protocol: none
Responsibility: PR #27991 (#27579), which wrote the resolver
Thread-read: none
Premise: re-measured by the card thread on
main69c39b16before this claim (premise holds)Serial constraints cleared: server seat 2 answered "No objection: take both" on #28284 (6539522584) and holds no overlapping work; server seat 1 was notified on #6367 and raised no objection within the 20-minute window. ui seat 3 siblings share no file with this card.
Maintainer 2026-10-31 05:10Z 「座位之间可以协调,你有空你就可以派」. Notice: #28284 6539514907 (+ amendment 6539527220). Order:
/mnt/project-files/ui-seat-3/r2026-10-31/dispatch-28194.md.objectstack-fleet commentedon Oct 31, 2026
domain:ui#3 · os-tesla · session_01L9qibyimd4GfDwsijRiftT
os-dev-report
{ "issue": 28194, "status": "done", "branch": "claude/project-thread-5zv5e6", "pr": "https://github.com/objectstack-ai/objectstack/pull/28360", "session": "session_01L9qibyimd4GfDwsijRiftT", "premise_still_valid": true, "summary": "measureCurrencyResolver.resolvedOf's non-derived branch now resolves a currency only for an amount aggregate, through the existing AMOUNT_AGGREGATES export of cube-record-currency-door.ts (no copy, nothing moved), so a count over an amount field or with its own currency is never a guard-2 operand. Per the seat's ruling, enrichResultColumns' fixed/tenant arm takes the same gate, so a count over a fixed or tenant-currency amount carries no currency on its column. Premise measured on main 69c39b16 before the fix: ratio(usd_total, priced_invoices) refused DATASET_INVALID; a count with a currency key reached monetaryOperands through the same branch (closed by the same gate, pinned).", "tests": "head 85afc7ba. record-currency-analytics.test.ts: 8 new tests; on the unfixed source 6 failed | 54 passed (60) (expected 'EUR' to be undefined; expected the refusal message to be undefined); with the fix 60 passed (60). Ablation 1 via scripts/ablation-replace.mjs on measure-currency-coherence.ts (resolver gate forced true, anchor 1 -> 0, blob 985caf62 -> e563f99c): 3 failed | 57 passed, the three accepted-derived tests; restored blob == HEAD, git diff HEAD empty. Ablation 2 on analytics-service.ts (column gate removed, blob 0ea0b0f3 -> 624524bf): 3 failed | 57 passed, the three count-column tests; restored, git diff HEAD empty. Tests import src relatively, no dist build involved. pnpm --filter @objectstack/service-analytics test: Test Files 200 passed (200), Tests 4814 passed | 282 skipped; typecheck tsc --noEmit exit 0 (os-verify-lock VERDICT command-exit 0).", "gates": "dispatch-gates --commands at 85afc7ba (4 paths vs merge base 69c39b16): 62 derived; 61 exit 0; pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (needs every package dist; only the service-analytics closure was built) = NOT MEASURED, declared narrowing, CI Lint and Repo Gates runs it. check-plugin-teardown-shape --self-test first exit 3 on the shallow clone (pinned fixture commit absent), exit 0 after fetching that commit. --ran reconciliation: 62 derived accounted for, 61 run, 1 NOT-MEASURED, 0 UNRUN. PR check-runs: in_progress at report time.", "line_budget": "114 changed lines (+107 / -7), under the 3000 human-merge threshold", "files_changed": [ ".changeset/28194-count-is-not-an-amount.md", "packages/services/service-analytics/src/measure-currency-coherence.ts", "packages/services/service-analytics/src/analytics-service.ts", "packages/services/service-analytics/src/__tests__/record-currency-analytics.test.ts" ], "deviations": [ "analytics-service.ts (enrichResultColumns) is outside the card's own task list; folded in by the seat's ruling and named in the claim's file surface", "main checkout detached to host the worktree on the platform-designated branch (worktree path objectstack-28194, not objectstack-issue-28194)", "one shallow-clone fetch of a pinned self-test fixture commit" ], "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "4 — mcp__github__issue_read (get x1, get_comments x2) and ToolSearch load; 0 writes", "api_writes": "2 — relay pr_create (objectstack-ai/objectstack#28360), relay comment os-dev-report on #28194; plus 1 git push", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed: an author-declared currency on a count still labels that count's column (unchanged behaviour, not judged by the card or the ruling)" ] }objectstack-fleet commentedon Oct 31, 2026
domain:ui#3 · os-tesla · session_01L9qibz8HEj53Wx2uphTo2o
Landed · 2026-10-31T07:08Z
d35db2cca7(ACCEPT 6540250940)completedby the PR'sFixeslineState:
pm:dispatchedremoved (closed card).