diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md
new file mode 100644
index 0000000000000000000000000000000000000000..14cd14aa432393ababced2f1c8597040b5f78c54
--- /dev/null
+++ b/.gitlab/issue_templates/Bug.md
@@ -0,0 +1,34 @@
+<!---
+Please read this!
+
+Before opening a new issue, make sure to search for keywords in the issues.
+
+and verify the issue you're about to submit isn't a duplicate.
+--->
+
+### Summary
+
+(Summarize the bug encountered concisely)
+
+### Steps to reproduce
+
+(How one can reproduce the issue - this is very important)
+
+### What is the current *bug* behavior?
+
+(What actually happens)
+
+### What is the expected *correct* behavior?
+
+(What you should see instead)
+
+### Relevant logs and/or screenshots
+
+(Paste any relevant logs - please use code blocks (```) to format console output,
+logs, and code as it's tough to read otherwise.)
+
+### Possible fixes
+
+(If you can, link to the line of code that might be responsible for the problem)
+
+/label ~bug
diff --git a/.gitlab/issue_templates/Feature.md b/.gitlab/issue_templates/Feature.md
new file mode 100644
index 0000000000000000000000000000000000000000..34243a26c599dcac551815c60ad98e7b3fe20888
--- /dev/null
+++ b/.gitlab/issue_templates/Feature.md
@@ -0,0 +1,17 @@
+### Problem to solve
+
+<!-- What problem do we solve? -->
+
+### Intended users
+
+<!-- Who will use this feature? If known, include any of the following: types of users (e.g. Developer, Operations), or specific company roles (e.g. Release Manager). It's okay to write "Unknown" and fill this field in later. -->
+
+### Further details
+
+<!-- Include use cases, benefits, and/or goals -->
+
+### Proposal
+
+<!-- How are we going to solve the problem? -->
+
+/label ~feature
diff --git a/catalogue/Catalogue.hpp b/catalogue/Catalogue.hpp
index 695eabebfe6c97884d521901eaa82f2ee46c7c1b..e3caf2ed1cfc999cfdf530ce55b08cdfd141006c 100644
--- a/catalogue/Catalogue.hpp
+++ b/catalogue/Catalogue.hpp
@@ -338,14 +338,6 @@ public:
    * @param vid The volume identifier of the tape to be reclaimed.
    */
   virtual void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid) = 0;
-  
-  /**
-   * This method should ONLY be used for TESTS. It does exactly the same as the real reclaimTape but it does not verify the 
-   * SUPERSEDED_BY_VID and SUPERSEDED_BY_FSEQ attributes
-   * @param admin The administrator.
-   * @param vid The volume identifier of the tape to be reclaimed.
-   */
-  virtual void fakeReclaimTapeForTests(const common::dataStructures::SecurityIdentity& admin, const std::string &vid) = 0;
 
   virtual void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &mediaType) = 0;
   virtual void modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &vendor) = 0;
@@ -599,16 +591,6 @@ public:
    * @return True if the tape exists.
    */
   virtual bool tapeExists(const std::string &vid) const = 0;
-  
-  /**
-   * Returns true if non superseded files exist after fSeq in the tape where vid is passed in parameter
-   * If there is only superseded files after fSeq, these tape files will be deleted
-   * 
-   * @param vid the vid of the tape to check if non superseded files exist after fSeq
-   * @param fSeq the fSeq after which we want to check if non superseded files exist
-   * @return true if non superseded files exist, false otherwise
-   */
-  virtual bool existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(const std::string &vid, const uint64_t fSeq) const  = 0;
 
 }; // class Catalogue
 
diff --git a/catalogue/CatalogueRetryWrapper.hpp b/catalogue/CatalogueRetryWrapper.hpp
index b9155d69c4b2ddb531286f31a60550cd144fb03b..65d98eaf85da745baeeed07f636dc4d6bd5f9943 100644
--- a/catalogue/CatalogueRetryWrapper.hpp
+++ b/catalogue/CatalogueRetryWrapper.hpp
@@ -232,10 +232,6 @@ public:
   void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid) override {
     return retryOnLostConnection(m_log, [&]{return m_catalogue->reclaimTape(admin, vid);}, m_maxTriesToConnect);
   }
-  
-  void fakeReclaimTapeForTests(const common::dataStructures::SecurityIdentity &admin, const std::string &vid) override {
-    return retryOnLostConnection(m_log, [&]{return m_catalogue->fakeReclaimTapeForTests(admin, vid);}, m_maxTriesToConnect);
-  }
 
   void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &mediaType) override {
     return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyTapeMediaType(admin, vid, mediaType);}, m_maxTriesToConnect);
@@ -388,11 +384,6 @@ public:
   bool tapeExists(const std::string &vid) const override {
     return retryOnLostConnection(m_log, [&]{return m_catalogue->tapeExists(vid);}, m_maxTriesToConnect);
   }
-  
-  bool existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(const std::string& vid, const uint64_t fSeq) const override {
-    return retryOnLostConnection(m_log,[&]{return m_catalogue->existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(vid,fSeq);},m_maxTriesToConnect);
-  }
-
 
 protected:
 
diff --git a/catalogue/CatalogueTest.cpp b/catalogue/CatalogueTest.cpp
index 97000ca464a268a50cb3f91811cc32ff7de48fae..7e98967beab39de7ede5f95c38fcf0d5b27c7309 100644
--- a/catalogue/CatalogueTest.cpp
+++ b/catalogue/CatalogueTest.cpp
@@ -12151,122 +12151,6 @@ TEST_P(cta_catalogue_CatalogueTest, reclaimTape_full_lastFSeq_1_one_tape_file_su
   }
 }
 
-TEST_P(cta_catalogue_CatalogueTest, exist_non_superseded_files_after_fseq) {
-  using namespace cta;
-
-  const std::string diskInstanceName1 = "disk_instance_1";
-
-  ASSERT_TRUE(m_catalogue->getTapes().empty());
-
-  const std::string vid1 = "VID123";
-  const std::string vid2 = "VID234";
-  const std::string mediaType = "media_type";
-  const std::string vendor = "vendor";
-  const std::string logicalLibraryName = "logical_library_name";
-  const bool logicalLibraryIsDisabled= false;
-  const std::string tapePoolName = "tape_pool_name";
-  const std::string vo = "vo";
-  const uint64_t nbPartialTapes = 2;
-  const bool isEncrypted = true;
-  const cta::optional<std::string> supply("value for the supply pool mechanism");
-  const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000;
-  const bool disabledValue = true;
-  const bool fullValue = false;
-  const std::string createTapeComment = "Create tape";
-  
-  m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library");
-  m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool");
-  m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes,
-    disabledValue, fullValue, createTapeComment);
-  
-  //A tape with no tape file have no files after FSeq 0
-  ASSERT_FALSE(m_catalogue->existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(vid1,0));
-  
-  const uint64_t archiveFileId = 1234;
-
-  ASSERT_FALSE(m_catalogue->getArchiveFilesItor().hasMore());
-  ASSERT_THROW(m_catalogue->getArchiveFileById(archiveFileId), exception::Exception);
-
-  common::dataStructures::StorageClass storageClass;
-  storageClass.diskInstance = diskInstanceName1;
-  storageClass.name = "storage_class";
-  storageClass.nbCopies = 1;
-  storageClass.comment = "Create storage class";
-  m_catalogue->createStorageClass(m_admin, storageClass);
-
-  /*
-   * Insert a file in the tape vid1
-   */
-  {
-    const uint64_t archiveFileSize = 1;
-    const std::string tapeDrive = "tape_drive";
-    const std::string checksumType = "checksum_type";
-    const std::string checksumValue = "checksum_value";
-
-    auto file1WrittenUP=cta::make_unique<cta::catalogue::TapeFileWritten>();
-    auto & file1Written = *file1WrittenUP;
-    std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet;
-    file1WrittenSet.insert(file1WrittenUP.release());
-    file1Written.archiveFileId        = archiveFileId;
-    file1Written.diskInstance         = storageClass.diskInstance;
-    file1Written.diskFileId           = "5678";
-    file1Written.diskFilePath         = "/public_dir/public_file";
-    file1Written.diskFileUser         = "public_disk_user";
-    file1Written.diskFileGroup        = "public_disk_group";
-    file1Written.size                 = archiveFileSize;
-    file1Written.checksumType         = checksumType;
-    file1Written.checksumValue        = checksumValue;
-    file1Written.storageClassName     = storageClass.name;
-    file1Written.vid                  = vid1;
-    file1Written.fSeq                 = 1;
-    file1Written.blockId              = 4321;
-    file1Written.compressedSize       = 1;
-    file1Written.copyNb               = 1;
-    file1Written.tapeDrive            = tapeDrive;
-    m_catalogue->filesWrittenToTape(file1WrittenSet);
-  }
-  //One file written : this file is not superseded by another one, existNonSupersededFilesAfterFSeq = true
-  ASSERT_TRUE(m_catalogue->existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(vid1,0));
-  //No file after the only file inserted, existNonSupersededFilesAfterFseq = false
-  ASSERT_FALSE(m_catalogue->existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(vid1,1));
-  
-  //Insert another file in another tape that will supersed the first one in vid1
-  {
-    m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes,
-    disabledValue, fullValue, createTapeComment);
-    const uint64_t archiveFileSize = 1;
-    const std::string tapeDrive = "tape_drive";
-    const std::string checksumType = "checksum_type";
-    const std::string checksumValue = "checksum_value";
-
-    auto file1WrittenUP=cta::make_unique<cta::catalogue::TapeFileWritten>();
-    auto & file1Written = *file1WrittenUP;
-    std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet;
-    file1WrittenSet.insert(file1WrittenUP.release());
-    file1Written.archiveFileId        = archiveFileId;
-    file1Written.diskInstance         = storageClass.diskInstance;
-    file1Written.diskFileId           = "5678";
-    file1Written.diskFilePath         = "/public_dir/public_file";
-    file1Written.diskFileUser         = "public_disk_user";
-    file1Written.diskFileGroup        = "public_disk_group";
-    file1Written.size                 = archiveFileSize;
-    file1Written.checksumType         = checksumType;
-    file1Written.checksumValue        = checksumValue;
-    file1Written.storageClassName     = storageClass.name;
-    file1Written.vid                  = vid2;
-    file1Written.fSeq                 = 1;
-    file1Written.blockId              = 4321;
-    file1Written.compressedSize       = 1;
-    file1Written.copyNb               = 1;
-    file1Written.tapeDrive            = tapeDrive;
-    m_catalogue->filesWrittenToTape(file1WrittenSet);
-  }
-  //The tape files written to tape vid2 are not superseded by any file, but the tape files in vid1 
-  //are superseded by the tape files in vid2
-  ASSERT_FALSE(m_catalogue->existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(vid1,0));
-  ASSERT_TRUE(m_catalogue->existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(vid2,0));
-}
-
 TEST_P(cta_catalogue_CatalogueTest, ping) {
   using namespace cta;
 
diff --git a/catalogue/DummyCatalogue.hpp b/catalogue/DummyCatalogue.hpp
index a67b479e1710340e5726459b69beefbe4aebda3f..5e83c60901025a45c9803006f015e233617a0311 100644
--- a/catalogue/DummyCatalogue.hpp
+++ b/catalogue/DummyCatalogue.hpp
@@ -107,7 +107,6 @@ public:
     const std::string &storageClassName, const common::dataStructures::UserIdentity &user) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile(const std::string& instanceName, const uint64_t archiveFileId, const common::dataStructures::UserIdentity& user, log::LogContext &lc) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void reclaimTape(const common::dataStructures::SecurityIdentity& admin, const std::string& vid) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
-  void fakeReclaimTapeForTests(const common::dataStructures::SecurityIdentity& admin, const std::string& vid) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void setTapeDisabled(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const bool disabledValue) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void setTapeFull(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const bool fullValue) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void setTapePoolEncryption(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const bool encryptionValue) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
@@ -116,7 +115,6 @@ public:
   void tapeMountedForArchive(const std::string& vid, const std::string& drive) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void tapeMountedForRetrieve(const std::string& vid, const std::string& drive) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   bool tapePoolExists(const std::string& tapePoolName) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
-  bool existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(const std::string& vid, const uint64_t fSeq) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
 
   // Special functions for unit tests.
   void addEnabledTape(const std::string & vid) {
diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp
index 4ad7b64be62195aac45f256293e23f88be420e48..fc5424be8cfd910d457a65f3fc8d045932936a58 100644
--- a/catalogue/RdbmsCatalogue.cpp
+++ b/catalogue/RdbmsCatalogue.cpp
@@ -1891,47 +1891,6 @@ bool RdbmsCatalogue::tapeExists(rdbms::Conn &conn, const std::string &vid) const
   }
 }
 
-bool RdbmsCatalogue::existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(const std::string& vid, const uint64_t fSeq) const {
-  try{
-    auto conn = m_connPool.getConn();
-    const char *const sql =
-    "SELECT VID "
-     "FROM TAPE_FILE "
-    "WHERE "
-      "VID = :VID AND "
-      "FSEQ > :FSEQ AND "
-      "SUPERSEDED_BY_VID IS NULL AND "
-      "SUPERSEDED_BY_FSEQ IS NULL";
-    auto stmt = conn.createStmt(sql);
-    stmt.bindString(":VID",vid);
-    stmt.bindUint64(":FSEQ",fSeq);
-    auto rset = stmt.executeQuery();
-    if(!rset.next()){
-      //No non-superseded files detected, we can delete the tape files
-      const char *const sqlDelete =
-      "DELETE FROM TAPE_FILE "
-      "WHERE "
-        "VID =:VID AND "
-        "FSEQ > :FSEQ AND "
-        "SUPERSEDED_BY_VID IS NOT NULL AND "
-        "SUPERSEDED_BY_FSEQ IS NOT NULL";
-      auto stmtDelete = conn.createStmt(sqlDelete);
-      stmtDelete.bindString(":VID",vid);
-      stmtDelete.bindUint64(":FSEQ",fSeq);
-      stmtDelete.executeNonQuery();
-      return false;
-    }
-    //Non superseded files are present
-    return true;
-  } catch(exception::UserError &) {
-    throw;
-  } catch(exception::Exception &ex) {
-    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
-    throw;
-  }
-}
-
-
 //------------------------------------------------------------------------------
 // deleteTape
 //------------------------------------------------------------------------------
@@ -2346,73 +2305,47 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getAllTapes() const {
 }
 
 //------------------------------------------------------------------------------
-// reclaimTape
+//getNbNonSupersededFilesOnTape
 //------------------------------------------------------------------------------
-void RdbmsCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid) {
+uint64_t RdbmsCatalogue::getNbNonSupersededFilesOnTape(rdbms::Conn& conn, const std::string& vid) const {
   try {
-    const time_t now = time(nullptr);
-    const char *const sql =
-      "UPDATE TAPE SET "
-        "DATA_IN_BYTES = 0,"
-        "LAST_FSEQ = 0,"
-        "IS_FULL = '0',"
-        "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME,"
-        "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
-        "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
-      "WHERE "
-        "VID = :UPDATE_VID AND "
-        "IS_FULL != '0' AND "
-        "NOT EXISTS (SELECT VID FROM TAPE_FILE WHERE VID = :SELECT_VID "
-    "                                            AND SUPERSEDED_BY_VID IS NULL "
-    "                                            AND SUPERSEDED_BY_FSEQ IS NULL)";
-    auto conn = m_connPool.getConn();
+    const char *const sql = 
+    "SELECT COUNT(*) AS NB_NON_SUPERSEDED_FILES FROM TAPE_FILE "
+    "WHERE VID = :VID "
+    "AND SUPERSEDED_BY_VID IS NULL "
+    "AND SUPERSEDED_BY_FSEQ IS NULL";
     auto stmt = conn.createStmt(sql);
-    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
-    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
-    stmt.bindUint64(":LAST_UPDATE_TIME", now);
-    stmt.bindString(":UPDATE_VID", vid);
-    stmt.bindString(":SELECT_VID", vid);
-    stmt.executeNonQuery();
-
-    // If the update failed due to a user error
-    if(0 == stmt.getNbAffectedRows()) {
-      // Try to determine the user error
-      //
-      // Please note that this is a best effort diagnosis because there is no
-      // lock on the database to prevent other concurrent updates from taking
-      // place on the TAPE and TAPE_FILE tables
-      TapeSearchCriteria searchCriteria;
-      searchCriteria.vid = vid;
-      const auto tapes = getTapes(conn, searchCriteria);
-
-      if(tapes.empty()) {
-        throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it does not exist");
-      } else {
-        if(!tapes.front().full) {
-          throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it is not FULL");
-        } else {
-          throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because there is at least one tape"
-            " file in the catalogue that is on the tape");
-        }
-      }
-    }
-  } catch(exception::UserError &) {
-    throw;
+    stmt.bindString(":VID", vid);
+    auto rset = stmt.executeQuery();
+    rset.next();
+    return rset.columnUint64("NB_NON_SUPERSEDED_FILES");
   } catch(exception::Exception &ex) {
     ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
     throw;
   }
 }
 
-//------------------------------------------------------------------------------
-//fakeReclaimTapeForTests
-//------------------------------------------------------------------------------
 
-void RdbmsCatalogue::fakeReclaimTapeForTests(const common::dataStructures::SecurityIdentity& admin, const std::string& vid) {
+void RdbmsCatalogue::deleteTapeFiles(rdbms::Conn& conn, const std::string& vid) const {
+  try {
+    const char * const sql = 
+    "DELETE FROM TAPE_FILE WHERE VID = :VID "
+    "AND SUPERSEDED_BY_VID IS NOT NULL "
+    "AND SUPERSEDED_BY_FSEQ IS NOT NULL";
+    auto stmt = conn.createStmt(sql);
+    stmt.bindString(":VID", vid);
+    stmt.executeNonQuery();
+  } catch(exception::Exception &ex) {
+    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
+    throw;
+  }
+}
+
+void RdbmsCatalogue::resetTapeCounters(rdbms::Conn& conn, const common::dataStructures::SecurityIdentity& admin, const std::string& vid) const {
   try {
     const time_t now = time(nullptr);
-    const char *const sql =
-      "UPDATE TAPE SET "
+    const char * const sql =
+    "UPDATE TAPE SET "
         "DATA_IN_BYTES = 0,"
         "LAST_FSEQ = 0,"
         "IS_FULL = '0',"
@@ -2420,47 +2353,55 @@ void RdbmsCatalogue::fakeReclaimTapeForTests(const common::dataStructures::Secur
         "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
         "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
       "WHERE "
-        "VID = :UPDATE_VID AND "
-        "IS_FULL != '0'";
-    auto conn = m_connPool.getConn();
+        "VID = :VID";
     auto stmt = conn.createStmt(sql);
     stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
     stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
     stmt.bindUint64(":LAST_UPDATE_TIME", now);
-    stmt.bindString(":UPDATE_VID", vid);
+    stmt.bindString(":VID", vid);
     stmt.executeNonQuery();
+  } catch (exception::Exception &ex){
+    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
+    throw;
+  }
+}
 
-    // If the update failed due to a user error
-    if(0 == stmt.getNbAffectedRows()) {
-      // Try to determine the user error
-      //
-      // Please note that this is a best effort diagnosis because there is no
-      // lock on the database to prevent other concurrent updates from taking
-      // place on the TAPE and TAPE_FILE tables
-      TapeSearchCriteria searchCriteria;
-      searchCriteria.vid = vid;
-      const auto tapes = getTapes(conn, searchCriteria);
-
-      if(tapes.empty()) {
-        throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it does not exist");
-      } else {
-        if(!tapes.front().full) {
-          throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it is not FULL");
-        } else {
-          throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because there is at least one tape"
+//------------------------------------------------------------------------------
+// reclaimTape
+//------------------------------------------------------------------------------
+void RdbmsCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid) {
+  try{
+    auto conn = m_connPool.getConn();
+    
+    TapeSearchCriteria searchCriteria;
+    searchCriteria.vid = vid;
+    const auto tapes = getTapes(conn, searchCriteria);
+
+    if(tapes.empty()) {
+      throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it does not exist");
+    }  else {
+      if(!tapes.front().full){
+        throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it is not FULL");
+      } 
+    }
+    //The tape exists and is full, we can try to reclaim it
+    if(getNbNonSupersededFilesOnTape(conn,vid) == 0){
+      //There is no non-superseded files on the tape, we can reclaim it : delete the files and reset the counters
+      deleteTapeFiles(conn,vid);
+      resetTapeCounters(conn,admin,vid);
+    } else {
+      throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because there is at least one tape"
             " file in the catalogue that is on the tape");
-        }
-      }
     }
-  } catch(exception::UserError &) {
+  } catch (exception::UserError& ue) {
     throw;
-  } catch(exception::Exception &ex) {
+  }
+  catch (exception::Exception &ex) {
     ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
     throw;
   }
 }
 
-
 //------------------------------------------------------------------------------
 // getTapeLogFromRset
 //------------------------------------------------------------------------------
diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp
index 766dca01f7390bd4176adcd2e7535998b8a3431b..584074885cb595fa34ef76c0b16ac1de35f02e9a 100644
--- a/catalogue/RdbmsCatalogue.hpp
+++ b/catalogue/RdbmsCatalogue.hpp
@@ -332,7 +332,27 @@ public:
    * @param vid The volume identifier of the tape to be reclaimed.
    */
   void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid) override;
-  void fakeReclaimTapeForTests(const common::dataStructures::SecurityIdentity& admin, const std::string& vid) override;
+   /**
+   * Returns the number of non superseded files contained in the tape identified by its vid
+   * @param conn the database connection
+   * @param vid the vid in which we will count non superseded files
+   * @return the number of non superseded files on the vid
+   */
+  uint64_t getNbNonSupersededFilesOnTape(rdbms::Conn &conn, const std::string &vid) const;
+  /**
+   * Delete all the tape files of the VID passed in parameter
+   * @param conn the database connection
+   * @param vid the vid in which we want to remove all the tape files
+   */
+  void deleteTapeFiles(rdbms::Conn &conn, const std::string& vid) const;
+  
+  /**
+   * Reset the counters of a tape
+   * @param conn the database connection
+   * @param admin the administrator
+   * @param vid the vid to reset the counters
+   */
+  void resetTapeCounters(rdbms::Conn &conn, const common::dataStructures::SecurityIdentity &admin ,const std::string& vid) const;
   void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &mediaType) override;
   void modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &vendor) override;
   void modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &logicalLibraryName) override;
@@ -715,17 +735,6 @@ protected:
    * @return True if the tape exists.
    */
   bool tapeExists(rdbms::Conn &conn, const std::string &vid) const;
-  
-  /**
-   * Returns true if non superseded files exist after fSeq in the tape where vid is passed in parameter
-   * If there is only superseded files after fSeq, these tape files will be deleted
-   * 
-   * @param vid the vid of the tape to check if non superseded files exist after fSeq
-   * @param fSeq the fSeq after which we want to check if non superseded files exist
-   * @return true if non superseded files exist, false otherwise
-   */
-  bool existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(const std::string& vid, const uint64_t fSeq) const override;
-
 
   /**
    * Returns the list of tapes that meet the specified search criteria.
@@ -735,7 +744,7 @@ protected:
    * @return The list of tapes.
    */
   std::list<common::dataStructures::Tape> getTapes(rdbms::Conn &conn, const TapeSearchCriteria &searchCriteria) const;
-
+  
   /**
    * Returns true if the specified logical library exists.
    *
diff --git a/catalogue/common_catalogue_schema.sql b/catalogue/common_catalogue_schema.sql
index e37a2d5022b9a3b87d071002acff2f1171485b29..a5f2a3b80170a6d71f2d5ad4de64a8fe835c2d84 100644
--- a/catalogue/common_catalogue_schema.sql
+++ b/catalogue/common_catalogue_schema.sql
@@ -75,17 +75,17 @@ CREATE TABLE LOGICAL_LIBRARY(
   CONSTRAINT LOGICAL_LIBRARY_ID_BOOL_CK CHECK(IS_DISABLED IN ('0', '1'))
 );
 CREATE TABLE TAPE(
-  VID                     VARCHAR(100)    CONSTRAINT TAPE_V_UN    NOT NULL,
+  VID                     VARCHAR(100)    CONSTRAINT TAPE_V_NN    NOT NULL,
   MEDIA_TYPE              VARCHAR(100)    CONSTRAINT TAPE_MT_NN   NOT NULL,
   VENDOR                  VARCHAR(100)    CONSTRAINT TAPE_V2_NN   NOT NULL,
-  LOGICAL_LIBRARY_NAME    VARCHAR(100)    CONSTRAINT TAPE_LLN_UN  NOT NULL,
-  TAPE_POOL_NAME          VARCHAR(100)    CONSTRAINT TAPE_TPN_UN  NOT NULL,
+  LOGICAL_LIBRARY_NAME    VARCHAR(100)    CONSTRAINT TAPE_LLN_NN  NOT NULL,
+  TAPE_POOL_NAME          VARCHAR(100)    CONSTRAINT TAPE_TPN_NN  NOT NULL,
   ENCRYPTION_KEY          VARCHAR(100),
-  CAPACITY_IN_BYTES       NUMERIC(20, 0)  CONSTRAINT TAPE_CIB_UN  NOT NULL,
-  DATA_IN_BYTES           NUMERIC(20, 0)  CONSTRAINT TAPE_DIB_UN  NOT NULL,
-  LAST_FSEQ               NUMERIC(20, 0)  CONSTRAINT TAPE_LF_UN   NOT NULL,
-  IS_DISABLED             CHAR(1)         CONSTRAINT TAPE_ID_UN   NOT NULL,
-  IS_FULL                 CHAR(1)         CONSTRAINT TAPE_IF_UN   NOT NULL,
+  CAPACITY_IN_BYTES       NUMERIC(20, 0)  CONSTRAINT TAPE_CIB_NN  NOT NULL,
+  DATA_IN_BYTES           NUMERIC(20, 0)  CONSTRAINT TAPE_DIB_NN  NOT NULL,
+  LAST_FSEQ               NUMERIC(20, 0)  CONSTRAINT TAPE_LF_NN   NOT NULL,
+  IS_DISABLED             CHAR(1)         CONSTRAINT TAPE_ID_NN   NOT NULL,
+  IS_FULL                 CHAR(1)         CONSTRAINT TAPE_IF_NN   NOT NULL,
   LABEL_DRIVE             VARCHAR(100),
   LABEL_TIME              NUMERIC(20, 0),
   LAST_READ_DRIVE         VARCHAR(100),
@@ -94,13 +94,13 @@ CREATE TABLE TAPE(
   LAST_WRITE_TIME         NUMERIC(20, 0),
   READ_MOUNT_COUNT        NUMERIC(20, 0)  DEFAULT 0 CONSTRAINT TAPE_RMC_NN NOT NULL,
   WRITE_MOUNT_COUNT       NUMERIC(20, 0)  DEFAULT 0 CONSTRAINT TAPE_WMC_NN NOT NULL,
-  USER_COMMENT            VARCHAR(1000)   CONSTRAINT TAPE_UC_UN   NOT NULL,
-  CREATION_LOG_USER_NAME  VARCHAR(100)    CONSTRAINT TAPE_CLUN_UN NOT NULL,
-  CREATION_LOG_HOST_NAME  VARCHAR(100)    CONSTRAINT TAPE_CLHN_UN NOT NULL,
+  USER_COMMENT            VARCHAR(1000)   CONSTRAINT TAPE_UC_NN   NOT NULL,
+  CREATION_LOG_USER_NAME  VARCHAR(100)    CONSTRAINT TAPE_CLUN_NN NOT NULL,
+  CREATION_LOG_HOST_NAME  VARCHAR(100)    CONSTRAINT TAPE_CLHN_NN NOT NULL,
   CREATION_LOG_TIME       NUMERIC(20, 0)  CONSTRAINT TAPE_CLT_NN  NOT NULL,
-  LAST_UPDATE_USER_NAME   VARCHAR(100)    CONSTRAINT TAPE_LUUN_UN NOT NULL,
-  LAST_UPDATE_HOST_NAME   VARCHAR(100)    CONSTRAINT TAPE_LUHN_UN NOT NULL,
-  LAST_UPDATE_TIME        NUMERIC(20, 0)  CONSTRAINT TAPE_LUT_UN  NOT NULL,
+  LAST_UPDATE_USER_NAME   VARCHAR(100)    CONSTRAINT TAPE_LUUN_NN NOT NULL,
+  LAST_UPDATE_HOST_NAME   VARCHAR(100)    CONSTRAINT TAPE_LUHN_NN NOT NULL,
+  LAST_UPDATE_TIME        NUMERIC(20, 0)  CONSTRAINT TAPE_LUT_NN  NOT NULL,
   CONSTRAINT TAPE_PK PRIMARY KEY(VID),
   CONSTRAINT TAPE_LOGICAL_LIBRARY_FK FOREIGN KEY(LOGICAL_LIBRARY_NAME)
     REFERENCES LOGICAL_LIBRARY(LOGICAL_LIBRARY_NAME),
diff --git a/cmdline/CtaAdminCmd.cpp b/cmdline/CtaAdminCmd.cpp
index 338e2a25083fd2df654a64e461716522ecd139c6..47fe7a749a0a367d4c9dec82793cf36d5168dae9 100644
--- a/cmdline/CtaAdminCmd.cpp
+++ b/cmdline/CtaAdminCmd.cpp
@@ -78,6 +78,7 @@ void IStreamBuffer<cta::xrd::Data>::DataCallback(cta::xrd::Data record) const
          case Data::kLprSummary:    std::cout << Log::DumpProtobuf(&record.lpr_summary());  break;
          case Data::kTplsItem:      std::cout << Log::DumpProtobuf(&record.tpls_item());    break;
          case Data::kTalsItem:      std::cout << Log::DumpProtobuf(&record.tals_item()); break;
+         case Data::kRelsItem:       std::cout << Log::DumpProtobuf(&record.rels_item()); break;
          default:
             throw std::runtime_error("Received invalid stream data from CTA Frontend.");
       }
@@ -94,6 +95,7 @@ void IStreamBuffer<cta::xrd::Data>::DataCallback(cta::xrd::Data record) const
          case Data::kLprSummary:    CtaAdminCmd::print(record.lpr_summary());  break;
          case Data::kTplsItem:      CtaAdminCmd::print(record.tpls_item());    break;
          case Data::kTalsItem:      CtaAdminCmd::print(record.tals_item());    break;
+         case Data::kRelsItem:      CtaAdminCmd::print(record.rels_item());    break;
          default:
             throw std::runtime_error("Received invalid stream data from CTA Frontend.");
    }
@@ -237,6 +239,7 @@ void CtaAdminCmd::send() const
             case HeaderType::LISTPENDINGRETRIEVES_SUMMARY: printLprSummaryHeader(); break;
             case HeaderType::TAPEPOOL_LS:                  printTpLsHeader(); break;
             case HeaderType::TAPE_LS:                      printTapeLsHeader(); break;
+            case HeaderType::REPACK_LS:                    printRepackLsHeader(); break;
             case HeaderType::NONE:
             default:                                       break;
          }
@@ -731,6 +734,44 @@ void CtaAdminCmd::print(const cta::admin::TapeLsItem &tals_item){
               << std::endl;
 }
 
+void CtaAdminCmd::printRepackLsHeader(){
+  std::cout << TEXT_RED
+            << std::setfill(' ') << std::setw(7) << std::right << "vid"              << ' '
+            << std::setfill(' ') << std::setw(50) << std::right << "repackBufferURL"       << ' '
+            << std::setfill(' ') << std::setw(17)  << std::right << "userProvidedFiles"           << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right << "totalFilesToRetrieve" << ' '
+            << std::setfill(' ') << std::setw(19) << std::right <<  "totalBytesToRetrieve" << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right << "totalFilesToArchive"  << ' '
+            << std::setfill(' ') << std::setw(19) << std::right <<  "totalBytesToArchive"  << ' '
+            << std::setfill(' ') << std::setw(14)  << std::right << "retrievedFiles"               << ' '
+            << std::setfill(' ') << std::setw(13)  << std::right << "archivedFiles"   << ' '
+            << std::setfill(' ') << std::setw(21)  << std::right << "failedToRetrieveFiles"         << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right << "failedToRetrieveBytes"        << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right <<  "failedToArchiveFiles"        << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right <<  "failedToArchiveBytes"             << ' '
+            << std::setfill(' ') << std::setw(16)  << std::right <<  "lastExpandedFSeq"             << ' '
+            <<                                                      "status"         << ' '
+            << TEXT_NORMAL << std::endl;
+}
+
+void CtaAdminCmd::print(const cta::admin::RepackLsItem &rels_item){
+  std::cout << std::setfill(' ') << std::setw(7) << std::right << rels_item.vid()           << ' '
+            << std::setfill(' ') << std::setw(50) << std::right << rels_item.repack_buffer_url()      << ' '
+            << std::setfill(' ') << std::setw(17)  << std::right << rels_item.user_provided_files()           << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right << rels_item.total_files_to_retrieve() << ' '
+            << std::setfill(' ') << std::setw(19) << std::right <<  rels_item.total_bytes_to_retrieve() << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right << rels_item.total_files_to_archive()  << ' '
+            << std::setfill(' ') << std::setw(19) << std::right <<  rels_item.total_bytes_to_archive()  << ' '
+            << std::setfill(' ') << std::setw(14)  << std::right << rels_item.retrieved_files()               << ' '
+            << std::setfill(' ') << std::setw(13)  << std::right << rels_item.archived_files()   << ' '
+            << std::setfill(' ') << std::setw(21)  << std::right << rels_item.failed_to_retrieve_files()        << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right << rels_item.failed_to_retrieve_bytes()        << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right <<  rels_item.failed_to_archive_files()       << ' '
+            << std::setfill(' ') << std::setw(20)  << std::right <<  rels_item.failed_to_retrieve_bytes()         << ' '
+            << std::setfill(' ') << std::setw(10)  << std::right <<  rels_item.last_expanded_fseq()             << ' '
+            << rels_item.status() << std::endl;
+}
+
 void CtaAdminCmd::print(const cta::admin::TapePoolLsItem &tpls_item)
 {
    std::string encrypt_str = tpls_item.encrypt() ? "true" : "false";
diff --git a/cmdline/CtaAdminCmd.hpp b/cmdline/CtaAdminCmd.hpp
index 68e1f285c0ba2c8fa306045623789f2c2e25a670..56cbc901b6c2058c9328c255cd568661e1cb86a3 100644
--- a/cmdline/CtaAdminCmd.hpp
+++ b/cmdline/CtaAdminCmd.hpp
@@ -58,6 +58,7 @@ public:
    static void printLprSummaryHeader();
    static void printTpLsHeader();
    static void printTapeLsHeader();
+   static void printRepackLsHeader();
    
    // Output records
    static void print(const ArchiveFileLsItem &afls_item);
@@ -70,6 +71,7 @@ public:
    static void print(const ListPendingRetrievesSummary &lpr_summary);
    static void print(const TapePoolLsItem &tpls_item);
    static void print(const cta::admin::TapeLsItem &tals_item);
+   static void print(const cta::admin::RepackLsItem &rels_item);
 
 private:
    //! Parse the options for a specific command/subcommand
diff --git a/common/dataStructures/RepackInfo.hpp b/common/dataStructures/RepackInfo.hpp
index e94e87246db7c47cecc94bb74aaddb237567561b..03b7666a0121a31a4d95419f2bbdcbdcd0ea18a4 100644
--- a/common/dataStructures/RepackInfo.hpp
+++ b/common/dataStructures/RepackInfo.hpp
@@ -58,6 +58,8 @@ struct RepackInfo {
   uint64_t failedBytesToRetrieve;
   uint64_t lastExpandedFseq;
   uint64_t userProvidedFiles;
+  uint64_t retrievedFiles;
+  uint64_t archivedFiles;
   bool isExpandFinished;
 //  std::string tag;
 //  uint64_t totalFiles;
diff --git a/common/log/Logger.cpp b/common/log/Logger.cpp
index 37638dec6567c53b7f4c53e1ffd594f6f773eadf..a3fb0e586f25af3eb637bfec5db9d6d451aee8b5 100644
--- a/common/log/Logger.cpp
+++ b/common/log/Logger.cpp
@@ -120,14 +120,14 @@ std::map<int, std::string>
   std::map<int, std::string> m;
 
   try {
-    m[LOG_EMERG]   = "Emerg";
-    m[ALERT]       = "Alert";
-    m[LOG_CRIT]    = "Crit";
-    m[ERR]         = "Error";
-    m[WARNING]     = "Warn";
-    m[LOG_NOTICE]  = "Notice";
-    m[INFO]        = "Info";
-    m[DEBUG]       = "Debug";
+    m[LOG_EMERG]   = "EMERG";
+    m[ALERT]       = "ALERT";
+    m[LOG_CRIT]    = "CRIT";
+    m[ERR]         = "ERROR";
+    m[WARNING]     = "WARN";
+    m[LOG_NOTICE]  = "NOTICE";
+    m[INFO]        = "INFO";
+    m[DEBUG]       = "DEBUG";
   } catch(std::exception &se) {
     exception::Exception ex;
     ex.getMessage() << "Failed to generate priority to text mapping: " <<
diff --git a/continuousintegration/orchestration/tests/repack.sh b/continuousintegration/orchestration/tests/repack.sh
deleted file mode 100755
index 6336b64e8d9e470cd05e5ea6ecfa9c657c994b09..0000000000000000000000000000000000000000
--- a/continuousintegration/orchestration/tests/repack.sh
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/bash
-
-usage() { cat <<EOF 1>&2
-Usage: $0 -n <namespace>
-EOF
-exit 1
-}
-
-while getopts "n:" o; do
-    case "${o}" in
-        n)
-            NAMESPACE=${OPTARG}
-            ;;
-        *)
-            usage
-            ;;
-    esac
-done
-shift $((OPTIND-1))
-
-if [ -z "${NAMESPACE}" ]; then
-    usage
-fi
-
-if [ ! -z "${error}" ]; then
-    echo -e "ERROR:\n${error}"
-    exit 1
-fi
-
-echo "Preparing namespace for the tests"
-./prepare_tests.sh -n ${NAMESPACE}
-
-kubectl -n ${NAMESPACE} cp client_helper.sh client:/root/client_helper.sh
-
-NB_FILES=1000
-FILE_SIZE_KB=15
-
-echo
-echo "Launching client_ar.sh on client pod"
-echo " Archiving ${NB_FILES} files of ${FILE_SIZE_KB}kB each"
-echo " Archiving files: xrdcp as user1"
-kubectl -n ${NAMESPACE} cp client_ar.sh client:/root/client_ar.sh
-kubectl -n ${NAMESPACE} exec client -- bash /root/client_ar.sh -n ${NB_FILES} -s ${FILE_SIZE_KB} -p 100 -d /eos/ctaeos/preprod -v -A || exit 1
-
-#kubectl -n ${NAMESPACE} exec ctaeos -- bash /root/grep_xrdlog_mgm_for_error.sh || exit 1
-
-source ./repack_helper.sh
-
-vidToRepack1=$(getFirstVidContainingFiles)
-if [ "$vidToRepack1" != "null" ] 
-then
-  echo
-  echo "Launching a repack on tape $vidToRepack1" 
-  echo
-  writeTapeSummary $vidToRepack1
-  executeRepack $vidToRepack1
-  echo
-  echo "Reclaiming tape $vidToRepack1"
-  executeReclaim $vidToRepack1
-  echo
-  writeTapeSummary $vidToRepack1
-else
-  echo "No vid found to repack"
-  exit 1
-fi
-
-vidDestination=$(getFirstVidContainingFiles)
-writeTapeSummary $vidDestination
\ No newline at end of file
diff --git a/continuousintegration/orchestration/tests/repack_generate_report.sh b/continuousintegration/orchestration/tests/repack_generate_report.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8182ca5c79ec8233d1cf0cacb832149d8c1eaa99
--- /dev/null
+++ b/continuousintegration/orchestration/tests/repack_generate_report.sh
@@ -0,0 +1,97 @@
+#!/bin/bash
+
+REPORT_DIRECTORY=/var/log
+
+die() {
+  echo "$@" 1>&2
+  test -z $TAILPID || kill ${TAILPID} &> /dev/null
+  exit 1
+}
+
+usage() { cat <<EOF 1>&2
+Usage: $0 -v <vid> [-r <report_directory>]
+Default report_directory = ${REPORT_DIRECTORY}
+EOF
+exit 1
+}
+
+if [ $# -lt 1 ]
+then
+  usage
+fi;
+
+while getopts "v:r:" o; do
+    case "${o}" in
+        v)
+            VID=${OPTARG}
+            ;;
+        r)
+            REPORT_DIRECTORY=${OPTARG}
+            ;;
+        *)
+            usage
+            ;;
+    esac
+done
+shift $((OPTIND-1))
+
+# get some common useful helpers for krb5
+. /root/client_helper.sh
+
+# Get kerberos credentials for user1
+admin_kinit
+admin_klist > /dev/null 2>&1 || die "Cannot get kerberos credentials for user ${USER}"
+
+echo "Generation of a repack report"
+
+DATE=`date +%d-%m-%y-%H:%M:%S`
+
+ARCHIVE_FILE_LS_RESULT_PATH=${REPORT_DIRECTORY}/${VID}_af_ls_${DATE}.json
+NOT_REPACKED_JSON_PATH=${REPORT_DIRECTORY}/${VID}_report_not_repacked_${DATE}.json
+SELF_REPACKED_JSON_PATH=${REPORT_DIRECTORY}/${VID}_report_self_repacked_${DATE}.json
+REPACKED_JSON_PATH=${REPORT_DIRECTORY}/${VID}_report_repacked_${DATE}.json
+
+
+echo "1. Generate archive file ls result into ${ARCHIVE_FILE_LS_RESULT_PATH} file..."
+admin_cta --json archivefile ls --vid ${VID} > ${ARCHIVE_FILE_LS_RESULT_PATH}
+echo "OK"
+
+echo "2. Generate the non-repacked files report into ${NOT_REPACKED_JSON_PATH} file..."
+jq -r '[.[] | select(.tf.supersededByVid == "")]' ${ARCHIVE_FILE_LS_RESULT_PATH} > ${NOT_REPACKED_JSON_PATH}
+echo "OK"
+
+echo "3. Generating the self-repacked files report into ${SELF_REPACKED_JSON_PATH} file..."
+jq -r  '[.[] | select((.tf.supersededByVid == .tf.vid) and (.tf.fSeq < .tf.supersededByFSeq))]' ${ARCHIVE_FILE_LS_RESULT_PATH} > ${SELF_REPACKED_JSON_PATH}
+echo "OK"
+
+echo "4. Generate the repacked files report into ${REPACKED_JSON_PATH} file..."
+jq -r  '[.[] | select((.tf.supersededByVid != "") and (.tf.supersededByVid != .tf.vid))]' ${ARCHIVE_FILE_LS_RESULT_PATH} > ${REPACKED_JSON_PATH}
+echo "OK"
+
+echo "5. Report of the repacked tape"
+echo
+NB_NON_REPACKED_FILES=$(jq '[.[]] | length' ${NOT_REPACKED_JSON_PATH} || 0)
+echo "Number of non repacked files : ${NB_NON_REPACKED_FILES}" 
+if [ ${NB_NON_REPACKED_FILES} -ne 0 ]
+then
+  header="ArchiveID\tFSeq\tSize"
+  { echo -e $header; jq -r '.[] | [.af.archiveId,.tf.fSeq, .af.size] | @tsv' ${NOT_REPACKED_JSON_PATH}; } | column -t
+fi; 
+echo
+NB_SELF_REPACKED_FILES=$(jq '[.[]] | length' ${SELF_REPACKED_JSON_PATH} || 0)
+echo "Number of self-repacked files : ${NB_SELF_REPACKED_FILES}"
+if [ ${NB_SELF_REPACKED_FILES} -ne 0 ]
+then
+  header="ArchiveID\tFSeq\tSize"
+  { echo -e $header; jq -r '.[] | [.af.archiveId, .tf.fSeq, .af.size] | @tsv' ${SELF_REPACKED_JSON_PATH}; } | column -t
+fi; 
+echo
+NB_REPACKED_FILES=$(jq '[.[]] | length' ${REPACKED_JSON_PATH} || 0)
+echo "Number of repacked files : ${NB_REPACKED_FILES}"
+if [ ${NB_REPACKED_FILES} -ne 0 ]
+then
+  header="DestinationVID\tNbFiles\ttotalSize\n"
+  { echo -e $header; jq -r 'group_by(.tf.supersededByVid)[] | [(.[0].tf.supersededByVid),([.[] | .tf.supersededByFSeq] | length),(reduce [.[] | .af.size | tonumber][] as $currentSize (0; . + $currentSize))] | @tsv' ${REPACKED_JSON_PATH}; } | column -t
+fi;
+
+echo "End of the repack report"
\ No newline at end of file
diff --git a/continuousintegration/orchestration/tests/repack_systemtest.sh b/continuousintegration/orchestration/tests/repack_systemtest.sh
index 306ef4cf0028644134257af006d0e0e0c8b0b58f..f6a911190cd1fa28ef017e4afbfa4f43639d2b68 100755
--- a/continuousintegration/orchestration/tests/repack_systemtest.sh
+++ b/continuousintegration/orchestration/tests/repack_systemtest.sh
@@ -22,12 +22,15 @@ exit 1
 
 testRepackBufferURL(){
   echo "Testing the repack buffer URL at root://${EOSINSTANCE}/${REPACK_BUFFER_BASEDIR}"
-  eos root://${EOSINSTANCE} ls -d ${REPACK_BUFFER_BASEDIR} || die "Repack bufferURL directory does not exist"
+  eos root://${EOSINSTANCE} ls -d ${REPACK_BUFFER_BASEDIR} 1> /dev/null || die "Repack bufferURL directory does not exist"
   echo "Testing the insertion of a test file in the buffer URL"
   tempFilePath=$(mktemp /tmp/testFile.XXXX)
   tempFileName=${tempFilePath##*/}
   xrdcp ${tempFilePath} ${FULL_REPACK_BUFFER_URL}/${tempFileName} || die "Unable to write a file into the repack buffer directory"
-  echo "OK"
+  echo "File ${tempFilePath} written in ${FULL_REPACK_BUFFER_URL}/${tempFileName}"
+  echo "Deleting test file from the test directory"
+  eos root://${EOSINSTANCE} rm ${REPACK_BUFFER_BASEDIR}/${tempFileName} || die "Unable to delete the testing file"
+  echo "Test repack buffer URL OK"
 }
 
 if [ $# -lt 2 ]
@@ -47,7 +50,7 @@ while getopts "v:e:b:t:" o; do
       REPACK_BUFFER_BASEDIR=${OPTARG}
       ;;
     t)
-      WAIT_FOR_REPACK_TIMEOUT={$OPTARG}
+      WAIT_FOR_REPACK_TIMEOUT=${OPTARG}
       ;;
     *)
       usage
@@ -82,9 +85,6 @@ admin_cta repack rm --vid ${VID_TO_REPACK}
 echo "Marking the tape ${VID_TO_REPACK} as full before Repacking it"
 admin_cta tape ch --vid ${VID_TO_REPACK} --full true
 
-echo "State of the tape VID ${VID_TO_REPACK} BEFORE repack"
-admin_cta --json tape ls --vid ${VID_TO_REPACK} | jq .
-
 echo "Launching repack request for VID ${VID_TO_REPACK}, bufferURL = ${FULL_REPACK_BUFFER_URL}"
 admin_cta re add --vid ${VID_TO_REPACK} --justmove --bufferurl ${FULL_REPACK_BUFFER_URL}
 
@@ -104,5 +104,4 @@ if test 1 = `admin_cta repack ls --vid ${VID_TO_REPACK} | grep -E "Failed" | wc
     exit 1
 fi
 
-echo "State of the tape VID ${VID_TO_REPACK} AFTER repack"
-admin_cta --json tape ls --vid ${VID_TO_REPACK} | jq .
\ No newline at end of file
+exec /root/repack_generate_report.sh -v ${VID_TO_REPACK}
\ No newline at end of file
diff --git a/continuousintegration/orchestration/tests/repack_systemtest_wrapper.sh b/continuousintegration/orchestration/tests/repack_systemtest_wrapper.sh
index fe31c8ce4223115bdbb3523e4775ac1b9acd37c3..dabdec972d5e8a11b3c42689459d34b442cf0705 100755
--- a/continuousintegration/orchestration/tests/repack_systemtest_wrapper.sh
+++ b/continuousintegration/orchestration/tests/repack_systemtest_wrapper.sh
@@ -49,6 +49,7 @@ kubectl -n ${NAMESPACE} exec ctaeos -- eos chmod 1777 ${REPACK_BUFFER_URL}
 
 source ./repack_helper.sh
 kubectl -n ${NAMESPACE} cp repack_systemtest.sh client:/root/repack_systemtest.sh
+kubectl -n ${NAMESPACE} cp repack_generate_report.sh client:/root/repack_generate_report.sh
 
 echo
 echo "Launching a round trip repack request"
diff --git a/mediachanger/castorrmc/rmc/cta-smc.1cta b/mediachanger/castorrmc/rmc/cta-smc.1cta
index 04002012116449e0d2032bd0d672b79a051b0650..b72afc7a5120d7ade1a27a4c911f10376836aa6b 100644
--- a/mediachanger/castorrmc/rmc/cta-smc.1cta
+++ b/mediachanger/castorrmc/rmc/cta-smc.1cta
@@ -24,32 +24,22 @@ cta-smc \- command line interface to drive robotic devices through SCSI
 .BI -D " drive_ordinal"
 [
 .BI -V " vid"
-] [
-.BI -v
-]
+] 
 .br
 .B cta-smc
 .BI -e
 .BI -V " vid"
-[
-.BI -v
-]
 .br
 .B cta-smc
 .BI -i
 [
 .BI -V " vid"
-] [
-.BI -v
-]
+] 
 .br
 .B cta-smc
 .BI -m
 .BI -D " drive_ordinal"
 .BI -V " vid"
