diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index e8c9b92..267f339 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agentlinkops", - "version": "0.6.12", + "version": "0.6.13", "description": "Connect an agent to AgentLinkOps and run backlink work with it: the connect skill (views, the three discovery verbs, evidence rules), local ledger and campaign skills, a portable CRM, the source-cited content pipeline, user-managed disavow lists, HTML reports and monitoring-event sync.", "author": { "name": "AgentLinkOps" diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index ff322fe..6fffa51 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agentlinkops", - "version": "0.6.12", + "version": "0.6.13", "description": "Connect an agent to AgentLinkOps and run backlink work with it: the connect skill (views, the three discovery verbs, evidence rules), local ledger and campaign skills, a portable CRM, the source-cited content pipeline, user-managed disavow lists, HTML reports and monitoring-event sync.", "author": { "name": "AgentLinkOps" diff --git a/CHANGELOG.md b/CHANGELOG.md index 70f0a60..47311c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to the `agentlinkops` package are recorded here. The version follows the plugin manifests in `.claude-plugin/` and `.codex-plugin/`. +## 0.6.13 (unreleased) + +- Show the latest attempt, conclusive source check and link verification separately in status, fleet and reports. Unknown checks retain the previous link verification for the same placement. +- Add `chronology pull` for saved placement history on compatible hosted versions and `chronology export` for frozen local pages. Exports retain denied origins, history gaps and partial paging. +- Preserve existing frozen version-two reports and reject exports that would replace an input or existing file. + ## 0.6.12 (2026-10-07) - Check every watch import result before updating sync mappings or reporting progress. Reject incomplete, duplicate or out-of-range results without resending the request. diff --git a/cli/catalog.js b/cli/catalog.js index 676742b..0507bdd 100644 --- a/cli/catalog.js +++ b/cli/catalog.js @@ -9,11 +9,12 @@ export const CATALOG_TOOLSETS = { "monitoring": "Watch earned links and destination URLs: create, list, update, import, export, recheck.", "evidence": "What a check observed: histories, snapshots, change feeds, check jobs, published contacts.", "rank": "Synthetic DataForSEO rank schedules and dated history; hosted collection disabled.", + "licensed": "Licensed source-search evidence and charge custody; operator admission required.", "discovery": "Import candidate rows, read stored runs, verify selected candidates, enroll them.", "baseline": "Scoped backlink baselines; supplier admission disabled.", "library": "Read and export the coverage-stated opportunity library.", "competitors": "Competitor sets, dated inventories, scheduled refresh, gap and domain-mix reports.", - "reports": "Profile, anchor and report summaries over the tracked dataset.", + "reports": "Placement chronology, service assurance and backlink reports.", "workspace": "Workspace, projects, usage, members, invitations, scratch-resource cleanup.", "notifications": "Email notification preferences, previews, tests and deliveries.", "webhooks": "Webhook endpoints, state, secrets and delivery records." @@ -21099,6 +21100,4233 @@ export const CATALOG_COMMANDS = [ "additionalProperties": {} } }, + { + "name": "configure_licensed_index_observations", + "toolset": "licensed", + "tier": "deferred", + "aliases": [], + "keywords": [ + "licensed index", + "site query", + "dataforseo" + ], + "confirm": "none", + "admissionGated": false, + "scopes": [ + "discovery:write", + "watches:write" + ], + "readOnly": false, + "description": "Configure the initial US/en licensed source-search observation lane for one project. Activation and supplier funding require separate operator admission.", + "inputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the project returned by its create or list operation." + }, + "enabled": { + "type": "boolean", + "description": "The enabled value; allowed values and bounds are specified in this schema." + }, + "locationCode": { + "type": "number", + "const": 2840, + "description": "The location code value; allowed values and bounds are specified in this schema." + }, + "language": { + "type": "string", + "const": "en", + "description": "The language value; allowed values and bounds are specified in this schema." + }, + "country": { + "type": "string", + "const": "US", + "description": "The country value; allowed values and bounds are specified in this schema." + }, + "dailyLimit": { + "description": "The daily limit value; allowed values and bounds are specified in this schema.", + "type": "integer", + "minimum": 1, + "maximum": 1000 + }, + "retentionDays": { + "description": "The retention days value; allowed values and bounds are specified in this schema.", + "type": "integer", + "minimum": 1, + "maximum": 90 + }, + "expectedRevision": { + "description": "Revision last read by the caller; mismatches reject concurrent updates.", + "anyOf": [ + { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "projectId", + "enabled", + "locationCode", + "language", + "country" + ], + "additionalProperties": false + }, + "outputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "settings": { + "anyOf": [ + { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "enabled": { + "type": "boolean" + }, + "revision": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "locationCode": { + "type": "number", + "const": 2840 + }, + "language": { + "type": "string", + "const": "en" + }, + "country": { + "type": "string", + "const": "US" + }, + "dailyLimit": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "retentionDays": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + } + }, + "required": [ + "projectId", + "enabled", + "revision", + "locationCode", + "language", + "country", + "dailyLimit", + "retentionDays", + "updatedAt" + ], + "additionalProperties": false + }, + { + "type": "null" + } + ] + }, + "transportEnabled": { + "type": "boolean" + } + }, + "required": [ + "projectId", + "settings", + "transportEnabled" + ], + "additionalProperties": {} + } + }, + { + "name": "get_licensed_index_settings", + "toolset": "licensed", + "tier": "deferred", + "aliases": [], + "keywords": [ + "licensed index", + "site query", + "dataforseo" + ], + "confirm": "none", + "admissionGated": false, + "scopes": [ + "discovery:read", + "watches:read" + ], + "readOnly": true, + "description": "Read project opt-in and transport configuration for licensed source-search observations. Configuration does not establish spending admission.", + "inputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the project returned by its create or list operation." + } + }, + "required": [ + "projectId" + ], + "additionalProperties": false + }, + "outputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "settings": { + "anyOf": [ + { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "enabled": { + "type": "boolean" + }, + "revision": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "locationCode": { + "type": "number", + "const": 2840 + }, + "language": { + "type": "string", + "const": "en" + }, + "country": { + "type": "string", + "const": "US" + }, + "dailyLimit": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "retentionDays": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + } + }, + "required": [ + "projectId", + "enabled", + "revision", + "locationCode", + "language", + "country", + "dailyLimit", + "retentionDays", + "updatedAt" + ], + "additionalProperties": false + }, + { + "type": "null" + } + ] + }, + "transportEnabled": { + "type": "boolean" + } + }, + "required": [ + "projectId", + "settings", + "transportEnabled" + ], + "additionalProperties": {} + } + }, + { + "name": "inspect_licensed_index_status", + "toolset": "licensed", + "tier": "deferred", + "aliases": [], + "keywords": [ + "licensed index", + "site query", + "dataforseo" + ], + "confirm": "none", + "admissionGated": false, + "scopes": [ + "discovery:write", + "watches:write" + ], + "readOnly": false, + "description": "Request one bounded licensed Google site-query observation for a monitored publisher URL. Sampled absence never establishes confirmed deindexing.", + "inputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the project returned by its create or list operation." + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the watch returned by its create or list operation." + }, + "idempotencyKey": { + "type": "string", + "pattern": "^[\\x21-\\x7e]{1,128}$", + "description": "Caller-generated key reused only for retries of the same operation and arguments in this workspace." + } + }, + "required": [ + "projectId", + "watchId", + "idempotencyKey" + ], + "additionalProperties": false + }, + "outputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "request": { + "anyOf": [ + { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "state": { + "type": "string", + "enum": [ + "reserved", + "dispatched", + "completed", + "uncertain", + "cancelled" + ] + }, + "createdAt": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "dispatchedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "completedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "cancelledAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "providerTaskId": { + "type": [ + "string", + "null" + ] + }, + "errorCode": { + "type": [ + "string", + "null" + ] + }, + "request": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "requestSha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "responseSha256": { + "anyOf": [ + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + { + "type": "null" + } + ] + }, + "observation": { + "anyOf": [ + { + "type": "object", + "properties": { + "observation_id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "checked_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "tier": { + "type": "string", + "enum": [ + "likely_indexed", + "not_found_in_site_query", + "unknown" + ] + }, + "confidence": { + "type": "string", + "enum": [ + "search_result_sample", + "unknown" + ] + }, + "reason": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "source_key": { + "type": "string" + } + }, + "required": [ + "observation_id", + "checked_at", + "tier", + "confidence", + "reason", + "url", + "source_key" + ], + "additionalProperties": {} + }, + { + "type": "null" + } + ] + }, + "evidenceAvailable": { + "type": "boolean" + }, + "rawResponse": { + "anyOf": [ + {}, + { + "type": "null" + } + ] + }, + "cost": { + "type": "object", + "properties": { + "ceilingMicrousd": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "actualMicrousd": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "state": { + "type": "string", + "enum": [ + "reserved", + "dispatched", + "ambiguous", + "consumed", + "released", + "unavailable" + ] + } + }, + "required": [ + "ceilingMicrousd", + "actualMicrousd", + "state" + ], + "additionalProperties": false + } + }, + "required": [ + "id", + "projectId", + "watchId", + "state", + "createdAt", + "dispatchedAt", + "completedAt", + "cancelledAt", + "providerTaskId", + "errorCode", + "request", + "requestSha256", + "responseSha256", + "observation", + "evidenceAvailable", + "rawResponse", + "cost" + ], + "additionalProperties": {} + }, + { + "type": "null" + } + ] + }, + "indexProjection": { + "type": "object", + "properties": { + "receiptId": { + "anyOf": [ + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + { + "type": "null" + } + ] + }, + "status": { + "type": "string", + "enum": [ + "retained", + "metadata_only", + "not_retained", + "not_projected", + "projection_unavailable" + ] + } + }, + "required": [ + "receiptId", + "status" + ], + "additionalProperties": {} + } + }, + "required": [ + "request", + "indexProjection" + ], + "additionalProperties": {} + } + }, + { + "name": "get_licensed_index_request", + "toolset": "licensed", + "tier": "deferred", + "aliases": [], + "keywords": [ + "licensed index", + "site query", + "dataforseo" + ], + "confirm": "none", + "admissionGated": false, + "scopes": [ + "discovery:read", + "watches:read" + ], + "readOnly": true, + "description": "Read a dated licensed source-search request, retained snapshot and cost settlement. This read performs no supplier call.", + "inputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the project returned by its create or list operation." + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the watch returned by its create or list operation." + }, + "requestId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the request returned by its create or list operation." + } + }, + "required": [ + "projectId", + "watchId", + "requestId" + ], + "additionalProperties": false + }, + "outputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "request": { + "anyOf": [ + { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "state": { + "type": "string", + "enum": [ + "reserved", + "dispatched", + "completed", + "uncertain", + "cancelled" + ] + }, + "createdAt": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "dispatchedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "completedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "cancelledAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "providerTaskId": { + "type": [ + "string", + "null" + ] + }, + "errorCode": { + "type": [ + "string", + "null" + ] + }, + "request": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "requestSha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "responseSha256": { + "anyOf": [ + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + { + "type": "null" + } + ] + }, + "observation": { + "anyOf": [ + { + "type": "object", + "properties": { + "observation_id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "checked_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "tier": { + "type": "string", + "enum": [ + "likely_indexed", + "not_found_in_site_query", + "unknown" + ] + }, + "confidence": { + "type": "string", + "enum": [ + "search_result_sample", + "unknown" + ] + }, + "reason": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "source_key": { + "type": "string" + } + }, + "required": [ + "observation_id", + "checked_at", + "tier", + "confidence", + "reason", + "url", + "source_key" + ], + "additionalProperties": {} + }, + { + "type": "null" + } + ] + }, + "evidenceAvailable": { + "type": "boolean" + }, + "rawResponse": { + "anyOf": [ + {}, + { + "type": "null" + } + ] + }, + "cost": { + "type": "object", + "properties": { + "ceilingMicrousd": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "actualMicrousd": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "state": { + "type": "string", + "enum": [ + "reserved", + "dispatched", + "ambiguous", + "consumed", + "released", + "unavailable" + ] + } + }, + "required": [ + "ceilingMicrousd", + "actualMicrousd", + "state" + ], + "additionalProperties": false + } + }, + "required": [ + "id", + "projectId", + "watchId", + "state", + "createdAt", + "dispatchedAt", + "completedAt", + "cancelledAt", + "providerTaskId", + "errorCode", + "request", + "requestSha256", + "responseSha256", + "observation", + "evidenceAvailable", + "rawResponse", + "cost" + ], + "additionalProperties": {} + }, + { + "type": "null" + } + ] + }, + "indexProjection": { + "type": "object", + "properties": { + "receiptId": { + "anyOf": [ + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + { + "type": "null" + } + ] + }, + "status": { + "type": "string", + "enum": [ + "retained", + "metadata_only", + "not_retained", + "not_projected", + "projection_unavailable" + ] + } + }, + "required": [ + "receiptId", + "status" + ], + "additionalProperties": {} + } + }, + "required": [ + "request", + "indexProjection" + ], + "additionalProperties": {} + } + }, + { + "name": "cancel_licensed_index_request", + "toolset": "licensed", + "tier": "deferred", + "aliases": [], + "keywords": [ + "licensed index", + "site query", + "dataforseo" + ], + "confirm": "none", + "admissionGated": false, + "scopes": [ + "discovery:write", + "watches:write" + ], + "readOnly": false, + "description": "Cancel an undispatched licensed-search reservation or hold an already dispatched uncertain effect. Cancellation does not prove a remote task was cancelled.", + "inputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the project returned by its create or list operation." + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the watch returned by its create or list operation." + }, + "requestId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the request returned by its create or list operation." + } + }, + "required": [ + "projectId", + "watchId", + "requestId" + ], + "additionalProperties": false + }, + "outputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "request": { + "anyOf": [ + { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "state": { + "type": "string", + "enum": [ + "reserved", + "dispatched", + "completed", + "uncertain", + "cancelled" + ] + }, + "createdAt": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "dispatchedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "completedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "cancelledAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "providerTaskId": { + "type": [ + "string", + "null" + ] + }, + "errorCode": { + "type": [ + "string", + "null" + ] + }, + "request": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "requestSha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "responseSha256": { + "anyOf": [ + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + { + "type": "null" + } + ] + }, + "observation": { + "anyOf": [ + { + "type": "object", + "properties": { + "observation_id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "checked_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "tier": { + "type": "string", + "enum": [ + "likely_indexed", + "not_found_in_site_query", + "unknown" + ] + }, + "confidence": { + "type": "string", + "enum": [ + "search_result_sample", + "unknown" + ] + }, + "reason": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "source_key": { + "type": "string" + } + }, + "required": [ + "observation_id", + "checked_at", + "tier", + "confidence", + "reason", + "url", + "source_key" + ], + "additionalProperties": {} + }, + { + "type": "null" + } + ] + }, + "evidenceAvailable": { + "type": "boolean" + }, + "rawResponse": { + "anyOf": [ + {}, + { + "type": "null" + } + ] + }, + "cost": { + "type": "object", + "properties": { + "ceilingMicrousd": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "actualMicrousd": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "state": { + "type": "string", + "enum": [ + "reserved", + "dispatched", + "ambiguous", + "consumed", + "released", + "unavailable" + ] + } + }, + "required": [ + "ceilingMicrousd", + "actualMicrousd", + "state" + ], + "additionalProperties": false + } + }, + "required": [ + "id", + "projectId", + "watchId", + "state", + "createdAt", + "dispatchedAt", + "completedAt", + "cancelledAt", + "providerTaskId", + "errorCode", + "request", + "requestSha256", + "responseSha256", + "observation", + "evidenceAvailable", + "rawResponse", + "cost" + ], + "additionalProperties": {} + }, + { + "type": "null" + } + ] + }, + "indexProjection": { + "type": "object", + "properties": { + "receiptId": { + "anyOf": [ + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + { + "type": "null" + } + ] + }, + "status": { + "type": "string", + "enum": [ + "retained", + "metadata_only", + "not_retained", + "not_projected", + "projection_unavailable" + ] + } + }, + "required": [ + "receiptId", + "status" + ], + "additionalProperties": {} + } + }, + "required": [ + "request", + "indexProjection" + ], + "additionalProperties": {} + } + }, + { + "name": "reconcile_licensed_index_request", + "toolset": "licensed", + "tier": "deferred", + "aliases": [], + "keywords": [ + "licensed index", + "site query", + "dataforseo" + ], + "confirm": "none", + "admissionGated": false, + "scopes": [ + "discovery:write", + "watches:write" + ], + "readOnly": false, + "description": "Reconcile an uncertain licensed-search effect using an operator-trusted supplier receipt. The original provider request is never resubmitted.", + "inputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the project returned by its create or list operation." + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the watch returned by its create or list operation." + }, + "requestId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the request returned by its create or list operation." + }, + "receiptReference": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "The receipt reference value; allowed values and bounds are specified in this schema." + } + }, + "required": [ + "projectId", + "watchId", + "requestId", + "receiptReference" + ], + "additionalProperties": false + }, + "outputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "request": { + "anyOf": [ + { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "state": { + "type": "string", + "enum": [ + "reserved", + "dispatched", + "completed", + "uncertain", + "cancelled" + ] + }, + "createdAt": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "dispatchedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "completedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "cancelledAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "providerTaskId": { + "type": [ + "string", + "null" + ] + }, + "errorCode": { + "type": [ + "string", + "null" + ] + }, + "request": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "requestSha256": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "responseSha256": { + "anyOf": [ + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + { + "type": "null" + } + ] + }, + "observation": { + "anyOf": [ + { + "type": "object", + "properties": { + "observation_id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "checked_at": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "tier": { + "type": "string", + "enum": [ + "likely_indexed", + "not_found_in_site_query", + "unknown" + ] + }, + "confidence": { + "type": "string", + "enum": [ + "search_result_sample", + "unknown" + ] + }, + "reason": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "source_key": { + "type": "string" + } + }, + "required": [ + "observation_id", + "checked_at", + "tier", + "confidence", + "reason", + "url", + "source_key" + ], + "additionalProperties": {} + }, + { + "type": "null" + } + ] + }, + "evidenceAvailable": { + "type": "boolean" + }, + "rawResponse": { + "anyOf": [ + {}, + { + "type": "null" + } + ] + }, + "cost": { + "type": "object", + "properties": { + "ceilingMicrousd": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "actualMicrousd": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "state": { + "type": "string", + "enum": [ + "reserved", + "dispatched", + "ambiguous", + "consumed", + "released", + "unavailable" + ] + } + }, + "required": [ + "ceilingMicrousd", + "actualMicrousd", + "state" + ], + "additionalProperties": false + } + }, + "required": [ + "id", + "projectId", + "watchId", + "state", + "createdAt", + "dispatchedAt", + "completedAt", + "cancelledAt", + "providerTaskId", + "errorCode", + "request", + "requestSha256", + "responseSha256", + "observation", + "evidenceAvailable", + "rawResponse", + "cost" + ], + "additionalProperties": {} + }, + { + "type": "null" + } + ] + }, + "indexProjection": { + "type": "object", + "properties": { + "receiptId": { + "anyOf": [ + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + { + "type": "null" + } + ] + }, + "status": { + "type": "string", + "enum": [ + "retained", + "metadata_only", + "not_retained", + "not_projected", + "projection_unavailable" + ] + } + }, + "required": [ + "receiptId", + "status" + ], + "additionalProperties": {} + } + }, + "required": [ + "request", + "indexProjection" + ], + "additionalProperties": {} + } + }, + { + "name": "get_placement_chronology", + "toolset": "reports", + "tier": "deferred", + "aliases": [], + "keywords": [ + "placement history", + "chronology", + "timeline", + "export" + ], + "admissionGated": false, + "scopes": [ + "watches:read" + ], + "readOnly": true, + "description": "Read one monitored placement’s retained source, target and index history with frozen continuation and explicit evidence gaps. This read performs no new checks.", + "examples": [ + { + "watchId": "watch_example", + "limit": 50 + } + ], + "inputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the watch returned by its create or list operation." + }, + "limit": { + "description": "Maximum rows in this page or bounded report; subject to the schema maximum.", + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "cursor": { + "description": "Opaque continuation returned by this same listing; omit for the first page.", + "type": "string", + "maxLength": 12000 + }, + "streams": { + "description": "The streams value; allowed values and bounds are specified in this schema.", + "minItems": 1, + "maxItems": 8, + "type": "array", + "items": { + "type": "string", + "enum": [ + "context", + "link_observations", + "target_observations", + "link_events", + "target_events", + "index_observations", + "index_events", + "local_submissions" + ] + } + } + }, + "required": [ + "watchId" + ], + "additionalProperties": false + }, + "outputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "schemaVersion": { + "type": "number", + "const": 1 + }, + "identity": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "sourceUrl": { + "type": "string", + "format": "uri" + }, + "targetUrl": { + "type": "string", + "format": "uri" + }, + "targetScope": { + "type": "string", + "enum": [ + "exact", + "domain", + "subdomain", + "path" + ] + }, + "targetId": { + "anyOf": [ + { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + { + "type": "null" + } + ] + }, + "localReference": { + "type": [ + "string", + "null" + ] + }, + "matchBasis": { + "type": "string", + "const": "configured_target_url" + } + }, + "required": [ + "workspaceId", + "projectId", + "watchId", + "sourceUrl", + "targetUrl", + "targetScope", + "targetId", + "localReference", + "matchBasis" + ], + "additionalProperties": false + }, + "asOf": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "snapshotId": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "rawId": { + "type": "string" + }, + "stream": { + "type": "string", + "enum": [ + "context", + "link_observations", + "target_observations", + "link_events", + "target_events", + "index_observations", + "index_events", + "local_submissions" + ] + }, + "kind": { + "type": "string" + }, + "identity": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "watchId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "sourceUrl": { + "type": "string", + "format": "uri" + }, + "targetUrl": { + "type": "string", + "format": "uri" + }, + "targetScope": { + "type": "string", + "enum": [ + "exact", + "domain", + "subdomain", + "path" + ] + }, + "targetId": { + "anyOf": [ + { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + { + "type": "null" + } + ] + }, + "localReference": { + "type": [ + "string", + "null" + ] + }, + "matchBasis": { + "type": "string", + "const": "configured_target_url" + } + }, + "required": [ + "workspaceId", + "projectId", + "watchId", + "sourceUrl", + "targetUrl", + "targetScope", + "targetId", + "localReference", + "matchBasis" + ], + "additionalProperties": false + }, + "observedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "recordedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "sortAt": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "state": { + "type": [ + "string", + "null" + ] + }, + "reason": { + "type": [ + "string", + "null" + ] + }, + "sourceKey": { + "type": [ + "string", + "null" + ] + }, + "method": { + "type": [ + "string", + "null" + ] + }, + "checkerVersion": { + "type": [ + "string", + "null" + ] + }, + "evidence": { + "type": "object", + "properties": { + "sha256": { + "type": [ + "string", + "null" + ] + }, + "reference": { + "type": [ + "string", + "null" + ] + }, + "expiresAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "availability": { + "type": "string" + } + }, + "required": [ + "sha256", + "reference", + "expiresAt", + "availability" + ], + "additionalProperties": {} + }, + "data": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "id", + "rawId", + "stream", + "kind", + "identity", + "observedAt", + "recordedAt", + "sortAt", + "state", + "reason", + "sourceKey", + "method", + "checkerVersion", + "evidence", + "data" + ], + "additionalProperties": {} + } + }, + "pageCursor": { + "type": [ + "string", + "null" + ] + }, + "nextCursor": { + "type": [ + "string", + "null" + ] + }, + "hasMore": { + "type": "boolean" + }, + "coverage": { + "type": "object", + "propertyNames": { + "type": "string", + "enum": [ + "context", + "link_observations", + "target_observations", + "link_events", + "target_events", + "index_observations", + "index_events", + "local_submissions" + ] + }, + "additionalProperties": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "available", + "denied", + "unavailable" + ] + }, + "reason": { + "type": "string" + } + }, + "required": [ + "status", + "reason" + ], + "additionalProperties": {} + } + }, + "historyMeaning": { + "type": "string" + } + }, + "required": [ + "schemaVersion", + "identity", + "asOf", + "snapshotId", + "items", + "pageCursor", + "nextCursor", + "hasMore", + "coverage", + "historyMeaning" + ], + "additionalProperties": {} + } + }, + { + "name": "get_monitoring_service_assurance", + "toolset": "reports", + "tier": "deferred", + "aliases": [], + "keywords": [ + "freshness", + "coverage", + "service health" + ], + "admissionGated": false, + "scopes": [ + "watches:read" + ], + "readOnly": true, + "description": "Read supplied-record coverage, freshness and scheduler availability for one project. Unknown evidence and unproved delivery or soak remain explicit.", + "examples": [ + { + "projectId": "pr_example" + } + ], + "inputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Identifier of the project returned by its create or list operation." + } + }, + "required": [ + "projectId" + ], + "additionalProperties": false + }, + "outputSchema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "schemaVersion": { + "type": "number", + "const": 1 + }, + "workspaceId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "projectId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "asOf": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "source": { + "type": "object", + "properties": { + "supplied": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "active": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "paused": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "neverAttempted": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "neverConclusive": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "due": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "overdue": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "currentUnknown": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "latestAttemptAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestAttemptAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestAttemptAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "latestConclusiveAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestConclusiveAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestConclusiveAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "supplied", + "active", + "paused", + "neverAttempted", + "neverConclusive", + "due", + "overdue", + "currentUnknown", + "latestAttemptAt", + "oldestAttemptAt", + "oldestAttemptAgeSeconds", + "latestConclusiveAt", + "oldestConclusiveAt", + "oldestConclusiveAgeSeconds" + ], + "additionalProperties": false + }, + "target": { + "type": "object", + "properties": { + "supplied": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "active": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "paused": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "neverAttempted": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "neverConclusive": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "due": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "overdue": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "currentUnknown": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "latestAttemptAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestAttemptAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestAttemptAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "latestConclusiveAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestConclusiveAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestConclusiveAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "supplied", + "active", + "paused", + "neverAttempted", + "neverConclusive", + "due", + "overdue", + "currentUnknown", + "latestAttemptAt", + "oldestAttemptAt", + "oldestAttemptAgeSeconds", + "latestConclusiveAt", + "oldestConclusiveAt", + "oldestConclusiveAgeSeconds" + ], + "additionalProperties": false + }, + "monitoringProjection": { + "type": "object", + "properties": { + "schemaVersion": { + "type": "number", + "const": 1 + }, + "source": { + "type": "object", + "properties": { + "coverage": { + "type": "object", + "properties": { + "supplied": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "active": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "paused": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "recordedHeld": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "schedulingCandidates": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "busy": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "dueCandidates": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "eligibility": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "unavailable" + }, + "eligible": { + "type": "null" + }, + "reason": { + "type": "string", + "const": "admission_not_rechecked" + } + }, + "required": [ + "status", + "eligible", + "reason" + ], + "additionalProperties": false + }, + "denominatorMeaning": { + "type": "string" + }, + "freshnessWindow": { + "type": "string" + }, + "cadenceSeconds": { + "type": "object", + "properties": { + "minimum": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "maximum": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "minimum", + "maximum" + ], + "additionalProperties": false + }, + "oldestOverdueAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestOverdueAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "nextScheduledAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "nextEligibleAt": { + "type": "null" + }, + "nextEligibleReason": { + "type": "string", + "const": "admission_not_rechecked" + }, + "neverAttempted": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "neverConclusive": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "currentUnknown": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "unknownReasons": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "freshConclusive": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "staleConclusive": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "shares": { + "type": "object", + "properties": { + "currentUnknown": { + "anyOf": [ + { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + { + "type": "null" + } + ] + }, + "neverAttempted": { + "anyOf": [ + { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + { + "type": "null" + } + ] + }, + "freshConclusive": { + "anyOf": [ + { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "currentUnknown", + "neverAttempted", + "freshConclusive" + ], + "additionalProperties": false + }, + "shareMeaning": { + "type": "string" + }, + "freshRetainedLinkVerification": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "linkVerificationMeaning": { + "type": "string" + }, + "reasonCounts": { + "type": "object", + "properties": { + "due": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "deferred": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "unavailable": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + } + }, + "required": [ + "due", + "deferred" + ], + "additionalProperties": false + } + }, + "required": [ + "supplied", + "active", + "paused", + "recordedHeld", + "schedulingCandidates", + "busy", + "dueCandidates", + "eligibility", + "denominatorMeaning", + "freshnessWindow", + "cadenceSeconds", + "oldestOverdueAt", + "oldestOverdueAgeSeconds", + "nextScheduledAt", + "nextEligibleAt", + "nextEligibleReason", + "neverAttempted", + "neverConclusive", + "currentUnknown", + "unknownReasons", + "freshConclusive", + "staleConclusive", + "shares", + "shareMeaning", + "reasonCounts" + ], + "additionalProperties": false + }, + "jobs": { + "type": "object", + "properties": { + "retained": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "queued": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "running": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "succeeded": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "failed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "cancelled": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "everClaimed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "claimAttempts": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "retryClaims": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "retryExhausted": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "expiredRunningLeases": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "oldestQueuedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestQueuedAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "oldestRunningAdmissionAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestRunningAdmissionAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "latestAdmissionAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "latestCompletionAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "scopedRetainedDeadLetters": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "deadLetterMeaning": { + "type": "string" + }, + "admissionToTerminal": { + "type": "object", + "properties": { + "samples": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "minimumSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "maximumSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "meaning": { + "type": "string" + } + }, + "required": [ + "samples", + "minimumSeconds", + "maximumSeconds", + "meaning" + ], + "additionalProperties": false + }, + "startedAt": { + "type": "null" + }, + "queueWaitSeconds": { + "type": "null" + }, + "providerLatencySeconds": { + "type": "null" + }, + "timingReason": { + "type": "string", + "const": "first_start_and_provider_timing_not_retained" + }, + "dispatch": { + "type": "object", + "properties": { + "outstanding": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "deferred": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "expiredSendingLeases": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "nextDispatchAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "meaning": { + "type": "string" + } + }, + "required": [ + "outstanding", + "deferred", + "expiredSendingLeases", + "nextDispatchAt", + "meaning" + ], + "additionalProperties": false + }, + "historyMeaning": { + "type": "string" + } + }, + "required": [ + "retained", + "queued", + "running", + "succeeded", + "failed", + "cancelled", + "everClaimed", + "claimAttempts", + "retryClaims", + "retryExhausted", + "expiredRunningLeases", + "oldestQueuedAt", + "oldestQueuedAgeSeconds", + "oldestRunningAdmissionAt", + "oldestRunningAdmissionAgeSeconds", + "latestAdmissionAt", + "latestCompletionAt", + "scopedRetainedDeadLetters", + "deadLetterMeaning", + "admissionToTerminal", + "startedAt", + "queueWaitSeconds", + "providerLatencySeconds", + "timingReason", + "dispatch", + "historyMeaning" + ], + "additionalProperties": false + } + }, + "required": [ + "coverage", + "jobs" + ], + "additionalProperties": false + }, + "target": { + "type": "object", + "properties": { + "coverage": { + "type": "object", + "properties": { + "supplied": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "active": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "paused": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "recordedHeld": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "schedulingCandidates": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "busy": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "dueCandidates": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "eligibility": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "unavailable" + }, + "eligible": { + "type": "null" + }, + "reason": { + "type": "string", + "const": "admission_not_rechecked" + } + }, + "required": [ + "status", + "eligible", + "reason" + ], + "additionalProperties": false + }, + "denominatorMeaning": { + "type": "string" + }, + "freshnessWindow": { + "type": "string" + }, + "cadenceSeconds": { + "type": "object", + "properties": { + "minimum": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "maximum": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "minimum", + "maximum" + ], + "additionalProperties": false + }, + "oldestOverdueAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestOverdueAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "nextScheduledAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "nextEligibleAt": { + "type": "null" + }, + "nextEligibleReason": { + "type": "string", + "const": "admission_not_rechecked" + }, + "neverAttempted": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "neverConclusive": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "currentUnknown": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "unknownReasons": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "freshConclusive": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "staleConclusive": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "shares": { + "type": "object", + "properties": { + "currentUnknown": { + "anyOf": [ + { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + { + "type": "null" + } + ] + }, + "neverAttempted": { + "anyOf": [ + { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + { + "type": "null" + } + ] + }, + "freshConclusive": { + "anyOf": [ + { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "currentUnknown", + "neverAttempted", + "freshConclusive" + ], + "additionalProperties": false + }, + "shareMeaning": { + "type": "string" + }, + "freshRetainedLinkVerification": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "linkVerificationMeaning": { + "type": "string" + }, + "reasonCounts": { + "type": "object", + "properties": { + "due": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "deferred": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "unavailable": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + } + }, + "required": [ + "due", + "deferred" + ], + "additionalProperties": false + } + }, + "required": [ + "supplied", + "active", + "paused", + "recordedHeld", + "schedulingCandidates", + "busy", + "dueCandidates", + "eligibility", + "denominatorMeaning", + "freshnessWindow", + "cadenceSeconds", + "oldestOverdueAt", + "oldestOverdueAgeSeconds", + "nextScheduledAt", + "nextEligibleAt", + "nextEligibleReason", + "neverAttempted", + "neverConclusive", + "currentUnknown", + "unknownReasons", + "freshConclusive", + "staleConclusive", + "shares", + "shareMeaning", + "reasonCounts" + ], + "additionalProperties": false + }, + "jobs": { + "type": "object", + "properties": { + "retained": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "queued": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "running": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "succeeded": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "failed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "cancelled": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "everClaimed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "claimAttempts": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "retryClaims": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "retryExhausted": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "expiredRunningLeases": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "oldestQueuedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestQueuedAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "oldestRunningAdmissionAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestRunningAdmissionAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "latestAdmissionAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "latestCompletionAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "scopedRetainedDeadLetters": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "deadLetterMeaning": { + "type": "string" + }, + "admissionToTerminal": { + "type": "object", + "properties": { + "samples": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "minimumSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "maximumSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "meaning": { + "type": "string" + } + }, + "required": [ + "samples", + "minimumSeconds", + "maximumSeconds", + "meaning" + ], + "additionalProperties": false + }, + "startedAt": { + "type": "null" + }, + "queueWaitSeconds": { + "type": "null" + }, + "providerLatencySeconds": { + "type": "null" + }, + "timingReason": { + "type": "string", + "const": "first_start_and_provider_timing_not_retained" + }, + "dispatch": { + "type": "object", + "properties": { + "outstanding": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "deferred": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "expiredSendingLeases": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "nextDispatchAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "meaning": { + "type": "string" + } + }, + "required": [ + "outstanding", + "deferred", + "expiredSendingLeases", + "nextDispatchAt", + "meaning" + ], + "additionalProperties": false + }, + "historyMeaning": { + "type": "string" + } + }, + "required": [ + "retained", + "queued", + "running", + "succeeded", + "failed", + "cancelled", + "everClaimed", + "claimAttempts", + "retryClaims", + "retryExhausted", + "expiredRunningLeases", + "oldestQueuedAt", + "oldestQueuedAgeSeconds", + "oldestRunningAdmissionAt", + "oldestRunningAdmissionAgeSeconds", + "latestAdmissionAt", + "latestCompletionAt", + "scopedRetainedDeadLetters", + "deadLetterMeaning", + "admissionToTerminal", + "startedAt", + "queueWaitSeconds", + "providerLatencySeconds", + "timingReason", + "dispatch", + "historyMeaning" + ], + "additionalProperties": false + } + }, + "required": [ + "coverage", + "jobs" + ], + "additionalProperties": false + }, + "index": { + "oneOf": [ + { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "denied" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "status", + "reason" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "unavailable" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "status", + "reason" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "available" + }, + "reason": { + "type": "string" + }, + "suppliedSourceWatches": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "activeSourceWatches": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "lanes": { + "minItems": 2, + "maxItems": 2, + "type": "array", + "items": { + "type": "object", + "properties": { + "lane": { + "type": "string", + "enum": [ + "gsc", + "licensed_site" + ] + }, + "retainedStates": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "observedActiveWatches": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "neverObservedActiveWatches": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "currentUnknownStates": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "latestObservationAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestObservationAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestObservationAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "lane", + "retainedStates", + "observedActiveWatches", + "neverObservedActiveWatches", + "currentUnknownStates", + "latestObservationAt", + "oldestObservationAt", + "oldestObservationAgeSeconds" + ], + "additionalProperties": false + } + }, + "schedule": { + "oneOf": [ + { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "unavailable" + }, + "reason": { + "type": "string", + "const": "schema_unavailable" + } + }, + "required": [ + "status", + "reason" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "available" + }, + "projectOptedIn": { + "type": "boolean" + }, + "inspectionEnabled": { + "type": "boolean" + }, + "schedulerEnabled": { + "type": "boolean" + }, + "cadenceSeconds": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "dailyLimit": { + "anyOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + { + "type": "null" + } + ] + }, + "nextProjectScanAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "propertyEligibleWatches": { + "type": "null" + }, + "propertyEligibilityReason": { + "type": "string", + "const": "current_source_property_grant_not_assessed" + }, + "eligibleWatches": { + "type": "null" + }, + "eligibilityReason": { + "type": "string", + "const": "admission_not_rechecked" + } + }, + "required": [ + "status", + "projectOptedIn", + "inspectionEnabled", + "schedulerEnabled", + "cadenceSeconds", + "dailyLimit", + "nextProjectScanAt", + "propertyEligibleWatches", + "propertyEligibilityReason", + "eligibleWatches", + "eligibilityReason" + ], + "additionalProperties": false + } + ] + }, + "meaning": { + "type": "string" + } + }, + "required": [ + "status", + "reason", + "suppliedSourceWatches", + "activeSourceWatches", + "lanes", + "schedule", + "meaning" + ], + "additionalProperties": false + } + ] + }, + "serviceTickWindow": { + "type": "object", + "properties": { + "expectedTicks": { + "type": "null" + }, + "completedTicks": { + "type": "null" + }, + "availabilityShare": { + "type": "null" + }, + "reason": { + "type": "string", + "const": "tick_history_not_retained" + } + }, + "required": [ + "expectedTicks", + "completedTicks", + "availabilityShare", + "reason" + ], + "additionalProperties": false + }, + "capacity": { + "type": "object", + "properties": { + "dueOpportunities": { + "type": "null" + }, + "missedOpportunities": { + "type": "null" + }, + "checksPerEligibleWatch": { + "type": "null" + }, + "reason": { + "type": "string", + "const": "bounded_roster_opportunity_history_not_retained" + } + }, + "required": [ + "dueOpportunities", + "missedOpportunities", + "checksPerEligibleWatch", + "reason" + ], + "additionalProperties": false + }, + "meaning": { + "type": "string" + } + }, + "required": [ + "schemaVersion", + "source", + "target", + "index", + "serviceTickWindow", + "capacity", + "meaning" + ], + "additionalProperties": false + }, + "sourceLinkVerification": { + "type": "object", + "properties": { + "latestRetainedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestRetainedAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "observedWatches": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "meaning": { + "type": "string" + } + }, + "required": [ + "latestRetainedAt", + "oldestRetainedAt", + "observedWatches", + "meaning" + ], + "additionalProperties": false + }, + "sourceJobs": { + "type": "object", + "properties": { + "queued": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "running": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "required": [ + "queued", + "running" + ], + "additionalProperties": false + }, + "overdueReasons": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "index": { + "oneOf": [ + { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "available" + }, + "reason": { + "type": "string" + }, + "observedWatches": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "latestObservationAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestObservationAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "oldestObservationAgeSeconds": { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "null" + } + ] + }, + "denominator": { + "type": "string" + } + }, + "required": [ + "status", + "reason", + "observedWatches", + "latestObservationAt", + "oldestObservationAt", + "oldestObservationAgeSeconds", + "denominator" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "denied" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "status", + "reason" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "unavailable" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "status", + "reason" + ], + "additionalProperties": false + } + ] + }, + "serviceTicks": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "available", + "unavailable" + ] + }, + "meaning": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "plan": { + "type": "string" + }, + "latestAttemptAt": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + "latestCompletionAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "latestSuccessAt": { + "anyOf": [ + { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" + }, + { + "type": "null" + } + ] + }, + "latestOutcome": { + "type": "string", + "enum": [ + "running", + "succeeded", + "failed" + ] + }, + "ageSeconds": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "plan", + "latestAttemptAt", + "latestCompletionAt", + "latestSuccessAt", + "latestOutcome", + "ageSeconds" + ], + "additionalProperties": false + } + } + }, + "required": [ + "status", + "meaning", + "items" + ], + "additionalProperties": false + }, + "assurance": { + "type": "object", + "properties": { + "elapsedSoak": { + "type": "string", + "const": "not_established" + }, + "backupRestore": { + "type": "string", + "const": "not_established" + }, + "externalDelivery": { + "type": "string", + "const": "not_established" + } + }, + "required": [ + "elapsedSoak", + "backupRestore", + "externalDelivery" + ], + "additionalProperties": false + }, + "denominator": { + "type": "string" + } + }, + "required": [ + "schemaVersion", + "workspaceId", + "projectId", + "asOf", + "source", + "target", + "sourceLinkVerification", + "sourceJobs", + "overdueReasons", + "index", + "serviceTicks", + "assurance", + "denominator" + ], + "additionalProperties": {} + } + }, { "name": "list_index_observations", "toolset": "evidence", @@ -21609,6 +25837,11 @@ export const CATALOG_COMMANDS = [ "type": "integer", "minimum": 1, "maximum": 100 + }, + "beforeId": { + "description": "Identifier of the before returned by its create or list operation.", + "type": "string", + "pattern": "^[a-f0-9]{64}$" } }, "required": [ @@ -21687,6 +25920,20 @@ export const CATALOG_COMMANDS = [ ], "additionalProperties": {} } + }, + "nextCursor": { + "anyOf": [ + { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + { + "type": "null" + } + ] + }, + "hasMore": { + "type": "boolean" } }, "required": [ diff --git a/cli/chronology.js b/cli/chronology.js new file mode 100644 index 0000000..fc438e0 --- /dev/null +++ b/cli/chronology.js @@ -0,0 +1,39 @@ +import {readFile,writeFile,mkdir,copyFile,unlink} from 'node:fs/promises'; +import {constants} from 'node:fs'; +import {dirname,resolve} from 'node:path'; +import {loadConfig,ConfigError} from './config.js'; +import {cloudConnection} from './connection.js'; +import {createClient} from './client.js'; +import {freezeChronology,normalizeLocalSubmissions} from '../shared/monitoring-chronology-export.js'; +const help='agentlinkops chronology pull --watch-id ID [--limit 50] [--cursor TOKEN] [--all] [--out NEW_FILE] | export --pages FILE [--submissions FILE] [--out NEW_FILE]'; +async function output(value,args,{cwd,out}){ + const text=JSON.stringify(value,null,2)+'\n'; + if(!args.out){out(text.trimEnd());return;} + if(typeof args.out!=='string'||!args.out.trim())throw new ConfigError('--out requires a file'); + const path=resolve(cwd,args.out),temp=`${path}.${crypto.randomUUID()}.tmp`; + await mkdir(dirname(path),{recursive:true}); + try{await writeFile(temp,text,{flag:'wx',mode:0o600});await copyFile(temp,path,constants.COPYFILE_EXCL);}finally{await unlink(temp).catch(e=>{if(e.code!=='ENOENT')throw e;});} + out(`wrote ${path}`); +} +export async function chronologyMain(args,{cwd=process.cwd(),env=process.env,fetchImpl=globalThis.fetch,out=console.log}={}){ + const command=args._[1],allowed=new Set(['_','tag','watch-id','limit','cursor','all','out','pages','submissions']); + if(args._.length!==2||args.tag?.length||Object.keys(args).some(key=>!allowed.has(key)))throw new ConfigError(help); + if(command==='export'){ + if(typeof args.pages!=='string'||args['watch-id']!==undefined||args.limit!==undefined||args.cursor!==undefined||args.all!==undefined)throw new ConfigError(help); + const input=JSON.parse(await readFile(resolve(cwd,args.pages),'utf8')),pages=Array.isArray(input)?input:[input]; + const localItems=args.submissions?await normalizeLocalSubmissions(JSON.parse(await readFile(resolve(cwd,args.submissions),'utf8')),pages[0]?.identity):[]; + await output(await freezeChronology(pages,{localItems}),args,{cwd,out});return 0; + } + if(command!=='pull'||typeof args['watch-id']!=='string'||args.pages!==undefined||args.submissions!==undefined||args.all!==undefined&&args.all!==true)throw new ConfigError(help); + const limit=Number(args.limit??50);if(!Number.isInteger(limit)||limit<1||limit>100||args.cursor===true)throw new ConfigError(help); + const config=await loadConfig({cwd}),connection=cloudConnection(config,env); + if(!connection.projectId)throw new ConfigError('Connect this project before reading hosted chronology.'); + const client=createClient({...connection,fetchImpl}),pages=[];let cursor=args.cursor; + do{ + const page=await client.callCommand('get_placement_chronology',{watchId:args['watch-id'],limit,...(cursor?{cursor}: {})}); + if(page.identity?.projectId!==connection.projectId||page.identity?.watchId!==args['watch-id']||connection.workspaceId&&page.identity?.workspaceId!==connection.workspaceId)throw new ConfigError('Chronology identity does not match the connected project and selected watch.'); + pages.push(page);cursor=page.nextCursor; + if(pages.length===100&&args.all&&cursor)throw new ConfigError('Chronology exceeds the 100-page read bound. Pull explicit pages and export their qualified partial dataset.'); + }while(args.all&&cursor); + await output(args.all?await freezeChronology(pages):pages[0],args,{cwd,out});return 0; +} diff --git a/cli/client.js b/cli/client.js index a631b6b..b49acca 100644 --- a/cli/client.js +++ b/cli/client.js @@ -5,7 +5,7 @@ export {CloudError} from './cloud-error.js'; // A small HTTP client for the cloud. Scoped keys only; no human session ever reaches here. // DP-0036-T13: the CLI names itself so the usage counters can tell it from other REST callers. // The version follows the plugin manifests; bump it with them. -export const CLI_VERSION = '0.6.12'; +export const CLI_VERSION = '0.6.13'; export const CLI_USER_AGENT = `agentlinkops-cli/${CLI_VERSION}`; const MAX_ATTEMPTS = 3; const MAX_RETRY_WAIT_MS = 5_000; diff --git a/cli/fleet.js b/cli/fleet.js index 81ad3c1..d1cce9b 100644 --- a/cli/fleet.js +++ b/cli/fleet.js @@ -6,54 +6,62 @@ // and a summary that deduplicated them would silently pick one. So every number below is // per project, the only cross-project arithmetic is a sum of counts, and the output says so. // -// "Earned" follows the ledger contract, not a status column: an entry is earned when its -// latest OBSERVATION says present. A project with no observation file has earned nothing and -// is reported as never checked rather than as zero links. +// "Earned" follows known conclusive presence; a later inconclusive attempt is disclosed +// separately. Activity is supplied explicitly per project, never discovered in another repo. import { readLedger } from './ledger.js'; -import { readObservations, latestByEntry } from './mirror.js'; +import { readObservations } from './mirror.js'; +import { readState } from './state.js'; +import { projectPlacements } from './placement-projection.js'; const plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`; /** One project's row. Everything is computed inside the project; nothing crosses the boundary. */ -export async function fleetProject(name, ledgerPath, observationsPath) { +export async function fleetProject(name, ledgerPath, observationsPath, statePath = null) { const ledger = await readLedger(ledgerPath); if (ledger.missing) { const error = new Error(`no ledger at ${ledgerPath}`); error.code = 'NO_LEDGER'; throw error; } const byIntent = { wanted: 0, expected: 0, retired: 0 }; for (const entry of ledger.entries) byIntent[entry.intent] = (byIntent[entry.intent] ?? 0) + 1; const { rows } = observationsPath ? await readObservations(observationsPath) : { rows: [] }; - const latest = latestByEntry(rows); - let earned = 0, observed = 0; - for (const [id, row] of latest) { - if (!ledger.entries.some(entry => entry.id === id)) continue; // observations from another ledger's ids - observed++; - if (row.state === 'present') earned++; - } - const lastCheck = rows.length ? rows.map(row => row.checked_at).sort().at(-1) : null; + const state = statePath ? await readState(statePath) : null; + const eligible = ledger.entries.filter(entry => entry.intent !== 'retired'); + const projected = projectPlacements(eligible, rows, { state }); + const observed = projected.filter(item => item.latest_attempt).length; + const earned = projected.filter(item => item.current_state === 'present').length; + const newest = values => values.filter(Boolean).sort((a, b) => Date.parse(a) - Date.parse(b)).at(-1) ?? null; return { project: name, ledger: ledgerPath, entries: ledger.entries.length, ...byIntent, problems: ledger.problems.length, observed_entries: observed, earned, - never_checked: ledger.entries.filter(entry => entry.intent !== 'retired').length - observed, - last_observation: lastCheck, + never_checked: eligible.length - observed, + last_observation: newest(projected.map(item => item.evidence_observed_at)), + last_attempt_at: newest(projected.map(item => item.latest_attempt?.checked_at)), + last_success_at: newest(projected.map(item => item.last_successful_observation?.checked_at)), + last_link_verification_at: newest(projected.map(item => item.last_link_verification?.checked_at)), + uncertain_entries: projected.filter(item => item.uncertain).length, + activity_available: projected.some(item => item.activity_available), + activity_entries: projected.filter(item => item.activity_available).length, + coverage: { denominator: 'non_retired_ledger_entries', eligible_entries: eligible.length, + identity_unmatched_entries: projected.filter(item => item.identity_status === 'not_matched').length, + activity_input: statePath ? 'explicit_state_file' : 'not_supplied' }, // Due volume, the same arithmetic the dogfood records use to price a fleet. implied_weekly_checks: byIntent.wanted + byIntent.expected * 7, }; } /** Summons the fleet. Same numbers per project, one sum of counts, no merged intent. */ -export async function fleetSummary(projects, { observationsOf = {} } = {}) { +export async function fleetSummary(projects, { observationsOf = {}, statesOf = {} } = {}) { const rows = []; - for (const { name, ledger } of projects) rows.push(await fleetProject(name, ledger, observationsOf[name] ?? null)); + for (const { name, ledger } of projects) rows.push(await fleetProject(name, ledger, observationsOf[name] ?? null, statesOf[name] ?? null)); const totals = rows.reduce((acc, row) => { - for (const key of ['entries', 'wanted', 'expected', 'retired', 'earned', 'observed_entries', 'never_checked', 'implied_weekly_checks']) { + for (const key of ['entries', 'wanted', 'expected', 'retired', 'earned', 'observed_entries', 'never_checked', 'uncertain_entries', 'activity_entries', 'implied_weekly_checks']) { acc[key] = (acc[key] ?? 0) + row[key]; } return acc; }, {}); return { - v: 1, projects: rows, totals, + v: 2, projects: rows, totals, // The sum answers "how big is the operation". It is not a merged view: the same platform // counted in two projects is two intents, and only a human can say which one they meant. intent_merged_across_repos: false, @@ -75,6 +83,9 @@ export function renderFleet(summary, out = console.log) { + `${String(t.never_checked).padStart(13)} (sum of counts)`); out(''); out(`implied weekly check volume across the fleet: ${t.implied_weekly_checks}`); + for (const row of summary.projects) { + out(`${row.project}: latest attempt ${row.last_attempt_at ?? 'not recorded'}; last conclusive check ${row.last_success_at ?? 'not recorded'}; last link verification ${row.last_link_verification_at ?? 'not recorded'}; activity ${row.activity_available ? `${row.activity_entries} entr(ies)` : 'not available'}; uncertain ${row.uncertain_entries}`); + } if (summary.projects.some(row => row.problems)) { out(`ledger problems: ${summary.projects.map(row => `${row.project}=${row.problems}`).filter(s => !s.endsWith('=0')).join(', ')}`); } diff --git a/cli/main.js b/cli/main.js index 42f21b8..ab0aa3b 100644 --- a/cli/main.js +++ b/cli/main.js @@ -1,3 +1,5 @@ +import {projectPlacements} from './placement-projection.js'; +import {chronologyMain} from './chronology.js'; import { acquireSyncLock } from './sync-lock.js'; import {lifecycleMain} from './lifecycle.js'; import {admissionMain} from './admission.js'; @@ -52,6 +54,8 @@ const USAGE = `agentlinkops — a backlink ledger that lives in your repository [--mode local|hosted|external] read-only setup plan; no account required agentlinkops add --source URL --target URL [--intent wanted|expected] [--scope …] [--anchor TEXT] [--rel a,b] [--ref TEXT] [--tag t --tag t] [--note TEXT] + agentlinkops chronology pull --watch-id ID [--limit N] [--cursor TOKEN] [--all] [--out FILE] + agentlinkops chronology export --pages FILE [--submissions FILE] [--out FILE] agentlinkops index pull --watch-id ID [--limit N] [--before ID] agentlinkops lifecycle get|update|clear|renew|report agentlinkops admission list|add|update|remove|evaluate|reevaluate|receipt --project ID @@ -63,7 +67,7 @@ const USAGE = `agentlinkops — a backlink ledger that lives in your repository agentlinkops import FILE --target DOMAIN [--from SUPPLIER] [--map source=COL,target=COL] [--exact-url] [--no-subdomains] [--generated-at ISO] [--json] agentlinkops adopt CRM.sqlite [--scope exact|domain] [--write] - agentlinkops fleet --project NAME=LEDGER [--project …] [--observations-of NAME=FILE] [--json] + agentlinkops fleet --project NAME=LEDGER [--project …] [--observations-of NAME=FILE] [--state-of NAME=FILE] [--json] agentlinkops platforms [HOST] [--observations FILE]… [--benchmark FILE]… [--seed FILE]… [--for-candidates FILE] [--json] agentlinkops context COMMAND… first-party search context and site profile @@ -100,7 +104,7 @@ const USAGE = `agentlinkops — a backlink ledger that lives in your repository agentlinkops adopt-result FILE [--intent wanted|expected] save result to local ledger agentlinkops receipt add --file CLAIM.json project.site declares public site hosts agentlinkops receipt history [--performance FILE.json] claims, history and optional dated context - agentlinkops status [--json] + agentlinkops status [--all] [--json] agentlinkops diff [--json] agentlinkops report [--out FILE] [--title T] [--brand B] [--as-of ISO] [--include-notes] [--include-retired] [--digest-only] [--json] @@ -122,7 +126,7 @@ evidence · 2 usage, configuration or ledger error. Unknown is nonfailing by def Names: \`linktrail\` still runs this CLI, LINKTRAIL_* variables are still read, and an existing .linktrail/ directory is still used, each with a one-line notice, until the DP-0029 cutover.`; -const parseArgs = argv => parseArguments(argv,["tag", "project", "observations-of", "observations", "benchmark", "seed"],{tag:[]}); +const parseArgs = argv => parseArguments(argv,["tag", "project", "observations-of", "state-of", "observations", "benchmark", "seed"],{tag:[]}); const plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`; @@ -154,6 +158,7 @@ export async function main(argv = process.argv.slice(2), { cwd = process.cwd(), if (command === 'lifecycle') return await lifecycleMain(args,{cwd,env,fetchImpl,out,err}); if (command === 'admission') { const config=await loadConfig({cwd}); return await admissionMain(argv.slice(1),{client:createClient({...cloudConnection(config,env),fetchImpl}),out,err}); } if (command === 'disavow') return await disavowMain(args,{cwd,env,fetchImpl,out}); + if (command === 'chronology') return await chronologyMain(args,{cwd,env,fetchImpl,out}); if (command === 'index') return await indexMain(args,{cwd,env,fetchImpl,out}); if (command === 'setup') return await setupPlanMain(argv, { cwd, out }); if (command === 'tools' || command === 'describe' || command === 'schema' || command === 'call') return await commandsMain(argv, { cwd, out, err, env, fetchImpl }); @@ -306,7 +311,15 @@ export async function main(argv = process.argv.slice(2), { cwd = process.cwd(), if (!name || !path) throw new ConfigError(`--observations-of expects NAME=FILE, got "${value}"`); observationsOf[name] = path; } - const summary = await fleetSummary(pairs, { observationsOf }); + const statesOf = {}; + for (const value of [].concat(args['state-of'] ?? [])) { + const separator = String(value).indexOf('='); + const name = String(value).slice(0, separator), path = String(value).slice(separator + 1); + if (separator < 1 || !path || !pairs.some(project => project.name === name)) throw new ConfigError('--state-of expects a declared NAME=FILE'); + if (Object.hasOwn(statesOf, name)) throw new ConfigError(`Duplicate state input for ${name}`); + statesOf[name] = path; + } + const summary = await fleetSummary(pairs, { observationsOf, statesOf }); if (args.json) { out(JSON.stringify(summary, null, 1)); return 0; } return renderFleet(summary, out); } @@ -392,6 +405,7 @@ export async function main(argv = process.argv.slice(2), { cwd = process.cwd(), // so it is unchanged by a cosmetic edit to the template and changes the moment a figure does. const asOf = args['as-of'] === true ? null : (args['as-of'] ?? null); const dataset = freezeDataset(ledger.entries, observations.rows, { + activityState: await readState(config.paths.state), asOf: asOf ?? new Date().toISOString().slice(0, 10), title: args.title === true ? 'Backlink report' : (args.title ?? 'Backlink report'), includeNotes: args['include-notes'] === true, @@ -500,24 +514,29 @@ export async function main(argv = process.argv.slice(2), { cwd = process.cwd(), } if (command === 'status' || command === 'diff') { - const found = command === 'status' ? disagreements(ledger.entries, observations.rows) : transitions(observations.rows); - if (args.json) { out(JSON.stringify(found, null, 1)); return 0; } + const activityState = command === 'status' ? await readState(config.paths.state) : null; + const found = command === 'status' ? disagreements(ledger.entries, observations.rows, { state: activityState }) : transitions(observations.rows); + const activity = command === 'status' && args.all ? projectPlacements(ledger.entries, observations.rows, { state: activityState }).map(({ entry, row, ...facts }) => ({ id: entry.id, source: entry.source, target: entry.target, scope: entry.scope, ...facts })) : null; + if (args.json) { out(JSON.stringify(activity ? { disagreements: found, placements: activity } : found, null, 1)); return 0; } reportProblems(ledger.problems, 'ledger line(s)', out); if (command === 'diff') { if (!found.length) out('no state changes recorded'); for (const change of found.slice(0, 100)) out(` ${change.at.slice(0, 10)} ${change.from} -> ${change.to} ${change.id}`); return 0; } - const groups = { appeared: 'appeared', lost: 'LOST', suspected_missing: 'suspected missing', cannot_say: 'cannot say', never_checked: 'never checked' }; + const groups = { appeared: 'appeared', lost: 'confirmed missing', suspected_missing: 'suspected missing', cannot_say: 'cannot say', never_checked: 'never checked' }; for (const [kind, label] of Object.entries(groups)) { const rows = found.filter(item => item.kind === kind); if (!rows.length) continue; out(`\n${label} (${rows.length})`); for (const item of rows.slice(0, 50)) { out(` ${item.entry.id} ${item.entry.source}${item.row ? ` [${item.row.reason}]` : ''}`); + out(` Latest attempt: ${item.activity?.latest_attempt?.checked_at ?? 'not retained'} (${item.activity?.latest_attempt?.reason ?? 'unknown'})`); + out(` Last conclusive: ${item.activity?.last_successful_observation?.checked_at ?? 'not retained'}; last link verification: ${item.activity?.last_link_verification?.checked_at ?? 'not retained'}`); } } if (!found.length) out('intent and observations agree on every entry'); + if (activity) for (const item of activity) out(` ${item.id}: latest attempt ${item.latest_attempt?.checked_at ?? 'not retained'}; last conclusive ${item.last_successful_observation?.checked_at ?? 'not retained'}; last link verification ${item.last_link_verification?.checked_at ?? 'not retained'}`); return 0; } @@ -590,7 +609,7 @@ export async function main(argv = process.argv.slice(2), { cwd = process.cwd(), if (ledger.problems.length) { reportProblems(ledger.problems, 'ledger line(s)', err); return 2; } const state = await readState(config.paths.state); const selected = selectEntries(ledger.entries, { filter: args.filter === true ? null : args.filter }); - const entries = args.all ? selected : dueEntries(selected, lastCheckedMap(state)); + const entries = args.all ? selected : dueEntries(selected, lastCheckedMap(state, selected)); if (!entries.length) { (args.json ? err : out)(`nothing due (${plural(selected.length, 'entry', 'entries')} in scope; pass --all to recheck)`); return 0; } if (!args.json) err(`checking ${plural(entries.length, 'entry', 'entries')}…`); const rows = await runCheck(entries, { diff --git a/cli/mcp-client.js b/cli/mcp-client.js index fac0922..0935424 100644 --- a/cli/mcp-client.js +++ b/cli/mcp-client.js @@ -62,7 +62,7 @@ function retryDelay(error, attempt, now) { async function sdkClient({url, token, workspaceId, fetchImpl}) { const {Client, StreamableHTTPClientTransport} = await import('@modelcontextprotocol/client'); - const client = new Client({name: 'agentlinkops-cli', version: '0.6.12'}); + const client = new Client({name: 'agentlinkops-cli', version: '0.6.13'}); const destination = new URL(url); const transport = new StreamableHTTPClientTransport(destination, { authProvider: {token: async () => token}, @@ -71,7 +71,7 @@ async function sdkClient({url, token, workspaceId, fetchImpl}) { if (target.href !== destination.href) fail('OAUTH_TOKEN_DESTINATION_MISMATCH'); const headers = new Headers(init.headers ?? (input instanceof Request ? input.headers : undefined)); if (workspaceId) headers.set('X-Workspace-ID', workspaceId); - headers.set('User-Agent', 'agentlinkops-cli/0.6.12'); + headers.set('User-Agent', 'agentlinkops-cli/0.6.13'); const response = await fetchImpl(input, {...init, headers, redirect: 'error', signal: AbortSignal.timeout(30000)}); if (response.redirected || response.status >= 300 && response.status < 400 || response.url && response.url !== destination.href) fail('OAUTH_TOKEN_DESTINATION_MISMATCH'); diff --git a/cli/placement-projection.js b/cli/placement-projection.js new file mode 100644 index 0000000..ec7d8ca --- /dev/null +++ b/cli/placement-projection.js @@ -0,0 +1,106 @@ +// One identity-bound projection for local activity and retained observations. A change-only +// mirror is not a complete probe log, so local absence remains provisional. Hosted watch +// state is carried independently from the raw check; this module never confirms loss. +import { mirrorEvidenceReference } from '../src/evidence-reference.js'; + +const conclusive = new Set(['present', 'absent', 'source_unavailable']); +const watchStates = new Set(['present', 'suspected_missing', 'confirmed_missing', 'source_unavailable']); +export const validTime = value => typeof value === 'string' && Number.isFinite(Date.parse(value)); + +export function placementIdentity(value) { + const record = value?.result ?? value; + const source = record?.sourceUrl ?? record?.source_url ?? record?.source; + const target = record?.targetUrl ?? record?.target_url ?? record?.target; + const scope = record?.targetScope ?? record?.target_scope ?? record?.scope ?? 'exact'; + return typeof source === 'string' && typeof target === 'string' + ? JSON.stringify([source, target, scope]) : null; +} + +export function attemptSummary(row, { retained = false } = {}) { + if (!validTime(row?.checked_at)) return null; + const cloud = row.source === 'cloud'; + const rawState = cloud && conclusive.has(row.result?.checkState) ? row.result.checkState + : ['suspected_missing', 'confirmed_missing'].includes(row.state) ? 'absent' : row.state; + const method = row.result?.evidence?.method ?? null; + return { + checked_at: row.checked_at, placement: placementIdentity(row), + state: rawState, reason: row.reason ?? null, complete: row.complete === true, + origin: row.source ?? 'local', + watch_state: cloud && watchStates.has(row.result?.watchState) ? row.result.watchState + : ['suspected_missing', 'confirmed_missing'].includes(row.state) ? row.state : null, + link_signature: row.result?.linkSignature ?? null, + method, checker_version: row.checker_version ?? row.result?.evidence?.checkerVersion ?? null, + content_hash: row.result?.evidence?.sha256 ?? null, + evidence_reference: retained ? mirrorEvidenceReference({ entryId: row.id, checkedAt: row.checked_at, origin: row.source ?? 'local' }) : null, + retained, + }; +} + +export const isConclusive = attempt => attempt?.complete === true && conclusive.has(attempt.state); +export const isLinkVerification = attempt => isConclusive(attempt) && ['present', 'absent'].includes(attempt.state); + +// Equal timestamps never qualify another probe. Stable tie-breaking makes frozen exports +// independent of input ordering; an activity summary cannot replace a richer retained receipt. +const compareText = (a, b) => a < b ? -1 : a > b ? 1 : 0; +function latest(items) { + return items.filter(item => item && validTime(item.checked_at)).sort((a, b) => + Date.parse(b.checked_at) - Date.parse(a.checked_at) + || Number(b.retained === true) - Number(a.retained === true) + || compareText(JSON.stringify(a), JSON.stringify(b)))[0] ?? null; +} + +function activityAttempt(record, identity) { + if (record?.last_placement !== identity) return null; + if (record.last_attempt?.placement === identity && record.last_attempt.checked_at === record.last_checked + && validTime(record.last_attempt.checked_at)) return record.last_attempt; + // Legacy activity can prove its last conclusive time, but cannot invent a method/hash or + // reconstruct the overwritten successful check after a later unknown attempt. + if (!validTime(record.last_checked)) return null; + return { checked_at: record.last_checked, placement: identity, state: record.last_state ?? 'unknown', + reason: record.last_reason ?? null, complete: record.last_complete === true, origin: 'local', + watch_state: null, link_signature: record.last_signature ?? null, method: null, + checker_version: null, content_hash: null, evidence_reference: null, retained: false }; +} + +export function projectPlacement(entry, observations, { state = null } = {}) { + const identity = placementIdentity(entry); + const history = identity ? observations.filter(row => row.id === entry.id && placementIdentity(row) === identity && validTime(row.checked_at)) : []; + const attempts = history.map(row => attemptSummary(row, { retained: true })); + const record = state?.entries?.[entry.id]; + const locate = item => item?.retained === true && !attempts.some(receipt => receipt.checked_at === item.checked_at + && receipt.origin === item.origin && receipt.content_hash === item.content_hash) + ? { ...item, retained: false, evidence_reference: null } : item; + const activity = locate(identity ? activityAttempt(record, identity) : null); + const saved = key => locate(identity && record?.last_placement === identity && record[key]?.placement === identity ? record[key] : null); + const latestAttempt = latest([...attempts, activity]); + const savedSuccess = saved('last_successful_observation'), savedLink = saved('last_link_verification'); + const lastSuccessful = latest([...attempts.filter(isConclusive), isConclusive(savedSuccess) ? savedSuccess : null, isConclusive(activity) ? activity : null]); + const lastLink = latest([...attempts.filter(isLinkVerification), isLinkVerification(savedLink) ? savedLink : null, isLinkVerification(activity) ? activity : null]); + const retained = latest(attempts); + const row = retained ? history.filter(item => JSON.stringify(attemptSummary(item, { retained: true })) === JSON.stringify(retained)) + .sort((a, b) => compareText(JSON.stringify(a), JSON.stringify(b)))[0] ?? null : null; + const firstDates = attempts.filter(item => isConclusive(item) && item.state === 'present').map(item => item.checked_at); + const first = saved('first_present_observation'); + if (isConclusive(first) && first.state === 'present' && validTime(first.checked_at)) firstDates.push(first.checked_at); + const firstPresent = firstDates.sort((a, b) => Date.parse(a) - Date.parse(b))[0] ?? null; + const current = latestAttempt?.watch_state ?? lastSuccessful?.watch_state ?? (lastSuccessful?.state === 'absent' ? 'suspected_missing' + : lastSuccessful?.state ?? (latestAttempt ? 'unknown' : 'unchecked')); + return { + entry, row, placement: identity, current_state: current, + uncertain: !!latestAttempt && !isConclusive(latestAttempt), + latest_attempt: latestAttempt, last_successful_observation: lastSuccessful, + last_link_verification: lastLink, first_present: firstPresent, + evidence_observed_at: retained?.checked_at ?? null, + activity_available: activity !== null, + identity_status: history.length || activity ? 'matched' : observations.some(item => item.id === entry.id) || record ? 'not_matched' : 'not_observed', + }; +} + +export function projectPlacements(entries, observations, options = {}) { + const byId = new Map(); + for (const row of observations) { + if (!byId.has(row.id)) byId.set(row.id, []); + byId.get(row.id).push(row); + } + return entries.map(entry => projectPlacement(entry, byId.get(entry.id) ?? [], options)); +} diff --git a/cli/report.js b/cli/report.js index 896cced..d341714 100644 --- a/cli/report.js +++ b/cli/report.js @@ -18,13 +18,15 @@ // evidence reference that resolves to the observation itself. One dataset feeds both exports: // this HTML view for a human client, and `report --json` for an agent, so the two can never // disagree about what was observed. +// v3 freezes activity separately from retained receipts. Older v2 datasets still render with +// their original columns and wording; activity never changes an old observation's date/hash. import {indexRowsForUrl} from './index-observations.js'; import {reconcileIndexObservations} from '../src/index-observation.js'; import { createHash } from 'node:crypto'; -import { latestByEntry } from './mirror.js'; +import { projectPlacements } from './placement-projection.js'; import { mirrorEvidenceReference } from '../src/evidence-reference.js'; -export const REPORT_VERSION = 2; +export const REPORT_VERSION = 3; /** HTML-escape. Every value below is publisher or customer content and none of it is trusted. */ export const escape = value => String(value ?? '') @@ -35,6 +37,10 @@ const STATE_LABEL = Object.freeze({ present: 'Present', absent: 'Not found', unknown: 'Could not check', source_unavailable: 'Page unavailable', unchecked: 'Never checked', }); +const CURRENT_STATE_LABEL = Object.freeze({ + ...STATE_LABEL, + suspected_missing: 'Suspected missing', confirmed_missing: 'Confirmed missing', +}); /** * The frozen dataset a report renders. @@ -42,12 +48,10 @@ const STATE_LABEL = Object.freeze({ * Selection happens here and nowhere else, so a caller can hold this object, assert it, and know * the rendered document is a pure function of it. */ -export function freezeDataset(entries, observations, { asOf, title = 'Backlink report', includeNotes = false, includeRetired = false, indexObservations = [] } = {}) { - const latest = latestByEntry(observations); - const rows = entries - .filter(entry => includeRetired || entry.intent !== 'retired') - .map(entry => { - const row = latest.get(entry.id) ?? null; +export function freezeDataset(entries, observations, { asOf, title = 'Backlink report', includeNotes = false, includeRetired = false, indexObservations = [], activityState = null } = {}) { + const rows = projectPlacements(entries.filter(entry => includeRetired || entry.intent !== 'retired'), observations, { state: activityState }) + .map(projection => { + const { entry, row } = projection; const indexRows=indexRowsForUrl(indexObservations,entry.source); const origin = row?.source === 'cloud' ? 'cloud' : (row?.source ?? null); return { @@ -57,6 +61,16 @@ export function freezeDataset(entries, observations, { asOf, title = 'Backlink r reason: row?.reason ?? null, occurrences: row?.occurrences ?? 0, checked_at: row?.checked_at ?? null, + current_state: projection.current_state, + uncertain: projection.uncertain, + activity: { + available: projection.activity_available, + identity_status: projection.identity_status, + latest_attempt: projection.latest_attempt, + last_successful_observation: projection.last_successful_observation, + last_link_verification: projection.last_link_verification, + first_present: projection.first_present, + }, checked_by: row?.source ?? null, anchor: row?.result?.occurrences?.[0]?.anchor ?? null, rel: row?.result?.occurrences?.[0]?.rel ?? [], @@ -105,10 +119,16 @@ export function freezeDataset(entries, observations, { asOf, title = 'Backlink r // Stated rather than implied. A report over a ledger nobody has checked is not a report about // links, and the reader should see that before the table. coverage: { - checked: rows.filter(row => row.checked_at).length, - never_checked: rows.filter(row => !row.checked_at).length, + checked: rows.filter(row => row.activity.latest_attempt).length, + never_checked: rows.filter(row => !row.activity.latest_attempt).length, + retained_receipt_entries: rows.filter(row => row.checked_at).length, + missing_receipt_entries: rows.filter(row => !row.checked_at).length, observed_from: dates[0] ?? null, observed_to: dates.at(-1) ?? null, + activity_entries: rows.filter(row => row.activity.available).length, + identity_unmatched_entries: rows.filter(row => row.activity.identity_status === 'not_matched').length, + denominator: includeRetired ? 'all_ledger_entries' : 'non_retired_ledger_entries', + known_present_after_unknown: rows.filter(row => row.current_state === 'present' && row.uncertain).length, }, }; } @@ -149,6 +169,18 @@ export function renderReport(dataset, { brand = null } = {}) { const digest = createHash('sha256').update(JSON.stringify(dataset)).digest('hex'); const card = (label, value) => `
${brand ? `${escape(brand)} · ` : ''}Prepared ${escape(dataset.as_of)}
What these dates mean. Every row shows the date that link was last observed, between ${escape(coverage.observed_from ?? 'n/a')} and ${escape(coverage.observed_to ?? 'n/a')}. The date at the top is when this document was prepared and does not make any observation newer -than it is. ${coverage.never_checked ? `${coverage.never_checked} of ${dataset.totals.entries} links have never been checked and are listed as such.` : ''}
+than it is. ${coverage.never_checked ? `${coverage.never_checked} of ${dataset.totals.entries} links have never been checked and are listed as such.` : ''}${hasActivity ? '\nActivity and verification. The result and receipt date describe the retained observation. Activity lists later attempts and complete checks separately; an unchanged recheck can be newer than that receipt. An inconclusive attempt preserves the earlier verified state, and does not prove loss. A complete unavailable source is a conclusive source check, not a link verification. Missing activity is not inferred from a report preparation date.
' : ''}What a result means. “Present” means the link was in the observed HTML. “Could not check” is not the same as “not found”: it means the page could not be read, and no conclusion was drawn. Each receipt identifies the check method when it was recorded. A snapshot alone does not prove the link was visible on screen.
| Source page | Target | Result | Anchor | Observed | Evidence | ${hasIndex?'Index evidence | ':''}${dataset.include_notes ? 'Notes | ' : ''} +Source page | Target | Result | Anchor | Observed | Evidence | ${hasActivity ? 'Activity and verified state | ' : ''}${hasIndex?'Index evidence | ':''}${dataset.include_notes ? 'Notes | ' : ''}
|---|