Repository navigation
仪表盘对齐方案 p20:逾期项、清单完备度、各部门逾期分布、本月工作构成 #109
Copy link
Copy link
Closed
Description
Activity
Claiming this issue.
- Session:
01SqkTcrxUFci7nqXdbBSe2p(https://claude.ai/code/session_01SqkTcrxUFci7nqXdbBSe2p) - Branch:
claude/issue-109-dashboard-p20 - Worktree:
../duly-issue-109offmain(dd3c619)
Scope: the four KPI tiles + two charts of deck p20 on
duly_duty_health— datasets + widget metadata only. Note thereview_statusdependency on the parallel 清单确认与审定 card (#107): I will define the 清单完备度 measure againstreview_statusregardless and mergemainif #107 lands first / report the gate refusal if it has not.
Generated by Claude Code
- Session:
- added a commit that references this issue
on Sep 2, 2026 { "issue": 109, "status": "done", "branch": "claude/issue-109-dashboard-p20", "pr": "https://github.com/objectstack-ai/duly/pull/111", "premise_still_valid": true, "summary": "Added the two missing p20 KPI cards and both p20 charts to duly_duty_health, all as metadata: a new measure duly_duty_health.tasks_overdue (late_after < {today} AND status IN (open,in_progress) — a plain date filter on #52's dispatch stamp, never a due_date window), a new fourth dataset duly_duty_register based on duly_duty (the only object that can see standing and unapproved duties), and four widgets — Overdue tile, List completeness tile, Overdue-by-unit bar ordered by unit name, and a Work mix pie over duly_duty.form. TWO DEVIATIONS, both documented in the module header rather than silently taken. (1) The completeness tile ships WITHOUT the card's 'N to confirm / M to approve' sub-caption: a dataset-bound KPI renders values[0] and drops the rest, and the authored sub-caption slot (options.description, translation key ...subCaption) is read only on the inline metric path, which no spec-valid widget can reach because `dataset` is required. Measured in objectui and filed as objectstack-ai/objectui#7293; not faked as static text, and the two counts are deliberately not declared on the dataset until the renderer can show them. (2) The deck's 'four cards, two charts' is delivered as six tiles and four charts: the three stagnation tiles ARE the deck's 停滞项 card (the file header's nested-threshold reasoning, pinned by test/dashboard.test.ts), and the two existing charts were not retired to hit a slide count. No seed change was needed — the fixture already produces 4 overdue tasks across 3 units.", "tests": "Gates at f3047e8 under the shared verify lock (scripts/pm/os-verify-lock.sh), exit codes captured before any pipe. validate: 'os-verify-lock: VERDICT command-exit 0' / '✓ Validation passed (545ms)' with the one expected hierarchy-security warning. typecheck: VERDICT command-exit 0, tsc --noEmit silent. build: VERDICT command-exit 0 / '✓ Build complete (723ms)'. test: VERDICT command-exit 1 — 'Test Files 1 failed | 28 passed (29) / Tests 1 failed | 753 passed (754)'. The single failure is the #107 dependency and nothing else: test/metadata-bindings.test.ts prints \"dataset duly_duty_register · measures 'duties_approved'.filter key: \\\"review_status\\\" — \\\"review_status\\\" is not a field on duly_duty\". NOTE the card predicted `pnpm validate` would refuse it; measured, validate exits 0 because it does not resolve dataset field references at all (objectstack#14105) — the unit gate is the only one that sees it. MERGE MEASURED, not assumed: merging #107's pushed branch head 868c8a5 into mine in a throwaway worktree (953bf9e, 17 files / 985 insertions, no conflicts) gives all four gates green — validate 0, typecheck 0, 'Test Files 30 passed (30) / Tests 787 passed (787)', build 0. So it is landing order only; whoever lands second merges main and re-runs. BROWSER: pnpm demo on port 4109, fresh DB, own PIDs killed by recorded pid (never by name). Live off POST /api/v1/analytics/dataset/query — tasks_overdue = 4; by business_unit = Northgate Operations 1, Riverside Plant 1, Northgate Quality 2 (the largest bar renders in the MIDDLE, so the by-name order is visible on screen); duties_in_register by form = Recurring 23, One-off 1, Standing 3. The completeness tile shows the runtime's own 400 naming review_status — refused loudly at query time, not silently zero. SIMULATION of #107's field (local, uncommitted, labelled as such in the PR): mutation confirmed on disk by anchored grep -c counts BEFORE any reading (review_status lines 0->1, to_confirm 0->1) and restored by an EXIT/INT/TERM trap with git status clean after; the tile then rendered 0.85 from {duties_approved: 23, duties_in_register: 27}. A first simulation run left every duty at the approved default and rendered 1.00 — which independently re-confirms #101's finding that '0.0%' would have printed 1.0% on a perfect register. New unit coverage: test/datasets.test.ts gains the task-vs-duty base-object split, the overdue measure's late_after/{today} threshold plus 'reads no due_date', and five duly_duty_register assertions; test/dashboard.test.ts gains a block pinning the four p20 numbers by the measure each binds. test/i18n-coverage.test.ts's untranslatable dataset-label count moved 29 -> 36 (the new measure label + the new dataset's six strings), updated with the reason in the comment.", "open_questions": [ { "question": "The deck's p20 is 'four KPI cards and two charts'. This PR ADDS the two missing cards and the two deck charts, leaving the screen at six tiles and four charts. Is that the intended end state, or should the two pre-existing charts (Not moving by unit / Coming up) be retired so the screen matches the slide exactly?", "options": [ "A — keep all four charts (what shipped). The issue's own table marks the three stagnation tiles as 保留 and never asks for a removal; the file header defends both existing charts (earliest actionable signal per unit, and the forward look); and test/dashboard.test.ts pins the >30d tile's 'subset' wording plus needs a widget filter to exist at all, so removals would mean weakening pinned guards.", "B — retire 'Not moving, by unit' and 'Coming up' so the screen is literally four tiles and two charts for the demo.", "C — keep them but move them below the two deck charts so the first screenful is exactly p20." ], "recommendation": "A, because nothing on the card asks for a removal and both existing charts carry measured product reasoning in the module header that this task was told to extend rather than contradict. If the demo needs a literal p20 screenful, C is the cheap version (a layout-only change to two `layout.y` values) and does not delete anything." } ], "out_of_scope_findings": [ "filed as objectstack-ai/objectui#7293: a dataset-bound KPI tile can render no sub-caption at all — DatasetWidget's isMetric branch drops every measure after values[0], and the authored options.description sub-caption (translation key ...subCaption, resolved by tWidgetSubCaption, overlaid server-side by translateDashboard) reaches only the inline object-metric path, which no spec-valid widget can take because `dataset` is required on DashboardWidgetSchema — a declared-and-unenforced key with four layers of live plumbing behind it" ] }
Generated by Claude Code
os-dev-report
(Replaces the comment above: GitHub's body sanitizer ate the HTML-comment marker on that one, so this is the same report with a literal-text marker the PM scan can see. There is no edit-comment tool available in this session, hence a replacement rather than a fix in place.)
{ "issue": 109, "status": "done", "branch": "claude/issue-109-dashboard-p20", "pr": "https://github.com/objectstack-ai/duly/pull/111", "premise_still_valid": true, "summary": "Added the two missing p20 KPI cards and both p20 charts to duly_duty_health, all as metadata: a new measure duly_duty_health.tasks_overdue (late_after earlier than {today} AND status IN (open,in_progress) — a plain date filter on #52's dispatch stamp, never a due_date window), a new fourth dataset duly_duty_register based on duly_duty (the only object that can see standing and unapproved duties), and four widgets — Overdue tile, List completeness tile, Overdue-by-unit bar ordered by unit name, and a Work mix pie over duly_duty.form. TWO DEVIATIONS, both documented in the module header rather than silently taken. (1) The completeness tile ships WITHOUT the card's 'N to confirm / M to approve' sub-caption: a dataset-bound KPI renders values[0] and drops the rest, and the authored sub-caption slot (options.description, translation key ending .subCaption) is read only on the inline metric path, which no spec-valid widget can reach because `dataset` is required. Measured in objectui and filed as objectstack-ai/objectui#7293; not faked as static text, and the two counts are deliberately not declared on the dataset until the renderer can show them. (2) The deck's 'four cards, two charts' is delivered as six tiles and four charts: the three stagnation tiles ARE the deck's 停滞项 card (the file header's nested-threshold reasoning, pinned by test/dashboard.test.ts), and the two existing charts were not retired to hit a slide count. No seed change was needed — the fixture already produces 4 overdue tasks across 3 units.", "tests": "Gates at f3047e8 under the shared verify lock (scripts/pm/os-verify-lock.sh), exit codes captured before any pipe. validate: 'os-verify-lock: VERDICT command-exit 0' / '✓ Validation passed (545ms)' with the one expected hierarchy-security warning. typecheck: VERDICT command-exit 0, tsc --noEmit silent. build: VERDICT command-exit 0 / '✓ Build complete (723ms)'. test: VERDICT command-exit 1 — 'Test Files 1 failed | 28 passed (29) / Tests 1 failed | 753 passed (754)'. The single failure is the #107 dependency and nothing else: test/metadata-bindings.test.ts prints [dataset duly_duty_register · measures 'duties_approved'.filter key: \"review_status\" — \"review_status\" is not a field on duly_duty]. NOTE the card predicted `pnpm validate` would refuse it; measured, validate exits 0 because it does not resolve dataset field references at all (objectstack#14105) — the unit gate is the only one that sees it. MERGE MEASURED, not assumed: merging #107's pushed branch head 868c8a5 into mine in a throwaway worktree (953bf9e, 17 files / 985 insertions, no conflicts) gives all four gates green — validate 0, typecheck 0, 'Test Files 30 passed (30) / Tests 787 passed (787)', build 0. So it is landing order only; whoever lands second merges main and re-runs. BROWSER: pnpm demo on port 4109, fresh DB, own PIDs killed by recorded pid (never by name). Live off POST /api/v1/analytics/dataset/query — tasks_overdue = 4; by business_unit = Northgate Operations 1, Riverside Plant 1, Northgate Quality 2 (the largest bar renders in the MIDDLE, so the by-name order is visible on screen); duties_in_register by form = Recurring 23, One-off 1, Standing 3. The completeness tile shows the runtime's own 400 naming review_status — refused loudly at query time, not silently zero. SIMULATION of #107's field (local, uncommitted, labelled as such in the PR): mutation confirmed on disk by anchored grep -c counts BEFORE any reading (review_status lines 0 to 1, to_confirm 0 to 1) and restored by an EXIT/INT/TERM trap with git status clean after; the tile then rendered 0.85 from {duties_approved: 23, duties_in_register: 27}. A first simulation run left every duty at the approved default and rendered 1.00 — which independently re-confirms #101's finding that '0.0%' would have printed 1.0% on a perfect register. New unit coverage: test/datasets.test.ts gains the task-vs-duty base-object split, the overdue measure's late_after/{today} threshold plus 'reads no due_date', and five duly_duty_register assertions; test/dashboard.test.ts gains a block pinning the four p20 numbers by the measure each binds. test/i18n-coverage.test.ts's untranslatable dataset-label count moved 29 to 36 (the new measure label + the new dataset's six strings), updated with the reason in the comment.", "open_questions": [ { "question": "The deck's p20 is 'four KPI cards and two charts'. This PR ADDS the two missing cards and the two deck charts, leaving the screen at six tiles and four charts. Is that the intended end state, or should the two pre-existing charts (Not moving by unit / Coming up) be retired so the screen matches the slide exactly?", "options": [ "A — keep all four charts (what shipped). The issue's own table marks the three stagnation tiles as 保留 and never asks for a removal; the file header defends both existing charts (earliest actionable signal per unit, and the forward look); and test/dashboard.test.ts pins the 30d tile's 'subset' wording and needs a widget filter to exist at all, so removals would mean weakening pinned guards.", "B — retire 'Not moving, by unit' and 'Coming up' so the screen is literally four tiles and two charts for the demo.", "C — keep them but move them below the two deck charts so the first screenful is exactly p20." ], "recommendation": "A, because nothing on the card asks for a removal and both existing charts carry measured product reasoning in the module header that this task was told to extend rather than contradict. If the demo needs a literal p20 screenful, C is the cheap version (a layout-only change to two `layout.y` values) and does not delete anything." } ], "out_of_scope_findings": [ "filed as objectstack-ai/objectui#7293: a dataset-bound KPI tile can render no sub-caption at all — DatasetWidget's isMetric branch drops every measure after values[0], and the authored options.description sub-caption (translation key ending .subCaption, resolved by tWidgetSubCaption, overlaid server-side by translateDashboard) reaches only the inline object-metric path, which no spec-valid widget can take because `dataset` is required on DashboardWidgetSchema — a declared-and-unenforced key with four layers of live plumbing behind it" ] }
Generated by Claude Code
售前演示优先级 p0。 方案 v7 p20 是「领导端的第一屏」:四个指标卡 + 两张图。现在
duly_duty_health有停滞三卡 + 按期率 + 两张图,但方案的四卡里缺两张、两张图都不是方案的。全部是数据集 + 组件元数据。四个指标卡(p8、p20 同一组)
late_after是普通日期列:late_after < {today} AND status IN (open, in_progress),治理口径format问题见 #101,不要绕review_status计数、不按条目数:approved占全部治理职责的比例,附「N 条待确认 / M 条待审定」副标。字段由同批「清单确认与审定」卡片提供;先落地的一方定义数据集,后落地的合 main。绝不做「谁条目数偏低」——AGENTS.md 不变量两张图(p20)
duly_duty.form计数(recurring / one_off / standing)。注意常设职责没有任务,这张图数的是职责不是任务;图下一句口径说明「完成率只统计重复事项」(p20 原文)。规则(沿用现有仪表盘文件头)
showDataLabels: false的对比度理由在文件头,别改。验收
test/dashboard.test.ts的「不按人排序」属性守卫仍然通过并覆盖新组件