-[
-.BI -v
-]
 .br
 .B cta-smc
 .B -q D
@@ -57,19 +47,19 @@ cta-smc \- command line interface to drive robotic devices through SCSI
 .BI -D " drive_ordinal"
 ]
 [
-.BI -v
+.BI -j
 ]
 .br
 .B cta-smc
 .B -q L
 [
-.BI -v
+.BI -j
 ]
 .br
 .B cta-smc
 .B -q P
 [
-.BI -v
+.BI -j
 ]
 .br
 .B cta-smc
@@ -79,7 +69,7 @@ cta-smc \- command line interface to drive robotic devices through SCSI
 ] [
 .BI -S " starting_slot"
 ] [
-.BI -v
+.BI -j
 ]
 .br
 .B cta-smc
@@ -89,7 +79,7 @@ cta-smc \- command line interface to drive robotic devices through SCSI
 ] [
 .BI -V " vid"
 ] [
-.BI -v
+.BI -j
 ]
 .SH DESCRIPTION
 .B cta-smc
@@ -161,8 +151,8 @@ specifies the starting slot address for the query operation.
 A full vid or a pattern may be specified. In the latter case wild card
 characters '*' and '?' may be used but must be escaped because of the shell.
 .TP
-.B \-v
-verbose mode. On query requests it prints headers on top of the columns.
+.B \-j
+script mode. On query requests it prints json.
 
 .SH EXAMPLES
 .LP
