Permission Diff
identity.permission_diff
Overview
You send before and after arrays of canonical permission strings. caseSensitivity defaults to SENSITIVE; ASCII_INSENSITIVE lowercases with Locale.ROOT. Optional hierarchyDelimiter plus expandHierarchy=false expands ancestors when true. Results are sorted. This does not decide authorization or look up a directory.
A permission change that both adds and removes grants is not a pure increase.
Reliability
Order is lexical after canonicalization. PERMISSION_DIFF_INVALID — trigger: expandHierarchy without a one-character delimiter; retryable: no; next: send hierarchyDelimiter. IDENTITY_LIMIT_EXCEEDED — trigger: more than 10,000 permissions; retryable: no; next: split the lists.
Context footprint
Sorted names and counts only. A successful call costs 1 execution credit.
When to use it
When two already-canonical permission lists must be compared.
When you need to decide authorization or expand roles from a directory.
Scope
Non-goals
- Does not decide authorization
- Does not look up a directory
- Does not evaluate wildcards
Properties
Capabilities
Cost & billing
Flat rate per invocation
File handling
How we handle your data
What this means
This skill is designed to detect, mask, redact, validate, or otherwise process sensitive data.
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.
- Targets 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.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| before | array | Yes | Bounded array of 0 through 10001 previous permissions; runtime accepts at most 10000. |
| after | array | Yes | Bounded array of 0 through 10001 next permissions; runtime accepts at most 10000. |
| caseSensitivity | string | No | SENSITIVE or ASCII_INSENSITIVE. Omit it for SENSITIVE. |
| hierarchyDelimiter | string | No | Single-character ancestor delimiter. Omit it when hierarchy is unused. |
| expandHierarchy | boolean | No | Whether to add ancestor permissions. Omit it for false. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| added | array | Yes | Bounded array of 0 through 10000 sorted canonical permission strings. |
| removed | array | Yes | Bounded array of 0 through 10000 sorted canonical permission strings. |
| unchanged | array | Yes | Bounded array of 0 through 10000 sorted canonical permission strings. |
| addedCount | integer | Yes | How many permissions were added. |
| removedCount | integer | Yes | How many permissions were removed. |
| unchangedCount | integer | Yes | How many permissions stayed the same. |
| privilegeChange | string | Yes | INCREASE, DECREASE, MIXED or NONE. |
| caseSensitivity | string | Yes | Applied case mode SENSITIVE or ASCII_INSENSITIVE. |
| expandHierarchy | boolean | Yes | Whether ancestors were expanded. |
| rulesetVersion | string | Yes | Pinned permission-diff ruleset identifier. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"identity.permission_diff","input":{"before":["docs.read"],"after":["docs.read","docs.write"]}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("identity.permission_diff", {"before":["docs.read"],"after":["docs.read","docs.write"]});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| PERMISSION_DIFF_INVALID | 400 | No | The request payload failed this skill's input validation. |
| IDENTITY_LIMIT_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- Does not decide authorization
- Does not look up a directory
- Does not evaluate wildcards
- Enforcing the resulting set
- Expanding roles from a directory
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "identity.permission_diff",
"input": {
"before": [
"docs.read"
],
"after": [
"docs.read",
"docs.write"
]
}
}Examples
Adding docs.write is INCREASE
{
"before": [
"docs.read"
],
"after": [
"docs.read",
"docs.write"
]
}{
"expandHierarchy": false,
"unchanged": [
"docs.read"
],
"addedCount": 1,
"unchangedCount": 1,
"removed": [],
"privilegeChange": "INCREASE",
"rulesetVersion": "identity.permission_diff.v1",
"removedCount": 0,
"added": [
"docs.write"
],
"caseSensitivity": "SENSITIVE"
}Replacing admin and read with write is MIXED
{
"before": [
"docs.read",
"admin"
],
"after": [
"docs.write"
]
}{
"expandHierarchy": false,
"unchanged": [],
"addedCount": 1,
"unchangedCount": 0,
"removed": [
"admin",
"docs.read"
],
"privilegeChange": "MIXED",
"rulesetVersion": "identity.permission_diff.v1",
"removedCount": 2,
"added": [
"docs.write"
],
"caseSensitivity": "SENSITIVE"
}Recommended use cases
- Detect an increase when a write grant is added
- Report MIXED when grants both appear and disappear
Avoid for
- Enforcing the resulting set
- Expanding roles from a directory
Related skills
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.