Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Retention Policy Check

governance.retention_policy_check

ProductionBounded custom (Class B)Deterministicstrictinstantv1.0.0
No network

Overview

You send one object's metadata — its timestamps, classification, legal-hold flag and attributes — plus your retention clauses and the instant to judge them at, and we return the action, the due instant, and the clause that decided. Calendar durations add in the zone you declare, so a year is a year and not 365 days, and month arithmetic clamps to the last valid day. A legal hold short-circuits every clause. Where two clauses compete, the published order is highest precedence, then the more conservative action, then the longer duration, then the smallest id — and every clause that order discarded comes back so you can see the delete rule that lost. We recommend; we delete nothing, hold nothing and never look at the object itself.

Retention arithmetic is where records management quietly goes wrong: a year added as 365 days, a month that runs off the end of February, a delete clause that beat a legal hold, or a due date nobody can reproduce because it came from a server's clock. You get the arithmetic, the clause that decided, and the clauses that lost.

Reliability

Fully deterministic and independent of the machine: no clock is read, and the same request gives the same answer on any host, in any default zone or locale. Every window is half-open, so the action fires exactly when asOf reaches dueAt, not a second later. Day-and-above duration components add as calendar amounts in your declared zone while PT components add on the exact instant timeline, which is why P1D and PT24H differ across a daylight-saving transition — that difference is deliberate, and it is why a Y, M, W or D duration needs a zone. A legal hold is answered before any clause is consulted, so there is no predicate for it to test: metadata.legalHold true returns LEGAL_HOLD_BLOCKED whatever your clauses say. Refusals, and what to do about each. GOV_RETENTION_INPUT_TOO_LARGE means the declared request is past the 65,536-byte inline limit, so send fewer clauses or shorter attributes. GOV_RETENTION_METADATA_INVALID means a metadata field is the wrong shape or past its length — a non-scalar attribute value, an attribute string over 256 characters, an empty timestamps object — and the message names the path. GOV_RETENTION_FIELD_UNKNOWN means a property we do not declare turned up, which we refuse rather than ignore so a stray key can never carry a credential in, so delete it. GOV_RETENTION_POLICY_INVALID means a clause is the wrong shape, such as a missing retention block or a non-string predicate value, so fix the named path. GOV_RETENTION_CLAUSE_ID_DUPLICATE means two clauses share an id, which would make the receipt ambiguous, so make them unique. GOV_RETENTION_CLAUSE_LIMIT_EXCEEDED means more than 100 clauses arrived, so split the policy. GOV_RETENTION_PREDICATE_LIMIT_EXCEEDED means one clause carries more than 16 predicates, so split that clause in two. GOV_RETENTION_PREDICATE_UNSUPPORTED means a predicate name is not one of the three, so correct the name — we accept no regular expression or glob as a predicate, and there is no legal-hold predicate because a hold is answered before matching. GOV_RETENTION_ACTION_UNSUPPORTED means a clause action or your defaultAction is not RETAIN, REVIEW or DELETE; LEGAL_HOLD_BLOCKED is ours to produce and cannot be declared. GOV_RETENTION_MEASURED_FROM_UNSUPPORTED means measuredFrom is not one of the five timestamp names, so pick one of them. GOV_RETENTION_TIMESTAMP_MISSING means a matching clause measures from a timestamp your metadata does not carry, and we refuse rather than fall back to createdAt or skip the clause, so supply that timestamp. GOV_RETENTION_TIMESTAMP_INVALID means a timestamp is not an ISO-8601 instant with an explicit offset, and a local time is never assumed to be UTC, so add the offset. GOV_RETENTION_DURATION_INVALID means a duration is not ISO-8601, is negative, or exceeds the P36500D equivalent, so correct it. GOV_RETENTION_ASOF_INVALID means asOf is missing its offset or is not an instant we can parse, so send the full form. GOV_RETENTION_TIMEZONE_REQUIRED means a clause duration carries a Y, M, W or D component but no timeZone came with it, and calendar addition depends on the zone, so declare one. GOV_RETENTION_TIMEZONE_UNKNOWN means the zone id is not one the platform knows, so use an IANA name such as Europe/Amsterdam rather than an abbreviation. GOV_RETENTION_WORK_REFUSED means the projected predicate evaluations went past 1600, and the refusal reports both the projection and the budget, so reduce clauses or predicates per clause.

Context footprint

One action plus a bounded receipt: at most 64 reason entries and one entry per competing clause. Your policy is never echoed back. A successful call costs 1 execution credit.