@@ -195,7 +185,7 @@ Device Count = 2, Start = 1030
 To query the status of all the drives:
 .br
 .RS
-.B "cta-smc -q D -v"
+.B "cta-smc -q D"
 .sp
 .nf
 .cs R 20
@@ -209,7 +199,7 @@ Drive Ordinal   Element Addr.   Status          Vid
 To get the list of a few slots in the library:
 .br
 .RS
-.B "cta-smc -q S -S 20 -N 10 -v"
+.B "cta-smc -q S -S 20 -N 10"
 .sp
 .nf
 .cs R 20
@@ -231,7 +221,7 @@ Element Addr.   Vid
 To get the status of volumes for which the vid starts with JK200
 .br
 .RS
-.B "cta-smc -q V -V 'JK200*' -v"
+.B "cta-smc -q V -V 'JK200*'"
 .sp
 .nf
 .cs R 20
diff --git a/mediachanger/castorrmc/rmc/smc.c b/mediachanger/castorrmc/rmc/smc.c
index 54b229003d5055b6837df2852917423bb1d2b745..52669b475fe4a908d646f3e40d27e47da7fe5b5b 100644
--- a/mediachanger/castorrmc/rmc/smc.c
+++ b/mediachanger/castorrmc/rmc/smc.c
@@ -14,12 +14,15 @@
 #include "serrno.h"
 #include "smc_constants.h"
 #include "getconfent.h"
