Skip to content

Commit 9f8e53c

Browse files
authored
fix: allow DEPRECATED -> ACTIVE reactivation for convergent manifest apply (#2101)
* fix: allow DEPRECATED -> ACTIVE transition for convergent manifest apply When a manifest is re-applied to a tenant that previously had different manifests, instruments and account types from the prior manifest get deprecated. When the new manifest re-declares them, the activate step fails because DEPRECATED was terminal. Allow DEPRECATED -> ACTIVE transition for both instruments and account types, enabling convergent re-application of manifests. * test: update tests for DEPRECATED -> ACTIVE reactivation Update tests that asserted DEPRECATED was terminal to reflect the new convergent-apply behavior where DEPRECATED instruments and account types can be reactivated. * test: fix remaining deprecated-terminal assertions in instrument registry --------- Co-authored-by: Ben Coombs <bjcoombs@users.noreply.github.com>
1 parent fdc0fbf commit 9f8e53c

5 files changed

Lines changed: 15 additions & 17 deletions

File tree

services/reference-data/accounttype/definition_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,9 @@ func TestStatusCanTransitionTo_ActiveToDraftForbidden(t *testing.T) {
152152
assert.False(t, accounttype.StatusActive.CanTransitionTo(accounttype.StatusDraft))
153153
}
154154

155-
func TestStatusCanTransitionTo_DeprecatedIsTerminal(t *testing.T) {
155+
func TestStatusCanTransitionTo_DeprecatedAllowsReactivation(t *testing.T) {
156156
assert.False(t, accounttype.StatusDeprecated.CanTransitionTo(accounttype.StatusDraft))
157-
assert.False(t, accounttype.StatusDeprecated.CanTransitionTo(accounttype.StatusActive))
157+
assert.True(t, accounttype.StatusDeprecated.CanTransitionTo(accounttype.StatusActive))
158158
}
159159

160160
func TestStatusCanTransitionTo_SameStatusForbidden(t *testing.T) {

services/reference-data/accounttype/status.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var validStatusTransitions = map[Status]map[Status]bool{
3030
StatusDeprecated: true,
3131
},
3232
StatusDeprecated: {
33-
// Terminal state - no valid transitions
33+
StatusActive: true, // Convergent apply: re-declare in manifest to reactivate
3434
},
3535
}
3636

services/reference-data/registry/instrument_status.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
//
1111
// DRAFT -> ACTIVE (activation)
1212
// ACTIVE -> DEPRECATED (deprecation)
13-
// DEPRECATED is terminal - no transitions allowed
13+
// DEPRECATED -> ACTIVE (reactivation via convergent manifest apply)
1414
var validInstrumentStatusTransitions = map[Status]map[Status]bool{
1515
StatusDraft: {
1616
StatusActive: true,
@@ -19,7 +19,7 @@ var validInstrumentStatusTransitions = map[Status]map[Status]bool{
1919
StatusDeprecated: true,
2020
},
2121
StatusDeprecated: {
22-
// Terminal state - no valid transitions
22+
StatusActive: true, // Convergent apply: re-declare in manifest to reactivate
2323
},
2424
}
2525

services/reference-data/registry/instrument_status_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func TestInstrumentStatus_CanTransitionTo(t *testing.T) {
3030
{"ACTIVE to DRAFT", registry.StatusActive, registry.StatusDraft, false},
3131
{"ACTIVE to ACTIVE", registry.StatusActive, registry.StatusActive, false},
3232
{"DEPRECATED to DRAFT", registry.StatusDeprecated, registry.StatusDraft, false},
33-
{"DEPRECATED to ACTIVE", registry.StatusDeprecated, registry.StatusActive, false},
33+
{"DEPRECATED to ACTIVE", registry.StatusDeprecated, registry.StatusActive, true},
3434
{"DEPRECATED to DEPRECATED", registry.StatusDeprecated, registry.StatusDeprecated, false},
3535
{"unknown to ACTIVE", registry.Status("UNKNOWN"), registry.StatusActive, false},
3636
}
@@ -65,9 +65,9 @@ func TestValidateStatusTransition(t *testing.T) {
6565
assert.Contains(t, err.Error(), "cannot transition")
6666
})
6767

68-
t.Run("DEPRECATED is terminal", func(t *testing.T) {
68+
t.Run("DEPRECATED to ACTIVE is valid (reactivation)", func(t *testing.T) {
6969
err := registry.ValidateStatusTransition(registry.StatusDeprecated, registry.StatusActive)
70-
require.ErrorIs(t, err, registry.ErrInvalidStateTransition)
70+
require.NoError(t, err)
7171
})
7272
}
7373

services/reference-data/registry/postgres_registry_test.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ func TestPostgresRegistry_StatusStateMachine(t *testing.T) {
909909
t.Run("valid transitions", func(t *testing.T) {
910910
assert.NoError(t, registry.ValidateStatusTransition(registry.StatusDraft, registry.StatusActive))
911911
assert.NoError(t, registry.ValidateStatusTransition(registry.StatusActive, registry.StatusDeprecated))
912+
assert.NoError(t, registry.ValidateStatusTransition(registry.StatusDeprecated, registry.StatusActive))
912913
})
913914

914915
t.Run("invalid transitions", func(t *testing.T) {
@@ -920,10 +921,6 @@ func TestPostgresRegistry_StatusStateMachine(t *testing.T) {
920921
err = registry.ValidateStatusTransition(registry.StatusDeprecated, registry.StatusDraft)
921922
require.ErrorIs(t, err, registry.ErrInvalidStateTransition)
922923

923-
// DEPRECATED -> ACTIVE
924-
err = registry.ValidateStatusTransition(registry.StatusDeprecated, registry.StatusActive)
925-
require.ErrorIs(t, err, registry.ErrInvalidStateTransition)
926-
927924
// DRAFT -> DEPRECATED (not allowed for instrument definitions)
928925
err = registry.ValidateStatusTransition(registry.StatusDraft, registry.StatusDeprecated)
929926
require.ErrorIs(t, err, registry.ErrInvalidStateTransition)
@@ -944,12 +941,12 @@ func TestPostgresRegistry_StatusStateMachine(t *testing.T) {
944941
assert.True(t, registry.StatusDraft.CanTransitionTo(registry.StatusActive))
945942
assert.True(t, registry.StatusActive.CanTransitionTo(registry.StatusDeprecated))
946943
assert.False(t, registry.StatusActive.CanTransitionTo(registry.StatusDraft))
947-
assert.False(t, registry.StatusDeprecated.CanTransitionTo(registry.StatusActive))
944+
assert.True(t, registry.StatusDeprecated.CanTransitionTo(registry.StatusActive))
948945
assert.False(t, registry.StatusDraft.CanTransitionTo(registry.StatusDraft))
949946
})
950947
}
951948

952-
func TestPostgresRegistry_DeprecatedIsTerminal(t *testing.T) {
949+
func TestPostgresRegistry_DeprecatedCanReactivate(t *testing.T) {
953950
reg, pool := setupTestRegistry(t)
954951
ctx := setupTenantContext(t, pool, "test-tenant-terminal")
955952

@@ -964,14 +961,15 @@ func TestPostgresRegistry_DeprecatedIsTerminal(t *testing.T) {
964961
require.NoError(t, reg.ActivateInstrument(ctx, "TERMINAL1", 1))
965962
require.NoError(t, reg.DeprecateInstrument(ctx, "TERMINAL1", 1, nil))
966963

967-
t.Run("cannot activate deprecated instrument", func(t *testing.T) {
964+
t.Run("can reactivate deprecated instrument", func(t *testing.T) {
968965
err := reg.ActivateInstrument(ctx, "TERMINAL1", 1)
969-
require.ErrorIs(t, err, registry.ErrNotDraft)
966+
require.NoError(t, err)
970967
})
971968

972969
t.Run("cannot deprecate already deprecated instrument", func(t *testing.T) {
970+
// Re-deprecate after reactivation should work
973971
err := reg.DeprecateInstrument(ctx, "TERMINAL1", 1, nil)
974-
require.ErrorIs(t, err, registry.ErrNotActive)
972+
require.NoError(t, err)
975973
})
976974

977975
t.Run("cannot update deprecated instrument", func(t *testing.T) {

0 commit comments

Comments
 (0)