{
	"info": {
		"name": "Keycard Access Policies",
		"description": "Complete workflow for creating, drafting, publishing, and simulating access policies in a Keycard zone.\n\nSet these environment variables before running:\n- `client_id` — your service account client ID\n- `client_secret` — your service account client secret\n\nAll other variables (token, zone_id, principal_id, resource_id, policy_id, etc.) are auto-set by post-response scripts. The setup section creates a test application and resource for use as the principal and resource in policy evaluations. The collection picks the first zone from your account by default.\n\nRun all requests sequentially using Postman Runner.",
		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
	},
	"variable": [
		{
			"key": "base_url",
			"value": "https://api.keycard.ai",
			"description": "Default API base URL. Override in your Postman environment to target a different host."
		}
	],
	"item": [
		{
			"name": "1 — Setup",
			"description": "Authenticate, discover zones, and fetch the current policy schema version.",
			"item": [
				{
					"name": "1.1 Authenticate",
					"request": {
						"method": "POST",
						"header": [],
						"url": {
							"raw": "{{base_url}}/service-account-token",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"service-account-token"
							]
						},
						"body": {
							"mode": "urlencoded",
							"urlencoded": [
								{
									"key": "grant_type",
									"value": "client_credentials"
								},
								{
									"key": "client_id",
									"value": "{{client_id}}"
								},
								{
									"key": "client_secret",
									"value": "{{client_secret}}"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var jsonData = pm.response.json();",
									"pm.environment.set(\"token\", jsonData.access_token);"
								]
							}
						}
					]
				},
				{
					"name": "1.2 List zones",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones"
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var jsonData = pm.response.json();",
									"if (jsonData.items && jsonData.items.length > 0) {",
									"    pm.environment.set(\"zone_id\", jsonData.items[0].id);",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "1.3 List schemas",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-schemas",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-schemas"
							],
							"query": [
								{
									"key": "filter[default]",
									"value": "true",
									"description": "Exact-match boolean. When true, returns only the zone default schema; when false, only non-default schemas. Omit for all.",
									"disabled": true
								},
								{
									"key": "is_default",
									"value": "true",
									"description": "DEPRECATED — use filter[default] instead. Sending both with disagreeing values returns 400.",
									"disabled": true
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var jsonData = pm.response.json();",
									"if (jsonData.items && jsonData.items.length > 0) {",
									"    pm.environment.set(\"schema_version\", jsonData.items[0].version);",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "1.4 Create application",
					"description": "Create a test application to use as the principal in policy evaluations.",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/applications",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"applications"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"name\": \"postman-test-app-{{test_suffix}}\",\n  \"identifier\": \"postman-test-app-{{test_suffix}}\"\n}"
						}
					},
					"event": [
						{
							"listen": "prerequest",
							"script": {
								"type": "text/javascript",
								"exec": [
									"if (!pm.environment.get('test_suffix')) {",
									"    var suffix = Math.random().toString(36).substring(2, 8);",
									"    pm.environment.set('test_suffix', suffix);",
									"}"
								]
							}
						},
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var body = pm.response.json();",
									"var appName = 'postman-test-app-' + pm.environment.get('test_suffix');",
									"if (pm.response.code === 200 || pm.response.code === 201) {",
									"    pm.environment.set('principal_id', body.id);",
									"    pm.environment.set('application_id', body.id);",
									"    console.log('Created application:', body.name, '(id:', body.id, ')');",
									"} else if (pm.response.code === 409) {",
									"    pm.sendRequest({",
									"        url: pm.variables.get('base_url') + '/zones/' + pm.environment.get('zone_id') + '/applications',",
									"        method: 'GET',",
									"        header: { 'Authorization': 'Bearer ' + pm.environment.get('token') }",
									"    }, function (err, res) {",
									"        var items = res.json().items || [];",
									"        for (var i = 0; i < items.length; i++) {",
									"            if (items[i].name === appName) {",
									"                pm.environment.set('principal_id', items[i].id);",
									"                pm.environment.set('application_id', items[i].id);",
									"                console.log('Reused existing application:', items[i].name, '(id:', items[i].id, ')');",
									"                break;",
									"            }",
									"        }",
									"    });",
									"} else {",
									"    pm.test('Status is 200, 201, or 409', function () { pm.expect.fail('Unexpected status: ' + pm.response.code); });",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "1.5 Create resource",
					"description": "Create a test resource to use in policy evaluations.",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/resources",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"resources"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"name\": \"postman-test-resource-{{test_suffix}}\",\n  \"identifier\": \"https://postman-test-{{test_suffix}}.example.com\"\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var body = pm.response.json();",
									"var resName = 'postman-test-resource-' + pm.environment.get('test_suffix');",
									"if (pm.response.code === 200 || pm.response.code === 201) {",
									"    pm.environment.set('resource_id', body.id);",
									"    console.log('Created resource:', body.name, '(id:', body.id, ')');",
									"} else if (pm.response.code === 409) {",
									"    pm.sendRequest({",
									"        url: pm.variables.get('base_url') + '/zones/' + pm.environment.get('zone_id') + '/resources',",
									"        method: 'GET',",
									"        header: { 'Authorization': 'Bearer ' + pm.environment.get('token') }",
									"    }, function (err, res) {",
									"        var items = res.json().items || [];",
									"        for (var i = 0; i < items.length; i++) {",
									"            if (items[i].name === resName) {",
									"                pm.environment.set('resource_id', items[i].id);",
									"                console.log('Reused existing resource:', items[i].name, '(id:', items[i].id, ')');",
									"                break;",
									"            }",
									"        }",
									"    });",
									"} else {",
									"    pm.test('Status is 200, 201, or 409', function () { pm.expect.fail('Unexpected status: ' + pm.response.code); });",
									"}"
								]
							}
						}
					]
				}
			]
		},
		{
			"name": "2 — Policy Lifecycle",
			"description": "Create a policy, author a draft with Cedar JSON, then publish an immutable version.",
			"item": [
				{
					"name": "2.1 Create policy",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"name\": \"require-token-credentials\",\n  \"description\": \"Require token credential type for all application access\"\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var jsonData = pm.response.json();",
									"if (pm.response.code === 201) {",
									"    pm.environment.set(\"policy_id\", jsonData.id);",
									"} else if (pm.response.code === 409) {",
									"    pm.sendRequest({",
									"        url: pm.variables.get(\"base_url\") + \"/zones/\" + pm.environment.get(\"zone_id\") + \"/policies\",",
									"        method: \"GET\",",
									"        header: { \"Authorization\": \"Bearer \" + pm.environment.get(\"token\") }",
									"    }, function (err, res) {",
									"        var items = res.json().items || [];",
									"        for (var i = 0; i < items.length; i++) {",
									"            if (items[i].name === \"require-token-credentials\") {",
									"                pm.environment.set(\"policy_id\", items[i].id);",
									"                if (items[i].latest_version_id) {",
									"                    pm.environment.set(\"policy_version_id\", items[i].latest_version_id);",
									"                }",
									"                break;",
									"            }",
									"        }",
									"    });",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "2.2 Upsert policy draft",
					"request": {
						"method": "PUT",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies/{{policy_id}}/draft",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies",
								"{{policy_id}}",
								"draft"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"cedar_json\": {\n    \"staticPolicies\": {\n      \"require-token-credentials\": {\n        \"effect\": \"forbid\",\n        \"principal\": { \"op\": \"is\", \"entity_type\": \"Keycard::Application\" },\n        \"action\": { \"op\": \"All\" },\n        \"resource\": { \"op\": \"All\" },\n        \"conditions\": [\n          {\n            \"kind\": \"unless\",\n            \"body\": {\n              \"&&\": {\n                \"left\": {\n                  \"has\": {\n                    \"left\": { \"Var\": \"principal\" },\n                    \"attr\": \"credential_type\"\n                  }\n                },\n                \"right\": {\n                  \"==\": {\n                    \"left\": {\n                      \".\": {\n                        \"left\": { \"Var\": \"principal\" },\n                        \"attr\": \"credential_type\"\n                      }\n                    },\n                    \"right\": { \"Value\": { \"__entity\": { \"type\": \"Keycard::CredentialType\", \"id\": \"token\" } } }\n                  }\n                }\n              }\n            }\n          }\n        ]\n      }\n    },\n    \"templates\": {},\n    \"templateLinks\": []\n  },\n  \"schema_version\": \"{{schema_version}}\"\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Draft has cedar_json', function () {",
									"    pm.expect(body.cedar_json).to.not.be.undefined;",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "2.3 Get policy draft",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies/{{policy_id}}/draft",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies",
								"{{policy_id}}",
								"draft"
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Draft contains cedar_json', function () {",
									"    pm.expect(body.cedar_json).to.not.be.undefined;",
									"});",
									"console.log('Draft cedar_json:', JSON.stringify(body.cedar_json, null, 2));"
								]
							}
						}
					]
				},
				{
					"name": "2.4 Create policy version (publish)",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies/{{policy_id}}/versions",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies",
								"{{policy_id}}",
								"versions"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"cedar_raw\": \"@id(\\\"require-token-credentials\\\")\\nforbid (\\n  principal is Keycard::Application,\\n  action,\\n  resource\\n) unless {\\n  principal has credential_type && principal.credential_type == Keycard::CredentialType::\\\"token\\\"\\n};\",\n  \"schema_version\": \"{{schema_version}}\"\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"if (pm.response.code === 201) {",
									"    var jsonData = pm.response.json();",
									"    pm.environment.set(\"policy_version_id\", jsonData.id);",
									"}"
								]
							}
						}
					]
				}
			]
		},
		{
			"name": "3 — Policy Set Lifecycle",
			"description": "Create a policy set, build a draft manifest with the custom policy, and publish an immutable version. Steps 3.2–3.3 discover the managed policy set for use in rollback (section 6).",
			"item": [
				{
					"name": "3.1 Create policy set",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"name\": \"custom-zone-policies\",\n  \"scope_type\": \"zone\"\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var jsonData = pm.response.json();",
									"if (pm.response.code === 201) {",
									"    pm.environment.set(\"policy_set_id\", jsonData.id);",
									"} else if (pm.response.code === 409) {",
									"    pm.sendRequest({",
									"        url: pm.variables.get(\"base_url\") + \"/zones/\" + pm.environment.get(\"zone_id\") + \"/policy-sets\",",
									"        method: \"GET\",",
									"        header: { \"Authorization\": \"Bearer \" + pm.environment.get(\"token\") }",
									"    }, function (err, res) {",
									"        var items = res.json().items || [];",
									"        for (var i = 0; i < items.length; i++) {",
									"            if (items[i].name === \"custom-zone-policies\" && items[i].owner_type === \"customer\") {",
									"                pm.environment.set(\"policy_set_id\", items[i].id);",
									"                break;",
									"            }",
									"        }",
									"    });",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "3.2 Get managed policy set",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets"
							],
							"query": [
								{
									"key": "query[name]",
									"value": "",
									"description": "Case-insensitive substring match on `name`. Repeatable; multiple terms are OR-ed.",
									"disabled": true
								},
								{
									"key": "query[]",
									"value": "",
									"description": "Unscoped substring search across all indexed fields (policy sets: `name`). Repeatable; OR-ed.",
									"disabled": true
								},
								{
									"key": "filter[owner_type]",
									"value": "platform",
									"description": "Exact-match filter: `platform` or `customer`.",
									"disabled": true
								},
								{
									"key": "filter[scope_type]",
									"value": "zone",
									"description": "Exact-match filter: `zone`, `resource`, `user`, or `session`.",
									"disabled": true
								},
								{
									"key": "filter[active]",
									"value": "true",
									"description": "Filter by active binding status. Replaces the deprecated `active` parameter.",
									"disabled": true
								},
								{
									"key": "active",
									"value": "true",
									"description": "DEPRECATED — use `filter[active]` instead. Sending both with disagreeing values returns 400.",
									"disabled": true
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var jsonData = pm.response.json();",
									"var items = jsonData.items || [];",
									"for (var i = 0; i < items.length; i++) {",
									"    if (items[i].owner_type === \"platform\") {",
									"        pm.environment.set(\"managed_ps_id\", items[i].id);",
									"        pm.environment.set(\"managed_ps_version_id\", items[i].latest_version_id);",
									"        break;",
									"    }",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "3.3 Get managed policy set version",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets/{{managed_ps_id}}/versions/{{managed_ps_version_id}}",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets",
								"{{managed_ps_id}}",
								"versions",
								"{{managed_ps_version_id}}"
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var jsonData = pm.response.json();",
									"var entries = jsonData.manifest.entries || [];",
									"pm.environment.set(\"managed_manifest_entries\", JSON.stringify(entries));",
									"if (jsonData.schema_version) {",
									"    pm.environment.set(\"managed_schema_version\", jsonData.schema_version);",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "3.4 Upsert policy set draft",
					"request": {
						"method": "PUT",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets/{{policy_set_id}}/draft",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets",
								"{{policy_set_id}}",
								"draft"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"manifest\": {\n    \"entries\": [\n      {\n        \"policy_id\": \"{{policy_id}}\",\n        \"policy_version_id\": \"{{policy_version_id}}\"\n      }\n    ]\n  },\n  \"schema_version\": \"{{schema_version}}\"\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Manifest has 1 entry', function () {",
									"    pm.expect(body.manifest.entries).to.have.lengthOf(1);",
									"});",
									"console.log('Draft created with custom policy, manifest entries:', body.manifest?.entries?.length || 0);"
								]
							}
						}
					]
				},
				{
					"name": "3.5 Get policy set draft",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets/{{policy_set_id}}/draft",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets",
								"{{policy_set_id}}",
								"draft"
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Manifest has entries', function () {",
									"    pm.expect(body.manifest.entries.length).to.be.above(0);",
									"});",
									"console.log('Draft manifest:', JSON.stringify(body.manifest, null, 2));"
								]
							}
						}
					]
				},
				{
					"name": "3.6 Create policy set version (publish)",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets/{{policy_set_id}}/versions",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets",
								"{{policy_set_id}}",
								"versions"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{{ps_version_body}}"
						}
					},
					"event": [
						{
							"listen": "prerequest",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var policyVersionId = pm.environment.get(\"policy_version_id\");",
									"if (!policyVersionId) {",
									"    console.warn(\"policy_version_id is not set — the policy version may not have been created. Check step 2.4.\");",
									"}",
									"var body = {",
									"    manifest: { entries: [{ policy_id: pm.environment.get(\"policy_id\"), policy_version_id: policyVersionId }] },",
									"    schema_version: pm.environment.get(\"schema_version\")",
									"};",
									"pm.environment.set(\"ps_version_body\", JSON.stringify(body, null, 2));"
								]
							}
						},
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"var jsonData = pm.response.json();",
									"pm.environment.set(\"ps_version_id\", jsonData.id);"
								]
							}
						}
					]
				}
			]
		},
		{
			"name": "4 — Activate & Verify",
			"description": "Activate the published policy set version and verify it is live.",
			"item": [
				{
					"name": "4.1 Activate policy set",
					"request": {
						"method": "PATCH",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets/{{policy_set_id}}/versions/{{ps_version_id}}",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets",
								"{{policy_set_id}}",
								"versions",
								"{{ps_version_id}}"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\"active\": true}"
						}
					}
				},
				{
					"name": "4.2 Verify",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets"
							]
						}
					}
				}
			]
		},
		{
			"name": "5 — Policy Simulation",
			"description": "Test policy evaluation against real entities before deployment. Supports evaluating a single policy draft, a published policy set, or raw Cedar text.\n\nSet `principal_id` and `resource_id` environment variables before running.",
			"item": [
				{
					"name": "5.1 Simulate — single policy (draft)",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"principal_type\": \"application\",\n  \"principal_id\": \"{{principal_id}}\",\n  \"action\": \"any\",\n  \"resource_id\": \"{{resource_id}}\",\n  \"policy_source\": {\n    \"policy\": {\n      \"policy_id\": \"{{policy_id}}\"\n    }\n  }\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Response has decision', function () {",
									"    pm.expect(body.decision).to.be.oneOf(['allow', 'deny']);",
									"});",
									"console.log('Decision:', body.decision);",
									"console.log('Determining policies:', JSON.stringify(body.determining_policies));",
									"if (body.diagnostics && body.diagnostics.length > 0) {",
									"    console.log('Diagnostics:', JSON.stringify(body.diagnostics, null, 2));",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "5.2 Delete policy draft (setup for 5.3)",
					"request": {
						"method": "DELETE",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies/{{policy_id}}/draft",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies",
								"{{policy_id}}",
								"draft"
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Draft deleted or not found', function () {",
									"    pm.expect(pm.response.code).to.be.oneOf([200, 204, 404]);",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "5.3 Simulate — policy (latest version fallback)",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"principal_type\": \"application\",\n  \"principal_id\": \"{{principal_id}}\",\n  \"action\": \"any\",\n  \"resource_id\": \"{{resource_id}}\",\n  \"policy_source\": {\n    \"policy\": {\n      \"policy_id\": \"{{policy_id}}\"\n    }\n  }\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"// ACC-72 case 2: no draft, published version exists — should use latest version",
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Response has decision', function () {",
									"    pm.expect(body.decision).to.be.oneOf(['allow', 'deny']);",
									"});",
									"console.log('Decision:', body.decision);",
									"console.log('Determining policies:', JSON.stringify(body.determining_policies));"
								]
							}
						}
					]
				},
				{
					"name": "5.4 Simulate — policy (no draft, no version)",
					"event": [
						{
							"listen": "prerequest",
							"script": {
								"type": "text/javascript",
								"exec": [
									"// Create a throwaway policy with no draft and no published version",
									"pm.sendRequest({",
									"    url: pm.variables.get('base_url') + '/zones/' + pm.environment.get('zone_id') + '/policies',",
									"    method: 'POST',",
									"    header: {",
									"        'Authorization': 'Bearer ' + pm.environment.get('token'),",
									"        'Content-Type': 'application/json'",
									"    },",
									"    body: {",
									"        mode: 'raw',",
									"        raw: JSON.stringify({ name: 'empty-policy-' + Date.now(), description: 'Throwaway for ACC-72 case 3' })",
									"    }",
									"}, function (err, res) {",
									"    if (res.code === 201) {",
									"        pm.environment.set('empty_policy_id', res.json().id);",
									"    }",
									"});"
								]
							}
						},
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"// ACC-72 case 3: no draft AND no versions — should return 400",
									"pm.test('Returns 400 for policy with no draft and no versions', function () {",
									"    pm.response.to.have.status(400);",
									"});",
									"",
									"var body = pm.response.json();",
									"console.log('Status:', pm.response.code, '| Message:', body.message);"
								]
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"principal_type\": \"application\",\n  \"principal_id\": \"{{principal_id}}\",\n  \"action\": \"any\",\n  \"resource_id\": \"{{resource_id}}\",\n  \"policy_source\": {\n    \"policy\": {\n      \"policy_id\": \"{{empty_policy_id}}\"\n    }\n  }\n}"
						}
					}
				},
				{
					"name": "5.5 Simulate — policy set (published)",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"principal_type\": \"application\",\n  \"principal_id\": \"{{principal_id}}\",\n  \"action\": \"any\",\n  \"resource_id\": \"{{resource_id}}\",\n  \"policy_source\": {\n    \"policy_set\": {\n      \"policy_set_id\": \"{{policy_set_id}}\",\n      \"version_id\": \"{{ps_version_id}}\"\n    }\n  }\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Response has decision', function () {",
									"    pm.expect(body.decision).to.be.oneOf(['allow', 'deny']);",
									"});",
									"console.log('Decision:', body.decision);",
									"console.log('Determining policies:', JSON.stringify(body.determining_policies));",
									"if (body.entity_snapshot) {",
									"    console.log('Entity snapshot:', JSON.stringify(body.entity_snapshot, null, 2));",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "5.6 Simulate — policy set (draft/latest)",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"principal_type\": \"application\",\n  \"principal_id\": \"{{principal_id}}\",\n  \"action\": \"any\",\n  \"resource_id\": \"{{resource_id}}\",\n  \"policy_source\": {\n    \"policy_set\": {\n      \"policy_set_id\": \"{{policy_set_id}}\"\n    }\n  }\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Response has decision', function () {",
									"    pm.expect(body.decision).to.be.oneOf(['allow', 'deny']);",
									"});",
									"console.log('Decision:', body.decision);",
									"console.log('Determining policies:', JSON.stringify(body.determining_policies));",
									"if (body.entity_snapshot) {",
									"    console.log('Entity snapshot:', JSON.stringify(body.entity_snapshot, null, 2));",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "5.7 Simulate — raw Cedar",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"principal_type\": \"application\",\n  \"principal_id\": \"{{principal_id}}\",\n  \"action\": \"any\",\n  \"resource_id\": \"{{resource_id}}\",\n  \"policy_source\": {\n    \"raw\": {\n      \"cedar\": \"permit(\\n  principal is Keycard::Application,\\n  action,\\n  resource\\n);\",\n      \"schema_version\": \"{{schema_version}}\"\n    }\n  }\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Response has decision', function () {",
									"    pm.expect(body.decision).to.be.oneOf(['allow', 'deny']);",
									"});",
									"console.log('Decision:', body.decision);",
									"console.log('Determining policies:', JSON.stringify(body.determining_policies));",
									"if (body.diagnostics && body.diagnostics.length > 0) {",
									"    console.log('Diagnostics:', JSON.stringify(body.diagnostics, null, 2));",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "5.8 Simulate — inline manifest",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"principal_type\": \"application\",\n  \"principal_id\": \"{{principal_id}}\",\n  \"action\": \"any\",\n  \"resource_id\": \"{{resource_id}}\",\n  \"policy_source\": {\n    \"manifest\": {\n      \"entries\": [\n        {\n          \"policy_id\": \"{{policy_id}}\",\n          \"policy_version_id\": \"{{policy_version_id}}\"\n        }\n      ],\n      \"schema_version\": \"{{schema_version}}\"\n    }\n  }\n}"
						},
						"description": "Evaluate against an in-progress policy-set manifest supplied inline — no stored policy set or version required. Useful for \"Run Test\" on a new-policy-set page in the console, and for testing edits to a draft before publishing. Results match what a stored policy set version with the same entries would return."
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Response has decision', function () {",
									"    pm.expect(body.decision).to.be.oneOf(['allow', 'deny']);",
									"});",
									"console.log('Decision:', body.decision);",
									"console.log('Determining policies:', JSON.stringify(body.determining_policies));",
									"if (body.diagnostics && body.diagnostics.length > 0) {",
									"    console.log('Diagnostics:', JSON.stringify(body.diagnostics, null, 2));",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "5.9 List evaluation requests",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations/requests?limit=20",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations",
								"requests"
							],
							"query": [
								{
									"key": "limit",
									"value": "20"
								},
								{
									"key": "after",
									"value": "",
									"disabled": true
								},
								{
									"key": "before",
									"value": "",
									"disabled": true
								},
								{
									"key": "sort",
									"value": "created_at",
									"description": "Sort field. Currently only `created_at` is supported.",
									"disabled": true
								},
								{
									"key": "order",
									"value": "desc",
									"description": "Sort direction: `asc` or `desc`. Default is `desc` (newest first).",
									"disabled": true
								},
								{
									"key": "expand[]",
									"value": "total_count",
									"description": "Opt-in to additional response fields. `total_count` adds `pagination.total_count` reflecting the filtered set size.",
									"disabled": true
								},
								{
									"key": "filter[active_decision]",
									"value": "deny",
									"description": "Filter by the evaluation's decision. Allowed: `allow`, `deny`. Repeatable; values OR within the filter.",
									"disabled": true
								},
								{
									"key": "filter[principal_type]",
									"value": "user",
									"description": "Filter by principal type. Allowed: `user`, `application`. Repeatable; OR within the filter.",
									"disabled": true
								},
								{
									"key": "filter[subject_type]",
									"value": "user",
									"description": "Filter by subject type. Allowed: `user`, `application`. Rows with NULL subject_type are excluded when this filter is set.",
									"disabled": true
								},
								{
									"key": "filter[authority_type]",
									"value": "delegation",
									"description": "Filter by authority type. Allowed: `delegation`, `impersonation`. Rows with NULL authority_type are excluded when this filter is set.",
									"disabled": true
								},
								{
									"key": "filter[has_shadow]",
									"value": "true",
									"description": "Filter by shadow evaluation presence. `true` = shadow_psv_id IS NOT NULL; `false` = IS NULL; omit for all rows.",
									"disabled": true
								},
								{
									"key": "filter[principal_id]",
									"value": "",
									"description": "Exact-match filter on principal_id. Repeatable; values OR within the filter.",
									"disabled": true
								},
								{
									"key": "filter[resource_id]",
									"value": "",
									"description": "Exact-match filter on resource_id. Repeatable; values OR within the filter.",
									"disabled": true
								},
								{
									"key": "filter[subject_id]",
									"value": "",
									"description": "Exact-match filter on subject_id. Rows with NULL subject_id are excluded when this filter is set.",
									"disabled": true
								},
								{
									"key": "query[action]",
									"value": "",
									"description": "Case-insensitive substring match on `action`. Repeatable; multiple terms are OR-ed.",
									"disabled": true
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Response has items array', function () {",
									"    pm.expect(body.items).to.be.an('array');",
									"});",
									"pm.test('Response has pagination', function () {",
									"    pm.expect(body.pagination).to.be.an('object');",
									"});",
									"console.log('Evaluation requests count:', body.items.length);",
									"if (body.items.length > 0) {",
									"    var first = body.items[0];",
									"    console.log('First request:', first.principal_type, first.principal_id, first.action, '->', first.active_decision);",
									"}"
								]
							}
						}
					]
				}
			]
		},
		{
			"name": "6 — Rollback",
			"description": "Re-activate the platform-managed policy set version to revert custom policies.",
			"item": [
				{
					"name": "6.1 Rollback",
					"request": {
						"method": "PATCH",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets/{{managed_ps_id}}/versions/{{managed_ps_version_id}}",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets",
								"{{managed_ps_id}}",
								"versions",
								"{{managed_ps_version_id}}"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\"active\": true}"
						}
					}
				}
			]
		},
		{
			"name": "7 — Shadow Mode",
			"description": "Test a candidate policy set against production traffic without affecting authorization decisions. Shadow evaluation runs in parallel with the active binding; results are compared for agreement metrics.\n\nPrerequisites: sections 1–6 must be completed (authenticated, zone selected, custom policy set created, activated, then rolled back to managed). The shadow binding will use the custom policy set version created in section 3 against the active managed version.",
			"item": [
				{
					"name": "7.1 Set shadow binding",
					"description": "Bind the custom policy set version as the shadow for this zone. After section 6 rollback, the managed version is active, so we shadow the custom version against it. All subsequent /policy/check requests will evaluate against both the active (managed) and shadow (custom) policy sets.",
					"request": {
						"method": "PUT",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							},
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-bindings",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-bindings"
							]
						},
						"body": {
							"mode": "raw",
							"raw": "{\n  \"scope_type\": \"zone\",\n  \"mode\": \"shadow\",\n  \"policy_set_id\": \"{{policy_set_id}}\",\n  \"policy_set_version_id\": \"{{ps_version_id}}\"\n}"
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Shadow binding has id', function () {",
									"    pm.expect(body.id).to.not.be.undefined;",
									"});",
									"pm.environment.set('binding_id', body.id);",
									"pm.test('Shadow binding has policy_set_id', function () {",
									"    pm.expect(body.policy_set_id).to.not.be.undefined;",
									"});",
									"console.log('Shadow binding set: id=' + body.id + ', policy_set_id=' + body.policy_set_id);"
								]
							}
						}
					]
				},
				{
					"name": "7.2 Get shadow binding",
					"description": "Retrieve the current shadow binding by ID.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-bindings/{{binding_id}}",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-bindings",
								"{{binding_id}}"
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Has policy_set_version_id', function () {",
									"    pm.expect(body.policy_set_version_id).to.not.be.undefined;",
									"});",
									"pm.environment.set('shadow_psv_id', body.policy_set_version_id);",
									"console.log('Current shadow: policy_set_id=' + body.policy_set_id + ', psv_id=' + body.policy_set_version_id);"
								]
							}
						}
					]
				},
				{
					"name": "7.3 Verify shadow in policy set list",
					"description": "List policy sets and verify the shadow_version_id field is populated.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets"
							],
							"query": [
								{
									"key": "query[name]",
									"value": "",
									"description": "Case-insensitive substring match on `name`. Repeatable; multiple terms are OR-ed.",
									"disabled": true
								},
								{
									"key": "query[]",
									"value": "",
									"description": "Unscoped substring search (policy sets: `name`). Repeatable; OR-ed.",
									"disabled": true
								},
								{
									"key": "filter[owner_type]",
									"value": "customer",
									"description": "Exact-match filter: `platform` or `customer`.",
									"disabled": true
								},
								{
									"key": "filter[scope_type]",
									"value": "zone",
									"description": "Exact-match filter: `zone`, `resource`, `user`, or `session`.",
									"disabled": true
								},
								{
									"key": "filter[active]",
									"value": "true",
									"description": "Filter by active binding status. Replaces the deprecated `active` parameter.",
									"disabled": true
								},
								{
									"key": "active",
									"value": "true",
									"description": "DEPRECATED — use `filter[active]` instead.",
									"disabled": true
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"var items = body.items || [];",
									"var hasShadow = items.some(function(ps) { return ps.shadow_version_id; });",
									"pm.test('At least one policy set has shadow_version_id', function () {",
									"    pm.expect(hasShadow).to.be.true;",
									"});",
									"items.forEach(function(ps) {",
									"    if (ps.shadow_version_id) {",
									"        console.log('Policy set', ps.name, '- shadow version:', ps.shadow_version_id, 'v' + ps.shadow_version);",
									"    }",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "7.4 Get shadow binding metrics",
					"description": "Get agreement metrics for the current shadow binding (last 24 hours by default).",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-bindings/{{binding_id}}/metrics",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-bindings",
								"{{binding_id}}",
								"metrics"
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Has total_evaluations field', function () {",
									"    pm.expect(body.total_evaluations).to.be.a('number');",
									"});",
									"console.log('Total evaluations:', body.total_evaluations);",
									"console.log('Agreement rate:', body.agreement_rate);",
									"console.log('Agree:', body.agree_count, '| Shadow allow/Active deny:', body.shadow_allow_active_deny_count, '| Shadow deny/Active allow:', body.shadow_deny_active_allow_count);",
									"if (body.avg_shadow_duration_ms !== undefined) {",
									"    console.log('Avg shadow duration:', body.avg_shadow_duration_ms, 'ms (stddev:', body.stddev_shadow_duration_ms, 'ms)');",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "7.5 Get zone shadow metrics",
					"description": "Get zone-level shadow metrics across all pairings using scope=zone.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-bindings/{{binding_id}}/metrics?scope=zone",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-bindings",
								"{{binding_id}}",
								"metrics"
							],
							"query": [
								{
									"key": "scope",
									"value": "zone"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"console.log('Zone-level shadow metrics:', JSON.stringify(body, null, 2));"
								]
							}
						}
					]
				},
				{
					"name": "7.6 Get shadow metrics for PSV",
					"description": "Get shadow metrics filtered to a specific policy set version, including per-pairing breakdown.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-bindings/{{binding_id}}/metrics?policy_set_id={{policy_set_id}}&psv_id={{shadow_psv_id}}",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-bindings",
								"{{binding_id}}",
								"metrics"
							],
							"query": [
								{
									"key": "policy_set_id",
									"value": "{{policy_set_id}}"
								},
								{
									"key": "psv_id",
									"value": "{{shadow_psv_id}}"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"console.log('PSV shadow metrics:', JSON.stringify(body, null, 2));",
									"if (body.pairings && body.pairings.length > 0) {",
									"    console.log('Pairings found:', body.pairings.length);",
									"    body.pairings.forEach(function(p) {",
									"        console.log('  Active:', p.active_psv_id, 'Shadow:', p.shadow_psv_id, '| Total:', p.total, 'Agree:', p.agree_count);",
									"    });",
									"}"
								]
							}
						}
					]
				},
				{
					"name": "7.7 Delete shadow binding",
					"description": "Clear the shadow binding, stopping shadow evaluation for the zone.",
					"request": {
						"method": "DELETE",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-bindings/{{binding_id}}",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-bindings",
								"{{binding_id}}"
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 204 No Content', function () {",
									"    pm.response.to.have.status(204);",
									"});",
									"console.log('Shadow binding cleared.');"
								]
							}
						}
					]
				},
				{
					"name": "7.8 Verify shadow removed",
					"description": "Confirm no shadow bindings remain (expect empty list).",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-bindings?mode=shadow",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-bindings"
							],
							"query": [
								{
									"key": "mode",
									"value": "shadow"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('No shadow bindings remain', function () {",
									"    pm.expect(body.items).to.be.an('array').that.is.empty;",
									"});",
									"console.log('Shadow binding confirmed removed.');"
								]
							}
						}
					]
				}
			]
		},
		{
			"name": "8 — Query & Filter Examples",
			"description": "Demonstrates the list-endpoint query and filter parameters on policies and policy sets.\n\n- `query[<field>]=term` — case-insensitive substring match on a specific field. Repeatable; multiple values are OR-ed within a field.\n- `query[]=term` — unscoped substring search across all indexed fields of the resource (policies: name + description; policy sets: name).\n- `filter[<field>]=value` — exact match on an enum/bool field.\n\nThese examples assume section 2 and 3 have been run so the seed policy and policy set exist.\n\n**Evaluation requests list (8.14-8.19)** exercises the same conventions on `/policy-evaluations/requests` — enum filters (`active_decision`, `principal_type`, etc.), bool `filter[has_shadow]`, exact-match ID filters, `query[action]` ILIKE, and composite replay-analysis queries.",
			"item": [
				{
					"name": "8.1 List policies — substring match by name",
					"description": "Case-insensitive substring search on `name`. Matches the seed policy `require-token-credentials`.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies?query[name]=token",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies"
							],
							"query": [
								{
									"key": "query[name]",
									"value": "token"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every result name contains the search term', function () {",
									"    items.forEach(function (p) {",
									"        pm.expect(p.name.toLowerCase()).to.include('token');",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.2 List policies — multi-term name search (OR)",
					"description": "Multiple `query[name]` terms are OR-ed within a field. Matches any policy whose name contains `token` OR `access`.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies?query[name]=token&query[name]=access",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies"
							],
							"query": [
								{
									"key": "query[name]",
									"value": "token"
								},
								{
									"key": "query[name]",
									"value": "access"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every result matches at least one term', function () {",
									"    items.forEach(function (p) {",
									"        var lc = p.name.toLowerCase();",
									"        pm.expect(lc.includes('token') || lc.includes('access')).to.be.true;",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.3 List policies — unscoped search across name & description",
					"description": "`query[]` searches all indexed fields (for policies: `name` and `description`). Useful for a single search box UI.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies?query[]=credential",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies"
							],
							"query": [
								{
									"key": "query[]",
									"value": "credential"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every result matches name or description', function () {",
									"    items.forEach(function (p) {",
									"        var name = (p.name || '').toLowerCase();",
									"        var desc = (p.description || '').toLowerCase();",
									"        pm.expect(name.includes('credential') || desc.includes('credential')).to.be.true;",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.4 List policies — filter by owner_type (customer only)",
					"description": "Exact-match filter. Excludes platform-managed policies. Combine with `query[...]` for scoped searches over customer resources only. `expand[]=total_count` makes the response include a count consistent with the filter.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies?filter[owner_type]=customer&expand[]=total_count",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies"
							],
							"query": [
								{
									"key": "filter[owner_type]",
									"value": "customer"
								},
								{
									"key": "expand[]",
									"value": "total_count"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"var items = body.items || [];",
									"pm.test('No platform-owned policies in response', function () {",
									"    items.forEach(function (p) {",
									"        pm.expect(p.owner_type).to.equal('customer');",
									"    });",
									"});",
									"pm.test('total_count included in pagination block', function () {",
									"    pm.expect(body.pagination).to.have.property('total_count');",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.5 List policy sets — substring match by name",
					"description": "Case-insensitive substring search on `name`. Matches the seed policy set `custom-zone-policies`.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets?query[name]=custom",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets"
							],
							"query": [
								{
									"key": "query[name]",
									"value": "custom"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every policy set name contains the search term', function () {",
									"    items.forEach(function (ps) {",
									"        pm.expect(ps.name.toLowerCase()).to.include('custom');",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.6 List policy sets — filter by scope_type=zone",
					"description": "Exact-match filter on `scope_type`. Valid values: `zone`, `resource`, `user`, `session`.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets?filter[scope_type]=zone",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets"
							],
							"query": [
								{
									"key": "filter[scope_type]",
									"value": "zone"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every policy set has scope_type=zone', function () {",
									"    items.forEach(function (ps) {",
									"        pm.expect(ps.scope_type).to.equal('zone');",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.7 List policy sets — filter by active (new param)",
					"description": "`filter[active]=true` returns only policy sets with an active binding. Replaces the deprecated top-level `active` query parameter. Sending both with conflicting values returns 400.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets?filter[active]=true",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets"
							],
							"query": [
								{
									"key": "filter[active]",
									"value": "true"
								},
								{
									"key": "active",
									"value": "true",
									"description": "DEPRECATED — use filter[active] instead. Toggle on for comparison.",
									"disabled": true
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every policy set has active=true', function () {",
									"    items.forEach(function (ps) {",
									"        pm.expect(ps.active).to.equal(true);",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.8 List policy sets — conflicting active values return 400",
					"description": "When the deprecated `active` and new `filter[active]` are supplied with disagreeing values the service returns 400. Supplying them with the same value is accepted.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets?active=true&filter[active]=false",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets"
							],
							"query": [
								{
									"key": "active",
									"value": "true"
								},
								{
									"key": "filter[active]",
									"value": "false"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 400 Bad Request', function () {",
									"    pm.response.to.have.status(400);",
									"});",
									"",
									"pm.test('Error message mentions the conflict', function () {",
									"    var body = pm.response.json();",
									"    var msg = (body && (body.message || body.error || '')) + '';",
									"    pm.expect(msg.toLowerCase()).to.include('conflict');",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.9 List policy schemas — filter[default]=true (new param)",
					"description": "`filter[default]=true` returns only the zone’s default schema. Replaces the deprecated top-level `is_default` query parameter. Sending both with conflicting values returns 400.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-schemas?filter[default]=true",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-schemas"
							],
							"query": [
								{
									"key": "filter[default]",
									"value": "true"
								},
								{
									"key": "is_default",
									"value": "true",
									"description": "DEPRECATED — use filter[default] instead. Kept here disabled for toggle-on comparison.",
									"disabled": true
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every returned schema is the zone default', function () {",
									"    items.forEach(function (s) {",
									"        pm.expect(s.is_default).to.equal(true);",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.10 List policy schemas — conflicting is_default values return 400",
					"description": "When the deprecated `is_default` and new `filter[default]` are supplied with disagreeing values, the service returns 400. Supplying them with the same value is accepted.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-schemas?is_default=true&filter[default]=false",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-schemas"
							],
							"query": [
								{
									"key": "is_default",
									"value": "true"
								},
								{
									"key": "filter[default]",
									"value": "false"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 400 Bad Request', function () {",
									"    pm.response.to.have.status(400);",
									"});",
									"",
									"pm.test('Error message mentions the conflict', function () {",
									"    var body = pm.response.json();",
									"    var msg = (body && (body.message || body.error || '')) + '';",
									"    pm.expect(msg.toLowerCase()).to.include('conflict');",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.11 List policies — filter[owner_type] OR (repeated)",
					"description": "Repeating `filter[owner_type]` OR-s across values (`platform` OR `customer`). This is the multi-value shape introduced with the shared `FilterValues` schema. For a scalar field like `owner_type`, this is functionally equivalent to omitting the filter — but it demonstrates the wire form you would use for any endpoint-specific enum filter that actually partitions the result set. Contrast with 8.13, which shows why the comma form is **not** accepted.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies?filter[owner_type]=platform&filter[owner_type]=customer&expand[]=total_count",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies"
							],
							"query": [
								{
									"key": "filter[owner_type]",
									"value": "platform"
								},
								{
									"key": "filter[owner_type]",
									"value": "customer"
								},
								{
									"key": "expand[]",
									"value": "total_count"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"var items = body.items || [];",
									"pm.test('Every item has an allowed owner_type', function () {",
									"    items.forEach(function (p) {",
									"        pm.expect(['platform', 'customer']).to.include(p.owner_type);",
									"    });",
									"});",
									"var byOwner = items.reduce(function (acc, p) {",
									"    acc[p.owner_type] = (acc[p.owner_type] || 0) + 1;",
									"    return acc;",
									"}, {});",
									"console.log('owner_type breakdown:', JSON.stringify(byOwner));"
								]
							}
						}
					]
				},
				{
					"name": "8.12 List policy sets — filter[scope_type] OR (repeated)",
					"description": "Repeating `filter[scope_type]` OR-s across values. Returns policy sets scoped to `zone` OR `resource` but excludes `user` and `session`. Combine with `query[name]` for a name-substring search inside the selected scopes.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-sets?filter[scope_type]=zone&filter[scope_type]=resource&expand[]=total_count",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-sets"
							],
							"query": [
								{
									"key": "filter[scope_type]",
									"value": "zone"
								},
								{
									"key": "filter[scope_type]",
									"value": "resource"
								},
								{
									"key": "expand[]",
									"value": "total_count"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"var items = body.items || [];",
									"pm.test('Every item scope_type is zone or resource', function () {",
									"    items.forEach(function (ps) {",
									"        pm.expect(['zone', 'resource']).to.include(ps.scope_type);",
									"    });",
									"});",
									"pm.test('total_count included in pagination block', function () {",
									"    pm.expect(body.pagination).to.have.property('total_count');",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.13 Comma-separated filter value returns 400",
					"description": "Per the `FilterValues` wire contract, commas inside a single filter value mean AND-within-value. That form is nonsensical for scalar enum fields (a row cannot simultaneously equal two distinct enum values), so the server rejects it with a 400 and a hint that repeats the parameter for the OR form you probably wanted. Use repeated parameters (see 8.11) for OR.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policies?filter[owner_type]=platform,customer",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policies"
							],
							"query": [
								{
									"key": "filter[owner_type]",
									"value": "platform,customer"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 400 Bad Request', function () {",
									"    pm.response.to.have.status(400);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('Error message points at filter[owner_type]', function () {",
									"    pm.expect(body.message || '').to.include('filter[owner_type]');",
									"});",
									"pm.test('Error message explains the AND/OR distinction', function () {",
									"    pm.expect(body.message || '').to.match(/comma-separated|repeat the parameter/);",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.14 List evaluation requests — filter[active_decision]=deny",
					"description": "Enum filter on the rendered decision. Returns only evaluation requests that evaluated to `deny`. Core shape for impact-analysis: \"show me everything that was denied under the active policy set.\"",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations/requests?filter[active_decision]=deny",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations",
								"requests"
							],
							"query": [
								{
									"key": "filter[active_decision]",
									"value": "deny"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every row has active_decision=deny', function () {",
									"    items.forEach(function (r) {",
									"        pm.expect(r.active_decision).to.equal('deny');",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.15 List evaluation requests — filter[active_decision] OR (repeated)",
					"description": "Repeat the parameter to OR across enum values. Returns rows where `active_decision` is `allow` OR `deny` (effectively no filter, but the pattern matters for other filters like `principal_type`).",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations/requests?filter[active_decision]=allow&filter[active_decision]=deny",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations",
								"requests"
							],
							"query": [
								{
									"key": "filter[active_decision]",
									"value": "allow"
								},
								{
									"key": "filter[active_decision]",
									"value": "deny"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every row has allow or deny decision', function () {",
									"    items.forEach(function (r) {",
									"        pm.expect(['allow', 'deny']).to.include(r.active_decision);",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.16 List evaluation requests — filter[has_shadow]=true",
					"description": "Boolean filter: `true` returns only requests that had a shadow policy set version (`shadow_psv_id IS NOT NULL`), useful for isolating traffic evaluated against a staged replacement. `false` returns only requests without one. Omit the parameter for all rows.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations/requests?filter[has_shadow]=true",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations",
								"requests"
							],
							"query": [
								{
									"key": "filter[has_shadow]",
									"value": "true"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every row has a non-null shadow_psv_id', function () {",
									"    items.forEach(function (r) {",
									"        pm.expect(r.shadow_psv_id).to.not.be.null;",
									"        pm.expect(r.shadow_psv_id).to.not.be.undefined;",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.17 List evaluation requests — query[action] substring OR",
					"description": "Case-insensitive substring search on `action`, repeatable to OR multiple terms. Matches rows whose action contains `read` OR `write`. Useful when actions follow a naming convention like `read:doc` or `write:doc`.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations/requests?query[action]=read&query[action]=write",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations",
								"requests"
							],
							"query": [
								{
									"key": "query[action]",
									"value": "read"
								},
								{
									"key": "query[action]",
									"value": "write"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Every action contains read or write', function () {",
									"    items.forEach(function (r) {",
									"        var a = (r.action || '').toLowerCase();",
									"        pm.expect(a.includes('read') || a.includes('write')).to.be.true;",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.18 List evaluation requests — composite impact-analysis query",
					"description": "Realistic replay-analysis shape: find all `deny` decisions for a specific principal on read/write actions. Filters AND across axes; `query[action]` ORs within itself. Pair with `expand[]=total_count` to get the filtered set size.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations/requests?filter[active_decision]=deny&filter[principal_id]={{principal_id}}&query[action]=read&query[action]=write&expand[]=total_count",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations",
								"requests"
							],
							"query": [
								{
									"key": "filter[active_decision]",
									"value": "deny"
								},
								{
									"key": "filter[principal_id]",
									"value": "{{principal_id}}",
									"description": "Set the `principal_id` collection variable before running, e.g. to a known user or application ID from `/policy/check` traffic."
								},
								{
									"key": "query[action]",
									"value": "read"
								},
								{
									"key": "query[action]",
									"value": "write"
								},
								{
									"key": "expand[]",
									"value": "total_count"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var body = pm.response.json();",
									"pm.test('total_count is present and numeric', function () {",
									"    pm.expect(body.pagination).to.be.an('object');",
									"    pm.expect(body.pagination.total_count).to.be.a('number');",
									"});",
									"pm.test('Every row matches the composite filter', function () {",
									"    (body.items || []).forEach(function (r) {",
									"        pm.expect(r.active_decision).to.equal('deny');",
									"        var a = (r.action || '').toLowerCase();",
									"        pm.expect(a.includes('read') || a.includes('write')).to.be.true;",
									"    });",
									"});"
								]
							}
						}
					]
				},
				{
					"name": "8.19 List evaluation requests — sort ascending (oldest first)",
					"description": "Reverses the default ordering. Cursor pagination still works: the `before` / `after` cursors in `pagination` reflect the current sort direction.",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "Authorization",
								"value": "Bearer {{token}}"
							}
						],
						"url": {
							"raw": "{{base_url}}/zones/{{zone_id}}/policy-evaluations/requests?order=asc&limit=5",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"zones",
								"{{zone_id}}",
								"policy-evaluations",
								"requests"
							],
							"query": [
								{
									"key": "order",
									"value": "asc"
								},
								{
									"key": "limit",
									"value": "5"
								}
							]
						}
					},
					"event": [
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									"pm.test('Status is 200 OK', function () {",
									"    pm.response.to.have.status(200);",
									"});",
									"",
									"var items = (pm.response.json().items) || [];",
									"pm.test('Items are ordered by created_at ascending', function () {",
									"    for (var i = 1; i < items.length; i++) {",
									"        var a = new Date(items[i-1].created_at).getTime();",
									"        var b = new Date(items[i].created_at).getTime();",
									"        pm.expect(a).to.be.at.most(b);",
									"    }",
									"});"
								]
							}
						}
					]
				}
			]
		}
	]
}
