{
  "$comment": "The credential-noun vocabulary: the words that make an identifier name a secret. Published so every consumer derives its own matcher from ONE list — a newly recognized noun reaches them all through a version bump instead of N hand edits. Read it from Python via agent_sanitizer.secrets (credential_name_segments / credential_field_name_patterns / non_secret_name_segments) or from JavaScript via the npm subpath export `agent-sanitizer/credential-names`. `parts` are the lowercase words of the noun; a consumer renders them for its own matcher (underscore-joined `API_KEY` and bare-joined `APIKEY` for an env-var NAME, `api[_-]?key` for a `field = value` regex). `uses` says which matcher may use the noun, because the two are not interchangeable: `env-name` matches a variable NAME and never inspects a value, so a broad noun there costs nothing, while `field-value` redacts whatever follows `noun = ` and a broad noun there mangles ordinary text — `key = <20 chars>` is a false-positive flood, so `key`, `pat`, `credential`, `credentials` and `secrets` are env-name only — `credential`/`credentials` are everyday variable names, and an attribute chain (`credentials = service_account.Credentials.from_service_account_info(info)`) escapes every value-shape skip, so a field-value rendering would redact ordinary source lines. `passphrase` is the exception among them: it is as shape-specific as `password`, and detect-secrets' own KeywordDetector DENYLIST omits it, so name-only would let `passphrase = <secret>` reach the model in cleartext. `nonSecretSuffixes` are the trailing words that make a credential-shaped name hold a NON-secret (a key's identifier, the public half of a keypair), which a consumer must not redact. Every part is restricted to a-z0-9 so it carries no regex metacharacter; the accessors enforce that and fail closed on a violation, an empty list, or an unknown `uses` value. It sits inside the Python package because a wheel can only ship data under its package directory, while npm's `files`/`exports` can name any path — so ONE physical file backs both ecosystems and there is no copy to drift.",
  "nouns": [
    { "parts": ["api", "key"], "uses": ["env-name", "field-value"] },
    { "parts": ["access", "key"], "uses": ["env-name", "field-value"] },
    { "parts": ["access", "token"], "uses": ["env-name", "field-value"] },
    { "parts": ["secret", "key"], "uses": ["env-name", "field-value"] },
    { "parts": ["client", "secret"], "uses": ["env-name", "field-value"] },
    { "parts": ["private", "key"], "uses": ["env-name", "field-value"] },
    { "parts": ["auth", "token"], "uses": ["env-name", "field-value"] },
    { "parts": ["auth", "key"], "uses": ["env-name", "field-value"] },
    { "parts": ["authorization"], "uses": ["env-name", "field-value"] },
    { "parts": ["password"], "uses": ["env-name", "field-value"] },
    { "parts": ["passwd"], "uses": ["env-name", "field-value"] },
    { "parts": ["passphrase"], "uses": ["env-name", "field-value"] },
    { "parts": ["bearer"], "uses": ["env-name", "field-value"] },
    { "parts": ["secret"], "uses": ["env-name", "field-value"] },
    { "parts": ["secrets"], "uses": ["env-name"] },
    { "parts": ["credential"], "uses": ["env-name"] },
    { "parts": ["credentials"], "uses": ["env-name"] },
    { "parts": ["token"], "uses": ["env-name", "field-value"] },
    { "parts": ["pat"], "uses": ["env-name"] },
    { "parts": ["key"], "uses": ["env-name"] }
  ],
  "nonSecretSuffixes": [
    ["key", "id"],
    ["public", "key"]
  ]
}
