Why MAX+1 without a lock breaks
The naive approach reads the highest existing ID, adds one, and writes it back. Under a single user that works fine. Under a Google Form with any real traffic, two submissions can fire within milliseconds of each other. Both executions read the same MAX value before either has written its result, and both write the same ID to different rows. You now have a duplicate, and no error was ever thrown.
LockService.getSpreadsheetLock() serializes access at the spreadsheet level. The first execution claims the lock; the second blocks at waitLock(10000), which means it will wait up to 10 seconds before throwing. In practice the first execution reads, increments, writes, and releases in well under a second, so the second execution then proceeds with an accurate MAX.
The first time I hit this problem, the sheet was a registration form for a small event. Two people submitted within the same second during an announcement email blast. Both got ticket number 47. That kind of collision is silent and only surfaces when you go to fulfill something downstream.