rail_conflict

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

A role's pay.rail contradicts the rail of the row for its act.

FixFails inExit
Leave pay.rail out, so the row's rail holds, or make the two agree.services/translation.ts:9 · roles.translator.pay.rail1

Owned by Refusals and cures: the page that explains what this gate holds.

npx services.dev check
  ✗ A role's pay.rail contradicts the rail of the row for its act. Leave pay.rail out, so the row's rail holds, or make the two agree. translator's pay.rail is 'brand', and the sign row's rail is 'member'.
    at services/translation.ts:9 · roles.translator.pay.rail
✗ 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,
  roles: { translator: { credential: 'sworn translator', pay: { usd: 30, rail: 'brand' } } },
  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 7069288..6a58339 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,
-  roles: { translator: { credential: 'sworn translator', pay: { usd: 30, rail: 'brand' } } },
+  roles: { translator: { credential: 'sworn translator', pay: { usd: 30 } } },
   deliver: {
     translate: 'ai',
     harden: { review: 'adversarial', lenses: ['meaning', 'terms'] },
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: '*', rail: 'member', 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/rules.ts
'trademark-response': {
  respond: { reserved: 'bar admission', where: '*', rail: 'member', position: 'A response for the applicant is signed by an attorney admitted in any state.' },
examples/legal/services/trademark-response.ts
roles: { attorney: { pool: attorneys, pay: 175 } },

Read them in context: The rules table, Trademark response.

npx services.dev check --json · the rail_conflict failure
{
  "code": "rail_conflict",
  "reason": "A role's pay.rail contradicts the rail of the row for its act.",
  "next": "Leave pay.rail out, so the row's rail holds, or make the two agree. translator's pay.rail is 'brand', and the sign row's rail is 'member'.",
  "doc_url": "https://services.dev/docs/reference/check/rail_conflict",
  "file": "services/translation.ts",
  "line": 9,
  "path": "roles.translator.pay.rail"
}
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"
    }
  ],
  "inert": [