Repository: git-town/git-town

Issue:
propose: falsely opens the rejected proposal instead of creating a new one
### Steps to reproduce

- use the Bitbucket-Cloud connector
- create a proposal for a branch
- decline the proposal (this is Bitbucket's way of closing it)
- run `git town propose` again to create a new proposal

expected behavior:

- it creates a new proposal

actual behavior:

- it opens the existing proposal in the browser

### Command output

```shell
~/g/bitbucket [branch-2b] > git propose

[branch-2b] git fetch --prune --tags

Looking for proposal online ... #6

[branch-2b] git checkout branch-2a
Switched to branch 'branch-2a'
Your branch is up to date with 'origin/branch-2a'.

[branch-2a] git checkout branch-2b
Switched to branch 'branch-2b'
Your branch is up to date with 'origin/branch-2b'.

[branch-2b] xdg-open https://bitbucket.org/git-town-qa/test-repo/pull-requests/6
```

### Additional information

The propose command should verify whether the proposal it is about to open in the browser is actually still open.

Discussion:

Solution patch:
diff --git a/internal/forge/bitbucketcloud/api_connector.go b/internal/forge/bitbucketcloud/api_connector.go
index 269b2ad1b..83981adce 100644
--- a/internal/forge/bitbucketcloud/api_connector.go
+++ b/internal/forge/bitbucketcloud/api_connector.go
@@ -40,7 +40,7 @@ func (self APIConnector) FindProposal(branch, target gitdomain.LocalBranchName)
 		Owner:    self.Organization,
 		RepoSlug: self.Repository,
 		Query:    query,
-		States:   []string{"open"},
+		States:   []string{"open", "new"},
 	})
 	if err != nil {
 		self.log.Failed(err.Error())
@@ -55,51 +55,35 @@ func (self APIConnector) FindProposal(branch, target gitdomain.LocalBranchName)
 		self.log.Failed(messages.APIUnexpectedResultDataStructure)
 		return None[forgedomain.Proposal](), nil
 	}
-	size1, has := result2["size"]
+	proposals1, has := result2["values"]
 	if !has {
 		self.log.Failed(messages.APIUnexpectedResultDataStructure)
 		return None[forgedomain.Proposal](), nil
 	}
-	size2, ok := size1.(float64)
+	proposals2, ok := proposals1.([]any)
 	if !ok {
 		self.log.Failed(messages.APIUnexpectedResultDataStructure)
 		return None[forgedomain.Proposal](), nil
 	}
-	size := int(size2)
-	if size == 0 {
-		self.log.Success("none")
-		return None[forgedomain.Proposal](), nil
-	}
-	if size > 1 {
-		self.log.Failed(fmt.Sprintf(messages.ProposalMultipleFromToFound, size, branch, target))
-		return None[forgedomain.Proposal](), nil
-	}
-	proposal1, has := result2["values"]
-	if !has {
-		self.log.Failed(messages.APIUnexpectedResultDataStructure)
-		return None[forgedomain.Proposal](), nil
-	}
-	proposal2, ok := proposal1.([]any)
-	if !ok {
-		self.log.Failed(messages.APIUnexpectedResultDataStructure)
-		return None[forgedomain.Proposal](), nil
-	}
-	if len(proposal2) == 0 {
-		self.log.Failed(messages.APIUnexpectedResultDataStructure)
-		return None[forgedomain.Proposal](), nil
-	}
-	proposal3, ok := proposal2[0].(map[string]any)
-	if !ok {
-		self.log.Failed(messages.APIUnexpectedResultDataStructure)
-		return None[forgedomain.Proposal](), nil
-	}
-	proposal4, err := parsePullRequest(proposal3)
-	if err != nil {
-		self.log.Failed(err.Error())
-		return None[forgedomain.Proposal](), nil
+	for _, proposal1 := range proposals2 {
+		proposal2, ok := proposal1.(map[string]any)
+		if !ok {
+			self.log.Failed(messages.APIUnexpectedResultDataStructure)
+			return None[forgedomain.Proposal](), nil
+		}
+		proposal3, err := parsePullRequest(proposal2)
+		if err != nil {
+			self.log.Failed(err.Error())
+			return None[forgedomain.Proposal](), nil
+		}
+		if !proposal3.Active {
+			continue
+		}
+		self.log.Success(fmt.Sprintf("#%d", proposal3.Number))
+		return Some(forgedomain.Proposal{Data: proposal3, ForgeType: forgedomain.ForgeTypeBitbucket}), nil
 	}
-	self.log.Success(fmt.Sprintf("#%d", proposal4.Number))
-	return Some(forgedomain.Proposal{Data: proposal4, ForgeType: forgedomain.ForgeTypeBitbucket}), nil
+	self.log.Success("none")
+	return None[forgedomain.Proposal](), nil
 }
 
 // ============================================================================
