Skip to main content
Glama
ShadowGraph

ShadowGraph

Official

shadowgraph_maintain

Destructive

Ages due decisions, expires stale facts, and evaluates reopen rules to maintain lifecycle state; records changes and returns changed IDs, due items, and stored signals.

Instructions

Age due owned decisions to stale, expire due owned facts, then evaluate reopen rules. shadowgraph_review evaluates without aging; shadowgraph_validate diagnoses integrity. Maintenance does not repair or restore. Uses now or the clock; saves lifecycle changes and signals, even on repeats. Grants widen audited reads, not writes. Returns changed IDs, due items and stored signals, including acknowledged ones.

Input Schema

NameRequiredDescriptionDefault
nowNoISO 8601 instant to treat as the current time. Defaults to the real clock; supplying it makes the run deterministic.
factsNoTemporary key/value overrides for object rules; unlisted keys use stored facts. Example: facts:{ready:true} tests {key:"ready",value:true}. This does not record a fact or fire a string rule; changedFacts supplies those changed-key signals.
grantIdNoAlias for accessId; conflicting identifiers are refused.
projectNoProject or confirmed workspace binding; otherwise origin-only. No identity returns an empty scoped view.
accessIdNoGrant ID, rechecked at use. Widens reads only, never write authority. Presenting an access key commits a revision and bounded operational audit: at most one aggregate per grant, surface, outcome and UTC day. Conflicts with a different grantId are refused.
originIdNoCapture-origin id; with no project the record belongs to it alone.
changedFactsNoEphemeral changed-key signals for string-form reopenWhen rules; not stored facts. Example: changedFacts:["budget"] fires reopenWhen:["budget"]. Object rules instead read values from facts overrides or stored facts.

Output Schema

