Thank you for your reply. I like your examples, especially because they are very similar to mine! 
Yes, my code does much the same as yours - including setting any viewports to 1:1 (or deleting them outright, which I have the luxury of doing in some cases), and it also removes the unwanted scales from every annotative object I can find in the drawing (see first few code snips below). But even after all this, whichever scale had been active when the file was first read into memory, was not "freed up" and made deleteable.
I came up with a hacky but satisfactory solution: S ave and dispose the Database after setting Database.Cannoscale to 1:1, and then reopen the Database to continue with the rest of the process (see code snips more toward the bottom). For some reason, that worked. But I'm not marking my own answer as the solution, because I'm hoping someone out there has a better one, or can at least explain this weird behavior.
Deleting Scales from All Annotative Objects (kind of a detour, just for interest's sake)
First I get the ObjectIds of all annotative objects in all layouts:
public static List<ObjectId> GetAnnoObjectIds(Database db)
{
var result = new List<ObjectId>();
using (var trans = db.TransactionManager.StartTransaction())
{
var blockTable = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
//iterate through all layouts including model space
var layoutDict = (DBDictionary)trans.GetObject(db.LayoutDictionaryId, OpenMode.ForWrite);
foreach (DBDictionaryEntry layoutEntry in layoutDict)
{
var layout = (Layout)trans.GetObject(layoutEntry.Value, OpenMode.ForRead);
var layoutBTR = (BlockTableRecord)trans.GetObject(layout.BlockTableRecordId, OpenMode.ForRead);
//iterate through objects in this layout
foreach (ObjectId objId in layoutBTR)
{
var obj = trans.GetObject(objId, OpenMode.ForRead);
if (obj.Annotative == AnnotativeStates.True) result.Add(obj.ObjectId);
obj.Dispose();
}
}
trans.Commit();
}
return result;
}
Then I get the current scale list, using a method similar to your GetAnnotationScales() that I won't show here because it's so similar. The only difference is that instead of returning a Dictionary, it returns a List<> of a data transfer object I've defined (that I will show here), for working with scales elsewhere in my codebase:
public class ScaleDTO
{
public bool isArchitectural { get; set; }
public bool isCivil { get; set; }
public string Name { get; set; }
public string LongName { get; set; }
public double ModelUnits { get; set; }
public double PaperUnits { get; set; }
}
Now that I have the List<ObjectId> of annotative object IDs, and the List<ScaleDTO> of current scales, I use the below method to delete all those scales from all those objects:
public static void DeleteScalesFromObjects(Database db, List<ScaleDTO> scales, List<ObjectId> objectIds)
{
//get ObjectContexts
var occ = db.ObjectContextManager.GetContextCollection("ACDB_ANNOTATIONSCALES");
var contextsToDelete = new List<ObjectContext>();
foreach (var scale in scales)
if (occ.HasContext(scale.Name) && scale.Name != "1:1" && scale.Name != db.Cannoscale.Name)
contextsToDelete.Add(occ.GetContext(scale.Name));
//iterate through DBObjects
using (var trans = db.TransactionManager.StartTransaction())
{
foreach (var objectId in objectIds)
{
var obj = trans.GetObject(objectId, OpenMode.ForWrite);
//remove contexts from object
foreach (var context in contextsToDelete)
if (obj.HasContext(context))
obj.RemoveContext(context);
}
trans.Commit();
}
}
Hacky Quasi-Solution: Saving & Disposing the Database in Between
Again, the above measures, combined with resetting or deleting viewports, and setting Database.Cannoscale, were for some reason not enough to free up the previous Database.Cannoscale for deletion. I would get an eObjectIsReferenced exception. So my hacky solution was to basically split the steps of the process into the below method (that only sets the .Cannoscale to 1:1, saves and disposes), and the rest of the process (i.e. delete or reset viewports, delete scales from annotative objects as above, and delete scales from the drawing itself). For unknown reasons, that worked. Note that the below method calls my method AddScalesToDwg() that I don't show here, but is similar to your CreateAnnotationScale(). (Except I use a List. Apparently I love Lists.)
/// <summary>
/// Creates if necessary the annotative scale 1:1 in the given .dwg file, and sets it current in model space via the Database.Cannoscale property.
/// Returns a List<string> of errors, which is empty in the success condition.
/// </summary>
/// <param name="filePath">The full path to the .dwg file</param>
public static List<string> SetUnityScaleCurrent(string filePath)
{
var errors = new List<string>();
//make sure path exists and points to a .dwg
if (Path.GetExtension(filePath).ToUpper() != ".DWG")
{
errors.Add("Can't add annoscale 1:1 to " + filePath + " (file isn't a .dwg).");
return errors;
}
else if (!File.Exists(filePath))
{
errors.Add("Can't add annoscale 1:1 to " + filePath + " (file doesn't exist).");
return errors;
}
//load file into side database
var db = new Database(false, true);
db.ReadDwgFile(filePath, FileOpenMode.OpenForReadAndWriteNoShare, false, null);
db.CloseInput(true);
//make sure drawing has unity scale
var unityScaleDTO = new ScaleDTO() { Name = "1:1", LongName = "1:1", ModelUnits = 1, PaperUnits = 1, ScaleFactor = 1 };
var occ = db.ObjectContextManager.GetContextCollection("ACDB_ANNOTATIONSCALES");
if (!occ.HasContext("1:1"))
errors.AddRange(AddScalesToDwg(db, new List<ScaleDTO>() { unityScaleDTO }));
var unityScaleContext = occ.GetContext("1:1");
//set unity scale current
db.Cannoscale = (AnnotationScale)unityScaleContext;
//save file & dispose
db.SaveAs(db.Filename, db.OriginalFileVersion);
db.Dispose();
return errors;
}