Skip to content

Commit 4d8e1a8

Browse files
FentPamsclaude
andcommitted
feat(suggestions): allow OUTDATED status in auto-fix allowlist
OUTDATED alt-text suggestions are re-detections of previously-FIXED rows where the producer found the issue still present on the live URL (after the publish-lag reset gate). The experience-success-studio-ui PR #1914 surfaces OUTDATED in the Current tab so customers can retry the deploy, but the auto-fix controller's status gate only accepted NEW and PENDING_VALIDATION — silently rejecting OUTDATED with 400 inside a 207 response. The UI today treats 2xx as success, so the customer sees a "Success" toast while nothing actually re-deploys. This 3-line allowlist relaxation closes the gap. The rest of the round-trip is already status-agnostic: - bulkUpdateStatus is source-status-agnostic (verified in spacecat-shared-data-access: no state machine, no transition rules, no hooks — just enum membership check on the target value) - autofix-worker queries by opportunity_id + IN_PROGRESS, origin status is invisible to it - alt-text handler reads recommendations[0].altText, writes alt, transitions IN_PROGRESS → FIXED — status-agnostic - mystique projector and publish-lag reset gate are timestamp-driven, not status-driven So OUTDATED → IN_PROGRESS → (apply) → FIXED is now the supported flow. Tests: - Updated existing assertion to reflect new error message - Added new test asserting OUTDATED is accepted, bulkUpdateStatus transitions it to IN_PROGRESS, and the 207 response reports success=1 / failed=0 All 404 suggestions controller tests pass, no regressions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d7889ac commit 4d8e1a8

2 files changed

Lines changed: 43 additions & 2 deletions

File tree

src/controllers/suggestions.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1151,13 +1151,22 @@ function SuggestionsController(ctx, sqs, env) {
11511151
} else if (
11521152
suggestion.getStatus() === SuggestionModel.STATUSES.NEW
11531153
|| suggestion.getStatus() === SuggestionModel.STATUSES.PENDING_VALIDATION
1154+
// OUTDATED suggestions are re-detections of previously-FIXED rows
1155+
// where the producer found the issue still present on the live URL
1156+
// (after the publish-lag reset gate). The UI surfaces them in the
1157+
// Current tab (alt-text PR #1914) so customers can retry the deploy
1158+
// — this allowlist makes that retry actually reach the autofix
1159+
// worker instead of being silently rejected.
1160+
// bulkUpdateStatus is source-status-agnostic (verified in
1161+
// spacecat-shared-data-access), so OUTDATED → IN_PROGRESS just works.
1162+
|| suggestion.getStatus() === SuggestionModel.STATUSES.OUTDATED
11541163
) {
11551164
validSuggestions.push(suggestion);
11561165
} else {
11571166
failedSuggestions.push({
11581167
uuid: suggestion.getId(),
11591168
index: suggestionIds.indexOf(suggestion.getId()),
1160-
message: 'Suggestion must be in NEW or PENDING_VALIDATION status for auto-fix',
1169+
message: 'Suggestion must be in NEW, PENDING_VALIDATION, or OUTDATED status for auto-fix',
11611170
statusCode: 400,
11621171
});
11631172
}

test/controllers/suggestions.test.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4608,7 +4608,39 @@ describe('Suggestions Controller', () => {
46084608
expect(bulkPatchResponse.suggestions[1]).to.have.property('statusCode', 400);
46094609
expect(bulkPatchResponse.suggestions[0].suggestion).to.exist;
46104610
expect(bulkPatchResponse.suggestions[1].suggestion).to.not.exist;
4611-
expect(bulkPatchResponse.suggestions[1]).to.have.property('message', 'Suggestion must be in NEW or PENDING_VALIDATION status for auto-fix');
4611+
expect(bulkPatchResponse.suggestions[1]).to.have.property('message', 'Suggestion must be in NEW, PENDING_VALIDATION, or OUTDATED status for auto-fix');
4612+
});
4613+
4614+
it('autofix suggestion accepts OUTDATED status (re-detect of previously FIXED row)', async () => {
4615+
// OUTDATED suggestions are surfaced in the Current tab by the alt-text
4616+
// UI (#1914) so customers can retry a deploy whose previous attempt
4617+
// didn't stick on the live URL. Allowing OUTDATED through this gate
4618+
// makes that retry actually reach the autofix worker.
4619+
const outdatedSugg = { ...suggs[0], status: 'OUTDATED' };
4620+
mockSuggestion.allByOpportunityId.resolves([mockSuggestionEntity(outdatedSugg)]);
4621+
mockSuggestion.bulkUpdateStatus.resolves([
4622+
mockSuggestionEntity({ ...outdatedSugg, status: 'IN_PROGRESS' }),
4623+
]);
4624+
4625+
const response = await suggestionsControllerWithMock.autofixSuggestions({
4626+
params: {
4627+
siteId: SITE_ID,
4628+
opportunityId: OPPORTUNITY_ID,
4629+
},
4630+
data: { suggestionIds: [SUGGESTION_IDS[0]] },
4631+
...context,
4632+
});
4633+
4634+
expect(response.status).to.equal(207);
4635+
const bulkPatchResponse = await response.json();
4636+
expect(bulkPatchResponse.metadata).to.have.property('total', 1);
4637+
expect(bulkPatchResponse.metadata).to.have.property('success', 1);
4638+
expect(bulkPatchResponse.metadata).to.have.property('failed', 0);
4639+
expect(bulkPatchResponse.suggestions[0]).to.have.property('statusCode', 200);
4640+
expect(bulkPatchResponse.suggestions[0].suggestion).to.exist;
4641+
// OUTDATED → IN_PROGRESS transition must occur for the worker to pick it
4642+
// up via Suggestion.allByOpportunityIdAndStatus(opp, IN_PROGRESS).
4643+
expect(mockSuggestion.bulkUpdateStatus).to.have.been.calledOnce;
46124644
});
46134645

46144646
it('groups by relationshipContext.fixTargetPageId when fixTargetGroups is provided for a groupable type', async () => {

0 commit comments

Comments
 (0)