# Minimum viable CRM AI context layer
#
# Seven entries. This is the whole starting library, and it is meant to look
# small. Every entry here is one you can write today without research, because
# you already know the answer. Everything after these should come from a wrong
# answer you logged and traced.
#
# Swap the object and field names for yours. The failure modes are universal.
#
# Schema:    https://gtmjosh.com/schema/context-layer-entry.schema.json
# Reference: https://gtmjosh.com/guides/context-layer-rule-schema
# Guide:     https://gtmjosh.com/guides/minimum-viable-context-layer

- id: R-001
  kind: rule
  title: >
    Use the configured fiscal calendar for every quarter, year, and
    period-over-period comparison
  category: temporal
  appliesTo: ["*"]
  alwaysLoad: true
  status: active
  version: 1
  ruleText: >
    The fiscal year starts on 1 February and is named for the calendar year its
    January end-month falls in. Never use calendar quarters for a business
    question. Derive the current fiscal period from today's date and state the
    exact date range used before giving any total.
  owner: revops
  evidence: Finance close calendar
  testIds: [GQ-05]
  updated: "2026-08-20"
- id: R-002
  kind: rule
  title: >
    Never sum or compare amounts across currencies without converting to the
    reporting currency first
  category: currency
  appliesTo: ["*"]
  alwaysLoad: true
  status: active
  version: 1
  ruleText: >
    Amount fields are stored in the record's own currency. Summing them across
    records produces a number that is meaningless and looks correct. Convert to
    the reporting currency using the dated conversion rate, or state that the
    total is single-currency and name which one.
  owner: revops
  testIds: [GQ-06]
  updated: "2026-08-20"
- id: R-003
  kind: rule
  title: >
    Exclude system-generated, test, and internal opportunities from all pipeline,
    win-rate, and forecast reporting
  category: exclusion
  appliesTo: [Opportunity]
  alwaysLoad: true
  status: active
  version: 1
  ruleText: >
    Before running any query on Opportunity, add the exclusion filters below
    unless the user has explicitly asked for operational testing records. These
    records are created by quoting and provisioning automation and are not real
    pipeline. Say which exclusions were applied before giving a total.
  filterFragment: "Type != 'Internal Test' AND IsSystemGenerated__c = false"
  owner: revops
  evidence: CPQ creates one artifact opportunity per quote revision
  testIds: [GQ-07]
  updated: "2026-08-20"
- id: R-004
  kind: rule
  title: >
    Credit the account executive from the opportunity owner and the development
    rep from the source contact role, never from a single owner field
  category: attribution
  appliesTo: [Opportunity, OpportunityContactRole]
  dependsOn: [R-003]
  status: active
  version: 1
  ruleText: >
    Two roles get credit for a deal and they live on different fields.
    Collapsing them onto one owner field credits the wrong person, silently and
    consistently. When asked who gets credit, name both roles and the field each
    came from.
  owner: revops
  testIds: [GQ-08]
  updated: "2026-08-20"
- id: R-005
  kind: rule
  title: >
    Treat any field whose API name begins with DNU_ as dead and never read it
  category: authority
  appliesTo: ["*"]
  alwaysLoad: true
  status: active
  version: 1
  ruleText: >
    Retired fields are renamed with a DNU_ prefix rather than deleted, because
    deleting them breaks history. A DNU_ field may still hold plausible-looking
    values from before it was retired. Never use one for routing, reporting, or
    any conclusion. One convention covers the entire long tail; there is no
    per-field entry for these.
  owner: revops
  testIds: [GQ-11]
  updated: "2026-08-20"
- id: R-006
  kind: rule
  title: >
    Query only the allowed objects and fields, and refuse rather than substitute
    a similar-sounding one
  category: security
  appliesTo: ["*"]
  alwaysLoad: true
  status: active
  version: 1
  ruleText: >
    The objects below are the complete set an agent may query. Anything outside
    it is refused, named as missing access, and never approximated from a related
    object. This entry is the semantic half of the policy; the same list must be
    enforced in code at the tool boundary, because guidance text is not
    authorization.
  fieldAllowlist:
    - Account.Id
    - Account.Name
    - Account.OwnerId
    - Opportunity.Id
    - Opportunity.Name
    - Opportunity.AccountId
    - Opportunity.OwnerId
    - Opportunity.StageName
    - Opportunity.Amount
    - Opportunity.CloseDate
    - Opportunity.CreatedDate
  owner: revops
  testIds: [GQ-01, GQ-02, GQ-04]
  updated: "2026-08-20"
- id: R-007
  kind: rule
  title: >
    Never group or filter on a multi-select or formula field; split or
    pre-compute the values instead
  category: anti_pattern
  appliesTo: ["*"]
  alwaysLoad: true
  status: active
  version: 1
  ruleText: >
    Grouping by a multi-select returns a distribution over stored combinations
    rather than over individual values, so "Cloud;Security" becomes its own
    bucket. Formula and calculated fields are derived at read time and do not
    behave like stored values in aggregates. Both operations succeed and return
    a plausible, wrong result, which is the expensive kind of failure. Split
    multi-select values before counting, and aggregate on the underlying stored
    field instead of the formula.
  owner: revops
  testIds: [GQ-09, GQ-10]
  updated: "2026-08-20"