When to use it

When you hold a retention policy and one object's metadata and need the action, the due instant and the clause behind them at a specific moment.

When you want the deletion carried out, when you need working-day deadlines, or when you have no policy to send and expect us to supply one.

Scope

Note
Calendar arithmetic and clause precedence over one object's metadata under the retention policy you send with the request.

Non-goals

  • Does not delete, archive, expire or move anything
  • Does not store, publish or version your retention policy
  • Does not read the object, its content or any storage system
  • Does not read a clock — the answer is computed at the asOf you supply
  • Does not certify compliance with any records-management standard

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

analysisvalidation

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call1 credit

File handling

Accepts file_refProduces file_refMax input64 KB

How we handle your data

Structured input
What this means

This skill only accepts structured technical values such as numbers, booleans, enums, timestamps, or identifiers. It does not process free-form text, files, or documents.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response does not contain submitted content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
metadataobjectYesClosed object metadata for retention arithmetic: required timestamps plus optional id, classification, legal hold, and scalar attributes.
policyobjectYesClosed retention policy with 1 to 100 clauses, a required default action, and an optional IANA zone for calendar durations.
evaluationobjectYesClosed evaluation clock with the asOf instant the answer is computed at, because no server clock is read.

Output schema

FieldTypeRequiredDescription
actionstringYesRecommended action now: RETAIN, REVIEW, DELETE, or LEGAL_HOLD_BLOCKED.
dueAtstringNoDeciding clause's due instant; omitted when a legal hold blocked or the default action applied.
reasonsarrayYesArithmetic receipt capped at 64 entries, each with a stable code and optional clause fields.
decidingClauseIdstringNoClause the precedence order selected; omitted when default or legal hold decided.
competingClausesarrayYesMatching clauses discarded by precedence, empty when only one clause matched.
summaryobjectYesClosed retention counters including optional objectId and timeZone, clause counts, asOf, legal-hold flag, default-applied flag, and truncation.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"governance.retention_policy_check","input":{"metadata":{"timestamps":{"createdAt":"2018-03-01T09:00:00+01:00"}},"policy":{"clauses":[{"id":"finance-7y","action":"DELETE","retention":{"measuredFrom":"CREATED_AT","duration":"P7Y"}}],"defaultAction":"RETAIN","timeZone":"Europe/Amsterdam"},"evaluation":{"asOf":"2026-07-29T12:00:00+02:00"}}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("governance.retention_policy_check", {"policy":{"timeZone":"Europe/Amsterdam","defaultAction":"RETAIN","clauses":[{"id":"finance-7y","match":[{"values":["financial-record"],"predicate":"classificationIn"}],"precedence":100,"action":"DELETE","retention":{"measuredFrom":"CREATED_AT","duration":"P7Y"}}]},"metadata":{"classification":"financial-record","timestamps":{"createdAt":"2018-03-01T09:00:00+01:00"},"objectId":"invoice-2018-0042"},"evaluation":{"asOf":"2026-07-29T12:00:00+02:00"}});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
GOV_RETENTION_INPUT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.
GOV_RETENTION_METADATA_INVALID400NoThe request payload failed this skill's input validation.
GOV_RETENTION_FIELD_UNKNOWN400NoThe request payload failed this skill's input validation.
GOV_RETENTION_POLICY_INVALID400NoThe request payload failed this skill's input validation.
GOV_RETENTION_CLAUSE_ID_DUPLICATE400NoThe request payload failed this skill's input validation.
GOV_RETENTION_CLAUSE_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GOV_RETENTION_PREDICATE_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GOV_RETENTION_PREDICATE_UNSUPPORTED400NoThe skill does not support the requested variant.
GOV_RETENTION_ACTION_UNSUPPORTED400NoThe skill does not support the requested variant.
GOV_RETENTION_MEASURED_FROM_UNSUPPORTED400NoThe skill does not support the requested variant.
GOV_RETENTION_TIMESTAMP_MISSING400NoThe request payload failed this skill's input validation.
GOV_RETENTION_TIMESTAMP_INVALID400NoThe request payload failed this skill's input validation.
GOV_RETENTION_DURATION_INVALID400NoThe request payload failed this skill's input validation.
GOV_RETENTION_ASOF_INVALID400NoThe request payload failed this skill's input validation.
GOV_RETENTION_TIMEZONE_REQUIRED400NoThe request payload failed this skill's input validation.
GOV_RETENTION_TIMEZONE_UNKNOWN400NoThe request payload failed this skill's input validation.
GOV_RETENTION_WORK_REFUSED429NoA size, quota, rate, or time limit was exceeded.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not delete, archive, expire or move anything
  • Does not store, publish or version your retention policy
  • Does not read the object, its content or any storage system
  • Does not read a clock — the answer is computed at the asOf you supply
  • Does not certify compliance with any records-management standard
  • Performing the deletion itself
  • Judging thousands of objects in one call — this answers for one object
  • Working-time or holiday-aware deadlines, which are a different calculation

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "governance.retention_policy_check",
  "input": {
    "policy": {
      "timeZone": "Europe/Amsterdam",
      "defaultAction": "RETAIN",
      "clauses": [
        {
          "id": "finance-7y",
          "match": [
            {
              "values": [
                "financial-record"
              ],
              "predicate": "classificationIn"
            }
          ],
          "precedence": 100,
          "action": "DELETE",
          "retention": {
            "measuredFrom": "CREATED_AT",
            "duration": "P7Y"
          }
        }
      ]
    },
    "metadata": {
      "classification": "financial-record",
      "timestamps": {
        "createdAt": "2018-03-01T09:00:00+01:00"
      },
      "objectId": "invoice-2018-0042"
    },
    "evaluation": {
      "asOf": "2026-07-29T12:00:00+02:00"
    }
  }
}

