feat(usage): distinguish real edits and template delivery with v5 consent (#1339)

* feat(usage): distinguish real edits and template delivery with v5 consent

* fix(usage): exclude queued test messages and count reorders as edits

- queueEmail carries usageEligible: false into email_data and the queue
  processor passes it on, so the dev tools' send-test-email no longer
  records email_template_delivery once the worker sends it.
- event-types/reorder and categories/reorder-global compare the persisted
  order before and after and record the v5 edit markers only when it
  changed, matching the display_order edit already counted on PUT.
- normalized() builds arrays with Array.from so a row array from the sqlite
  binding compares equal under Jest's separate realm.

* fix(usage): cover per-gallery category order and workflow test runs

- categories/reorder records category_editing when an event's override
  changes; reorder/:eventId records it when an override was actually
  removed.
- send_email and the collections handoff pass usageEligible: false for a
  workflow test run (engine.testRun sets __test), so a non-dry test send is
  not counted as template delivery.

---------

Co-authored-by: Paul Nothaft <[email protected]>
This commit is contained in:
Paul Nothaft
2026-09-07 20:03:15 +02:00
committed by GitHub
co-authored by Paul Nothaft
parent 69754f8a2c
commit 5c1e38d921
31 changed files with 5398 additions and 292 deletions
@@ -67,6 +67,14 @@ test('the collector has no way in: no inbound route and no scheduled pull', () =
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
if (!entry.isFile() || !entry.name.endsWith('.js')) continue;
if (entry.name === 'productUsageService.js') continue;
if (entry.name === 'emailProcessor.js') {
// v5 explicitly consents to one local background-mail bit, never a send
// to the collector. No mail details may be passed into the usage API.
const email = fs.readFileSync(path.join(dir, entry.name), 'utf8');
expect(email).toContain(".markUsed(['email_template_delivery'])");
expect(email).not.toMatch(/productUsageService'\)\.(?:tick|enable|command|deliver)/);
continue;
}
expect(fs.readFileSync(path.join(dir, entry.name), 'utf8'))
.not.toContain('productUsageService');
}