--- a
+++ b/scripts/migrations/001-restore-labels.py
@@ -0,0 +1,61 @@
+import sys
+import json
+import logging
+
+from pylons import c
+
+from ming.orm import session, MappedClass
+
+from allura import model as M
+
+log = logging.getLogger(__name__)
+
+def main():
+    test = sys.argv[-1] == 'test'
+    projects = M.Project.query.find().all()
+    log.info('Restoring labels on projects')
+    for p in projects:
+        restore_labels(p, test)
+    if not test:
+        session(p).flush()
+    log.info('Restoring labels on artifacts')
+    for p in projects:
+        if p.parent_id: continue
+        c.project = p
+        for name, cls in MappedClass._registry.iteritems():
+            if not issubclass(cls, M.Artifact): continue
+            if session(cls) is None: continue
+            for a in cls.query.find():
+                restore_labels(a, test)
+        if not test:
+            M.artifact_orm_session.flush()
+        M.artifact_orm_session.clear()
+
+def restore_labels(obj, test=True):
+    if not obj.labels: return
+    labels = obj.labels
+    while True:
+        if not labels or labels[0] != '[': return
+        lbllen = map(len, labels)
+        if max(lbllen) != 1: return
+        if min(lbllen) != 1: return
+        s = ''.join(labels)
+        s = s.replace("u'", "'")
+        s = s.replace('u"', '"')
+        jobj = '{"obj":' + s.replace("'", '"') + '}'
+        try:
+            new_labels = json.loads(jobj)['obj']
+        except ValueError:
+            # some weird problem with json decoding, just erase the labels
+            new_labels = []
+        if not isinstance(new_labels, list): return
+        for lbl in new_labels:
+            if not isinstance(lbl, basestring): return
+        log.info('%s: %s => %s', obj.__class__, labels, new_labels)
+        labels = new_labels
+        if not test:
+            log.info('...actually restoring labels') 
+            obj.labels = new_labels
+
+if __name__ == '__main__':
+    main()