One thing I noticed on the duplicate records is that one seems to be from SharePoint, because it contains all the data like created time/by, whilst the other seems to be only created in the temporary collection (colGridData) and it only contains the data points that are added by the app (ID, amount, category in this snip):

Some additional information, which might help troubleshooting:
The columns in the gallery template all have the following in their OnChange: Select(Parent)
The Gallery OnSelect is as follows:
Patch(colGridData,ThisItem,
{
ID: ThisItem.ID,
checklistID:{'@odata.type':"#Microsoft.Azure.Connectors.SharePoint.SPListExpandedReference",
Id:ThisItem.checklistID.Id,
Value:ThisItem.checklistID.Value},
rowNumber: Value(FundCommitments_rowNumber.Text),
category: {Value: "Fund Commitments"},
commitmentType: {Value: FundCommitments_commitmentType.Selected.Value},
amount: Value(FundCommitments_amount.Text),
comment: FundCommitments_comment.Text
}
);
The (later invisible) button btnLoadDataTCCommitment has the following OnSelect:
ClearCollect(colGridData,Filter(TC_commitment,checklistID.Id = lastForm));
The (later invisible) button btnSaveDataTCCommitment has the following OnSelect:
Patch(
TC_commitment,
UpdateIf(
colGridData,
Created = Blank(),
{ID: Blank(),checklistID: {Id:lastForm,Value:lastForm}}
)
);
Remove(TC_commitment,colDelete);
Clear(colDelete);
Select(btnLoadDataTCCommitment);
The trash icon in the gallery has the following OnSelect:
Collect(colDelete,ThisItem);
Remove(colGridData,ThisItem);
Explanation of the SaveData:
It patches the SharePoint list (TC_commitment) with the temporary collection colGridData from the gallery, but first updates the ID and checklistID if it's an item that does not yet exist in SharePoint.
It removes any items that were added to the colDelete collection by the user clicking the trash icon.
After patching, it loads the data fresh from the SharePoint list by selecting the load button.