Skip to content

Add a rails policy to the policy registry #116

Description

@bkd-dotcom

What this is

signetry-core ships a policy registry: a directory of YAML files, one per repository
shape, that says which paths an AI agent may touch for a given task and which it may not.
Six ship today (signetry_core/policies/):
python-library, node-service, monorepo-service, docs-only, dependency-bump,
ci-workflow-fix. A Rails application is missing.

This is the highest-leverage thing you can contribute without touching the kernel: one new
file, no Python, and no test to writetests/test_policy_registry.py is parametrized
over every file in that directory, so your policy is validated the moment it exists.

The deliverable

One file: signetry_core/policies/rails.yaml. Copy
python-library.yaml
as your starting shape — the # @policy header comments are load-bearing metadata, not
decoration.

A starting point, not a spec to type in verbatim — argue with it, the reasoning is the
contribution:

# @policy id: rails
# @policy title: Rails app (app/ + spec/, RSpec)
# @policy summary: A Rails application. The agent may change models, controllers, views, jobs and specs,
#   and must keep RSpec and RuboCop green. Migrations, the generated schema, initializers
#   and credentials stay off-limits.
# @policy stack: ruby, rails, rspec, rubocop, activerecord
# @policy author: your-github-handle
# @policy blocks: db/migrate/20260901120000_add_plan.rb, db/schema.rb, config/initializers/cors.rb, config/credentials.yml.enc, .github/workflows/deploy.yml
# @policy allows: app/models/subscription.rb, app/controllers/billing_controller.rb, spec/models/subscription_spec.rb, config/routes.rb, Gemfile
version: 2
task_type: feature-work

allowed_paths:
  - "app/**"
  - "spec/**"
  - "test/**"
  - "lib/**"
  - "config/routes.rb"
  - "config/locales/**"
  - "Gemfile"
  - "README.md"
  - "CHANGELOG.md"

forbidden_paths:
  # db/schema.rb is GENERATED by running migrations. Hand-editing it makes the
  # checked-in schema disagree with the migration history, and the next migration
  # run silently overwrites the edit.
  - "db/**"
  # Inside config/** — routes.rb and locales are allowed above, but initializers
  # run at boot before any spec loads, and can monkey-patch anything in the tree.
  - "config/initializers/**"
  - "config/credentials*"
  - "config/master.key"
  - "config/environments/production.rb"
  - ".github/**"
  - "Dockerfile*"
  - "**/.env*"
  - "**/*secret*"

max_files_changed: 15
required_checks:
  - "bundle exec rubocop"
  - "bundle exec rspec"

policy_owner: your-team
policy_version: "1.0"

The part people get wrong

Your blocks list must include at least one path that sits inside your own
allowed_paths
. Carving an exception out of a directory you otherwise own is the whole
skill. For a Rails application that exception is:

config/initializers/** — you want config/routes.rb and config/locales/**
allowed, so the natural instinct is to allow config/**; do that and the agent can
monkey-patch the framework from a file that runs before any spec.

The Rails trap worth a comment in the file

Gemfile without Gemfile.lock (or the reverse) is a build that resolves
differently on the next machine. And Rails' autoloading means adding a file under
app/ changes behaviour without any call site appearing in the diff
— a new
app/models/concerns/ module gets picked up by name.

Acceptance criteria

  • signetry_core/policies/rails.yaml exists; filename matches @policy id.
  • blocks and allows each list 3–4 realistic paths for this stack, and don't overlap.
  • At least one blocks entry is inside allowed_paths.
  • Every forbidden_paths entry that isn't self-evident carries a comment saying why,
    not just that it is. python-library forbids conftest.py at any depth and the comment
    explains it executes at collection time on every developer machine — that is the bar.
  • pytest tests/test_policy_registry.py is green. The suite proves each claimed block is
    actually refused by the real evaluate_contract, so a policy that misleads adopters
    fails CI rather than shipping.
  • If the policy permits something risky, it says so in a caution:signetry init
    prints it at adoption time. A risky policy with no caution gets sent back; a risky
    policy that's honest is fine.

Getting started

The full numbered walkthrough, including what makes a policy worth merging, is in
docs/site/policy-registry.md → "Contributing a policy".

git clone https://github.com/Signetry/core && cd core
uv sync
uv run pytest tests/test_policy_registry.py -q
uv run signetry policies          # your entry should appear here once the file exists

Comment to claim it — one policy per contributor so nobody's work gets duplicated. Happy to
review a half-finished scope list; the reasoning matters more than the YAML.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions