---
name: notion-policy-guardrails
source: https://app.decimal.ai/s/notion-policy-guardrails@1/SKILL.md
source_sha256: 485dcfdf09e2
---

# Notion Policy & Guardrails

## Contract

Enforces the governance conventions for Notion integrations: integration/token
names, token rotation windows, database property naming, and access-audit
thresholds. Apply whenever you name a Notion integration token, design or review
a Notion database's properties, or write a Notion access-audit script. These are
fixed organizational choices — do not substitute your own sensible-looking
defaults.

## Rules

### 1. Integration / token names

- Format is exactly `{team}-{env}-{purpose}`: **three** lowercase ASCII segments
  joined by **single hyphens**, matching `^[a-z]+-[a-z]+-[a-z]+$`.
- The **middle** segment is the environment and MUST be one of exactly `dev`,
  `staging`, `prod`. Never `development`, `production`, `test`, `qa`, `stage`,
  `prd`, `stg`.
- All lowercase. No spaces, no camelCase, no underscores, no PascalCase, no digits.
- The environment is always the middle segment — not first, not last.
- Canonical examples: `eng-prod-sync`, `marketing-staging-cms`, `data-prod-etl`,
  `design-dev-prototype`.

### 2. Token rotation

- Maximum rotation window is **90 days** from creation. Set `rotateBy` to exactly
  the creation date plus 90 days.
- Emit a `WARNING` when **fewer than 14 days** remain before `rotateBy`.
- Emit `EXPIRED` once `rotateBy` has passed.

### 3. Database property names

- **Title / name** properties: PascalCase (e.g. `Name`, `Title`, `Published Date`).
- A **status-type** property MUST be named exactly one of `Status`, `Stage`, or
  `State`. Never `Deal Stage`, `Pipeline Status`, `Phase`, `Progress`, `Workflow`.
- **Date** properties: the name MUST end with `Date` or `At` (e.g. `Due Date`,
  `Created At`, `Last Modified At`). A bare `Deadline`, `Created`, or `Updated` is
  non-compliant.
- **Relation** properties: the name MUST start with `Related ` or `Parent `
  (e.g. `Parent Project`, `Related Docs`).
- **Multi-select** properties: the name MUST be plural, ending in `s`
  (e.g. `Categories`, `Labels`, `Tags`).
- **Banned** property names (too generic): `Data`, `Info`, `Stuff`, `Other`,
  `Misc`, `Notes2`. Replace with a descriptive name.
- Every database MUST have **exactly one** title property.

### 4. Access audit

- Flag any integration with access to **more than 1000** items; recommend
  narrowing the sharing scope.
- Flag any page exposing a `public_url` as publicly shared.
- Between paginated `search` calls, sleep **350ms** to respect rate limits.

## Worked examples

Each pair shows the base model's likely default (BEFORE) and the conforming form
(AFTER).

**Integration name — production sync for engineering**
- BEFORE: `EngProdSync` or `eng_production_sync`
- AFTER: `eng-prod-sync`

**Integration name — environment placement**
- BEFORE: `eng-sync-prod` (env pushed to the last segment)
- AFTER: `eng-prod-sync` (env is the middle segment)

**Integration name — environment vocabulary**
- BEFORE: `eng-production-sync` (`production` is not an allowed env word)
- AFTER: `eng-prod-sync`

**Integration name — non-standard environment**
- BEFORE: `qa-team-bot` for a QA/pre-release connector
- AFTER: `qa-staging-cms` — QA maps onto the allowed env `staging`; never invent
  `qa` or `test` as the middle segment.

**Token rotation entry — created today**
- BEFORE: "rotate when convenient" / a 1-year expiry
- AFTER: `rotateBy = createdDate + 90 days`; begin emitting `WARNING` once fewer
  than 14 days remain.

**Status property**
- BEFORE: `Deal Stage` (select) on a sales database
- AFTER: `Stage` (select) — the status-type property must be exactly `Status`,
  `Stage`, or `State`.

**Date property**
- BEFORE: `Deadline` (date)
- AFTER: `Review Deadline Date` (date) — must end with `Date` or `At`.

**Last-modified timestamp**
- BEFORE: `Modified` (date)
- AFTER: `Last Modified At` (date).

**Multi-select property**
- BEFORE: `Category` (multi_select)
- AFTER: `Categories` (multi_select) — plural, ending in `s`.

