Cortex — Pack Reference
Pack schemas, inheritance model, authoring rules, and change management. The YAML files in the pack bundle directory (loaded into Elasticsearch by the loader) ARE the system; this spec describes it. The loading mechanics (archetype resolution, defaults merge, explode) are in component.cortex.domain-loading.
Pack Types and Ownership
| # | Pack Type | Owner | File | Lifecycle |
|---|---|---|---|---|
| 1 | Profile | Governance Manager | profiles.yaml |
Policy/IAM cycle |
| 2 | Domain | Data/Domain Manager | domain.yaml |
Quarterly |
| 3 | Experience | UX Manager | experiences.yaml |
Every sprint |
| 4 | Accountability | Governance Manager | accountability.yaml |
Policy cycle |
| 5 | Decision Template | Governance Manager | decision_templates.yaml |
Policy cycle |
| 6 | Task Template | Governance Manager | task_templates.yaml |
Policy cycle |
| 7 | Signal Policy | Governance Manager | signal_policies.yaml |
Policy cycle |
Seven files, seven concerns, seven lifecycles. Each file has one owner.
Bundle Directory Structure
packs/bundles/
├── _base/ ← Shared defaults (every domain inherits)
│ ├── profiles.yaml ← Role archetypes + base capabilities
│ ├── accountability.yaml ← Base guardrails + attestation rules
│ ├── experiences.yaml ← Default layout, nav, vocabulary
│ ├── decision_templates.yaml
│ └── task_templates.yaml
├── thebank/ ← Full domain (8 files): manifest, domain, signal_policies,
│ decision_templates, task_templates, experiences, profiles, accountability
├── pacific_sentinel/ ← Medium domain
├── sensor_iot/ ← Sensor domain
└── discovery/ ← Minimal domain (3 files only)
Inheritance Model
_base + domain = final via deep-merge. Domain values win. Explicit null removes a base value. Missing domain files = inherit from _base entirely. A minimal domain needs only 3 files: manifest, domain, profiles.
Base Defaults
| Field | Base Value |
|---|---|
minimum_evidence_count |
1 |
require_rationale |
true |
ai_summary_requires_citation |
true |
separation_of_duties |
true |
sla_hours |
48 |
hash_algorithm |
sha256 |
Inheritance Warning
Not all domain packs override all fields. The TheBank RM accountability pack has no guardrails section — it inherits the base default (minimum_evidence_count: 1). Code accessing guardrails.minimum_evidence_count without fallback gets undefined for RM.
Profile Pack Schema
profile_id: thebank_rm_v1
archetype: analyst # analyst | commander | principal
role: RELATIONSHIP_MANAGER # Matches SSO realm_roles
display_name: Relationship Manager
auth:
roles_any: [RELATIONSHIP_MANAGER] # OR-logic matching against JWT roles
uds_source: thebank
link_field: customer_id
uds:
visibility: [INTERNAL_KEY, FIN_PII_KEY, EXTERNAL_KEY] # Read keys for UDS ABAC
search:
allowed_models: [core_loans, risk_profile, crm_interactions]
capabilities: # Domain overrides beyond archetype
edition_read: true
edition_manage: true
representative_user: { display_name: Jane Chen, email: jane.chen@thebank.com, department: Commercial Lending }
Accountability Pack Schema
accountability_id: thebank_rm_accountability_v1
signals:
policies: [utilization_spike, high_ltv, high_exposure] # signal policy IDs this role receives
severity_filter: [critical, high] # only these severities pass
insights:
entry_modes: [signal_driven, curiosity_driven]
guardrails: # OPTIONAL — inherits from _base if missing
minimum_evidence_count: 1
require_rationale: true
ai_summary_requires_citation: true
allowed_decision_types: [action, no_action, deferred]
review_routing:
default_reviewers: { roles: [RISK_MANAGER] }
default_attesters: { roles: [RISK_MANAGER] }
escalation_path: [RISK_MANAGER] # OPEN GAP: defined but not enforced in code
decision_template_ids:
action: tmpl_credit_review_action_v1
no_action: tmpl_credit_review_noaction_v1
escalation: tmpl_credit_review_escalation_v1
# NOTE: 'deferred' has no template — OPEN GAP G-12
task_template_ids:
review: tmpl_task_risk_review_v1
Signal Policy Schema
policy_id: dscr_breach
name: DSCR Covenant Breach Risk
severity_default: high
source_model: core_loans # Must exist in domain.yaml
computation:
type: threshold
field: "dscr_last_qtr_#" # _# suffix = governed field
thresholds:
- { condition: "< 1.00", severity: critical, reason: "DSCR<1.00" }
- { condition: "< 1.20", severity: high, reason: "DSCR<1.20" }
- { condition: "< 1.35", severity: medium, reason: "DSCR<1.35" }
score_weight: { critical: 40, high: 25, medium: 10 }
Composite scoring (composite_score with weights and min_score_threshold): an entity triggers a signal only if its composite score ≥ min_score_threshold; boolean policies add full weight when true; threshold policies add weight for the severity bucket they hit. Lifecycle and evaluation semantics in component.cortex.signal-lifecycle#policies.
Decision Template Schema
template_id: tmpl_credit_review_action_v1
decision_type: action
required_evidence:
minimum_blocks: 3
required_block_kinds: [query_result]
required_evidence_classes: [loan_exposure, risk_profile]
required_sections:
decision_statement: { required: true }
executive_summary: { required: true, max_length: 500 }
key_risks: { required: true }
mitigations: { required: true }
next_step: { required: true }
system_of_record_statement: { required: true, default: "..." }
attestation_required: true
attestation_rules:
required_capabilities: [decision_attest] # NOTE: inconsistency — see component.cortex.platform-architecture G-13
tags: [credit-review, action, covenant-modification]
effects: # NOT YET IMPLEMENTED (Layer C, see component.cortex.task-and-effect#effect)
- { type: external_routing, target: core_banking_system }
- { type: notification, target_roles: [RELATIONSHIP_MANAGER] }
Edition Narrative Fields — Template-Driven
Edition narrative fields are template-driven and flexible, not a fixed schema. The REST wire format defines 5 base fields (title, executive_summary, methodology, conclusion, hash), but decision templates MAY define additional required_sections. The template's required_sections is the authoritative list for what an edition of that type must contain. Additional fields (e.g. decision_statement, key_risks, mitigation_measures) are stored as template-defined metadata, not as top-level narrative_snapshot fields. Different decision types need different narrative structures — a no-action decision needs minimal narrative; an escalation needs extensive justification.
TheBank Template Summary
| Template | Decision Type | Min Blocks | Attestation | Special |
|---|---|---|---|---|
tmpl_credit_review_action_v1 |
action |
3 | Required (1 attester) | 6 required sections |
tmpl_credit_review_noaction_v1 |
no_action |
1 | Not required | auto_freeze_on_close: true |
tmpl_credit_review_escalation_v1 |
escalation |
4 | Required (2 attesters) | Requires manual_note block kind |
Experience Pack Schema
experience_pack_id: thebank_experience_v1
vocabulary:
monitor: Dashboard
explore: Investigate
entity: Customer
signal: Alert
insight: Credit Review # VocabularyService key 'insight' → this term
ui:
defaults: { reference_timezone: America/Chicago } # IANA tz for LLM relative-date grounding
nav: [monitor, explore, investigations, tasks]
monitor: { blocks: [] }
explore: { suggested_actions: [] }
entity_page: { enabled: true }
ONE per bundle. No per-role override sections in TheBank (role differentiation happens via accountability packs and profile capabilities, not experience pack sections).
ui.defaults.reference_timezone
Optional IANA timezone name used by the LLM orchestrator to ground relative-date expressions ("today", "yesterday", "last 2 days"). When set, the LLM receives the current date/time in this timezone and uses it as the reference for range-bounded queries. Resolution precedence (user wins): (1) JWT zoneinfo claim on the access token; (2) ui.defaults.reference_timezone on the experience pack; (3) UTC. Invalid tz strings fall back to UTC silently; a missing key defaults to UTC (backward compatible). Pick values aligned with how the customer operates, not where the dataspace is hosted — dataspace timestamps are stored in UTC and converted before execution.
Domain Pack Schema
domain_pack_id: thebank_domain_v1
entity: { type: customer, id_field: customer_id }
models:
core_loans:
fields:
customer_id: { type: STRING, label: Customer ID }
customer_name_#: { type: STRING, label: Customer Name, metadata: { sensitivity: governance, visibility: FIN_PII_KEY } }
risk_rating_#: { type: STRING, label: Risk Rating, metadata: { sensitivity: governance, visibility: SENSITIVE_RISK_KEY } }
risk_profile: { fields: {} }
crm_interactions: { fields: {} }
treasury_monthly: { fields: {} }
Governed fields use the _# suffix (see component.cortex.platform-architecture#domain-model.governed-fields).
Pack Authoring Rules
| # | Rule | Rationale |
|---|---|---|
| P-01 | Packs are JSON/YAML only. No executable content. | Security: packs configure, never execute. |
| P-02 | Every pack has a version suffix (_v1, _v2). |
Rollback and A/B comparison. |
| P-03 | Changes within a major version are backwards-compatible. | Prevents breaking deployed profiles. |
| P-04 | Breaking changes → new version + profile update. | Existing users continue until migrated. |
| P-05 | Accountability ≠ Experience. Do not mix concerns. | A vocabulary change must never affect governance. |
| P-06 | All referenced pack IDs MUST exist. | Silent failure on missing refs (OPEN GAP G-03). |
| P-07 | Signal policy IDs MUST match actual definitions. | Exact ID matching required for routing. |
| P-08 | Vocabulary overrides MUST cover ALL user-facing terms. | Partial = mixed terminology. |
| P-09 | Domain vocab vs Experience vocab: experience pack wins for display. | Clear precedence. |
| P-10 | Field names use snake_case. |
Matches Python backend and JSON convention. |
Change Scenarios
- Add a new signal type: create signal policy YAML; add
policy_idtosignals.policies[]in relevant accountability pack(s); ensure severity is in target profiles'severity_filter[]. Pack change only, no code. - Add a new persona: SSO — create role in Keycloak, assign AUTHORIZATION keys; create profile pack with archetype + capability overrides; reuse the existing bundle-level experience (do NOT create a separate pack); create or reuse an accountability pack. Pack + SSO change.
- Change evidence requirements: edit accountability pack (
minimum_evidence_count,require_rationale); no code change (Cortex reads at MCP initialize, frontend via NgRx); roll out via _v2, pilot, expand, cleanup. - Change vocabulary: edit experience pack (
vocabulary.insight: "Case Review"); VocabularyService picks up on next MCP initialize; no code change.
Versioning and Migration
Versioning: {customer}_{purpose}_v{N} (e.g. thebank_credit_review_accountability_v2). Upgrade: copy _v1 → _v2, apply changes; update target profile(s) to reference _v2; test with pilot users; roll out; archive _v1 (do not delete — audit trail). Rollback: update profile(s) back to _v1; immediate on next MCP initialize.
TheBank Pack Matrix
Profiles
| Profile ID | Archetype | Role | Visibility Keys |
|---|---|---|---|
thebank_rm_v1 |
analyst | RELATIONSHIP_MANAGER | INTERNAL_KEY, FIN_PII_KEY, EXTERNAL_KEY |
thebank_risk_v1 |
commander | RISK_MANAGER | + SENSITIVE_RISK_KEY, WATCHLIST_KEY |
thebank_treasury_v1 |
analyst | TREASURY_ANALYST | INTERNAL_KEY, SENSITIVE_RISK_KEY, WATCHLIST_KEY, TREASURY_COUNTERPARTY_KEY |
thebank_auditor_v1 |
principal | AUDITOR | INTERNAL_KEY, AUDIT_KEY |
Accountability Packs
| Pack ID | Signal Policies | Severity | Decision Types | Guardrails |
|---|---|---|---|---|
thebank_rm_accountability_v1 |
3 policies | critical, high | action, no_action, deferred | Inherits base (min 1) |
thebank_risk_accountability_v1 |
all 6 | critical, high, medium | action, no_action, deferred, escalation | min_evidence: 2 |
thebank_treasury_accountability_v1 |
2 policies | critical, high | action, no_action, deferred | Inherits base |
thebank_auditor_accountability_v1 |
none | none | none | N/A (read-only) |
Depends on: component.cortex.intelligence
Realizes: product.pack, product.profile
Required by: component.cortex.domain-loading, component.cortex.investigation-lifecycle, component.cortex.platform-architecture, component.cortex.signal-lifecycle, component.cortex.task-and-effect