Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions docs/specs/cwv-trends-audit-enddate-slack-fix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# CWV Trends Audit endDate Fix

**Status:** Completed
**Branch:** `cwv-trends-audit-enddate-slack-fix`
**Commit:** `e7accf85`

---

## Problem

Running `@spacecat run-audit {site} audit:cwv-trends-audit endDate:2026-04-05` always used today's date instead of the provided `endDate`. The audit result window was never shifted to the requested date.

## Root Cause

The Slack bot serializes keyword args (e.g. `endDate:2026-04-05`) into `message.data`. The `RunnerAudit` framework parses `message.data` and places it at `auditContext.messageData.endDate`. The `cwvTrendsRunner` was only reading `auditContext.endDate` (top-level), so the value was silently ignored.

This fix is **self-contained in this repo** — the Slack bot and API service already forward the value correctly through the pipeline.

## Fix

**`src/cwv-trends-audit/utils.js`** — one line change:

```js
// Before
const endDate = parseEndDate(auditContext.endDate, log);

// After
const endDate = parseEndDate(auditContext.endDate ?? auditContext.messageData?.endDate, log);
```

## Tests

**`test/audits/cwv-trends-audit/utils.test.js`** — one new test added:

- `uses endDate from auditContext.messageData when auditContext.endDate is absent`

```bash
npm run test:spec -- test/audits/cwv-trends-audit/utils.test.js
# 26 passing
```

## Usage (after fix)

```
@spacecat run-audit www.example.com audit:cwv-trends-audit endDate:2026-04-05
```

The audit will now process the 28-day window ending on `2026-04-05` instead of today.
105 changes: 105 additions & 0 deletions docs/specs/cwv-trends-audit-enddate-slack-fix/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# CWV Trends Audit endDate Fix — spacecat-audit-worker

**Created:** 2026-04-06
**Status:** Completed

---

## Feature Overview

The `cwv-trends-audit` runner supports a custom `endDate` to process historical CWV data up to a specific date. However, when the audit is triggered via the SpaceCat Slack bot (`run-audit {site} audit:cwv-trends-audit endDate:2026-04-05`), the `endDate` value arrives in `auditContext.messageData.endDate` (placed there by the `RunnerAudit` framework), but the runner only reads `auditContext.endDate` — one level too shallow. The result is that `endDate` is silently ignored and today's date is always used.

This is a self-contained fix in the audit worker. No changes to `spacecat-api-service` are required — the Slack bot already serializes keyword args into `message.data`, which the `RunnerAudit` framework correctly surfaces as `auditContext.messageData`. The runner just needed to look there.

### Why

Operators need to re-run the audit against historical data windows (e.g. to backfill reports or debug regressions). The Slack bot command `run-audit {site} audit:cwv-trends-audit endDate:2026-04-05` already forwards the value correctly through the pipeline — the only missing piece was the runner reading it.

### Success Criteria

- [x] `run-audit {site} audit:cwv-trends-audit endDate:2026-04-05` produces an audit result with end date `2026-04-05`
- [x] Direct `auditContext.endDate` (SQS path) continues to work as before
- [x] Omitting `endDate` still defaults to today
- [x] 100% unit test coverage maintained

---

## What This Repo Does

Update a single line in `cwvTrendsRunner` (`src/cwv-trends-audit/utils.js`) to check both `auditContext.endDate` and `auditContext.messageData?.endDate`, preferring the direct field and falling back to the nested one.

---

## Requirements

1. **Read endDate from messageData as fallback**
- When `auditContext.endDate` is `undefined`, the runner must check `auditContext.messageData?.endDate`
- Acceptance criteria: audit uses the provided date, not today, when passed via Slack keyword args

2. **Preserve existing behavior**
- Direct `auditContext.endDate` takes precedence over `messageData.endDate`
- Absent `endDate` in both locations defaults to today via `parseEndDate`

---

## Data Flow

```
Slack: run-audit {site} audit:cwv-trends-audit endDate:2026-04-05
→ api-service: serialized as message.data = '{"endDate":"2026-04-05"}'
→ SQS audit-jobs queue
→ RunnerAudit.buildRunnerAuditContext():
auditContext = { slackContext: {...}, messageData: { endDate: "2026-04-05" } }
→ cwvTrendsRunner(finalUrl, context, site, auditContext)
endDate = parseEndDate(auditContext.endDate ?? auditContext.messageData?.endDate)
↑ undefined ↑ "2026-04-05" ✓
```

---

## Implementation

### Change: `src/cwv-trends-audit/utils.js`

```js
// Before
const endDate = parseEndDate(auditContext.endDate, log);

// After
const endDate = parseEndDate(auditContext.endDate ?? auditContext.messageData?.endDate, log);
```

### Tests added: `test/audits/cwv-trends-audit/utils.test.js`

1. `auditContext = { messageData: { endDate: '2026-04-05' } }` → runner uses `2026-04-05`
2. `auditContext = { endDate: '2026-04-05' }` → runner uses `2026-04-05` (regression)
3. `auditContext = {}` → runner uses today (regression)

---

## Code Patterns

The fix follows the same optional-chaining fallback pattern already used elsewhere in the codebase for `auditContext` fields. No new utilities or helpers are needed — `parseEndDate` already handles `undefined` gracefully by returning today's date.

---

## Testing

- Run full test suite: `npm test`
- Run specific test: `npm run test:spec -- test/audits/cwv-trends-audit/utils.test.js`
- Result: 26 passing

---

## Dependencies on Other Repos

**None.** This fix is entirely self-contained within `spacecat-audit-worker`.

---

## Risks

| Risk | Impact | Mitigation |
|------|--------|------------|
| `messageData` structure changes in RunnerAudit framework | Low | Optional chaining `?.endDate` is safe if `messageData` is absent or restructured |
| Invalid date string in `messageData.endDate` | Low | `parseEndDate` already validates and falls back to today for any invalid input |
2 changes: 1 addition & 1 deletion src/cwv-trends-audit/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ export default async function cwvTrendsRunner(finalUrl, context, site, auditCont

const siteId = site.getId();

const endDate = parseEndDate(auditContext.endDate, log);
const endDate = parseEndDate(auditContext.endDate ?? auditContext.messageData?.endDate, log);
const startDate = subtractDays(endDate, TREND_DAYS - 1);

log.info(`[${AUDIT_TYPE}] siteId: ${siteId} | Reading ${TREND_DAYS} days of S3 data`);
Expand Down
15 changes: 15 additions & 0 deletions test/audits/cwv-trends-audit/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,21 @@ describe('CWV Trends Audit Runner (utils.js)', () => {
expect(summary.good.change).to.equal(0);
});

it('uses endDate from auditContext.messageData when auditContext.endDate is absent', async () => {
const dates = makeDates(28, '2026-02-28');
const urls = [buildUrl('https://ex.com/p1', 'mobile')];
readTrendDataStub.resolves(buildDays(dates, urls));

const site = makeSite();
const context = makeContext();
const auditContext = { messageData: { endDate: '2026-03-27' } };

const result = await cwvTrendsRunner('https://ex.com', context, site, auditContext);

expect(mobileResult(result).metadata.endDate).to.equal('2026-03-27');
expect(mobileResult(result).metadata.startDate).to.equal('2026-02-28');
});

it('uses custom endDate from auditContext when provided', async () => {
const dates = makeDates(28, '2026-02-28');
const urls = [buildUrl('https://ex.com/p1', 'mobile')];
Expand Down
Loading