I think I've cracked it!
First I ran that console on my own savegame, paying particular attention to three cabincaptains who are genuine prisoners - numbers 7, 10 and 11. Down in the hold, I executed one, released one and hired one; then I returned to sea and ran the console again. The executed prisoner and hired prisoner still showed up as allies; only the released one had been cleared.
So I looked in "Cabinfight_dialog.c" to see what happens when a prisoner is executed. It decides randomly whether he's to be hanged or fed to the sharks; both cases do some stuff to steal his equipment, play the relevant video, and trigger event "LAi_RemoveDeadCap", which is handled in "LAi_boarding.c" by function 'Lai_RemoveDeadBody()', which kills the character. First question: if he's dead, why is he still in LAI_GROUP_PLAYER? Second question - why am I looking in "Cabinfight_dialog.c"? That's the file for when he's on his own deck - the one I should be looking in is "Prisoned_dialog.c".
OK, look in "Prisoned_dialog.c", which does some different things to the prisoner and ends by playing the same videos, but does
not trigger event "LAi_RemoveDeadCap". So I added that line at the end of both cases "Exit_hanged" and "Exit_sharks".
Next I added the "ClearUponExit" attribute to the original character at the end of 'TIH_PrisonerHiredAsOfficerProcess'. Then I repeated the test - loaded the savegame, ran the console to show all the cabincaptains, executed a prisoner, released a prisoner and hired a prisoner, and ran the console again. The executed prisoner still showed up but was no longer an ally - and as this version of "console.c" ends by calling 'FindFreeCabinCaptain()' to show which cabin is free, it now showed slot 7 (the one used by the dead captain) as being free. Meanwhile the hired captain had been cleared entirely. One odd thing, though - before adding the line to clear him, the hired captain went into "officer" mode and followed me around the hold. Now he just stood still and "compile.log" had an error about him not having an ai type. I added 'LAi_SetOfficerType(RefChar);' right above the line to set his "ClearUponExit" attribute, and then he behaved properly - he followed me around the hold and "compile.log" didn't have the error.
The attached "cabincaptain_fix.zip" contains the modified "Prisoned_dialog.c" and "Dialog_func.c".
Also attached is another version of "console.c". This one scans through all cabincaptains and clears any who aren't actual passengers. I loaded the savegame supplied in the previous thread and ran that console. It listed a whole load of cabincaptains being wiped, then I checked the "Passengers" list, where all the passengers and prisoners who had been there before the purge were still there. And then I boarded the nearby surrendered ship, where the captain duly appeared.
@nich666: if you're still having the problem with surrendered captains failing to show up, download this "console.c", load up your most current savegame and press F12. Also download "cabincaptain_fix.zip", unzip it and copy it into place, which should prevent the problem from happening again later.