Archiving risks in ServiceNow GRC is a known pain point. The naive approach of just deleting or moving records breaks audit trails and reporting. You need to preserve the full context—attachments, audit logs, relationships—without cluttering active workspaces.
Here's what I've validated in production:
* **Don't use delete.** Ever. It destroys your data integrity.
* **Create a dedicated archive table.** Clone your `sn_grc_risk` table schema. This is a one-time setup.
* **Use a scheduled data sync.** Move records where `state=closed` and `closed_date` is older than your retention policy (e.g., 7 years). The script must copy the entire record graph.
```javascript
// Example GlideRecord archive logic (simplified)
var source = new GlideRecord('sn_grc_risk');
source.addQuery('state', 'closed');
source.addQuery('closed_date', '<=', gs.yearsAgo(7));
source.query();
while (source.next()) {
var archive = new GlideRecord('sn_grc_risk_archive');
archive.initialize();
// Map all fields from source to archive
archive.setValue('sys_id', source.getValue('sys_id')); // Keep original key
// ... copy all other fields, including sys_created_on, sys_created_by, etc.
archive.insert();
// Only delete source after successful archive and relationship migration
source.deleteRecord();
}
```
* **Migrate related records.** Your script must also handle `sys_audit` entries, `sys_attachment` docs, and linked assessment/control records. This is the complex part.
* **Update reports.** Point historical reports to the archive table via a UNION view or adjusted queries.
The main trade-off is storage cost versus query performance. A well-indexed archive table is acceptable. The alternative—flagging records as "archived" in the live table—leads to table bloat and slower queries over time.