@@ -114,7 +98,7 @@ func (self APIConnector) SearchProposal(branch gitdomain.LocalBranchName) (Optio
 		Owner:    self.Organization,
 		RepoSlug: self.Repository,
 		Query:    fmt.Sprintf("source.branch.name = %q", branch),
-		States:   []string{"open"},
+		States:   []string{"open", "new"},
 	})
 	if err != nil {
 		self.log.Failed(err.Error())
@@ -125,43 +109,35 @@ func (self APIConnector) SearchProposal(branch gitdomain.LocalBranchName) (Optio
 		self.log.Failed(messages.APIUnexpectedResultDataStructure)
 		return None[forgedomain.Proposal](), nil
 	}
-	size1, has := response2["size"]
-	if !has {
-		self.log.Failed(messages.APIUnexpectedResultDataStructure)
-		return None[forgedomain.Proposal](), nil
-	}
-	size2, ok := size1.(float64)
-	if !ok {
-		self.log.Failed(messages.APIUnexpectedResultDataStructure)
-		return None[forgedomain.Proposal](), nil
-	}
-	size3 := int(size2)
-	if size3 == 0 {
-		self.log.Success("none")
-		return None[forgedomain.Proposal](), nil
-	}
-	if size3 > 1 {
-		self.log.Failed(fmt.Sprintf(messages.ProposalMultipleFromFound, size3, branch))
-		return None[forgedomain.Proposal](), nil
-	}
-	values1, has := response2["values"]
+	proposals1, has := response2["values"]
 	if !has {
 		self.log.Failed(messages.APIUnexpectedResultDataStructure)
 		return None[forgedomain.Proposal](), nil
 	}
-	values2, ok := values1.([]any)
+	proposals2, ok := proposals1.([]any)
 	if !ok {
 		self.log.Failed(messages.APIUnexpectedResultDataStructure)
 		return None[forgedomain.Proposal](), nil
 	}
-	proposal1 := values2[0].(map[string]any)
-	proposal2, err := parsePullRequest(proposal1)
-	if err != nil {
-		self.log.Failed(err.Error())
-		return None[forgedomain.Proposal](), nil
+	for _, proposal1 := range proposals2 {
+		proposal2, ok := proposal1.(map[string]any)
+		if !ok {
+			self.log.Failed(messages.APIUnexpectedResultDataStructure)
+			return None[forgedomain.Proposal](), nil
+		}
+		proposal3, err := parsePullRequest(proposal2)
+		if err != nil {
+			self.log.Failed(err.Error())
+			return None[forgedomain.Proposal](), nil
+		}
+		if !proposal3.Active {
+			continue
+		}
+		self.log.Success(fmt.Sprintf("#%d", proposal3.Number))
+		return Some(forgedomain.Proposal{Data: proposal3, ForgeType: forgedomain.ForgeTypeBitbucket}), nil
 	}
-	self.log.Success(proposal2.Target.String())
-	return Some(forgedomain.Proposal{Data: proposal2, ForgeType: forgedomain.ForgeTypeBitbucket}), nil
+	self.log.Success("none")
+	return None[forgedomain.Proposal](), nil
 }
 
 // ============================================================================
diff --git a/internal/forge/bitbucketcloud/parser.go b/internal/forge/bitbucketcloud/parser.go
index a145b769f..d1ecc7047 100644
--- a/internal/forge/bitbucketcloud/parser.go
+++ b/internal/forge/bitbucketcloud/parser.go
@@ -2,6 +2,7 @@ package bitbucketcloud
 
 import (
 	"errors"
+	"strings"
 
 	"github.com/git-town/git-town/v22/internal/forge/forgedomain"
 	"github.com/git-town/git-town/v22/internal/git/gitdomain"
@@ -35,6 +36,16 @@ func parsePullRequest(pullRequest map[string]any) (result forgedomain.BitbucketC
 	if !ok {
 		return result, errors.New(messages.APIUnexpectedResultDataStructure)
 	}
+	state1, has := pullRequest["state"]
+	if !has {
+		return result, errors.New(messages.APIUnexpectedResultDataStructure)
+	}
+	state2, ok := state1.(string)
+	if !ok {
+		return result, errors.New(messages.APIUnexpectedResultDataStructure)
+	}
+	state3 := strings.ToLower(state2)
+	isActive := state3 == "open" || state3 == "new"
 	destination1, has := pullRequest["destination"]
 	if !has {
 		return result, errors.New(messages.APIUnexpectedResultDataStructure)
@@ -125,6 +136,7 @@ func parsePullRequest(pullRequest map[string]any) (result forgedomain.BitbucketC
 	}
 	return forgedomain.BitbucketCloudProposalData{
 		ProposalData: forgedomain.ProposalData{
+			Active:       isActive,
 			MergeWithAPI: false,
 			Number:       number,
 			Source:       gitdomain.NewLocalBranchName(source6),
diff --git a/internal/forge/bitbucketdatacenter/parser.go b/internal/forge/bitbucketdatacenter/parser.go
index d45804acd..2148c59cc 100644
--- a/internal/forge/bitbucketdatacenter/parser.go
+++ b/internal/forge/bitbucketdatacenter/parser.go
@@ -10,6 +10,7 @@ import (
 
 func parsePullRequest(pullRequest PullRequest, repoURL string) forgedomain.ProposalData {
 	return forgedomain.ProposalData{
+		Active:       !pullRequest.Closed,
 		MergeWithAPI: false,
 		Number:       pullRequest.ID,
 		Source:       gitdomain.NewLocalBranchName(pullRequest.FromRef.DisplayID),
diff --git a/internal/forge/forgedomain/proposal_data.go b/internal/forge/forgedomain/proposal_data.go
index e3bef8c0a..1fca8ea65 100644
--- a/internal/forge/forgedomain/proposal_data.go
+++ b/internal/forge/forgedomain/proposal_data.go
@@ -6,6 +6,7 @@ import (
 )
 
 type ProposalData struct {
+	Active       bool // whether the proposal is open
 	Body         Option[string]
 	MergeWithAPI bool
 	Number       int
diff --git a/internal/forge/forgejo/api_connector.go b/internal/forge/forgejo/api_connector.go
index dd59f93fa..008bc0ea3 100644
--- a/internal/forge/forgejo/api_connector.go
+++ b/internal/forge/forgejo/api_connector.go
@@ -245,6 +245,7 @@ func filterPullRequests2(pullRequests []*forgejo.PullRequest, branch gitdomain.L
 
 func parsePullRequest(pullRequest *forgejo.PullRequest) forgedomain.ProposalData {
 	return forgedomain.ProposalData{
+		Active:       pullRequest.State == forgejo.StateOpen,
 		MergeWithAPI: pullRequest.Mergeable,
 		Number:       int(pullRequest.Index),
 		Source:       gitdomain.NewLocalBranchName(pullRequest.Head.Ref),
diff --git a/internal/forge/gh/parser.go b/internal/forge/gh/parser.go
index f4d82dc2a..8b9d64f9f 100644
--- a/internal/forge/gh/parser.go
+++ b/internal/forge/gh/parser.go
@@ -22,6 +22,7 @@ func ParseJSONOutput(output string, branch gitdomain.LocalBranchName) (Option[fo
 	data := parsed[0]
 	return Some(forgedomain.Proposal{
 		Data: forgedomain.ProposalData{
+			Active:       data.State == "open",
 			Body:         NewOption(data.Body),
 			MergeWithAPI: data.Mergeable == "MERGEABLE",
 			Number:       data.Number,
@@ -41,6 +42,7 @@ type jsonData struct {
 	HeadRefName string `json:"headRefName"`
 	Mergeable   string `json:"mergeable"`
 	Number      int    `json:"number"`
+	State       string `json:"state"`
 	Title       string `json:"title"`
 	URL         string `json:"url"`
 }
diff --git a/internal/forge/gitea/parser.go b/internal/forge/gitea/parser.go
index 8d9436c68..03fc5ae81 100644
--- a/internal/forge/gitea/parser.go
+++ b/internal/forge/gitea/parser.go
@@ -29,6 +29,7 @@ func FilterPullRequests2(pullRequests []*gitea.PullRequest, branch gitdomain.Loc
 
 func parsePullRequest(pullRequest *gitea.PullRequest) forgedomain.ProposalData {
 	return forgedomain.ProposalData{
+		Active:       pullRequest.State == "open",
 		MergeWithAPI: pullRequest.Mergeable,
 		Number:       int(pullRequest.Index),
 		Source:       gitdomain.NewLocalBranchName(pullRequest.Head.Ref),
diff --git a/internal/forge/github/new.go b/internal/forge/github/new.go
index d98c537d2..aa843bd9b 100644
--- a/internal/forge/github/new.go
+++ b/internal/forge/github/new.go
@@ -70,6 +70,7 @@ func RepositoryURL(hostNameWithStandardPort string, organization string, reposit
 // parsePullRequest extracts standardized proposal data from the given GitHub pull-request.
 func parsePullRequest(pullRequest *github.PullRequest) forgedomain.ProposalData {
 	return forgedomain.ProposalData{
+		Active:       pullRequest.GetState() == "open",
 		Body:         NewOption(pullRequest.GetBody()),
 		Number:       pullRequest.GetNumber(),
 		Source:       gitdomain.NewLocalBranchName(pullRequest.Head.GetRef()),
diff --git a/internal/forge/gitlab/parser.go b/internal/forge/gitlab/parser.go
index abb3b5b67..c43f9535b 100644
--- a/internal/forge/gitlab/parser.go
+++ b/internal/forge/gitlab/parser.go
@@ -9,6 +9,7 @@ import (
 
 func parseMergeRequest(mergeRequest *gitlab.BasicMergeRequest) forgedomain.ProposalData {
 	return forgedomain.ProposalData{
+		Active:       mergeRequest.State == "opened",
 		MergeWithAPI: true,
 		Number:       mergeRequest.IID,
 		Source:       gitdomain.NewLocalBranchName(mergeRequest.SourceBranch),
diff --git a/internal/forge/glab/parser.go b/internal/forge/glab/parser.go
index 7cfdfb78b..2e218fd65 100644
--- a/internal/forge/glab/parser.go
+++ b/internal/forge/glab/parser.go
@@ -51,6 +51,7 @@ type jsonData struct {
 	Mergeable    string `json:"detailed_merge_status"` //nolint:tagliatelle
 	Number       int    `json:"iid"`                   //nolint:tagliatelle
 	SourceBranch string `json:"source_branch"`         //nolint:tagliatelle
+	State        string `json:"state"`                 //nolint:tagliatelle
 	TargetBranch string `json:"target_branch"`         //nolint:tagliatelle
 	Title        string `json:"title"`
 	URL          string `json:"web_url"` //nolint:tagliatelle
@@ -59,6 +60,7 @@ type jsonData struct {
 func createProposal(data jsonData) forgedomain.Proposal {
 	return forgedomain.Proposal{
 		Data: forgedomain.ProposalData{
+			Active:       data.State == "open",
 			Body:         NewOption(data.Description),
 			MergeWithAPI: data.Mergeable == "mergeable",
 			Number:       data.Number,



Test patch:
diff --git a/internal/forge/bitbucketcloud/test_connector.go b/internal/forge/bitbucketcloud/test_connector.go
index 123191273..0a31d8414 100644
--- a/internal/forge/bitbucketcloud/test_connector.go
+++ b/internal/forge/bitbucketcloud/test_connector.go
@@ -35,6 +35,7 @@ func (self TestConnector) FindProposal(branch, target gitdomain.LocalBranchName)
 	}
 	proposal := forgedomain.BitbucketCloudProposalData{
 		ProposalData: forgedomain.ProposalData{
+			Active:       true,
 			Body:         None[string](),
 			MergeWithAPI: true,
 			Number:       123,
diff --git a/internal/forge/bitbucketdatacenter/test_connector.go b/internal/forge/bitbucketdatacenter/test_connector.go
index 291031b11..b23a9ef42 100644
--- a/internal/forge/bitbucketdatacenter/test_connector.go
+++ b/internal/forge/bitbucketdatacenter/test_connector.go
@@ -34,6 +34,7 @@ func (self TestConnector) FindProposal(branch, target gitdomain.LocalBranchName)
 		return None[forgedomain.Proposal](), nil
 	}
 	data := forgedomain.ProposalData{
+		Active:       true,
 		Body:         None[string](),
 		MergeWithAPI: true,
 		Number:       123,
diff --git a/internal/forge/forgedomain/proposal_data_test.go b/internal/forge/forgedomain/proposal_data_test.go
index d81006f5c..93ca0cef5 100644
--- a/internal/forge/forgedomain/proposal_data_test.go
+++ b/internal/forge/forgedomain/proposal_data_test.go
@@ -17,6 +17,7 @@ func TestBitbucketCloudProposalData(t *testing.T) {
 		t.Parallel()
 		data := forgedomain.BitbucketCloudProposalData{
 			ProposalData: forgedomain.ProposalData{
+				Active:       true,
 				Body:         Some("body"),
 				MergeWithAPI: true,
 				Number:       123,
@@ -33,6 +34,7 @@ func TestBitbucketCloudProposalData(t *testing.T) {
 		fmt.Println(string(serialized))
 		want := `
 {
+  "Active": true,
   "Body": "body",
   "MergeWithAPI": true,
   "Number": 123,
diff --git a/internal/forge/forgejo/test_connector.go b/internal/forge/forgejo/test_connector.go
index e47ee1e43..b0ce4fedd 100644
--- a/internal/forge/forgejo/test_connector.go
+++ b/internal/forge/forgejo/test_connector.go
@@ -35,6 +35,7 @@ func (self TestConnector) FindProposal(branch, target gitdomain.LocalBranchName)
 	}
 	return Some(forgedomain.Proposal{
 		Data: forgedomain.ProposalData{
+			Active:       true,
 			Body:         None[string](),
 			MergeWithAPI: true,
 			Number:       123,
diff --git a/internal/forge/gitea/test_connector.go b/internal/forge/gitea/test_connector.go
index 83b84aba2..c3bb06fbb 100644
--- a/internal/forge/gitea/test_connector.go
+++ b/internal/forge/gitea/test_connector.go
@@ -29,6 +29,7 @@ func (self TestConnector) FindProposal(branch, target gitdomain.LocalBranchName)
 	}
 	return Some(forgedomain.Proposal{
 		Data: forgedomain.ProposalData{
+			Active:       true,
 			Body:         None[string](),
 			MergeWithAPI: true,
 			Number:       123,
diff --git a/internal/forge/github/test_connector.go b/internal/forge/github/test_connector.go
index e3f9f1cd5..d6af74bdf 100644
--- a/internal/forge/github/test_connector.go
+++ b/internal/forge/github/test_connector.go
@@ -35,6 +35,7 @@ func (self TestConnector) FindProposal(branch, target gitdomain.LocalBranchName)
 	}
 	return Some(forgedomain.Proposal{
 		Data: forgedomain.ProposalData{
+			Active:       true,
 			Body:         None[string](),
 			MergeWithAPI: true,
 			Number:       123,
diff --git a/internal/forge/gitlab/test_connector.go b/internal/forge/gitlab/test_connector.go
index 147cb5ec7..11d580f77 100644
--- a/internal/forge/gitlab/test_connector.go
+++ b/internal/forge/gitlab/test_connector.go
@@ -35,6 +35,7 @@ func (self TestConnector) FindProposal(branch, target gitdomain.LocalBranchName)
 	}
 	return Some(forgedomain.Proposal{
 		Data: forgedomain.ProposalData{
+			Active:       true,
 			Body:         None[string](),
 			MergeWithAPI: true,
 			Number:       123,
diff --git a/internal/state/runstate/save_load_test.go b/internal/state/runstate/save_load_test.go
index 28683e8f9..ea2eec616 100644
--- a/internal/state/runstate/save_load_test.go
+++ b/internal/state/runstate/save_load_test.go
@@ -93,7 +93,7 @@ func TestLoadSave(t *testing.T) {
 				&opcodes.ConflictMergePhantomFinalize{},
 				&opcodes.ConflictMergePhantomResolveAll{CurrentBranch: "current", ParentBranch: gitdomain.NewLocalBranchNameOption("parent"), ParentSHA: Some(gitdomain.NewSHA("123456"))},
 				&opcodes.ConflictResolve{FilePath: "file", Resolution: gitdomain.ConflictResolutionOurs},
-				&opcodes.ConnectorProposalMerge{Branch: "branch", CommitMessage: Some(gitdomain.CommitMessage("commit message")), Proposal: forgedomain.Proposal{Data: forgedomain.BitbucketCloudProposalData{ProposalData: forgedomain.ProposalData{Body: Some("body"), MergeWithAPI: true, Number: 123, Source: "source", Target: "target", Title: "title", URL: "url"}}, ForgeType: forgedomain.ForgeTypeBitbucket}},
+				&opcodes.ConnectorProposalMerge{Branch: "branch", CommitMessage: Some(gitdomain.CommitMessage("commit message")), Proposal: forgedomain.Proposal{Data: forgedomain.BitbucketCloudProposalData{ProposalData: forgedomain.ProposalData{Active: true, Body: Some("body"), MergeWithAPI: true, Number: 123, Source: "source", Target: "target", Title: "title", URL: "url"}}, ForgeType: forgedomain.ForgeTypeBitbucket}},
 				&opcodes.ExecuteShellCommand{Args: []string{"arg1", "arg2"}, Executable: "executable"},
 				&opcodes.ExitToShell{},
 				&opcodes.FetchUpstream{Branch: "branch"},
@@ -114,9 +114,9 @@ func TestLoadSave(t *testing.T) {
 				&opcodes.MessageQueue{Message: "message"},
 				&opcodes.ProgramEndOfBranch{},
 				&opcodes.ProposalCreate{Branch: "branch", MainBranch: "main"},
-				&opcodes.ProposalUpdateTarget{Proposal: forgedomain.Proposal{Data: forgedomain.ProposalData{Body: Some("body"), MergeWithAPI: true, Number: 123, Source: "source", Target: "target", Title: "title", URL: "url"}, ForgeType: forgedomain.ForgeTypeGitLab}, NewBranch: "new-target", OldBranch: "old-target"},
-				&opcodes.ProposalUpdateTargetToGrandParent{Branch: "branch", Proposal: forgedomain.Proposal{Data: forgedomain.ProposalData{Body: Some("body"), MergeWithAPI: true, Number: 123, Source: "source", Target: "target", Title: "title", URL: "url"}, ForgeType: forgedomain.ForgeTypeGitea}, OldTarget: "old-target"},
-				&opcodes.ProposalUpdateSource{Proposal: forgedomain.Proposal{Data: forgedomain.ProposalData{Body: None[string](), MergeWithAPI: false, Number: 123, Source: "source", Target: "target", Title: "title", URL: "url"}, ForgeType: forgedomain.ForgeTypeForgejo}, NewBranch: "new-target", OldBranch: "old-target"},
+				&opcodes.ProposalUpdateTarget{Proposal: forgedomain.Proposal{Data: forgedomain.ProposalData{Active: true, Body: Some("body"), MergeWithAPI: true, Number: 123, Source: "source", Target: "target", Title: "title", URL: "url"}, ForgeType: forgedomain.ForgeTypeGitLab}, NewBranch: "new-target", OldBranch: "old-target"},
+				&opcodes.ProposalUpdateTargetToGrandParent{Branch: "branch", Proposal: forgedomain.Proposal{Data: forgedomain.ProposalData{Active: true, Body: Some("body"), MergeWithAPI: true, Number: 123, Source: "source", Target: "target", Title: "title", URL: "url"}, ForgeType: forgedomain.ForgeTypeGitea}, OldTarget: "old-target"},
+				&opcodes.ProposalUpdateSource{Proposal: forgedomain.Proposal{Data: forgedomain.ProposalData{Active: true, Body: None[string](), MergeWithAPI: false, Number: 123, Source: "source", Target: "target", Title: "title", URL: "url"}, ForgeType: forgedomain.ForgeTypeForgejo}, NewBranch: "new-target", OldBranch: "old-target"},
 				&opcodes.PullCurrentBranch{},
 				&opcodes.PushCurrentBranch{},
 				&opcodes.PushCurrentBranchForce{ForceIfIncludes: true},
@@ -451,6 +451,7 @@ func TestLoadSave(t *testing.T) {
         "CommitMessage": "commit message",
         "Proposal": {
           "data": {
+            "Active": true,
             "Body": "body",
             "MergeWithAPI": true,
             "Number": 123,
@@ -607,6 +608,7 @@ func TestLoadSave(t *testing.T) {
         "OldBranch": "old-target",
         "Proposal": {
           "data": {
+            "Active": true,
             "Body": "body",
             "MergeWithAPI": true,
             "Number": 123,
@@ -626,6 +628,7 @@ func TestLoadSave(t *testing.T) {
         "OldTarget": "old-target",
         "Proposal": {
           "data": {
+            "Active": true,
             "Body": "body",
             "MergeWithAPI": true,
             "Number": 123,
@@ -645,6 +648,7 @@ func TestLoadSave(t *testing.T) {
         "OldBranch": "old-target",
         "Proposal": {
           "data": {
+            "Active": true,
             "Body": null,
             "MergeWithAPI": false,
             "Number": 123,