In a response to my question, Miguel Sofer on tcl-core:
Begin quote -
First reaction, from memory, is: a literal should ALWAYS have a string rep - the exact string rep it had when stored as a literal. As that string rep is not guaranteed to be regenerated exactly, it should never be cleared.
Second reaction: Tcl_InvalidateStringRep must not be called on a shared object, ever. This is because ... because ... why was it?
Note that you can shimmer a shared Tcl_Obj, ie, change its internal rep. You can also generate a string rep if there was none to begin with. But a Tcl_Obj that has a string rep must retain it forever, until its last ref is gone and the obj is returned to free mem.
The second point is not mentioned in the Tcl_InvalidateStringRep man page. Not following this will result in a crash. This does not normally happen because in most uses because the object in question is being mutated and hence is unshared. In my particular case, I had a custom compact internal rep and was calling InvalidateStringRep just to save on memory (largish strings) thinking they can always be regenerated from internal rep.
The other two points are also very useful hints/explanations for someone writing a custom internal rep. Not sure where they should go. Maybe in the Tcl_RegisterObjType man page.