+#include "getopt.h"
 
 #include <ctype.h>
 			/* exit codes */
 
 #define	USERR	1
 #define PATH_CONF "cta-smc.conf"
+#define TEXT_RED    "\x1b[31;1m"
+#define TEXT_NORMAL "\x1b[0m"
 
 extern char *optarg;
 
@@ -33,30 +36,80 @@ static void smc_str_upper(char *const s) {
 
 static void smc_usage(const char *const cmd)
 {
-	fprintf (stderr, "usage: %s ", cmd);
+	fprintf (stderr, "Usage:\n");
 	fprintf (stderr,
-	    "-d -D drive_ordinal [-V vid] [-v]\n"
-	    "\t-e -V vid [-v]\n"
-	    "\t-i [-V vid] [-v]\n"
-	    "\t-m -D drive_ordinal -V vid [-v]\n"
-	    "\t-q D [-D drive_ordinal] [-v]\n"
-	    "\t-q L [-v]\n"
-	    "\t-q S [-N nbelem] [-S starting_slot] [-v]\n"
-	    "\t-q V [-N nbelem] [-V vid] [-v]\n");
+	    "  %s -d -D drive_ordinal [-V vid]\n"
+	    "  %s -e -V vid\n"
+	    "  %s -i [-V vid]\n"
+	    "  %s -m -D drive_ordinal -V vid\n"
+	    "  %s -q D [-D drive_ordinal] [-j]\n"
+	    "  %s -q L [-j]\n"
+            "  %s -q P [-j]\n"
+	    "  %s -q S [-N nbelem] [-S starting_slot] [-j]\n"
+	    "  %s -q V [-N nbelem] [-V vid] [-j]\n",
+            cmd, cmd, cmd, cmd, cmd, cmd, cmd, cmd, cmd);
 }
 
