Even if you delete and pack, the recno() order will still stay the same.
That's true, but you wouldn't have a constant identifier. And that wouldn't make it a primary key.
Edit: And that's what MarK also posted before me.
So the question becomes, whether it is okay to have a table without a primary key. You find a lot of discussion about it. One major point is it never hurts to have it. So why omit it? To save 4 bytes per record? Or even 32 to 38 if you go for a GUID and either or not include its minus signs and/or curly brackets.
So if you omit a primary key, that's possible in database theory, it makes a table just a heap. A heap should not be involved in a relationship between data. Not on both ends. So in Mandys case also not the detail table. Or you get the problem she has. You can only identify a single record for an SQL-UPDATE or SQL-DELETE, if you're lucky that there is a unique combination of values. In her case, that the unwanted transactions with the 340 and 350 amounts that should be mended to 890 and 670 respectively are unique within the transactions of the given account identifier. She didn't even specify it has to be account 0001, but that's the only with both of the wrong amounts. It's okay in this case, but only considering the data shown. As Mandy asked: What about when you have to consider thousands more records? It becomes more and more possible the 340 and 350 amounts are not unique.
In databases you don't want to consider luck a necessary ingredient for maintaining it, do you?
You can argue that in VFP the concept of opening a table and browsing it, navigating to a current row and then just using the xBase DELETE (NEXT 1) deleting the current row will always enable you to do that. And it's not just a feature you only have available as developer browsing the data, if you have UI that allows the user to select the record in a grid or listbox or even just navigate to it showing in a single textbox, you still have the current row concept. That's unique to VFP, though. And not a thing available in databases, generally.
So in the end, it's a problem you could say is unimportant in VFP, but it still means you would at least need to browse data and identify the records to maintain manually, you could not generally let only code identify records, you could list them and code to take the last one.
I admit, even with a primary key in Mandys described problem you could still have multiple records with 340 and 350 amounts and the primary key would only tell you which of them were added later, the current recno (no matter if it differed in the past due to PACKs done in the lifetime of the table) also tells you that. So you would need a manual decision, anyway.
That's why I also argued about adding data like the user who entered the transaction and a transaction date. The more data to have, the better you can identify the problematic data. The most relevant there would be a record of a cheque or bill or anything that states the debit or credit so you can verify the amount change by the transaction is correct, you could even omit the tranaction amount and take it from that related record, well, or let that table have the role of the transaction table. And you know what other data is usally attached to a cheque or bill or other such things: A unique identifier, an issue date, etc.
So in the end for generality you have a primary key mainly for databases where you can only think of a table as a set, without having the VFP concept of a current record. If in MSSQL you have two records 0001 340 in a heap ( a table without primary key) There is nothing to pick one record of them to update or to delete. SQL needs a unique key to address one of them only. And though VFP has that current record concept, I would still never recommend to have heap tables of anything else but logs in which addressing them never is a problem.
To give one more argument: In a table you regularly pack, you don't have long term gaps in the row numbering, as RECNOS() only ever have gaps due to currently deleted not yet fully removed rows that await the next PACK. And so you don't have a documented deleted identifier, ever. A gap is also an information. If you ever print a record id, that paper never changes with database changes, but would have witness of a record it pointed to and can be verified to be deleted or still present in the database. Now I open another can of worms as the general advice is to not print keys, as they are just surrogate and not actual data, but for that case it would be useful. You don't want to have moving targets by PACK renumbering records by removing gaps.
So in very short: Database theory doesn't care if your database offers a current record concept or not, so the rules require a table to have a key that's unique and non null and constant over the record lifecycle as the full extent of rules about it. VFPs RECNO doesn't fulfill the last aspect.
Finally the valid argument for a table without primary key is that it's a heap, which is allowed in all databases. A heaps rows can not be identified unless you'd restrict them to not have duplicates, i.e. make all columns a combined primary key. The fewer columns you have, the harder it is, in Mandy's two column transaction case it would never allow two transactions with the same amount to have identifiable rows. Well, and we're then talking about making a heap a normal table again, just with an awkward key. So a "real" heap would mean you have to allow duplicates which you could only handle with a concept like the current record to get a handle on one of them and only one of them and not their duplicates. Even if you argue storage of data is always in some form of file, so there always is a difference in the physical position of that data, be it in a VFP recno() or in a page structure or whatever, it's just not something straight forward available to you and natural to use in the SQL DML (the part of SQL about data manipulation in contrast to data definition DDL like CREATE TABLE/ALTER TABLE etc.). Notice VFPs recno() is not part of DML by that definion, The data itself has no recno(), that's only available as DBFs have records in physical order at a record number. Like already stated similarly any other database has a physical positon of a record however the data storage engine works, but RECNO() is not univeral. You don't want to introduce need of special treatment of cases because you omit a key, that's cheap and easy to have in all your tables. Don't use heaps unless you actually can treat data as heap, as in logs you can also ZAP or truncate or drop and recreate without loss of essential data to the whole database.