Examples

Seven-year ledger clause already past its due instant

Inputjson
{
  "policy": {
    "timeZone": "Europe/Amsterdam",
    "defaultAction": "RETAIN",
    "clauses": [
      {
        "id": "finance-7y",
        "match": [
          {
            "values": [
              "financial-record"
            ],
            "predicate": "classificationIn"
          }
        ],
        "precedence": 100,
        "action": "DELETE",
        "retention": {
          "measuredFrom": "CREATED_AT",
          "duration": "P7Y"
        }
      }
    ]
  },
  "metadata": {
    "classification": "financial-record",
    "timestamps": {
      "createdAt": "2018-03-01T09:00:00+01:00"
    },
    "objectId": "invoice-2018-0042"
  },
  "evaluation": {
    "asOf": "2026-07-29T12:00:00+02:00"
  }
}
Expected outputjson
{
  "dueAt": "2025-03-01T09:00:00+01:00",
  "reasons": [
    {
      "code": "RETENTION_CLAUSE_DUE",
      "dueAt": "2025-03-01T09:00:00+01:00",
      "measuredFrom": "CREATED_AT",
      "clauseId": "finance-7y"
    }
  ],
  "competingClauses": [],
  "action": "DELETE",
  "decidingClauseId": "finance-7y",
  "summary": {
    "objectId": "invoice-2018-0042",
    "clauseCount": 1,
    "matchedClauseCount": 1,
    "asOf": "2026-07-29T12:00:00+02:00",
    "timeZone": "Europe/Amsterdam",
    "legalHold": false,
    "defaultApplied": false,
    "truncated": false
  }
}

Legal hold blocks a top-precedence delete clause

Inputjson
{
  "policy": {
    "defaultAction": "REVIEW",
    "clauses": [
      {
        "action": "DELETE",
        "retention": {
          "measuredFrom": "CLOSED_AT",
          "duration": "PT17520H"
        },
        "precedence": 1000,
        "id": "closed-cases-2y"
      }
    ]
  },
  "metadata": {
    "timestamps": {
      "closedAt": "2021-11-30T17:00:00Z"
    },
    "objectId": "case-file-8891",
    "legalHold": true
  },
  "evaluation": {
    "asOf": "2026-07-29T12:00:00Z"
  }
}
Expected outputjson
{
  "action": "LEGAL_HOLD_BLOCKED",
  "reasons": [
    {
      "code": "RETENTION_LEGAL_HOLD_ACTIVE"
    }
  ],
  "competingClauses": [],
  "summary": {
    "objectId": "case-file-8891",
    "clauseCount": 1,
    "matchedClauseCount": 0,
    "asOf": "2026-07-29T12:00:00Z",
    "legalHold": true,
    "defaultApplied": false,
    "truncated": false
  }
}
  • Decide whether one record is past its retention boundary at a given instant
  • Show a reviewer which clause decided, and which competing clause was out-ranked
  • Prove a legal hold beats every clause, whatever precedence it carries

Avoid for

  • Performing the deletion itself
  • Judging thousands of objects in one call — this answers for one object
  • Working-time or holiday-aware deadlines, which are a different calculation

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

analysisretentionvalidationgovernance