Skip to content

feat(audit): show the sales-line audit payload as a readable Details column (#745) - #749

Merged
mforce merged 3 commits into
mainfrom
feat/745-audit-details-column
Sep 10, 2026
Merged

mforce merged 3 commits into
mainfrom
feat/745-audit-details-column

Conversation

@mforce

@mforce mforce commented Sep 10, 2026 •

Copy link
Copy Markdown
Owner

Closes #745.

The audit Details column renders SalesOrder.AddItem and SalesOrder.UpdateItem payloads as readable product and price summaries, with the old price struck through and the new price bold on updates. It falls back to the reason, then an em dash. English, Spanish and Tagalog labels are updated.

The renderer reads only the row payload and makes no network request. Money uses useFormat().money with the farm locale.

Two deliberate gaps against the artboard remain: the Entity column still renders Sales order 10d2c04d rather than SO-10D2C04D, because the latter is the order's reference number and is not in the audit data. SalesOrder.Confirm rows still show an em dash because that handler writes no reason, and the discount badge needs #721.

Validation from web/, run in the foreground: npm ci; G1 npm run typecheck passed; G2 npx vitest run src/routes/AuditPage.test.tsx src/i18n/catalogParity.test.ts passed (264 tests); G3 npm run test:coverage passed (121 files, 2730 tests; 91.08% statements, 87.36% branches, 86.33% functions, 94.04% lines); G4 npm run build passed. Only the five allow-listed frontend files changed. No Docker or dotnet commands were run; a stack-based visual comparison was not captured.

Before / after — captured at 1:1 from a stack rebuilt at this head

Audit Details column, before and after

Both halves are the same API, the same database and the same four audit rows — only the frontend
differs. main's Vite ran on :5174 from a worktree at 0481c06, this branch's on :5173, both proxying
to one API started from this branch's worktree. Captured with deviceScaleFactor: 1 and no downscaling,
per AGENTS.md #662: a downscaled capture is not a look.

What the capture shows, top to bottom in the AFTER half:

Row Renders Branch it exercises
Order line added Jumbo Eggs (unpriced) ×8 at $16.50 list price null — the no-list-price wording, never a zero
Order line changed Large Eggs $0.40 → $0.38 (list $0.45) the artboard's strikethrough + bold + parenthetical list
Order line added Large Eggs ×240 at list $0.45 the ordinary Add summary
Sales order created — a payload-less action still falls through, unchanged

The BEFORE half is the same four rows under the old Reason column: four em dashes, with the payload
reachable only as a raw JSON title tooltip.

@coderabbitai

coderabbitai Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 3e4426bb-c796-4783-bf13-90bac7d3d73b


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…t in the repo

Owner directive: review binaries do not belong in the repo. The 1:1
before/after capture for the Details column now lives at a
github.com/user-attachments URL referenced from the PR body, which depends
on no ref and survives the branch being deleted (verified: still 200 after
the uploading comment was removed).

735-picker-before-after.png is already on main and is left alone — that is
history, not this slice's call.
@mforce
mforce merged commit d26d389 into main Sep 10, 2026
10 checks passed
@mforce
mforce deleted the feat/745-audit-details-column branch September 10, 2026 17:18
mforce added a commit that referenced this pull request Sep 10, 2026
Both slices shipped without their design docs reaching the repo, which is
out of step with the sibling slice on the same epic (#723/#724, already on
main). These are the point-in-time records, not rewritten to match what
finally shipped.

The #722 design carries a superseded-by header instead, because two things
moved after it was written: the payload gained productName and unit (#747,
PR #748) after the audit artboard turned out to render product NAMES rather
than ids, and nothing rendered the payload at all until #745 (PR #749).
Rewriting the body would destroy the record of what was actually decided
and when; the header points at what changed.
mforce added a commit that referenced this pull request Sep 10, 2026
Both slices shipped without their design docs reaching the repo. The
sibling slice on the same epic —
`docs/plans/723-724-discount-visibility/` — is already on `main`, so
this brings #722 and #745 in line with it.

## What is here

| File | What it records |
|---|---|
| `docs/plans/722-audit-price-payload/01-design.md` | the design as
dispatched, including the line-identity decision and the
`ExecuteInTransactionAsync` + interleaved-save shape |
| `docs/plans/722-audit-price-payload/02-implementation-plan.md` | the
increment ordering and mutation rows |
| `docs/plans/745-audit-details-column/01-design.md` | read from the
artboard, `docs/images/discount-mockups/AuditRow.png` |

## These are point-in-time records, not retrofitted

The #722 design describes a payload carrying `productId` and **no**
product name. That is what was designed, and it was the defect: the
audit artboard renders product **names**, and resolving an id at read
time yields *today's* name, so a renamed product would re-render history
under a name the seller never saw. #747 (PR #748) fixed it by
snapshotting the name and unit at write time.

Rather than rewrite the body to match what shipped — which would destroy
the record of what was actually decided and when — the file carries a
**superseded-by header** naming both changes: the `productName`/`unit`
addition, and the fact that nothing rendered the payload at all until
#745 (PR #749). The full map lives in the amendment on #722.

## Verification

`SchemaDocsTests` run with these files in the index — that is the point,
since
`PostgresImagePin_`/`RedisImagePin_IsOneIdenticalStringAcrossEveryTrackedFile`
walk `git ls-files` and therefore begin applying to a document the
moment it is staged. AGENTS.md records that exact trap costing a full
implementer stop on #508.

```
Passed!  - Failed: 0, Passed: 4, Skipped: 0, Total: 4 - Cluckwork.Api.IntegrationTests.dll
```

Docs only — no source, no tests, no schema.

Co-authored-by: mforce <mforce@users.noreply.github.com>
mforce added a commit that referenced this pull request Sep 11, 2026
## TL;DR

The audit **Details** cell printed each sales line's **list** price as
though it were the price the line sold for. `AuditDetails` read
`unitPriceMinorUnits`, used it only as a null guard, then discarded it
whenever a list price existed — so every `SalesOrder.AddItem` row
rendered `at list $<list>`, whatever it actually sold for.

One branch in one component, plus tests. No API, payload, migration or
i18n-key change.

## The defect, on fixture order `SO-1318252C`

| Line | List | Sold | Sales screen | Audit **before** | Audit **after**
|
|---|---|---|---|---|---|
| Sim Cracked Eggs | $0.18 | $0.15 | Below list, 16.7% | `at list $0.18`
❌ | `at $0.15 (list $0.18)` |
| Sim Dirty Eggs | $0.22 | $0.30 | **Above list** | `at list $0.22` ❌ |
`at $0.30 (list $0.22)` |
| Sim Small Eggs | $0.30 | $0.30 | at list | `at list $0.30` ✅ | `at
list $0.30` |
| Sim Large Eggs | $0.45 | $0.20 | Below list, **55.6%** | `at list
$0.45` ❌ | `at $0.20 (list $0.45)` |

Three of four were wrong. The worst read as a line selling at $0.45 that
sold at $0.20.

Introduced by d26d389 (#749, for #745) — the commit that built the
Details column. It shipped this way; it did not drift. It survived
review and every test because `at list $0.45` is a plausible, correctly
formatted number, and nothing on screen contradicted it until #721 began
printing `Discount reason: Volume` directly beneath four rows all
claiming to have sold at list.

## Rendering contract

| Case | Renders | Changed? |
|---|---|---|
| no list price (`list === null`) | `at $0.15` | no |
| sold at list (`unit === list`) | `at list $0.30` | no |
| sold below **or above** list | `at $0.20 (list $0.45)` | **the fix** |

An off-list line gets **no marker word in either direction**. #719's
open question 4 deliberately treats a markup as not a discount, so the
cell states both facts and lets the reader see the direction rather than
editorialising. That reasoning is a comment in the code, not just here.

**No new translation strings.** `detailsAtPrice`, `detailsAtList` and
`detailsListParen` already existed in en, es and tl (3/3 each);
`detailsListParen` is the same key the `UpdateItem` branch already
renders in the same position, so per #688 each locale keeps its own
existing wording for *list price* rather than a fresh translation.

## Reviewer entry points

- **`web/src/routes/AuditPage.tsx`** — the whole behaviour change is the
`SalesOrder.AddItem` ternary, ~6 lines. Everything else in the diff is
the comment above it.
- **`web/src/routes/AuditPage.test.tsx`** — the four new cases.

### One deletion to look at deliberately

The previous test, *"renders an AddItem payload as the artboard's
summary"*, asserted `/\$0\.45/` against a payload with
`unitPriceMinorUnits: 40, listUnitPriceMinorUnits: 45`. **It pinned the
defect**, not the intended behaviour — it passed precisely because the
wrong number was on screen. It is replaced rather than weakened, by four
tests asserting the cell's **literal full text** (`toBe`, on the cell's
`textContent`, which is what pins the *order* of the two prices — a
regex on one number is what let this ship).

## Mutation evidence

Every new test was watched fail before being claimed. Three mutations,
each reverted; `git grep -n -e MUTANT -e 'DEBUG-' -- src tests web`
returns nothing.

| Mutation | Tests red | Observed |
|---|---|---|
| **M1** restore the shipped defect (`money(list)` in the off-list
branch) | below-list, above-list | `expected 'Large Eggs ×240 at list
$0.45' to be 'Large Eggs ×240 at $0.20 (list $0.45)'` |
| **M2** drop the `unit === list` collapse | at-list | `expected 'Large
Eggs ×240 at $0.30 (list $0.30)' to be 'Large Eggs ×240 at list $0.30'`
|
| **M3** stop `list === null` short-circuiting | no-list-price |
`expected 'Large Eggs ×240 at $0.15 (list $0.00)' to be 'Large Eggs ×240
at $0.15'` — M3 reproduces #720's zero-price failure mode exactly |

All four tests are individually load-bearing: no mutation reddened a
test that was not aimed at it.

## Gates

```
cd web && npm run typecheck   # clean
cd web && npx vitest run      # 122 files, 2816 tests, all passing
```

Web-only — nothing outside `web/` changes, so no .NET build and no
integration suite.

## Sibling check

`grep -rn listUnitPriceMinorUnits web/src` finds one other renderer,
`SalesPage.tsx`, which reads the sale and list prices separately and is
the screen the issue confirms was already **correct**. No sibling
defect; no coverage added there.

## Risk

Low. Read-only rendering of a payload field already present on every
row, in one component, behind four literal-text tests. No backfill
concern: the change is presentational, so historical rows render
correctly the moment this ships. The at-list and no-list-price paths are
byte-identical to before and pinned as regressions.

Closes #758


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Audit details now consistently display the sold unit price for added
sales order items.
- When a list price is available, matching prices are labeled “at list,”
while differing prices show both the sold and list prices without
classifying the difference as a discount or markup.
- Items without a list price continue to display their existing details.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: mforce <mforce@users.noreply.github.com>
@mforce mforce mentioned this pull request Sep 11, 2026
9 of 11 tasks
mforce pushed a commit that referenced this pull request Sep 12, 2026
🤖 I have created a release *beep* *boop*
---


## [0.1.0](v0.0.4...v0.1.0)
(2026-09-12)


### ⚠ BREAKING CHANGES

* log in by farm code, with per-account email identity
([#532](#532)) (#564)

### Features

* **accounts:** add Account.Slug (farm code), suspend/reactivate,
list-accounts verb
([#531](#531))
([3fe9754](3fe9754))
* **accounts:** provision additional farms
([#581](#581))
([006f298](006f298))
* add Aspire local development AppHost
([#567](#567))
([2c9e6b9](2c9e6b9))
* add configurable worker sale allocation
([#619](#619))
([0955095](0955095))
* add searchable entity pickers
([#642](#642))
([60d2053](60d2053))
* **api:** provision-account takes an optional --timezone at creation
([#603](#603))
([#694](#694))
([a0aee39](a0aee39))
* **audit:** show the sales-line audit payload as a readable Details
column ([#745](#745))
([#749](#749))
([d26d389](d26d389))
* **auth:** add ApplicationUser.StepUpLogoutEpoch column
([#338](#338))
([#554](#554))
([18306ee](18306ee))
* certify over-cap simulation fixture bands
([#633](#633))
([a67b2e1](a67b2e1)),
closes [#627](#627)
* **cli:** rename-account verb to change a farm code
([#732](#732))
([#733](#733))
([4b70559](4b70559))
* **customers:** edit existing customer details
([#625](#625))
([#626](#626))
([062a55c](062a55c))
* **jobs:** single-runner leader gate for the durable job worker
([#271](#271))
([#555](#555))
([4148f9b](4148f9b))
* let owners change user email addresses
([#605](#605))
([842347b](842347b))
* log in by farm code, with per-account email identity
([#532](#532))
([#564](#564))
([68adb62](68adb62))
* **ratelimit:** distributed IP-keyed auth limiters
([#544](#544))
([#558](#558))
([ec14972](ec14972))
* **ratelimit:** distributed per-account report concurrency cap with
local-ceiling fallback
([#545](#545))
([#559](#559))
([1522e4e](1522e4e))
* **sales:** mark discounted lines, total the discount, and show it in
the Orders list ([#723](#723),
[#724](#724))
([#741](#741))
([1a07441](1a07441))
* **sales:** record list, old and new price in the order-line audit
payload ([#722](#722))
([#742](#742))
([97c866f](97c866f))
* **sales:** refuse an over-ceiling confirm from a Sales user
([#727](#727))
([#766](#766))
([8c0792a](8c0792a))
* **sales:** show what each order still owes, and filter the list to
unpaid ([#771](#771))
([ca59d68](ca59d68))
* **sales:** snapshot the list price on the order line and show the
discount ([#734](#734))
([cffed5e](cffed5e))
* **sales:** snapshot the product name and unit in the order-line audit
payload ([#747](#747))
([#748](#748))
([0481c06](0481c06))
* scope Worker reads to assigned flocks
([#388](#388))
([#611](#611))
([5884a9a](5884a9a))
* shared-state ports with Redis + in-process fallback
([#543](#543))
([#552](#552))
([f767fa9](f767fa9))
* suspend-account / reactivate-account operator verbs
([#534](#534))
([#573](#573))
([d0be26c](d0be26c))
* **tenancy:** write-side tenant guard + single-assignment TenantContext
([#546](#546))
([#561](#561))
([f371f1d](f371f1d))
* **web:** dashboard rework — capture-status tiles, 14-day trend, stock
as a stacked bar
([#654](#654))
([396ba23](396ba23))
* **web:** date-range filters on audit and expenses, and the stock lot
filter gets its bounded toolbar
([#666](#666),
[#667](#667),
[#653](#653))
([94b188f](94b188f))
* **web:** elevation hierarchy and sentence-case labels
([#651](#651),
[#652](#652))
([#661](#661))
([28db4c7](28db4c7))
* **web:** Expenses and Audit keep a clear-filters control while rows
are still showing
([#679](#679))
([#697](#697))
([b859982](b859982))
* **web:** expenses filters by a date range like its sibling screens
([#667](#667))
([f13858f](f13858f))
* **web:** key the farm brand palette per farm
([#586](#586))
([#600](#600))
([7183a43](7183a43))
* **web:** let operators forget remembered farms
([#598](#598))
([577d94e](577d94e))
* **web:** one-line provenance, bounded date filters, and empty states
that invite action
([#653](#653),
[#655](#655))
([#668](#668))
([80b53f4](80b53f4))
* **web:** prefill the farm code from ?farm= and remember it
([#535](#535))
([#588](#588))
([b7f5cc6](b7f5cc6))
* **web:** split authenticated routes into lazy chunks
([#620](#620))
([5089271](5089271))
* **web:** the audit log filters by a date range, and says which window
is empty ([#666](#666))
([63027e0](63027e0))
* **web:** typeset numbers as numbers and refresh the Help glossary
([#650](#650),
[#657](#657))
([af4fe11](af4fe11))


### Bug fixes

* **api:** order same-instant audit events by a durable monotonic key
([#700](#700))
([8fcf084](8fcf084))
* **api:** print the farm code from bootstrap-admin
([#589](#589))
([#594](#594))
([34032ac](34032ac))
* **audit:** show the price a line sold for, not its list price
([#759](#759))
([e6b37d0](e6b37d0))
* **audit:** store catalog enums by name and guard the add-item
transaction shape
([#751](#751))
([23609ff](23609ff))
* **auth:** reject invalid account claims
([#622](#622))
([8d6c7fe](8d6c7fe))
* **auth:** require step-up for durable user access
([#360](#360))
([#607](#607))
([f767dce](f767dce))
* **ci:** bound the npm audit calls and give the web job room to finish
([#686](#686))
([153b7a8](153b7a8))
* **ci:** escalate the audit bound to SIGKILL, so it actually bounds
([#686](#686))
([a0c8f4e](a0c8f4e))
* **ci:** fail closed on invalid vulnerability config
([#621](#621))
([1690db8](1690db8))
* **ci:** lockfix covers the two AppHost lock files, derived from the
sln
([efb05e6](efb05e6))
* **ci:** lockfix covers the two AppHost lock files, derived from the
sln
([8986d77](8986d77))
* **ci:** remove invalid XML comment from nuget.lockfix.config
([#541](#541))
([5f1bc0a](5f1bc0a))
* **ci:** the advisory vuln gate no longer blocks on an unusable report
([#686](#686))
([aaf6934](aaf6934))
* **ci:** the advisory vuln gate no longer blocks on an unusable report
([#686](#686))
([64f1f53](64f1f53))
* **i18n:** tl help text names the saleable flag and unit-system setting
what their labels call them
([#688](#688))
([#696](#696))
([bfd24d7](bfd24d7))
* **infra:** AccountId must be a non-nullable Guid or both tenant write
layers refuse ([#673](#673))
([#695](#695))
([2470c4e](2470c4e))
* require step-up for flock scope changes
([#609](#609))
([4151f89](4151f89))
* **sales:** keep a line's discount markers agreeing while its price is
edited ([#752](#752))
([#753](#753))
([c159b4b](c159b4b))
* **sales:** say which kind of missing list price a line has
([#774](#774))
([489180e](489180e))
* scope legacy logout to selected farm
([#624](#624))
([fae8d82](fae8d82))
* **seed:** drain the daily-entry lock sweep so deep simulation fixtures
validate ([#644](#644))
([730fa23](730fa23)),
closes [#638](#638)
* **tenancy:** AccountId is a concurrency token, so the database refuses
a detached cross-tenant write
([#562](#562))
([4d1dfa3](4d1dfa3))
* **tenancy:** AspNetUserRoles carries a tenant column, so a role write
naming another farm's user is refused
([#670](#670))
([fc0552a](fc0552a))
* **tests:** bump the image-pin allow-list counts for the AppHost
LocalPorts tests
([#593](#593))
([58d3056](58d3056))
* **tests:** the OTLP collector survives a lost port race and ignores
traffic that is not an export
([#672](#672),
[#676](#676))
([#677](#677))
([965c737](965c737))
* **web:** a scoped audit view filtered to nothing names both the record
and the range ([#666](#666))
([41bbfe1](41bbfe1))
* **web:** an abandoned dialog attempt's success no longer hijacks the
replacement on Customers, Daily Entry, Flocks, Grades and Products
([#703](#703))
([#705](#705))
([85605db](85605db))
* **web:** an abandoned dialog attempt's success no longer hijacks the
replacement on Inventory, Expenses, History and Stock
([#703](#703))
([#706](#706))
([60a4997](60a4997))
* **web:** an abandoned edit's success no longer hijacks the dialog that
replaced it on Users
([#703](#703))
([#710](#710))
([778faab](778faab))
* **web:** an abandoned order attempt's success no longer hijacks the
dialog that replaced it
([#702](#702))
([522c699](522c699))
* **web:** capture screens open on the flock you last used, and
assigning one no longer guesses
([#646](#646))
([#699](#699))
([7f8f317](7f8f317))
* **web:** constrain dialog session helpers to declared scopes
([#715](#715))
([389e3c8](389e3c8))
* **web:** date validation gets one boundary table instead of one case
per review round
([#666](#666))
([215f830](215f830))
* **web:** keep a paged window and an item panel on the user's newest
intent ([#645](#645))
([d81bccf](d81bccf))
* **web:** keep Sales order panels closed after pending writes
([#711](#711))
([f0f7492](f0f7492))
* **web:** keep Sales panels closed after pending Open reads
([#716](#716))
([620411f](620411f))
* **web:** make login take the cross-tab cookie lock so a racing refresh
cannot restore the wrong session
([#648](#648))
([ff18beb](ff18beb))
* **web:** make the entity picker read as a search field and focus it on
open ([#736](#736))
([66ef667](66ef667)),
closes [#735](#735)
* **web:** page truncated customer and movement tables with usePagedList
([7cfe4d6](7cfe4d6))
* **web:** reconcile Sales line edits with refreshed orders
([#717](#717))
([d7dd2c9](d7dd2c9))
* **web:** the audit date filter accepts low-numbered years, and its
empty state covers every narrowing
([#666](#666))
([af52d25](af52d25))
* **web:** the audit date filter rejects impossible dates, and its
history guard actually guards
([#666](#666))
([8d51846](8d51846))
* **web:** the expense range bounds are not capped at today, which the
month-end default exceeds
([#667](#667))
([7e01864](7e01864))
* **web:** the help text calls the expiry field what the field calls
itself ([#666](#666))
([2fd1f3c](2fd1f3c))
* **web:** the stock lot date range sits in the bounded toolbar
([#653](#653))
([43dec5e](43dec5e))


### Refactoring

* **web:** extract SalesPage's dialog-write wrapper into a shared
useDialogAction hook
([#703](#703))
([#704](#704))
([60ee9d9](60ee9d9))


### Documentation

* add k6 preparation steps to the dev-database fixture runbook
([#643](#643))
([a4f1f09](a4f1f09))
* add runbook for loading the simulation fixture into a dev database
([#639](#639))
([2d143b8](2d143b8))
* **agents:** a PR closes its issue from the body, not the title
([#744](#744))
([39be13c](39be13c))
* **agents:** drop the commit and push gate, and require screenshots on
UI changes ([#757](#757))
([6225172](6225172))
* **agents:** find guards by grepping registry readers; amend issues a
PR overtakes ([#580](#580))
([fe3fde8](fe3fde8))
* **agents:** the Playwright specs have been in CI since 2026-08-08
([#768](#768))
([68ee612](68ee612))
* **aspire:** record the second local database and pin the AppHost
dashboard ports ([#623](#623))
([713b941](713b941))
* compress AGENTS.md to one paragraph per rule, and draw the two orders
that matter ([#551](#551))
([997ae8a](997ae8a))
* item 7 names each screen's actual initial filter value
([#666](#666))
([70a53d8](70a53d8))
* multi-farm tenancy decision record and AGENTS/GLOSSARY sync
([#537](#537))
([#601](#601))
([2c34771](2c34771))
* name the scoped filtered-empty key and state the
[#653](#653) relationship
plainly ([#666](#666))
([0e93dac](0e93dac))
* note that a PackageReference in Directory.Build.props is invisible to
the dependency graph
([4845724](4845724))
* **plans:** commit the
[#722](#722) and
[#745](#745) design records
([#754](#754))
([c942fcd](c942fcd))
* record [#579](#579) as
won't-fix — suspension is immediate for use, not issuance
([#582](#582))
([7a3be40](7a3be40))
* record the [#508](#508)
audit ordering key and the tracked-file guard lesson
([#701](#701))
([08964e9](08964e9))
* **runbooks:** add procedure to rename the default farm's code after
upgrade ([#731](#731))
([2f6e242](2f6e242))
* screenshots of the running SPA in the README
([#550](#550))
([711488a](711488a))
* **sim:** commit the dashboard screenshot, capture the palette matrix,
and record the
[#651](https://github.com/mforce/cluckwork/issues/651)/[#652](https://github.com/mforce/cluckwork/issues/652)
conventions ([#660](#660),
[#662](#662),
[#663](#663),
[#664](#664))
([#665](#665))
([930ea30](930ea30))
* specify searchable entity picker
([#641](#641))
([91d4300](91d4300))
* split the README into audience-scoped docs and adopt repo-template
scaffolding ([#548](#548))
([b3f3fcf](b3f3fcf))
* surface Aspire local development workflow
([#568](#568))
([a343baa](a343baa))
* **web:** record the per-screen idempotency-key policies and runWrite's
refresh contract
([#703](#703))
([#707](#707))
([8bee651](8bee651))
* **web:** the date-cap help text covers every stocked item, not only
feed ([#666](#666),
[#667](#667))
([c8433c5](c8433c5))
* **web:** the help text claims only what is true of recording, and says
nothing about filter caps
([#666](#666),
[#667](#667))
([e2f63d1](e2f63d1))
* **web:** the help text describes the date-range filters that shipped
([#666](#666),
[#667](#667))
([c3275b7](c3275b7))
* **web:** the help text stops describing a cap the filters no longer
have ([#666](#666),
[#667](#667))
([49654cd](49654cd))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: cluckwork-lockfix[bot] <309265648+cluckwork-lockfix[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SPA: render audit detailsJson as a readable per-key table instead of a raw tooltip

1 participant