feat(data-access): status transition guard + deriveSuggestionStatus (SITES-47091)#1748
Open
alinarublea wants to merge 4 commits into
Open
feat(data-access): status transition guard + deriveSuggestionStatus (SITES-47091)#1748alinarublea wants to merge 4 commits into
alinarublea wants to merge 4 commits into
Conversation
…SITES-47091) Add JS-side enforcement primitives for the Suggestion <-> FixEntity status lifecycle (ADR adobe/mysticat-architecture#174), shipped warn-only by default: - FixEntity + Suggestion transition tables + isAllowed* predicates - guardTransition + getEnforcementMode (env STATUS_TRANSITION_ENFORCEMENT, default warn; enforce throws ValidationError; off skips) - setStatus override + transitionStatus alias on both models, so every JS writer is checked at one chokepoint with zero behavior change in warn mode - deriveSuggestionStatus: non-CWV 1:1 bubble-up only; CWV multi-issue deferred to SITES-47076 (per-issue vocabulary lives as PATCH_* on the overloaded issue.status field, not yet reconciled in the JS enum) Default warn mode is byte-equivalent to the prior auto-generated setter, so consumers can bump and observe violation logs before flipping to enforce. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The integration-test docker-compose pinned mysticat-data-service:v5.24.1, whose ECR image has been pruned (lifecycle policy) — `manifest unknown` on pull, failing test:it for any branch freshly cut from main. v5.24.1 also predates the Preflight migrations the new IT exercises (20260626153444_drop_async_job_owned_columns_from_preflights.sql first appears in v5.52.0). Bump to v5.52.0 (latest; image present in ECR; contains the required migration), matching the "bump on schema-migration change" convention in the file's comment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
This PR will trigger a minor release when merged. |
MysticatBot
approved these changes
Jun 29, 2026
There was a problem hiding this comment.
Hey @alinarublea,
Verdict: Approve - well-designed state machine guard with a safe warn-only rollout strategy.
Complexity: HIGH - large diff (977 lines, 16 files).
Changes: Adds status transition tables, a tri-mode enforcement guard, setStatus overrides on FixEntity and Suggestion models, and deriveSuggestionStatus bubble-up function (16 files).
Non-blocking (3): minor issues and suggestions
- nit: Duplicate status constants across
fix-entity.transitions.js,suggestion.transitions.js, andderive-status.jscreate a sync hazard when the enum grows -packages/spacecat-shared-data-access/src/models/fix-entity/fix-entity.transitions.js:17. The circular-import rationale is sound, but consider extracting to a leaf constants module before flipping toenforcemode. - suggestion:
transitionStatus(to)is a pure pass-through tosetStatuswith no distinct behavior or documented guidance on when to prefer it -packages/spacecat-shared-data-access/src/models/fix-entity/fix-entity.model.js:63. Either document the intended semantic split or defer the alias until behavior diverges. - suggestion:
deriveSuggestionStatussilently returnsnullwhen a fix entry isnull/undefinedor has an unrecognized status. Consider adding a test pinning this edge-case behavior (e.g.deriveSuggestionStatus([null])returnsnull) so the contract is explicit -packages/spacecat-shared-data-access/src/models/suggestion/derive-status.js:90.
Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 1m 37s | Cost: $3.91 | Commit: 44c7c12e0de4811f4d6828be9e1704812c5620ba
If this code review was useful, please react with 👍. Otherwise, react with 👎.
v5.52.0 ships SITES-47254 (drop result/error/started_at from preflights), but the current spacecat-shared Preflight model still defines startedAt/ result/error and the IT fixture still inserts them — so against v5.52.0 the preflight seed INSERT fails and the Preflight IT sees no rows. v5.51.0 is the latest data-service release that still has those columns (pre-drop), matching the model on main. Pin there until the shared model is updated in lockstep with the SITES-47254 column drop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…LIDATION->IN_PROGRESS - CLAUDE.md: add "Status Transition Lifecycle" section + STATUS_TRANSITION_ENFORCEMENT env var, so consumers/agents discover transitionStatus/setStatus, the predicates + tables, and deriveSuggestionStatus (incl. the CWV deferral to SITES-47285). - suggestion.transitions.js: add PENDING_VALIDATION -> IN_PROGRESS. api-service autofixSuggestions legitimately transitions paid-customer suggestions from PENDING_VALIDATION to IN_PROGRESS; the V1 table wrongly omitted it (would have produced false warnings now and false ValidationErrors under enforce). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why (SITES-47091)
Adds the JS-side enforcement primitives for the Suggestion ↔ FixEntity status lifecycle defined in ADR adobe/mysticat-architecture#174. Today
spacecat-sharedvalidatesstatusonly as a closed enum — any value from any value, no state machine. This PR adds the transition table + guard + the shared bubble-up function, shipped warn-only by default.Changes (spacecat-shared-data-access only)
fix-entity.transitions.js(canonical FixEntity table from the ADR),suggestion.transitions.js(intentionally V1-permissive; the warn logs inform tightening before enforce).util/status-transition-guard.js—getEnforcementMode()readsSTATUS_TRANSITION_ENFORCEMENT∈off | warn | enforce, defaultwarn.guardTransition(): allowed/no-op → pass;warn→ log violation (Entity id from -> to) and proceed;enforce→ throwValidationError;off→ skip.setStatusoverride +transitionStatusalias on FixEntity and Suggestion models — a model-definedsetStatusblocks the auto-generated setter (base.model.js:128), so this is a single chokepoint capturing every JS writer (api-service single PATCH,bulkUpdateStatus, autofix-worker). Defaultwarnis byte-equivalent to the old setter (isReferencewas alwaysfalseforstatus).deriveSuggestionStatus— the non-CWV 1:1 bubble-up only (DEPLOYED/PUBLISHED→FIXED, FAILED→ERROR, PENDING→IN_PROGRESS, ROLLED_BACK→SKIPPED; severity collapse for >1 fix)..d.tsexports.Rollout / behavior
Default
warn⇒ zero behavior change on consumer bump. Consumers adopt and observe violation logs, then flip toenforce— tracked in SITES-47286. This guard covers only the two JS writers; mystique (Python direct-DB) bypasses it and needs a separate guard later.Deferred (agreed, split out)
The CWV multi-issue bubble-up is deferred to SITES-47285: the ADR's per-issue vocabulary (
cwvIssueStatus=PATCH_*/GUIDANCE_GENERATED) exists only in mystique, written into the overloaded per-issuestatusfield via direct-DB, while the JSISSUE_STATUSESenum lists only the Suggestion vocabulary.deriveSuggestionStatusthrows if a non-emptyissues[]is passed until that's reconciled.FixEntity.REJECTEDis likewise omitted (not in the enum yet).Tests
2441 data-access tests pass; all new files at 100% coverage; lint clean.
Tracking: SITES-47091 · parent SITES-47076 · follow-ups SITES-47285, SITES-47286.
🤖 Generated with Claude Code