+void smc_qdrive_humanPrint(const struct robot_info *const robot_info,
+  const struct smc_element_info *const element_info, const int numberOfElements, 
+  const int useSpectraLib) {
+  char *pstatus;
+  int i;
+  printf (TEXT_RED "Drive Ordinal\tElement Addr.\t  Status     Vid\n" TEXT_NORMAL);
+  for (i = 0; i < numberOfElements; i++) {
+    if (((element_info+i)->state & 0x1) == 0)
+            pstatus = "free";
+    else if ((element_info+i)->state & 0x4)
+            pstatus = "error";
+    else if ((element_info+i)->state & 0x8 && !useSpectraLib)
+            pstatus = "unloaded";
+    else
+            pstatus = "loaded";
+    printf ("%13d\t%13d\t%8s  %s\n",
+            (element_info+i)->element_address-robot_info->device_start,
+            (element_info+i)->element_address, pstatus,
+            (element_info+i)->name);
+  }
+}
+void smc_qdrive_jsonPrint(const struct robot_info *const robot_info,
+  const struct smc_element_info *const element_info, const int numberOfElements,
+  const int useSpectraLib) {
+  char *pstatus;
+  int i;
+  printf ("[");
+  for (i = 0; i < numberOfElements; i++) {
+    if (((element_info+i)->state & 0x1) == 0)
+            pstatus = "free";
+    else if ((element_info+i)->state & 0x4)
+            pstatus = "error";
+    else if ((element_info+i)->state & 0x8 && !useSpectraLib)
+            pstatus = "unloaded";
+    else
+            pstatus = "loaded";
+    if (0 != i) {
+      printf(",");
+    }
+    printf ("{\"driveOrdinal\":%d,"
+            "\"elementAddress\":%d,"
+            "\"status\":\"%s\","
+            "\"vid\":\"%s\"}",
+            (element_info+i)->element_address-robot_info->device_start,
+            (element_info+i)->element_address,
+             pstatus,
+            (element_info+i)->name);                
+  }
+  printf ("]");  
+}
 static int smc_qdrive (
 	const char *const rmchost,
 	const int fd,
 	const struct robot_info *const robot_info,
 	int drvord,
-	const int verbose)
+        const int isJsonEnabled)
 {
         int c;
         struct smc_element_info *element_info;
-	int i;
 	int nbelem;
-	char *pstatus;
         char *smcLibraryType;
         char useSpectraLib;
  
@@ -75,59 +128,120 @@ static int smc_qdrive (
 		free (element_info);
 		return (c);
 	}
-	if (verbose)
-		printf ("Drive Ordinal\tElement Addr.\tStatus\t\tVid\n");
-
         useSpectraLib=0;
         smcLibraryType = getconfent_fromfile(PATH_CONF,"SMC","LIBRARY_TYPE",0);
         if (NULL != smcLibraryType && 
             0 == strcasecmp(smcLibraryType,"SPECTRA")) {
           useSpectraLib = 1;
         }
- 
-	for (i = 0; i < c; i++) {
-		if (((element_info+i)->state & 0x1) == 0)
-			pstatus = "free";
-		else if ((element_info+i)->state & 0x4)
-			pstatus = "error";
-		else if ((element_info+i)->state & 0x8 && !useSpectraLib)
-			pstatus = "unloaded";
-		else
-			pstatus = "loaded";
-		printf ("	%2d\t    %d\t%s\t%s\n",
-			(element_info+i)->element_address-robot_info->device_start,
-			(element_info+i)->element_address, pstatus,
-			(element_info+i)->name);
-	}
+        if (isJsonEnabled) {
+          smc_qdrive_jsonPrint(robot_info, element_info, c, useSpectraLib);
+	} else {
+          smc_qdrive_humanPrint(robot_info, element_info, c, useSpectraLib);
+        }      
 	free (element_info);
 	return (0);
 }
 
-static int smc_qlib (const struct robot_info *const robot_info)
+void smc_qlib_humanPrint(const struct robot_info *const robot_info) {
+  printf ("Vendor/Product/Revision = <%s>\n", robot_info->inquiry);
+  printf ("Transport Count = %d, Start = %d\n",
+          robot_info->transport_count, robot_info->transport_start);
+  printf ("Slot Count = %d, Start = %d\n",
+          robot_info->slot_count, robot_info->slot_start);
+  printf ("Port Count = %d, Start = %d\n",
+          robot_info->port_count, robot_info->port_start);
+  printf ("Device Count = %d, Start = %d\n",
+          robot_info->device_count, robot_info->device_start);
+}
+
+void smc_qlib_jsonPrint(const struct robot_info *const robot_info) {
+  char T10Vendor[9];
+  char prodId[17];
+  char prodRevLvl[5];
+  memcpy (T10Vendor, robot_info->inquiry, 8);
+  T10Vendor[8] = '\0';
+  memcpy(prodId, robot_info->inquiry + 8, 16);
+  prodId[16] = '\0';
+  memcpy(prodRevLvl,robot_info->inquiry + 8 + 16, 4);
+  prodRevLvl[4] = '\0';      
+  printf ("[");
+  printf ("{\"inquiry\":{\"vendor\":\"%s\",\"product\":\"%s\",\"revision\":\"%s\"},",
+          T10Vendor, prodId, prodRevLvl);
+  printf ("\"transport\":{\"count\":%d,\"start\":%d},",
+          robot_info->transport_count, robot_info->transport_start);
+  printf ("\"slot\":{\"count\":%d,\"start\":%d},",
+          robot_info->slot_count, robot_info->slot_start);
+  printf ("\"port\":{\"count\":%d,\"start\":%d},",
+          robot_info->port_count, robot_info->port_start);
+  printf ("\"device\":{\"count\":%d,\"start\":%d}",
+          robot_info->device_count, robot_info->device_start);            
+  printf ("}]");
+}
+
+static int smc_qlib (const struct robot_info *const robot_info,
+  const int isJsonEnabled)
 {
-	printf ("Vendor/Product/Revision = <%s>\n", robot_info->inquiry);
-	printf ("Transport Count = %d, Start = %d\n",
-		robot_info->transport_count, robot_info->transport_start);
-	printf ("Slot Count = %d, Start = %d\n",
-		robot_info->slot_count, robot_info->slot_start);
-	printf ("Port Count = %d, Start = %d\n",
-		robot_info->port_count, robot_info->port_start);
-	printf ("Device Count = %d, Start = %d\n",
-		robot_info->device_count, robot_info->device_start);
+        if (isJsonEnabled) {
+          smc_qlib_jsonPrint(robot_info);
+	} else {
+          smc_qlib_humanPrint(robot_info);
+        }
 	return (0);
 }
 
