act_unruled
A step names an act the rules table has no row for, under its Service or shared. There is no fallback.
| Fix | Fails in | Suggests | Exit |
|---|---|---|---|
| Add a row for the act to the rules table, with its position, or name an act the table has. | rules.ts:6 · rules.services['translation'].seal | rules.services['translation'].seal: { reserved: '<credential>', where: '*', position: '…' } | 1 |
Owned by File it somewhere: the page that explains what this gate holds.
✗ A step names an act the rules table has no row for, under its Service or shared. There is no fallback. Add a row for the act to the rules table, with its position, or name an act the table has. seal sets no act, so it performs the act seal, and rules 2026-10 has no row for it under translation and no shared row.
at rules.ts:6 · rules.services['translation'].seal
✗ The rules table binds a name nothing reads: a key that names no Service file, or a row no step performs that is neither an advice class nor refused. Rename it to what it means, or take it out. rules.services['translation'].sign is a row no step of translation performs. A row binds nothing until a step does its act.
at rules.ts:7 · rules.services['translation'].sign
✗ 2 to fixThe same file failed rule_unread in the same run. Each has its own page.
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' } },
deliver: {
translate: 'ai',
harden: { review: 'adversarial', lenses: ['meaning', 'terms'] },
seal: { by: 'translator', stamp: true },
},
price: 89,
})diff --git a/services/translation.ts b/services/translation.ts
index c8b9770..580cb85 100644
--- a/services/translation.ts
+++ b/services/translation.ts
@@ -10,7 +10,7 @@ export default Service({
deliver: {
translate: 'ai',
harden: { review: 'adversarial', lenses: ['meaning', 'terms'] },
- seal: { by: 'translator', stamp: true },
+ seal: { by: 'translator', act: 'sign', stamp: true },
},
price: 89,
})✓ ready to sell · 1 Service · it keeps at least 80% of every jobimport { 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.
deliver: {
// …
advise_entity: { by: 'attorney', act: 'advise_entity_choice', est: '30min', checklist: ['the founders know why this entity, in this state'] },formation: {
advise_entity_choice: { reserved: 'bar admission', where: 'client', kind: 'advice', rail: 'member', position: 'Which entity to form is advice.' },Read them in context: Company formation, The rules table.
{
"code": "act_unruled",
"reason": "A step names an act the rules table has no row for, under its Service or shared. There is no fallback.",
"next": "Add a row for the act to the rules table, with its position, or name an act the table has. seal sets no act, so it performs the act seal, and rules 2026-10 has no row for it under translation and no shared row.",
"doc_url": "https://services.dev/docs/reference/check/act_unruled",
"file": "rules.ts",
"line": 6,
"path": "rules.services['translation'].seal",
"suggest": {
"path": "rules.services['translation'].seal",
"value": "{ reserved: '<credential>', where: '*', position: '…' }"
}
}The whole document check --json prints
{
"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": [