custodian_unqualified

The running jobjob_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged

A subject's custodian ladder leaves the brand of record for a role whose credential the brand doesn't hold.

FixFails inSuggestsExit
Put a role that holds the credential ahead of 'brand' in custodian, or declare the brand's credential in brand.ts.services/translation.ts:9 · subject.of_record.custodiansubject.of_record.custodian: ['translator', 'brand']1

Owned by Of record: the page that explains what this gate holds.

npx services.dev check
  ✗ A subject's custodian ladder leaves the brand of record for a role whose credential the brand doesn't hold. Put a role that holds the credential ahead of 'brand' in custodian, or declare the brand's credential in brand.ts. translation's certified translation names the brand as custodian of record for the translator, and the brand holds no sworn translator: put a role that does first.
    at services/translation.ts:9 · subject.of_record.custodian
✗ 1 to fix
services/translation.ts
import { Service } from 'services.dev'
import rules from '../rules.ts'

export default Service({
  name: 'Translation',
  input: { document: 'file', to: 'language: a BCP 47 tag, such as fr-CA' },
  output: { document: 'file' },
  rules,
  subject: { kind: 'certified translation', key: 'document', of_record: { role: 'translator', named_at: 'sign', custodian: ['brand'] } },
  roles: { translator: { credential: 'sworn translator' }, reviewer: { credential: 'sworn translator' } },
  deliver: {
    translate: 'ai',
    harden: { review: 'adversarial', lenses: ['meaning', 'terms'] },
    sign: { by: 'translator', stamp: true },
  },
  price: 89,
})
git add -A && git diff --staged
diff --git a/services/translation.ts b/services/translation.ts
index 59ba02a..e0b0ae5 100644
--- a/services/translation.ts
+++ b/services/translation.ts
@@ -6,7 +6,7 @@ export default Service({
   input: { document: 'file', to: 'language: a BCP 47 tag, such as fr-CA' },
   output: { document: 'file' },
   rules,
-  subject: { kind: 'certified translation', key: 'document', of_record: { role: 'translator', named_at: 'sign', custodian: ['brand'] } },
+  subject: { kind: 'certified translation', key: 'document', of_record: { role: 'translator', named_at: 'sign', custodian: ['reviewer', 'brand'] } },
   roles: { translator: { credential: 'sworn translator' }, reviewer: { credential: 'sworn translator' } },
   deliver: {
     translate: 'ai',
npx services.dev check
✓ ready to sell · 1 Service · it keeps at least 80% of every job
rules.ts
import { Rules } from 'services.dev'

export default Rules({
  version: '2026-10',
  services: {
    translation: {
      sign: { reserved: 'sworn translator', where: '*', position: 'A sworn translator signs a translation filed with a registry.' },
    },
  },
})

How the legal example passes this gate, in lines read from its files.

examples/legal/pools/attorneys.ts
roles: {
// …
  practitioner: { credential: ['patent attorney', 'patent agent'], where: '*' },
examples/legal/services/provisional-patent.ts
subject: {

Read them in context: The attorneys' Pool, Provisional patent application.

npx services.dev check --json · the custodian_unqualified failure
{
  "code": "custodian_unqualified",
  "reason": "A subject's custodian ladder leaves the brand of record for a role whose credential the brand doesn't hold.",
  "next": "Put a role that holds the credential ahead of 'brand' in custodian, or declare the brand's credential in brand.ts. translation's certified translation names the brand as custodian of record for the translator, and the brand holds no sworn translator: put a role that does first.",
  "doc_url": "https://services.dev/docs/reference/check/custodian_unqualified",
  "file": "services/translation.ts",
  "line": 9,
  "path": "subject.of_record.custodian",
  "suggest": {
    "path": "subject.of_record.custodian",
    "value": "['translator', 'brand']"
  }
}
The whole document check --json prints
npx services.dev check --json
{
  "ai": {
    "cents_per_call": 42,
    "simulated": true
  },
  "mcp": {
    "tools": 13,
    "tokens": 4490,
    "sandbox": 9,
    "budget": 8000
  },
  "files": [
    {
      "path": "rules.ts",
      "lines": 6,
      "kind": "rules",
      "says": "rules 2026-10 · 1 Service · 1 row"
    }
  ],
  "services": [