64eac0cbbb6b76db0974612fe3731779cde05b63
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 031dc6b995 |
D12 - the productivity factor, on the dashboard (was BL-023)
Nick's decision: 'find a spot on the dashboard.' The spot: an eighth metric
card beside Est./Actual hrs - actual/estimated to two decimals, green at or
under 1.0, red over. Both hour fields are optional (CR-017), so with nothing
to divide the card shows an em dash rather than vanishing: a metric that
disappears reads as 'no such measure', not 'nothing logged yet'. Server sums
(B4), the same m.est_hours/actual_hours its neighbours already render - zero
new fetches, and the card stays inside the block the metrics-failure path
skips, so an outage still shows the error panel and no cards.
aggregates_check gains the pin (16 -> 17): the card must equal the quotient
of the SERVER's sums, or the em dash when either sum is zero - derived, not
hardcoded. Backlog entry corrected in passing where it credited
/api/projects/{id}/summary with hour sums it never carried.
Items: D12 (decisions-2026-08-20.md), CR-017 read, B4 discipline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|||
| 815f266039 |
T6.5 - A7: cards say their state, the footer says what it is showing
A7's "do not" is louder than its "do", so that first: admin.js:484-517 handles
language and time, it is a shipped feature, the review specifically endorsed
keeping it, and if the proposal reads as removing it that reading is wrong. It
is UNTOUCHED. The probe checks that by diffing the file against HEAD as well as
by driving the feature — switching locale, saving, reloading, and confirming the
saved value came back from the server.
Card status lines
Two things were doing one job badly. The SOP card said "SOP complete" when it
was and NOTHING when it was not — so the commonest state on a live project was
the one with no status line at all. And the Work Package card carried its state
in its BUTTON ("Complete SOP first", "Checking..."), which is a button
describing a situation instead of naming what pressing it does.
Now every card says its state in its own line, in all three states, and no
button changes text to report one:
complete green, the canonical success token
not yet secondary text - a real answer, and neither green nor a warning
unknown the suite's amber, and it names the failure
Each carries a glyph and a word as well as a colour. The line is replaced in
place rather than removed and re-added, because a card that briefly has no
status line reads as "no status" and that is one of the three real answers.
role="status" on it: the text is written by a fetch that lands after the page
has settled, which is what aria-live is for (S10).
Footer
Was "Work Package Suite v1.0 | Prime Controls - Business Technology Group |
Pilot Use Only", which leaves three questions open: v1.0 of what, who Business
Technology Group is to this page, and what Pilot Use Only actually restricts.
Now two sentences. The first names the product and who maintains it. The
second says what "pilot" means in the only terms that matter to somebody about
to type a real work package into it: the work is real and is kept, the tools
around it are still changing. The bare version string is gone rather than left
claiming to be a version of something unspecified.
html/index.html three-state card status, the footer
tests/cards_check.py new - 44 checks
tests/aggregates_check.py two assertions re-pointed (see below)
Done when
[x] card status lines read clearly and use the canonical status colours
[x] the footer is unambiguous about what it is showing
[x] localization still functions - verified by switching language, saving,
reloading and reading the value back off the server
[x] admin.js:484-517 behaviour is unchanged - and the file is byte-identical
Two probes needed re-pointing, and both were asserting wording rather than
behaviour
aggregates_check waited for the card's status line to be non-empty and then
matched the phrase "SOP complete". The wait is now wrong for a second reason:
the line is non-empty from the moment the page loads, because it says
"Checking the SOP...". It waits for the answer instead, and matches the
ANSWER rather than the sentence - which is what that check was ever about,
since it exists to prove the answer came from the server and not the cache.
A probe that breaks when wording changes is a probe that will be edited
carelessly the next time wording changes. Both are now written so that only a
behaviour change can fail them.
Verified one at a time
cards_check 44/44 new
aggregates 16/16 (two assertions re-pointed)
browser_check 71/71
a11y 22/22
launcher 58/58
f_items F1-F5 FIXED, F6 REPRODUCES (T7.2)
No colour literal added: the three status colours are --cds-support-success,
--cds-text-secondary and --wp-status-warning-text, all already in
theme-light.css.
Question for the PR, per CLAUDE.md: the footer now says work packages created in
the pilot are kept. That is true of the database and it is the thing people
actually want to know, but it is a promise, and whoever owns the pilot should
confirm it is one we are making.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|||
| b670ae719d |
T4.1 - B4: the counts come from the server, and disagreement is said out loud
The defect B4 names is not that the numbers were wrong. On one browser with one
cache they were right. It is that they were derived from the caller's own
localStorage, so two people on the same project saw different numbers and neither
was told.
SERVER. /api/wps/metrics now returns everything the creator's dashboard shows -
total, mine, release-ready, on hold, overdue, est/actual hours, by_status,
by_discipline, progress (overall and per discipline) and the gating list. It
already existed for a subset; the rest was being summed in the browser.
Two things moved to the server rather than being duplicated there:
- PROGRESS_WEIGHT, the status-to-percentage table. It was PROGRESS_W in
wp-creation-app.js; the JS copy is deleted rather than left in place, because
two copies of a weighting table is how the two drift apart.
- "release-ready" now counts `waitingOn` predecessors as blocking, which the
browser did and the old endpoint did not. Without that the phrase would have
changed meaning the moment the dashboard stopped computing it locally.
New GET /api/projects/{id}/summary gives the launcher the SOP state it was
reading out of localStorage.
by_location is shaped for CR-018 in wave 6, per the task's instruction not to
build a shape that cannot group by building/floor/sector. It reports its own
dimensions alongside the groups:
{"dimensions": ["location"], "groups": [{"key": {...}, "total": n,
"release_ready": n, "on_hold": n, "overdue": n, "by_status": {...}}]}
Today a package carries one free-text `location`, so that is the one dimension.
_location_key() already prefers structured building/floor/sector when present, so
CR-004 changes the dimensions and the keys and leaves the response shape alone.
CLIENT. The launcher's SOP card and the dashboard's tiles, chips, progress bars
and gating panel all read the server. There is deliberately no cache fallback: a
silently-stale number that looks authoritative is the thing being removed, so a
failed request renders an explicit error and a retry.
Writes flush through the outbox before the counts are re-read (dashRefreshAfterWrite).
Without that the refresh races the push and shows pre-write totals - the same
stale number arriving by a different route.
THE ONE COUNT STILL COMPUTED LOCALLY, stated rather than skipped: the board table
is a LIST of the packages this browser holds, which is what keeps the field view
working offline, and its header counts rows. Rather than pretend otherwise, it is
reconciled against the server's total and shows "this browser has N of M" when
they differ - usually a save that has not finished syncing. Nobody now sees a
number that disagrees with the project without being told, which is what B4 asks
for.
VERIFICATION. tests/aggregates_check.py, 16 checks, all passing. It tests what was
broken rather than whether the totals are right - the latter passed before this
change:
- root and pat get byte-identical aggregates for the same project
- the dashboard shows the server's total after localStorage is POISONED with a
different package list; it cannot do that if it is summing the cache
- a simulated outage renders "Counts unavailable", names the failure, offers a
retry, renders no tiles beside it, and announces via role=alert
- the launcher reports the SOP complete against a cache that says otherwise,
and says "Could not check" when the request fails
- by_location's groups are keyed by its declared dimensions, carry their own
rollups, and sum to the project total
browser_check 71/71, f_items 5 FIXED / F6 REPRODUCES.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|