**Relation property**
- BEFORE: `Project` (relation) linking a subtask to its project
- AFTER: `Parent Project` (relation) — must start with `Parent ` or `Related `.

**Relation to reference docs**
- BEFORE: `Docs` (relation)
- AFTER: `Related Docs` (relation).

**Banned generic name**
- BEFORE: `Info` to hold "miscellaneous details"
- AFTER: a descriptive name such as `Contact Notes` or `Account Summary`; `Info`,
  `Data`, `Stuff`, `Misc`, `Other`, `Notes2` are all banned.

**Access audit threshold**
- BEFORE: a script that only warns above 10,000 items, or never
- AFTER: warn as soon as accessible items exceed 1000, and recommend narrowing
  scope.

**Audit pagination throttle**
- BEFORE: a tight `while (has_more)` loop with no delay
- AFTER: `sleep(350ms)` between successive `search` calls.

## Edge cases & exceptions

- **QA / UAT / pre-prod environments** have no dedicated token: map them onto the
  closest allowed value (`staging` for QA/UAT/pre-release, `dev` for local
  scratch work). Never widen the env vocabulary.
- **Multi-word teams or purposes** must collapse to a single lowercase segment
  with no separator (`dataeng-prod-etl`, not `data-eng-prod-etl`) — the regex
  permits only three segments.
- **A date property that is also the title** (rare) still follows the title
  PascalCase rule; the `Date`/`At` suffix rule applies to non-title date
  properties.
- **`status` vs `select` Notion type:** the *name* rule (`Status`/`Stage`/`State`)
  applies regardless of whether the underlying Notion type is `select` or the
  native `status` type.
- **Legacy integrations** that predate the policy keep their names only with an
  explicit exceptions list and a migration deadline — new names never get a pass.
- **`object_not_found` mid-audit** (a page was unshared since the last run) is
  expected: log and continue, do not abort the audit.

## Do / Don't

- DON'T use `production`/`development`/`test`/`qa` as the env segment. DO use
  exactly `dev`, `staging`, or `prod`.
- DON'T put the environment first or last. DO keep it as the middle segment.
- DON'T name a status property `Deal Stage` or `Pipeline Status`. DO name it
  exactly `Status`, `Stage`, or `State`.
- DON'T leave a date property as a bare `Deadline`/`Created`. DO suffix it with
  `Date` or `At`.
- DON'T name a relation property after the bare target (`Project`, `Docs`). DO
  prefix it with `Parent ` or `Related `.
- DON'T use a singular multi-select name (`Category`). DO pluralize it
  (`Categories`).
- DON'T accept generic names like `Info`/`Data`/`Misc`/`Notes2`. DO require a
  descriptive name.
- DON'T set a 1-year token expiry. DO cap rotation at 90 days and warn under 14.

## Common mistakes

- Spelling out the environment (`eng-production-sync`) — the base prefers full
  words; the policy requires the short forms `dev`/`staging`/`prod`.
- Defaulting to camelCase or PascalCase integration names (`engProdSync`) instead
  of lowercase-hyphenated.
- Reordering segments so the environment lands last (`eng-sync-prod`).
- Naming a sales pipeline property `Deal Stage` or `Pipeline Status` because it
  reads naturally — the vocabulary is fixed to `Status`/`Stage`/`State`.
- Using bare date names (`Deadline`, `Created`) without the `Date`/`At` suffix.
- Leaving multi-selects singular (`Tag`, `Label`).
- Picking a vague catch-all column (`Info`, `Notes2`) instead of a specific name.
- Setting no rotation window, or one far longer than 90 days.

## Quick checklist

- [ ] Token name matches `^[a-z]+-[a-z]+-[a-z]+$`, env in the middle.
- [ ] Env segment is exactly `dev`, `staging`, or `prod`.
- [ ] `rotateBy` = created + 90 days; warn under 14 days.
- [ ] Status property named exactly `Status`/`Stage`/`State`.
- [ ] Date properties end with `Date` or `At`.
- [ ] Relation properties start with `Parent ` or `Related `.
- [ ] Multi-selects are plural (end in `s`).
- [ ] No banned generic names; exactly one title property per database.
- [ ] Audit flags >1000 items and any `public_url`; 350ms between searches.