+void smc_qport_humanPrint(const struct smc_element_info *const element_info,
+  const int numberOfElements) {
+  char *pstatus;
+  int i;
+  printf (TEXT_RED "Element Addr.\tVid\tImpExp\n" TEXT_NORMAL);
+  for (i = 0; i < numberOfElements; i++) {
+    if (((element_info+i)->state & 0x1) == 0)
+            pstatus = "";
+    else if (((element_info+i)->state & 0x2) == 0)
+            pstatus = "export";
+    else
+            pstatus = "import";
+    printf ("    %4d\t%s\t%s\n",
+            (element_info+i)->element_address,
+            (element_info+i)->name, pstatus);
+  }
+}
+
+void smc_qport_jsonPrint(const struct smc_element_info *const element_info,
+  const int numberOfElements) {
+  char *pstatus;
+  int i;
+  printf ("[");
+  for (i = 0; i < numberOfElements; i++) {
+    if (((element_info+i)->state & 0x1) == 0)
+            pstatus = "";
+    else if (((element_info+i)->state & 0x2) == 0)
+            pstatus = "export";
+    else
+            pstatus = "import";
+    if (0 != i) {
+      printf(",");
+    }
+    printf ("{\"elementAddress\":%d,"
+            "\"vid\":\"%s\","
+            "\"state\":\"%s\"}",
+            (element_info+i)->element_address,
+            (element_info+i)->name,
+             pstatus); 
+  }
+  printf ("]");
+}
+
 static int smc_qport (
 	const char *const rmchost,
 	const int fd,
 	const struct robot_info *const robot_info,
-	const int verbose)
+        const int isJsonEnabled)
 {
 	int c;
 	struct smc_element_info *element_info;
-	int i;
 	int nbelem;
-	char *pstatus;
 
 	nbelem = robot_info->port_count;
 	if ((element_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) {
@@ -140,34 +254,51 @@ static int smc_qport (
 		free (element_info);
 		return (serrno - ERMCRBTERR);
 	}
-	if (verbose)
-		printf ("Element Addr.\tVid\tImpExp\n");
-	for (i = 0; i < c; i++) {
-		if (((element_info+i)->state & 0x1) == 0)
-			pstatus = "";
-		else if (((element_info+i)->state & 0x2) == 0)
-			pstatus = "export";
-		else
-			pstatus = "import";
-		printf ("    %4d\t%s\t%s\n",
-			(element_info+i)->element_address,
-			(element_info+i)->name, pstatus);
+	if (isJsonEnabled) {
+          smc_qport_jsonPrint(element_info, c);
+	} else {
+          smc_qport_humanPrint(element_info, c);
 	}
 	free (element_info);
 	return (0);
 }
- 
+
+void smc_qslot_humanPrint(const struct smc_element_info *element_info,
+  const int numberOfElements) {
+  int i;
+  printf (TEXT_RED "Element Addr.\tVid\n" TEXT_NORMAL);
+  for (i = 0; i < numberOfElements; i++) {
+    printf ("    %4d\t%s\n",
+            element_info[i].element_address, element_info[i].name);
+  }
+} 
+
+void smc_qslot_jsonPrint(const struct smc_element_info *element_info,
+  const int numberOfElements) {
+  int i;
+  printf ("[");
+  for (i = 0; i < numberOfElements; i++) {
+    if (0 != i) {
+      printf(",");
+    }
+    printf ("{\"elementAddress\":%4d,"
+            "\"vid\":\"%s\"}",
+            element_info[i].element_address, 
+            element_info[i].name); 
+  }
+  printf ("]");
+}
+
 static int smc_qslot (
 	const char *const rmchost,
 	const int fd,
 	const struct robot_info *robot_info,
 	int slotaddr,
 	int nbelem,
-	const int verbose)
+        const int isJsonEnabled)
 {
         int c;
         struct smc_element_info *element_info;
-	int i;
  
 	if (nbelem == 0) {
 		if (slotaddr < 0)
@@ -187,29 +318,74 @@ static int smc_qslot (
 		free (element_info);
 		return (serrno - ERMCRBTERR);
 	}
-	if (verbose)
-		printf ("Element Addr.\tVid\n");
-	for (i = 0; i < c; i++) {
-		printf ("    %4d\t%s\n",
-			element_info[i].element_address, element_info[i].name);
-	}
+        if (isJsonEnabled) {
+          smc_qslot_jsonPrint(element_info, c);
+	} else {
+          smc_qslot_humanPrint(element_info, c);
+        }
 	free (element_info);
 	return (0);
 }
 
+void smc_qvid_humanPrint(const struct smc_element_info *const element_info,
+  const int numberOfElements){
+  int i;
+  char *ptype;
+  char ptypes[5][6] = {"", "hand", "slot", "port", "drive"};
+  printf (TEXT_RED "Vid\tElement Addr.\tElement Type\n" TEXT_NORMAL);
+  for (i = 0; i < numberOfElements; i++) {
+    ptype = ptypes[(element_info+i)->element_type];
+    if ((element_info+i)->element_type == 3) {
+      if (((element_info+i)->state & 0x2) == 0) {
+        ptype = "export";
+      } else {
+        ptype = "import";
+      }
+    }
+    printf ("%s\t    %4d\t%s\n",
+            (element_info+i)->name, (element_info+i)->element_address,
+            ptype);
+  }
+}
+
+void smc_qvid_jsonPrint(const struct smc_element_info *const element_info,
+  const int numberOfElements){
+  int i;
+  char *ptype;
+  char ptypes[5][6] = {"", "hand", "slot", "port", "drive"};
+  printf ("[");
+  for (i = 0; i < numberOfElements; i++) {
+    ptype = ptypes[(element_info+i)->element_type];
+    if ((element_info+i)->element_type == 3) {
+      if (((element_info+i)->state & 0x2) == 0) {
+        ptype = "export";
+      } else {
+        ptype = "import";
+      }
+    }
+    if (0 != i) {
+      printf(",");
+    }
+    printf ("{\"vid\":\"%s\","
+            "\"elementAddress\":%d,"
+            "\"elementType\":\"%s\"}",
+            (element_info+i)->name,
+            (element_info+i)->element_address,
+            ptype);
+  }
+  printf ("]");
+}
+
 static int smc_qvid (
 	const char *const rmchost,
 	const int fd,
 	const struct robot_info *const robot_info,
 	const char *reqvid,
 	int nbelem,
-	const int verbose)
+        const int isJsonEnabled)
 {
         int c;
         struct smc_element_info *element_info;
-	int i;
-	char *ptype;
-	static char ptypes[5][6] = {"", "hand", "slot", "port", "drive"};
 	const char *vid;
  
 	if (*reqvid)
@@ -233,21 +409,11 @@ static int smc_qvid (
 		free (element_info);
 		return (serrno - ERMCRBTERR);
 	}
-	if (verbose)
-		printf ("Vid\tElement Addr.\tElement Type\n");
-	for (i = 0; i < c; i++) {
-		ptype = ptypes[(element_info+i)->element_type];
-		if ((element_info+i)->element_type == 3) {
-			if (((element_info+i)->state & 0x2) == 0) {
-				ptype = "export";
-			} else {
-				ptype = "import";
-                        }
-                }
-		printf ("%s\t    %4d\t%s\n",
-			(element_info+i)->name, (element_info+i)->element_address,
-			ptype);
-	}
+         if (isJsonEnabled) {
+           smc_qvid_jsonPrint(element_info, c); 
+	} else {   
+           smc_qvid_humanPrint(element_info, c);
+        }
 	free (element_info);
 	return (0);
 }
@@ -268,14 +434,25 @@ int main(const int argc,
 	struct robot_info robot_info;
 	const char *rmchost = "localhost";
 	int slotaddr = -1;
-	int targetslotaddr = -1;
-	int verbose = 0;
 	char vid[7];
+        int isJsonEnabled = 0;
 
 	/* parse and check command options */
-
+        struct option longopts [] = {
+          {"drive",  required_argument, NULL, 'D'},
+          {"dismount",     no_argument, NULL, 'd'},
+          {"export",       no_argument, NULL, 'e'},
+          {"import",       no_argument, NULL, 'i'},
+          {"mount",        no_argument, NULL, 'm'},
+          {"nbelem", required_argument, NULL, 'N'},
+          {"query",  required_argument, NULL, 'q'},
+          {"slot",   required_argument, NULL, 'S'},
+          {"vid",    required_argument, NULL, 'V'},
+          {"json",         no_argument, NULL, 'j'},
+          {NULL,                     0, NULL,   0}
+        };
 	memset (vid, '\0', sizeof(vid));
-	while ((c = getopt (argc, argv, "D:deimN:q:S:V:vT:")) != EOF) {
+	while ((c = getopt_long(argc, argv, "D:deimN:q:S:V:j", longopts, NULL)) != EOF) {
 		switch (c) {
 		case 'D':	/* drive ordinal */
 			drvord = strtol (optarg, &dp, 10);
@@ -335,13 +512,6 @@ int main(const int argc,
 				errflg++;
 			}
 			break;
-		case 'T':	/* Target slot */
-			targetslotaddr = strtol (optarg, &dp, 10);
-			if (*dp != '\0' || targetslotaddr < 0) {
-				fprintf (stderr, SR001);
-				errflg++;
-			}
-			break;
 		case 'V':	/* vid */
 			n = strlen (optarg);
 			if (n > 6) {
@@ -352,9 +522,9 @@ int main(const int argc,
 				smc_str_upper (vid);
 			}
 			break;
-		case 'v':
-			verbose = 1;
-			break;
+                case 'j':
+                        isJsonEnabled = 1;
+                        break;
 		case '?':
 			errflg++;
 			break;
@@ -422,21 +592,21 @@ int main(const int argc,
 		switch (qry_type) {
 		case 'D':
 			c = smc_qdrive (rmchost, fd, &robot_info, drvord,
-			    verbose);
+                            isJsonEnabled);
 			break;
 		case 'L':
-			c = smc_qlib (&robot_info);
+			c = smc_qlib (&robot_info, isJsonEnabled);
 			break;
 		case 'P':
-			c = smc_qport (rmchost, fd, &robot_info, verbose);
+			c = smc_qport (rmchost, fd, &robot_info, isJsonEnabled);
 			break;
 		case 'S':
 			c = smc_qslot (rmchost, fd, &robot_info, slotaddr,
-			    nbelem, verbose);
+			    nbelem, isJsonEnabled);
 			break;
 		case 'V':
 			c = smc_qvid (rmchost, fd, &robot_info, vid,
-			    nbelem, verbose);
+			    nbelem, isJsonEnabled);
 			break;
 		}
 		break;
diff --git a/objectstore/RepackRequest.cpp b/objectstore/RepackRequest.cpp
index 0a0bb02505c8e06d831ad49b49f3379e75fd3668..a61e58e3097ccd4fb06f8c7ac80acb7be77caa31 100644
--- a/objectstore/RepackRequest.cpp
+++ b/objectstore/RepackRequest.cpp
@@ -138,6 +138,8 @@ common::dataStructures::RepackInfo RepackRequest::getInfo() {
   ret.failedBytesToArchive = m_payload.failedtoarchivebytes();
   ret.failedFilesToRetrieve = m_payload.failedtoretrievefiles();
   ret.failedBytesToRetrieve = m_payload.failedtoretrievebytes();
+  ret.archivedFiles = m_payload.archivedfiles();
+  ret.retrievedFiles = m_payload.retrievedfiles();
   ret.lastExpandedFseq = m_payload.lastexpandedfseq();
   ret.userProvidedFiles = m_payload.userprovidedfiles();
   ret.isExpandFinished = m_payload.is_expand_finished();
@@ -194,9 +196,9 @@ void RepackRequest::setStatus(){
         return;
       }
     }
-    //Expand is finished or not, if we have retrieved files, we are in Running,
+    //Expand is finished or not, if we have retrieved files or not (first reporting), we are in Running,
     //else we are in starting
-    if(m_payload.retrievedfiles()){
+    if(m_payload.retrievedfiles() || m_payload.failedtoretrievefiles()){
       setStatus(common::dataStructures::RepackInfo::Status::Running);
     } else {
       setStatus(common::dataStructures::RepackInfo::Status::Starting);
diff --git a/python/eosfstgcd/cta-fst-gcd b/python/eosfstgcd/cta-fst-gcd
index 1c579306e3c72dce84be5a228527cbd587525303..358a983c12c62b545a02a36194028946e9db0f19 100755
--- a/python/eosfstgcd/cta-fst-gcd
+++ b/python/eosfstgcd/cta-fst-gcd
@@ -100,10 +100,10 @@ class Gc:
     logging.config.dictConfig(config)
 
   def configurereallogging(self):
-    if None == self.logfilepath:
+    if None == self.logfile:
       raise Exception("Cannot configure file based logging because the log file path has not been set")
 
-    loggingdir = os.path.dirname(self.logfilepath)
+    loggingdir = os.path.dirname(self.logfile)
     if not os.path.isdir(loggingdir):
       raise UserError("The logging directory {} is not a directory or does not exist".format(loggingdir))
     if not os.access(loggingdir, os.W_OK):
@@ -124,7 +124,7 @@ class Gc:
           'level': 'INFO',
           'formatter': 'stdout',
           'class': 'logging.handlers.TimedRotatingFileHandler',
-          'filename' : self.logfilepath,
+          'filename' : self.logfile,
           'when' : 'midnight'
         }
       },
@@ -142,16 +142,16 @@ class Gc:
       raise UserError(err)
 
   def configurelogging(self):
-    if None == self.logfilepath:
+    if None == self.logfile:
       self.configuredummylogging()
     else:
       self.configurereallogging()
 
-  def __init__(self, env, logfilepath = '/var/log/eos/fst/cta-fst-gcd.log'):
+  def __init__(self, env, logfile):
     self.programname = 'cta-fst-gcd'
     self.env = env
     self.conffilepath = '/etc/cta/cta-fst-gcd.conf'
-    self.logfilepath = logfilepath
+    self.logfile = logfile
     self.fqdn = socket.getfqdn()
     self.localfilesystempaths = []
     self.nbfilesconsideredsincelastreport = 0
@@ -188,7 +188,7 @@ class Gc:
 
     return result
 
-  def eosstagerrm(self, fxid):
+  def eosstagerrm(self, fxid, subdir, freebytes):
     logger = logging.getLogger('gc')
     mgmurl = "root://{}".format(self.mgmhost)
     cmd = "eos {} stagerrm fxid:{}".format(mgmurl, fxid)
@@ -197,7 +197,7 @@ class Gc:
     process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
     stdout,stderr = process.communicate()
     if 0 == process.returncode:
-      logger.info("Executed {}".format(cmd))
+      logger.info("minfreebytes={} subdir={} freebytesbefore={} executed='{}'".format(self.minfreebytes, subdir, freebytes, cmd))
 
   def processfile(self, subdir, fstfile):
     statvfs = os.statvfs(subdir)
@@ -210,7 +210,7 @@ class Gc:
       now = time.time()
       agesecs = now - statinfo.st_ctime
       if agesecs > self.gcagesecs:
-        self.eosstagerrm(fstfile)
+        self.eosstagerrm(fstfile, subdir, freebytes)
 
     self.nbfilesconsideredsincelastreport = self.nbfilesconsideredsincelastreport + 1
     if self.nbfilesbeforereport == self.nbfilesconsideredsincelastreport:
@@ -304,12 +304,11 @@ class Gc:
         time.sleep(sleeptime)
 
 def main():
-  programname = 'cta-fst-gcd'
-
   parser = argparse.ArgumentParser()
+  parser.add_argument("-l", "--logfile", default="/var/log/eos/fst/cta-fst-gcd.log", help="Log file path")
   args = parser.parse_args()
 
-  gc = Gc(os.environ)
+  gc = Gc(env=os.environ, logfile=args.logfile)
 
   try:
     gc.run()
diff --git a/python/eosfstgcd/cta-fst-gcd.1cta b/python/eosfstgcd/cta-fst-gcd.1cta
index 046af3f0af166f626a2f58be19e723daa2267478..1ababe513f20ea1037d715374ea53f6b66defa01 100644
--- a/python/eosfstgcd/cta-fst-gcd.1cta
+++ b/python/eosfstgcd/cta-fst-gcd.1cta
@@ -39,6 +39,9 @@ filename and then running \fBeos stagerm fxid:<fid-hex>\fP.
 .TP
 \fB\-h, \-\-help
 Prints the usage message.
+.TP
+\fB\-l LOGFILE, \-\-logfile LOGFILE
+Sets the path of the log file to \fBLOGFILE\fP. If not set then the default value of \fB/var/log/eos/fst/cta-fst-gcd\fP is used.
 .SH RETURN VALUE
 Zero on success and non-zero on failure.
 .SH FILES
@@ -48,7 +51,7 @@ The configuration file of the \fBcta-fst-gcd\fP daemon.
 
 .TP
 .B /var/log/eos/fst/cta-fst-gcd.log
-The log file of the \fBcta-fst-gcd\fP daemon.
+The default log file of the \fBcta-fst-gcd\fP daemon.  This can be overriden by using the \fB\-l\fP/\fB\-\-logfile\fP option.
 
 .SH AUTHOR
 \fBCTA\fP Team
diff --git a/scheduler/ArchiveMount.cpp b/scheduler/ArchiveMount.cpp
index 0cb2df62a402ab24b70cb7cce06e6b23592e2fe1..818f703a145990c1c236c4ac53275f12d361a07c 100644
--- a/scheduler/ArchiveMount.cpp
+++ b/scheduler/ArchiveMount.cpp
@@ -104,16 +104,6 @@ uint32_t cta::ArchiveMount::getNbFiles() const {
   return m_dbMount->nbFilesCurrentlyOnTape;
 }
 
-//------------------------------------------------------------------------------
-// checkTapeFSeqForWriting
-//------------------------------------------------------------------------------
-void cta::ArchiveMount::checkTapeFSeqAndDeleteTapeFilesForWriting(uint64_t fSeq) const {
-  if(m_catalogue.existNonSupersededFilesAfterFSeqAndDeleteTapeFilesForWriting(getVid(),fSeq)){
-    throw cta::exception::Exception("Non superseded files have been detected in the tape "+getVid() +" after "+std::to_string(fSeq));
-  }
-}
-
-
 //------------------------------------------------------------------------------
 // createDiskReporter
 //------------------------------------------------------------------------------
diff --git a/scheduler/ArchiveMount.hpp b/scheduler/ArchiveMount.hpp
index 509895d54031396f1e61b93a7b3cfb8759ca3831..2073545e4d03613f27ddaf10fb90cf96f5407a18 100644
--- a/scheduler/ArchiveMount.hpp
+++ b/scheduler/ArchiveMount.hpp
@@ -172,14 +172,6 @@ namespace cta {
      */
     uint32_t getNbFiles() const override;
     
-    /**
-     * Checks wether the writing is possible after the FSeq passed in parameter
-     * If TapeFiles are located after FSeq and are not superseded by other TapeFiles
-     * we throw an exception : We don't want these files to be lost.
-     * @param fSeq : The fSeq after which we want to check if the writing is possible
-     */
-    void checkTapeFSeqAndDeleteTapeFilesForWriting(uint64_t fSeq) const;
-    
     /**
      * Creates a disk reporter for the ArchiveJob (this is a wrapper).
      * @param URL: report address
diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp
index 825b7a67c217feed73c74ad011c0863d33a233f4..b378b9e31816409b9d17331da43f5b220bbbef7b 100644
--- a/scheduler/OStoreDB/OStoreDB.cpp
+++ b/scheduler/OStoreDB/OStoreDB.cpp
@@ -1591,6 +1591,26 @@ std::unique_ptr<SchedulerDatabase::RepackReportBatch> OStoreDB::getNextRepackRep
   return nullptr;
 }
 
+//------------------------------------------------------------------------------
+// OStoreDB::getRepackReportBatches()
+//------------------------------------------------------------------------------
+std::list<std::unique_ptr<SchedulerDatabase::RepackReportBatch>> OStoreDB::getRepackReportBatches(log::LogContext &lc){
+  std::list<std::unique_ptr<SchedulerDatabase::RepackReportBatch>> ret;
+  try{
+    ret.push_back(std::move(getNextSuccessfulRetrieveRepackReportBatch(lc)));
+  } catch (const NoRepackReportBatchFound &){}
+  try{
+    ret.push_back(std::move(getNextFailedRetrieveRepackReportBatch(lc)));
+  } catch (const NoRepackReportBatchFound &){}
+  try{
+    ret.push_back(std::move(getNextSuccessfulArchiveRepackReportBatch(lc)));
+  } catch (const NoRepackReportBatchFound &){}
+  try{
+    ret.push_back(std::move(getNextFailedArchiveRepackReportBatch(lc)));
+  } catch (const NoRepackReportBatchFound &){}
+  return ret;
+}
+
 //------------------------------------------------------------------------------
 // OStoreDB::getNextSuccessfulRetrieveRepackReportBatch()
 //------------------------------------------------------------------------------
diff --git a/scheduler/OStoreDB/OStoreDB.hpp b/scheduler/OStoreDB/OStoreDB.hpp
index a5daab47a625e58bf97a5e412ea38a1073e1d1c4..97c4ad316a05e11bbb030445af97bd28ad731fd9 100644
--- a/scheduler/OStoreDB/OStoreDB.hpp
+++ b/scheduler/OStoreDB/OStoreDB.hpp
@@ -500,6 +500,9 @@ public:
   };
   
   std::unique_ptr<SchedulerDatabase::RepackReportBatch> getNextRepackReportBatch(log::LogContext& lc) override;
+  
+  std::list<std::unique_ptr<SchedulerDatabase::RepackReportBatch>> getRepackReportBatches(log::LogContext &lc) override;
+  
 private:
   CTA_GENERATE_EXCEPTION_CLASS(NoRepackReportBatchFound);
   const size_t c_repackReportBatchSize = 500;
diff --git a/scheduler/OStoreDB/OStoreDBFactory.hpp b/scheduler/OStoreDB/OStoreDBFactory.hpp
index 1e9694ebdcdea1616838228219186b3a00de90c4..b578aedce0b2731c402c5541a803ffffbb9b8912 100644
--- a/scheduler/OStoreDB/OStoreDBFactory.hpp
+++ b/scheduler/OStoreDB/OStoreDBFactory.hpp
@@ -157,6 +157,10 @@ public:
   std::unique_ptr<RepackReportBatch> getNextRepackReportBatch(log::LogContext& lc) override {
     return m_OStoreDB.getNextRepackReportBatch(lc);
   }
+  
+  std::list<std::unique_ptr<SchedulerDatabase::RepackReportBatch>> getRepackReportBatches(log::LogContext &lc) override {
+    return m_OStoreDB.getRepackReportBatches(lc);
+  }
 
   JobsFailedSummary getRetrieveJobsFailedSummary(log::LogContext &lc) override {
     return m_OStoreDB.getRetrieveJobsFailedSummary(lc);
diff --git a/scheduler/RepackRequestManager.cpp b/scheduler/RepackRequestManager.cpp
index cf5fbf7b6adc9ef497334c9eafbe8a5384c3a218..09c69a09f9f4d02820ee9e4b08bbb566c30b9b3c 100644
--- a/scheduler/RepackRequestManager.cpp
+++ b/scheduler/RepackRequestManager.cpp
@@ -48,8 +48,10 @@ void RepackRequestManager::runOnePass(log::LogContext& lc) {
   }
   
   {
-    // Do one round of repack subrequest reporting (heavy lifting is done internally).
-    m_scheduler.getNextRepackReportBatch(lc).report(lc);
+    // Do all round of repack subrequest reporting (heavy lifting is done internally).
+    for(auto& reportBatch: m_scheduler.getRepackReportBatches(lc)){
+      reportBatch.report(lc);
+    }
   }
   
 }
diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp
index 6d6670763e1886d6395321c1db83e82839020916..16f0d76829485c41d2dbda2b76bcd94f366fb4f5 100644
--- a/scheduler/Scheduler.cpp
+++ b/scheduler/Scheduler.cpp
@@ -586,6 +586,16 @@ Scheduler::RepackReportBatch Scheduler::getNextRepackReportBatch(log::LogContext
   return ret;
 }
 
+std::list<Scheduler::RepackReportBatch> Scheduler::getRepackReportBatches(log::LogContext &lc){
+  std::list<Scheduler::RepackReportBatch> ret;
+  for(auto& reportBatch: m_db.getRepackReportBatches(lc)){
+    Scheduler::RepackReportBatch report;
+    report.m_DbBatch.reset(reportBatch.release());
+    ret.push_back(std::move(report));
+  }
+  return ret;
+}
+
 //------------------------------------------------------------------------------
 // Scheduler::RepackReportBatch::report
 //------------------------------------------------------------------------------
diff --git a/scheduler/Scheduler.hpp b/scheduler/Scheduler.hpp
index d0e2aa2985b6bd7078d081d91a10966abd082262..d19820ed86e91aa9ab21d2ac6473805ab869f386 100644
--- a/scheduler/Scheduler.hpp
+++ b/scheduler/Scheduler.hpp
@@ -347,6 +347,8 @@ public:
     bool empty() { return nullptr == m_DbBatch; }
   };
   RepackReportBatch getNextRepackReportBatch(log::LogContext & lc);
+  std::list<Scheduler::RepackReportBatch> getRepackReportBatches(log::LogContext &lc);
+  
   /*======================= Failed archive jobs support ======================*/
   SchedulerDatabase::JobsFailedSummary getArchiveJobsFailedSummary(log::LogContext &lc);
 
diff --git a/scheduler/SchedulerDatabase.hpp b/scheduler/SchedulerDatabase.hpp
index ee1de1f9ba1c223e66c5a0995f4c47411d70b087..c58874553c05aaf371df6380ba44b45f0a96bb4c 100644
--- a/scheduler/SchedulerDatabase.hpp
+++ b/scheduler/SchedulerDatabase.hpp
@@ -492,6 +492,13 @@ public:
    */
   virtual std::unique_ptr<RepackReportBatch> getNextRepackReportBatch(log::LogContext & lc) = 0;
   
+  /**
+   * Return all batches of subrequests from the database to be reported to repack.
+   * @param lc log context
+   * @return the list of all batches to be reported
+   */
+  virtual std::list<std::unique_ptr<RepackReportBatch>> getRepackReportBatches(log::LogContext &lc) = 0;
+  
   /**
    * Set a batch of jobs as reported (modeled on ArchiveMount::setJobBatchSuccessful().
    * @param jobsBatch
diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp
index 4bd976026c1b9892e871d48d0d9544448af9392c..1326e57d1c8e7d1db82ea51c1747c0ea4fb2dc11 100644
--- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp
+++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp
@@ -1858,166 +1858,6 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullOnFlushMigration) {
                                                "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\""));
 }
 
-TEST_P(DataTransferSessionTest, WriteDataInTapeWithNonSupersededFilesOnIt) {
-  // 0) Prepare the logger for everyone
-  cta::log::StringLogger logger("dummy","tapeServerUnitTest",cta::log::DEBUG);
-  cta::log::LogContext logContext(logger);
-  
-  setupDefaultCatalogue();
-  // 1) prepare the fake scheduler
-  std::string vid = s_vid;
-  std::string vid2 = s_vid+"2";
-  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;
-
-  // 3) Prepare the necessary environment (logger, plus system wrapper), 
-  castor::tape::System::mockWrapper mockSys;
-  mockSys.delegateToFake();
-  mockSys.disableGMockCallsCounting();
-  mockSys.fake.setupForVirtualDriveSLC6();
-  
-  // 4) Create the scheduler
-  auto & catalogue = getCatalogue();
-  auto & scheduler = getScheduler();
-  
-  // Always use the same requester
-  const cta::common::dataStructures::SecurityIdentity requester("user", "group");
-  
-  // List to remember the path of each remote file so that the existance of the
-  // files can be tested for at the end of the test
-  std::list<std::string> remoteFilePaths;
-  
-  // 5) Create the environment for the migration to happen (library + tape) 
-    const std::string libraryComment = "Library comment";
-  const bool libraryIsDisabled = false;
-  catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName,
-    libraryIsDisabled, libraryComment);
-  {
-    auto libraries = catalogue.getLogicalLibraries();
-    ASSERT_EQ(1, libraries.size());
-    ASSERT_EQ(s_libraryName, libraries.front().name);
-    ASSERT_EQ(libraryComment, libraries.front().comment);
-  }
-  const uint64_t capacityInBytes = 12345678;
-  const std::string tapeComment = "Tape comment";
-  bool disabled = false;
-  bool full = false;
-  catalogue.createTape(s_adminOnAdminHost, s_vid, s_mediaType, s_vendor, s_libraryName, s_tapePoolName, capacityInBytes,
-    disabled, full, tapeComment);
-  catalogue.createTape(s_adminOnAdminHost, vid2, s_mediaType, s_vendor, s_libraryName, s_tapePoolName, capacityInBytes,
-    disabled, full, tapeComment);
-  
-  // Create the mount criteria
-  catalogue.createMountPolicy(requester, "immediateMount", 1000, 0, 1000, 0, 1, "Policy comment");
-  catalogue.createRequesterMountRule(requester, "immediateMount", s_diskInstance, requester.username, "Rule comment");
-
-  //delete is unnecessary
-  //pointer with ownership will be passed to the application,
-  //which will do the delete
-  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive();
-  
-  // We can prepare files for writing on the drive.
-  // Tempfiles are in this scope so they are kept alive 
-  std::vector<std::unique_ptr<unitTests::TempFile>> sourceFiles;
-  std::list<uint64_t> archiveFileIds;
-  {    
-    // Label the tape
-    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], s_vid, false);
-    catalogue.tapeLabelled(s_vid, "T10D6116");
-    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
-    
-    // Create the files and schedule the archivals
-    for(int fseq=1; fseq <= 10 ; fseq ++) { 
-      // Create a source file.
-      sourceFiles.emplace_back(cta::make_unique<unitTests::TempFile>());
-      sourceFiles.back()->randomFill(1000);
-      remoteFilePaths.push_back(sourceFiles.back()->path());
-      // Schedule the archival of the file
-      cta::common::dataStructures::ArchiveRequest ar;
-      ar.checksumType="ADLER32";
-      ar.checksumValue=sourceFiles.back()->adler32();
-      ar.storageClass=s_storageClassName;
-      ar.srcURL=std::string("file://") + sourceFiles.back()->path();
-      ar.requester.name = requester.username;
-      ar.requester.group = "group";
-      ar.fileSize = 1000;
-      ar.diskFileID = std::to_string(fseq);
-      ar.diskFileInfo.path = "y";
-      ar.diskFileInfo.owner = "z";
-      ar.diskFileInfo.group = "g";
-      const auto archiveFileId = scheduler.checkAndGetNextArchiveFileId(s_diskInstance, ar.storageClass, ar.requester, logContext);
-      archiveFileIds.push_back(archiveFileId);
-      scheduler.queueArchiveWithGivenId(archiveFileId,s_diskInstance,ar,logContext);
-    }
-  }
-  scheduler.waitSchedulerDbSubthreadsComplete();
-  // Report the drive's existence and put it up in the drive register.
-  cta::tape::daemon::TpconfigLine driveConfig("T10D6116", "TestLogicalLibrary", "/dev/tape_T10D6116", "manual");
-  cta::common::dataStructures::DriveInfo driveInfo;
-  driveInfo.driveName=driveConfig.unitName;
-  driveInfo.logicalLibrary=driveConfig.logicalLibrary;
-  driveInfo.host="host";
-  // We need to create the drive in the registry before being able to put it up.
-  scheduler.reportDriveStatus(driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Down, logContext);
-  scheduler.setDesiredDriveState(s_adminOnAdminHost, driveConfig.unitName, true, false, logContext);
-
-  // Create the data transfer session
-  DataTransferConfig castorConf;
-  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
-  castorConf.nbBufs = 10;
-  castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000;
-  castorConf.bulkRequestRecallMaxFiles = 1000;
-  castorConf.bulkRequestMigrationMaxBytes = UINT64_C(100)*1000*1000*1000;
-  castorConf.bulkRequestMigrationMaxFiles = 1000;
-  castorConf.nbDiskThreads = 1;
-  cta::log::DummyLogger dummyLog("dummy", "dummy");
-  cta::mediachanger::MediaChangerFacade mc(dummyLog);
-  cta::server::ProcessCap capUtils;
-  castor::messages::TapeserverProxyDummy initialProcess;
-  DataTransferSession sess("tapeHost", logger, mockSys, driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
-  sess.execute();
-  
-  catalogue.setTapeFull(requester,vid,true);
-  //Fake reclaim the tape to reset tape's counters
-  catalogue.fakeReclaimTapeForTests(requester,vid);
-  
-  //Try to write files on tape vid = TstVid
-  // Create the files and schedule the archivals
-  {
-    for(int fseq=1; fseq <= 10 ; fseq ++) { 
-      // Create a source file.
-      sourceFiles.emplace_back(cta::make_unique<unitTests::TempFile>());
-      sourceFiles.back()->randomFill(1000);
-      remoteFilePaths.push_back(sourceFiles.back()->path());
-      // Schedule the archival of the file
-      cta::common::dataStructures::ArchiveRequest ar;
-      ar.checksumType="ADLER32";
-      ar.checksumValue=sourceFiles.back()->adler32();
-      ar.storageClass=s_storageClassName;
-      ar.srcURL=std::string("file://") + sourceFiles.back()->path();
-      ar.requester.name = requester.username;
-      ar.requester.group = "group";
-      ar.fileSize = 1000;
-      ar.diskFileID = std::to_string(fseq);
-      ar.diskFileInfo.path = "y";
-      ar.diskFileInfo.owner = "z";
-      ar.diskFileInfo.group = "g";
-      const auto archiveFileId = scheduler.checkAndGetNextArchiveFileId(s_diskInstance, ar.storageClass, ar.requester, logContext);
-      archiveFileIds.push_back(archiveFileId);
-      scheduler.queueArchiveWithGivenId(archiveFileId,s_diskInstance,ar,logContext);
-    }
-  }
-  scheduler.waitSchedulerDbSubthreadsComplete();
-  {
-    DataTransferSession sess("tapeHost2", logger, mockSys, driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
-    sess.execute();
-  }
-  //The session should fail because of the checking of writing in a tape with files that are not superseded
-  std::string logToCheck = logger.getLog();
-  ASSERT_NE(std::string::npos, logToCheck.find("MSG=\"In MigrationReportPacker::reportEndOfSessionWithErrors(), "
-          "pushing a report.\" thread=\"TapeWrite\" tapeDrive=\"T10D6116\" tapeVid=\"TstVid\" mountId=\"2\" "
-          "ErrorMesage=\"Non superseded files have been detected in the tape TstVid after 0\" type=\"ReportEndofSessionWithErrors\""));
-}
-
 #undef TEST_MOCK_DB
 #ifdef TEST_MOCK_DB
 static cta::MockSchedulerDatabaseFactory mockDbFactory;
diff --git a/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.cpp b/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.cpp
index 3258b2458a4c8f9617bf1e2248af65c3299b82d8..f209e4f0df2568daab19f7731b35653012fc47da 100644
--- a/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.cpp
+++ b/tapeserver/castor/tape/tapeserver/daemon/TapeWriteSingleThread.cpp
@@ -319,8 +319,6 @@ void castor::tape::tapeserver::daemon::TapeWriteSingleThread::run() {
       params.add("capacityInBytes",m_archiveMount.getCapacityInBytes());
       m_logContext.log(cta::log::INFO, "Tape session started");
       mountTapeReadWrite();
-      currentErrorToCount = "Error_tapeFSeqCheckAndTapeFileCleanup";
-      m_archiveMount.checkTapeFSeqAndDeleteTapeFilesForWriting(m_lastFseq);
       currentErrorToCount = "Error_tapeLoad";
       waitForDrive();
       currentErrorToCount = "Error_checkingTapeAlert";
diff --git a/xroot_plugins/XrdCtaRepackLs.hpp b/xroot_plugins/XrdCtaRepackLs.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..010fdd29b2c4f83fb628aac6ff7310259b22e274
--- /dev/null
+++ b/xroot_plugins/XrdCtaRepackLs.hpp
@@ -0,0 +1,115 @@
+/**
+ * The CERN Tape Archive (CTA) project
+ * Copyright © 2018 CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <XrdSsiPbOStreamBuffer.hpp>
+#include <catalogue/Catalogue.hpp>
+#include <xrootd/private/XrdSsi/XrdSsiStream.hh>
+
+
+
+namespace cta { namespace xrd {
+ /*!
+ * Stream object which implements "repack ls" command.
+ */
+  class RepackLsStream: public XrdSsiStream {
+  public:
+    
+    RepackLsStream(cta::Scheduler& scheduler, const cta::optional<std::string> vid):
+    XrdSsiStream(XrdSsiStream::isActive),m_scheduler(scheduler), m_vid(vid){
+      XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "RepackLsStream() constructor");
+      if(!vid){
+	m_repackList = m_scheduler.getRepacks();
+      } else {
+	m_repackList.push_back(m_scheduler.getRepack(vid.value()));
+      }
+    }
+    
+    virtual ~RepackLsStream(){
+      XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG,LOG_SUFFIX,"~RepackLsStream() destructor");
+    }
+    
+    virtual Buffer *GetBuff(XrdSsiErrInfo &eInfo,int &dlen, bool &last) override {
+      XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "GetBuff(): XrdSsi buffer fill request (", dlen, " bytes)");
+
+      XrdSsiPb::OStreamBuffer<Data> *streambuf;
+
+      try {
+	
+	if(m_repackList.empty()) {
+	  // Nothing more to send, close the stream
+	  last = true;
+	  return nullptr;
+	}
+	
+	streambuf = new XrdSsiPb::OStreamBuffer<Data>(dlen);
+	
+	for(bool is_buffer_full = false; !m_repackList.empty() && !is_buffer_full; m_repackList.pop_front()){
+	  Data record;
+	  auto &repackRequest = m_repackList.front();
+	  auto repackRequestItem = record.mutable_rels_item();
+	  repackRequestItem->set_vid(repackRequest.vid);
+	  repackRequestItem->set_repack_buffer_url(repackRequest.repackBufferBaseURL);
+	  repackRequestItem->set_user_provided_files(repackRequest.userProvidedFiles);
+	  repackRequestItem->set_total_files_to_retrieve(repackRequest.totalFilesToRetrieve);
+	  repackRequestItem->set_total_bytes_to_retrieve(repackRequest.totalBytesToRetrieve);
+	  repackRequestItem->set_total_files_to_archive(repackRequest.totalFilesToArchive);
+	  repackRequestItem->set_total_bytes_to_archive(repackRequest.totalBytesToArchive);
+	  repackRequestItem->set_retrieved_files(repackRequest.retrievedFiles);
+	  repackRequestItem->set_archived_files(repackRequest.archivedFiles);
+	  repackRequestItem->set_failed_to_retrieve_files(repackRequest.failedFilesToRetrieve);
+	  repackRequestItem->set_failed_to_retrieve_bytes(repackRequest.failedBytesToRetrieve);
+	  repackRequestItem->set_failed_to_archive_files(repackRequest.failedFilesToArchive);
+	  repackRequestItem->set_failed_to_archive_bytes(repackRequest.failedBytesToArchive);
+	  repackRequestItem->set_status(toString(repackRequest.status));
+	  //Last expanded fSeq is in reality the next FSeq to Expand. So last one is next - 1
+	  repackRequestItem->set_last_expanded_fseq(repackRequest.lastExpandedFseq != 0 ? repackRequest.lastExpandedFseq - 1 : 0);
+	  is_buffer_full = streambuf->Push(record);
+	}
+	
+	dlen = streambuf->Size();
+	XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "GetBuff(): Returning buffer with ", dlen, " bytes of data.");
+	
+      } catch(cta::exception::Exception &ex) {
+      std::ostringstream errMsg;
+      errMsg << __FUNCTION__ << " failed: Caught CTA exception: " << ex.what();
+      eInfo.Set(errMsg.str().c_str(), ECANCELED);
+      delete streambuf;
+      } catch(std::exception &ex) {
+	std::ostringstream errMsg;
+	errMsg << __FUNCTION__ << " failed: " << ex.what();
+	eInfo.Set(errMsg.str().c_str(), ECANCELED);
+	delete streambuf;
+      } catch(...) {
+	std::ostringstream errMsg;
+	errMsg << __FUNCTION__ << " failed: Caught an unknown exception";
+	eInfo.Set(errMsg.str().c_str(), ECANCELED);
+	delete streambuf;
+      }
+      return streambuf;
+    }
+  
+  private:
+    cta::Scheduler &m_scheduler;
+    const cta::optional<std::string> m_vid;
+    std::list<common::dataStructures::RepackInfo> m_repackList;
+    static constexpr const char * const LOG_SUFFIX = "RepackLsStream";
+  };
+
+}}
\ No newline at end of file
diff --git a/xroot_plugins/XrdSsiCtaRequestMessage.cpp b/xroot_plugins/XrdSsiCtaRequestMessage.cpp
index fa2729517d5aec8a7badf2fbffdd5e40f9ba9499..a72b041d0e63fc2fc4d2adbedf50e7bf3102918c 100644
--- a/xroot_plugins/XrdSsiCtaRequestMessage.cpp
+++ b/xroot_plugins/XrdSsiCtaRequestMessage.cpp
@@ -31,7 +31,7 @@ using XrdSsiPb::PbException;
 #include "XrdCtaTapePoolLs.hpp"
 #include "XrdSsiCtaRequestMessage.hpp"
 #include "XrdCtaTapeLs.hpp"