NameRequiredDescriptionDefault
atYesThe instant maintenance ran against.
dueYesDecisions due for reconsideration after the run.
diagnosticsNoConditions that could not be settled, or that rest on facts which disagree.
reviewSignalsYesEvery persisted review signal after the run, open and acknowledged alike.
readProvenanceNoOriginal read bounds; reuse intersects these with currently valid authority.
agedDecisionIdsYesCompatibility alias of staleDecisionIds for older callers.
staleDecisionIdsYesDecisions moved to stale because they passed reviewAfter.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changedv0.42.3
    • changedInput schema / properties / changedFacts / description
      Previous value: -"Fact keys that just changed. Only string-form reopenWhen rules match this list; it is an ephemeral signal, not durable state."New value: +"Ephemeral changed-key signals for string-form reopenWhen rules; not stored facts. Example: changedFacts:[\"budget\"] fires reopenWhen:[\"budget\"]. Object rules instead read values from facts overrides or stored facts."
    • changedInput schema / properties / facts / description
      Previous value: -"Fact key/value overrides evaluated instead of the stored facts of the same key. Stored facts are used for every key not listed here, so reopen rules still work after a restart."New value: +"Temporary key/value overrides for object rules; unlisted keys use stored facts. Example: facts:{ready:true} tests {key:\"ready\",value:true}. This does not record a fact or fire a string rule; changedFacts supplies those changed-key signals."
  2. Changed1 schema field changedv0.42.2
    • changedInput schema / properties / accessId / description
      Previous value: -"Grant ID, rechecked at use."New value: +"Grant ID, rechecked at use. Widens reads only, never write authority. Presenting an access key commits a revision and bounded operational audit: at most one aggregate per grant, surface, outcome and UTC day. Conflicts with a different grantId are refused."
  3. Changed12 schema fields changedv0.42.1
    • addedInput schema / properties / accessId
      Added value: +{
      +  "description": "Grant ID, rechecked at use.",
      +  "type": "string"
      +}
    • addedInput schema / properties / grantId
      Added value: +{
      +  "description": "Alias for accessId; conflicting identifiers are refused.",
      +  "type": "string"
      +}
    • addedInput schema / properties / originId
      Added value: +{
      +  "description": "Capture-origin id; with no project the record belongs to it alone.",
      +  "type": "string"
      +}
    • addedInput schema / properties / project
      Added value: +{
      +  "description": "Project or confirmed workspace binding; otherwise origin-only. No identity returns an empty scoped view.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / diagnostics
      Added value: +{
      +  "description": "Conditions that could not be settled, or that rest on facts which disagree.",
      +  "items": {
      +    "description": "Unresolved or contested conditions on one decision or attempt. Not a review signal: neither a breach nor a confirmed-safe decision.",
      +    "properties": {
      +      "attemptId": {
      +        "description": "The attempt involved, for reusableWhen conditions.",
      +        "type": "string"
      +      },
      +      "conditions": {
      +        "description": "The unresolved or contested conditions.",
      +        "items": {
      +          "description": "One evaluated reopen condition. Verdict \"unknown\" means it could not be evaluated from available evidence, which is not a pass.",
      +          "properties": {
      +            "alternativeId": {
      +              "description": "Alternative carrying it.",
      +              "type": "string"
      +            },
      +            "alternativeLabel": {
      +              "description": "Label of that alternative.",
      +              "type": "string"
      +            },
      +            "attemptId": {
      +              "description": "Attempt the condition belongs to, for a reusableWhen rule.",
      +              "type": "string"
      +            },
      +            "conflictingEvidence": {
      +              "description": "Equally applicable facts that disagree. The verdict rests on the deterministic winner.",
      +              "items": {
      +                "description": "A fact a verdict came from. Unrecorded fields are omitted, never filled in.",
      +                "properties": {
      +                  "factId": {
      +                    "description": "The observed fact.",
      +                    "type": "string"
      +                  },
      +                  "observedAt": {
      +                    "description": "When observed, if recorded.",
      +                    "type": "string"
      +                  },
      +                  "sourceClass": {
      +                    "description": "Provenance class, if recorded.",
      +                    "type": "string"
      +                  },
      +                  "validFrom": {
      +                    "description": "Validity start, if recorded.",
      +                    "type": "string"
      +                  },
      +                  "value": {
      +                    "anyOf": [
      +                      {
      +                        "type": "string"
      +                      },
      +                      {
      +                        "type": "number"
      +                      },
      +                      {
      +                        "type": "boolean"
      +                      },
      +                      {
      +                        "type": "null"
      +                      },
      +                      {
      +                        "type": "array"
      +                      },
      +                      {
      +                        "type": "object"
      +                      }
      +                    ],
      +                    "description": "A stored value, any lossless JSON value."
      +                  },
      +                  "verificationStatus": {
      +                    "description": "Verification status, if recorded.",
      +                    "type": "string"
      +                  }
      +                },
      +                "required": [
      +                  "factId",
      +                  "value"
      +                ],
      +                "type": "object"
      +              },
      +              "type": "array"
      +            },
      +            "decisionId": {
      +              "description": "Decision the condition belongs to, for a reopenWhen rule.",
      +              "type": "string"
      +            },
      +            "evidence": {
      +              "description": "Provenance of the value used.",
      +              "type": "object"
      +            },
      +            "expected": {
      +              "anyOf": [
      +                {
      +                  "type": "string"
      +                },
      +                {
      +                  "type": "number"
      +                },
      +                {
      +                  "type": "boolean"
      +                },
      +                {
      +                  "type": "null"
      +                },
      +                {
      +                  "type": "array"
      +                },
      +                {
      +                  "type": "object"
      +                }
      +              ],
      +              "description": "A stored value, any lossless JSON value."
      +            },
      +            "key": {
      +              "anyOf": [
      +                {
      +                  "type": "string"
      +                },
      +                {
      +                  "type": "null"
      +                }
      +              ],
      +              "description": "Fact key read."
      +            },
      +            "observed": {
      +              "anyOf": [
      +                {
      +                  "type": "string"
      +                },
      +                {
      +                  "type": "number"
      +                },
      +                {
      +                  "type": "boolean"
      +                },
      +                {
      +                  "type": "null"
      +                },
      +                {
      +                  "type": "array"
      +                },
      +                {
      +                  "type": "object"
      +                }
      +              ],
      +              "description": "A stored value, any lossless JSON value."
      +            },
      +            "operator": {
      +              "anyOf": [
      +                {
      +                  "type": "string"
      +                },
      +                {
      +                  "type": "null"
      +                }
      +              ],
      +              "description": "Operator the rule declared."
      +            },
      +            "reason": {
      +              "description": "Why this verdict.",
      +              "type": "string"
      +            },
      +            "unit": {
      +              "description": "Unit the rule declared, if any.",
      +              "type": "string"
      +            },
      +            "verdict": {
      +              "description": "Evaluation result.",
      +              "enum": [
      +                "true",
      +                "false",
      +                "unknown"
      +              ],
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "key",
      +            "operator",
      +            "verdict",
      +            "reason"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "decisionId": {
      +        "description": "The decision involved, for reopenWhen conditions.",
      +        "type": "string"
      +      },
      +      "title": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Decision title, when stored."
      +      }
      +    },
      +    "required": [
      +      "conditions"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / due / items / properties / reviewSignalId
      Added value: +{
      +  "description": "Pass this to shadowgraph_ack_review to acknowledge this review.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / due / items / properties / reviewSignalStatus
      Added value: +{
      +  "description": "Whether this review is open or acknowledged, or unpersisted: no stored signal, because context is a read or the evaluation was wider. Entries are recomputed from current evidence; an acknowledged one still appears.",
      +  "enum": [
      +    "open",
      +    "acknowledged",
      +    "unpersisted"
      +  ],
      +  "type": "string"
      +}
    • addedOutput schema / properties / due / items / properties / violatedConditions
      Added value: +{
      +  "description": "The conditions that actually fired, each naming its operator, expected and observed value, and the fact it was computed from.",
      +  "items": {
      +    "description": "One evaluated reopen condition. Verdict \"unknown\" means it could not be evaluated from available evidence, which is not a pass.",
      +    "properties": {
      +      "alternativeId": {
      +        "description": "Alternative carrying it.",
      +        "type": "string"
      +      },
      +      "alternativeLabel": {
      +        "description": "Label of that alternative.",
      +        "type": "string"
      +      },
      +      "attemptId": {
      +        "description": "Attempt the condition belongs to, for a reusableWhen rule.",
      +        "type": "string"
      +      },
      +      "conflictingEvidence": {
      +        "description": "Equally applicable facts that disagree. The verdict rests on the deterministic winner.",
      +        "items": {
      +          "description": "A fact a verdict came from. Unrecorded fields are omitted, never filled in.",
      +          "properties": {
      +            "factId": {
      +              "description": "The observed fact.",
      +              "type": "string"
      +            },
      +            "observedAt": {
      +              "description": "When observed, if recorded.",
      +              "type": "string"
      +            },
      +            "sourceClass": {
      +              "description": "Provenance class, if recorded.",
      +              "type": "string"
      +            },
      +            "validFrom": {
      +              "description": "Validity start, if recorded.",
      +              "type": "string"
      +            },
      +            "value": {
      +              "anyOf": [
      +                {
      +                  "type": "string"
      +                },
      +                {
      +                  "type": "number"
      +                },
      +                {
      +                  "type": "boolean"
      +                },
      +                {
      +                  "type": "null"
      +                },
      +                {
      +                  "type": "array"
      +                },
      +                {
      +                  "type": "object"
      +                }
      +              ],
      +              "description": "A stored value, any lossless JSON value."
      +            },
      +            "verificationStatus": {
      +              "description": "Verification status, if recorded.",
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "factId",
      +            "value"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "decisionId": {
      +        "description": "Decision the condition belongs to, for a reopenWhen rule.",
      +        "type": "string"
      +      },
      +      "evidence": {
      +        "description": "Provenance of the value used.",
      +        "type": "object"
      +      },
      +      "expected": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "number"
      +          },
      +          {
      +            "type": "boolean"
      +          },
      +          {
      +            "type": "null"
      +          },
      +          {
      +            "type": "array"
      +          },
      +          {
      +            "type": "object"
      +          }
      +        ],
      +        "description": "A stored value, any lossless JSON value."
      +      },
      +      "key": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Fact key read."
      +      },
      +      "observed": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "number"
      +          },
      +          {
      +            "type": "boolean"
      +          },
      +          {
      +            "type": "null"
      +          },
      +          {
      +            "type": "array"
      +          },
      +          {
      +            "type": "object"
      +          }
      +        ],
      +        "description": "A stored value, any lossless JSON value."
      +      },
      +      "operator": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Operator the rule declared."
      +      },
      +      "reason": {
      +        "description": "Why this verdict.",
      +        "type": "string"
      +      },
      +      "unit": {
      +        "description": "Unit the rule declared, if any.",
      +        "type": "string"
      +      },
      +      "verdict": {
      +        "description": "Evaluation result.",
      +        "enum": [
      +          "true",
      +          "false",
      +          "unknown"
      +        ],
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "key",
      +      "operator",
      +      "verdict",
      +      "reason"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / readProvenance
      Added value: +{
      +  "description": "Original read bounds; reuse intersects these with currently valid authority.",
      +  "properties": {
      +    "accessId": {
      +      "description": "Original grant, revalidated on every reuse.",
      +      "type": "string"
      +    },
      +    "expiresAt": {
      +      "description": "Original effective expiry; reuse cannot extend it.",
      +      "type": "string"
      +    },
      +    "request": {
      +      "description": "Original request ownership, preserved during expansion.",
      +      "properties": {
      +        "originId": {
      +          "anyOf": [
      +            {
      +              "type": "string"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ],
      +          "description": "Original capture origin, or null when absent."
      +        },
      +        "project": {
      +          "anyOf": [
      +            {
      +              "type": "string"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ],
      +          "description": "Original resolved project, or null when unresolved."
      +        }
      +      },
      +      "required": [
      +        "project",
      +        "originId"
      +      ],
      +      "type": "object"
      +    },
      +    "scope": {
      +      "description": "Finite explicit owner bounds; project names, origins and legacy attribution are disjoint.",
      +      "properties": {
      +        "legacyAttributions": {
      +          "description": "Explicit legacy ownership classes; neither is a named project.",
      +          "items": {
      +            "enum": [
      +              "legacy_ambiguous",
      +              "legacy_unattributed"
      +            ],
      +            "type": "string"
      +          },
      +          "type": "array"
      +        },
      +        "originIds": {
      +          "description": "Exact nonempty origin identifiers for unattributed content.",
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        },
      +        "projects": {
      +          "description": "Exact named projects, including a real project named default if requested.",
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "surfaces": {
      +      "description": "Original permitted surfaces; reuse can only narrow them.",
      +      "items": {
      +        "enum": [
      +          "cli",
      +          "mcp",
      +          "http"
      +        ],
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "version": {
      +      "const": 1,
      +      "description": "Version of this bounded read provenance.",
      +      "type": "integer"
      +    }
      +  },
      +  "required": [
      +    "version",
      +    "request",
      +    "accessId",
      +    "scope",
      +    "surfaces",
      +    "expiresAt"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / properties / reviewSignals / items / properties / coverage
      Added value: +{
      +  "description": "Exact conditions covered, and part of this identity.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / properties / reviewSignals / items / properties / reason / description
      Previous value: -"Why the signal was raised. Together with decisionId this is the dedupe identity, so the same cause never raises a second signal."New value: +"Why it was raised. Identity is this plus decisionId and coverage."
    • changedOutput schema / properties / reviewSignals / items / required
      Previous value: -[
      -  "id",
      -  "kind",
      -  "decisionId",
      -  "reason",
      -  "alternativesToReconsider",
      -  "status",
      -  "createdAt"
      -]New value: +[
      +  "id",
      +  "kind",
      +  "decisionId",
      +  "status",
      +  "createdAt"
      +]
  4. Changed5 schema fields changedv0.40.1
    • addedInput schema / properties / changedFacts / description
      Added value: +"Fact keys that just changed. Only string-form reopenWhen rules match this list; it is an ephemeral signal, not durable state."
    • addedInput schema / properties / changedFacts / items
      Added value: +{
      +  "type": "string"
      +}
    • addedInput schema / properties / facts / description
      Added value: +"Fact key/value overrides evaluated instead of the stored facts of the same key. Stored facts are used for every key not listed here, so reopen rules still work after a restart."
    • addedInput schema / properties / now / description
      Added value: +"ISO 8601 instant to treat as the current time. Defaults to the real clock; supplying it makes the run deterministic."
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "description": "What maintenance changed and what is now due.",
      +  "properties": {
      +    "agedDecisionIds": {
      +      "description": "Compatibility alias of staleDecisionIds for older callers.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "at": {
      +      "description": "The instant maintenance ran against.",
      +      "type": "string"
      +    },
      +    "due": {
      +      "description": "Decisions due for reconsideration after the run.",
      +      "items": {
      +        "description": "One decision whose rejected alternatives are due for reconsideration.",
      +        "properties": {
      +          "alternativesToReconsider": {
      +            "description": "Labels of the alternatives to look at again; all of them when the trigger was not alternative-specific.",
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "decisionId": {
      +            "description": "The decision to reconsider.",
      +            "type": "string"
      +          },
      +          "reason": {
      +            "description": "Comma-separated causes: the fact keys whose reopenWhen rules matched, \"review date reached\", or \"decision outcome failed\".",
      +            "type": "string"
      +          },
      +          "title": {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Decision title, when the stored decision has one."
      +          }
      +        },
      +        "required": [
      +          "decisionId",
      +          "reason",
      +          "alternativesToReconsider"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "reviewSignals": {
      +      "description": "Every persisted review signal after the run, open and acknowledged alike.",
      +      "items": {
      +        "description": "A persisted review signal.",
      +        "properties": {
      +          "acknowledgedAt": {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "ISO 8601 time of the most recent acknowledgement."
      +          },
      +          "alternativesToReconsider": {
      +            "description": "Alternative labels to look at again.",
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "createdAt": {
      +            "description": "ISO 8601 time the signal was raised.",
      +            "type": "string"
      +          },
      +          "decisionId": {
      +            "description": "The decision this signal is about.",
      +            "type": "string"
      +          },
      +          "id": {
      +            "description": "Signal identifier, used by shadowgraph_ack_review.",
      +            "type": "string"
      +          },
      +          "kind": {
      +            "const": "review",
      +            "description": "Always \"review\".",
      +            "type": "string"
      +          },
      +          "reason": {
      +            "description": "Why the signal was raised. Together with decisionId this is the dedupe identity, so the same cause never raises a second signal.",
      +            "type": "string"
      +          },
      +          "status": {
      +            "description": "open until acknowledged.",
      +            "enum": [
      +              "open",
      +              "acknowledged"
      +            ],
      +            "type": "string"
      +          },
      +          "title": {
      +            "anyOf": [
      +              {
      +                "type": "string"
      +              },
      +              {
      +                "type": "null"
      +              }
      +            ],
      +            "description": "Decision title, when the stored decision has one."
      +          }
      +        },
      +        "required": [
      +          "id",
      +          "kind",
      +          "decisionId",
      +          "reason",
      +          "alternativesToReconsider",
      +          "status",
      +          "createdAt"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "staleDecisionIds": {
      +      "description": "Decisions moved to stale because they passed reviewAfter.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "at",
      +    "staleDecisionIds",
      +    "agedDecisionIds",
      +    "reviewSignals",
      +    "due"
      +  ],
      +  "type": "object"
      +}
  5. First observedv0.40.0

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructive=true, idempotent=false, readOnly=false, and the description adds real context beyond them: lifecycle changes and signals persist 'even on repeats' (explaining the non-idempotent behavior), aging/expiry is irreversible here since it does not repair or restore, and grants widen audited reads only, never write authority. It does not spell out what happens to already-stale items on a re-run, which keeps it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action is front-loaded in the first sentence and every sentence carries distinct information about siblings, boundaries, or return contents. The phrasing is telegraphic ('Uses now or the clock', 'Grants widen audited reads, not writes'), which is dense but occasionally requires re-parsing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, destructive, multi-parameter maintenance tool with an output schema and full annotations, the description covers what mutates (decisions aged, facts expired), what it will not do (repair/restore), determinism via now, and the return contents (changed IDs, due items, stored signals including acknowledged ones). An agent has enough to call it correctly and to know the side effects.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all seven parameters in depth. The description adds marginal value only, restating that the run uses 'now or the clock' and that grants widen reads, not writes; it contributes nothing new about facts, changedFacts, or origin/project scoping beyond what the schema states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names three concrete operations (age decisions to stale, expire facts, evaluate reopen rules) with a specific verb+resource scope. It then explicitly contrasts itself with shadowgraph_review (evaluates without aging) and shadowgraph_validate (diagnoses integrity), so an agent can separate the three without reading schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description routes the agent explicitly: use shadowgraph_review to evaluate without aging, shadowgraph_validate for integrity diagnosis, and it states the negative boundary 'Maintenance does not repair or restore.' That is a clear when-to-use/when-not/alternative set, with only the operational cadence left implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.