-
+#include "XrdCtaRepackLs.hpp"
 
 
 namespace cta {
@@ -193,7 +193,7 @@ void RequestMessage::process(const cta::xrd::Request &request, cta::xrd::Respons
                processRepack_Rm(request.admincmd(), response);
                break;
             case cmd_pair(AdminCmd::CMD_REPACK, AdminCmd::SUBCMD_LS):
-               processRepack_Ls(request.admincmd(), response);
+               processRepack_Ls(request.admincmd(), response, stream);
                break;
             case cmd_pair(AdminCmd::CMD_REPACK, AdminCmd::SUBCMD_ERR):
                processRepack_Err(request.admincmd(), response);
@@ -1364,55 +1364,21 @@ void RequestMessage::processRepack_Rm(const cta::admin::AdminCmd &admincmd, cta:
 
 
 
-void RequestMessage::processRepack_Ls(const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response)
+void RequestMessage::processRepack_Ls(const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response, XrdSsiStream* &stream)
 {
    using namespace cta::admin;
+  
+  auto vid = getOptional(OptionString::VID);
 
-   std::stringstream cmdlineOutput;
-
-   auto vid = getOptional(OptionString::VID);
-
-   std::list<cta::common::dataStructures::RepackInfo> list;
-
-   if(!vid) {      
-      list = m_scheduler.getRepacks();
-   } else {
-      list.push_back(m_scheduler.getRepack(vid.value()));
-   }
+  // Create a XrdSsi stream object to return the results
+  stream = new RepackLsStream(m_scheduler, vid);
 
-   if(!list.empty())
-   {
-      std::vector<std::vector<std::string>> responseTable;
-      std::vector<std::string> header = {
-         "vid","file buffer URL","UserProvidedFiles","FilesToRetrieve","BytesToRetrieve","FilesToArchive","BytesToArchive","FailedToRetrieve (files)","FailedToRetrieve (bytes)","FailedToArchive (files)","FailedToArchive (bytes)","LastExpandedFSeq","status"//,"name","host","time"
-      };
-      if(has_flag(OptionBoolean::SHOW_HEADER)) responseTable.push_back(header);    
-      for(auto it = list.cbegin(); it != list.cend(); it++)
-      {
-        std::vector<std::string> currentRow;
-        currentRow.push_back(it->vid);
-        currentRow.push_back(utils::midEllipsis(it->repackBufferBaseURL,40));//std::to_string(static_cast<unsigned long long>(it->totalFiles)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->userProvidedFiles)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->totalFilesToRetrieve)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->totalBytesToRetrieve)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->totalFilesToArchive)));//std::to_string(static_cast<unsigned long long>(it->totalSize)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->totalBytesToArchive)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->failedFilesToRetrieve)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->failedBytesToRetrieve)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->failedFilesToArchive)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->failedBytesToArchive)));
-        currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->lastExpandedFseq)));//std::to_string(static_cast<unsigned long long>(it->filesArchived)));
-        currentRow.push_back(common::dataStructures::toString(it->status));
-        //currentRow.push_back("-");//it->creationLog.username);
-        //currentRow.push_back("-");//it->creationLog.host);
-        //currentRow.push_back("-");//timeToString(it->creationLog.time));
-        responseTable.push_back(currentRow);
-      }
-      cmdlineOutput << formatResponse(responseTable);
-   }
+  // Should the client display column headers?
+  if(has_flag(OptionBoolean::SHOW_HEADER)) {
+     response.set_show_header(HeaderType::REPACK_LS);
+  }
 
-   response.set_message_txt(cmdlineOutput.str());
-   response.set_type(cta::xrd::Response::RSP_SUCCESS);
+  response.set_type(cta::xrd::Response::RSP_SUCCESS);
 }
 
 
diff --git a/xroot_plugins/XrdSsiCtaRequestMessage.hpp b/xroot_plugins/XrdSsiCtaRequestMessage.hpp
index a0074ec87f90e52de6639ccfcd72a6df1f1585c2..085d77d1047efb59a50d017f3b5d9e7a062b01f8 100644
--- a/xroot_plugins/XrdSsiCtaRequestMessage.hpp
+++ b/xroot_plugins/XrdSsiCtaRequestMessage.hpp
@@ -177,7 +177,7 @@ private:
    void processMountPolicy_Ls        (const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response);
    void processRepack_Add            (const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response);
    void processRepack_Rm             (const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response);
-   void processRepack_Ls             (const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response);
+   //void processRepack_Ls             (const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response);
    void processRepack_Err            (const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response);
    void processRequesterMountRule_Add(const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response);
    void processRequesterMountRule_Ch (const cta::admin::AdminCmd &admincmd, cta::xrd::Response &response);
@@ -213,6 +213,7 @@ private:
    admincmdstream_t processListPendingRetrieves;
    admincmdstream_t processTapePool_Ls;
    admincmdstream_t processTape_Ls;
+   admincmdstream_t processRepack_Ls;
 
    /*!
     * Log an admin command