Cortex — Axonis Developer Rules
System invariants — what code MUST and MUST NOT do across the Axonis Decision Intelligence platform. Normative for all engineers and Claude Code agents. The authoritative sources these rules point at are the object schemas (component.cortex.decision-evidence), the lifecycle specs (component.cortex.signal-lifecycle, component.cortex.investigation-lifecycle, component.cortex.task-and-effect), the pack schemas (component.cortex.pack-reference), and the runtime archetypes/capability list (bundle profiles.yaml). Drift detection methods and fixes live in the sdd-validate drift-patterns reference.
Inference Prohibitions
Code MUST NOT infer — it MUST read from the authoritative source.
| # | Rule | Authoritative Source |
|---|---|---|
| I-01 | MUST NOT infer capabilities from SSO roles | Profile pack capabilities field |
| I-02 | MUST NOT infer visibility from profiles | JWT token AUTHORIZATION.READ[] |
| I-03 | MUST NOT infer workflow sequence from tasks | Accountability pack |
| I-04 | MUST NOT infer decision types from UI labels | allowed_decision_types[] |
| I-05 | MUST NOT infer data filtering rules | UDS query layer |
| I-06 | MUST NOT infer signal routing from signal type | Policy ID + severity + visibility keys |
Configuration Rules
Everything expressible as pack configuration MUST be pack configuration, not code.
| # | Config-driven (pack) | Code-driven (only if packs can't express it) |
|---|---|---|
| C-01 | Domain vocabulary | New object types |
| C-02 | Signal generation rules | New MCP tools |
| C-03 | Accountability rules (evidence mins, attestation) | New UI components |
| C-04 | UI navigation, suggested queries, KPIs | New block visualization types |
| C-05 | Decision template structure | Decision Effects (Layer C) |
| C-06 | Task assignment roles and SLAs | — |
Test: "Can this if statement be a pack field?" If yes → pack. If no → code with documented rationale. Pack access: Code MUST NOT read pack YAML files directly. All pack access MUST go through the Cortex pack loader (handles _base inheritance, version resolution, caching).
Server-Side Enforcement
These MUST be enforced in Cortex. Frontend MAY gate as UX convenience but MUST NOT be the only enforcement. A frontend-only guard without a matching Cortex check is a security defect.
| # | Check | Enforced At | Cortex Handler |
|---|---|---|---|
| E-01 | Minimum evidence count | Edition creation | create_edition |
| E-02 | Rationale requirement | Edition freeze | freeze_edition_for_attestation |
| E-03 | Allowed decision types | Edition creation | create_edition |
| E-04 | Separation of duties (attester ≠ author) | Attestation | attest_edition |
| E-05 | Attester capability validation | Attestation | attest_edition |
| E-06 | Content hash computation | Edition freeze | freeze_edition_for_attestation |
| E-07 | Block freeze (result_hash) | Block freeze | freeze_block |
UI Rendering Rules
The UI renders; it does not decide.
| # | Rule |
|---|---|
| U-01 | Use VocabularyService for all user-facing terms |
| U-02 | Use column_meta.label for field labels |
| U-03 | Use viz_hints as advisory only |
| U-04 | Capability checks are UX hints only (disable buttons, don't throw errors) |
| U-05 | Data comes from UDS — render as-is, never filter in frontend |
| U-06 | Signal routing comes from packs — render what Cortex sends |
AI Assistant Prohibitions
| # | Rule | Reference |
|---|---|---|
| A-01 | DO NOT invent pack fields not in schema | bundle schemas |
| A-02 | DO NOT invent MCP tools | Cortex tool registry |
| A-03 | DO NOT invent event types | component.cortex.decision-evidence#event |
| A-04 | DO NOT invent state transitions | DES lifecycle specs |
| A-05 | DO NOT invent capabilities | bundle profiles.yaml archetypes |
| A-06 | DO NOT pass profile_id in chat body |
Cortex reads from Redis session |
| A-07 | DO NOT set root_path on FastAPI |
Conflicts with BASE_PATH route prefixes |
| A-08 | DO NOT use fallback field names | Use exact: profile_id, profile_name |
| A-09 | DO NOT implement retry logic | Let failures propagate |
| A-10 | DO NOT access Elasticsearch directly | Use userspace/dataspace via the athena client |
Capability Rules
Source of truth: bundle profiles.yaml archetypes define the ONLY valid capability names. Three archetypes (deep-merge inheritance):
- Analyst:
explore_block,query_block,aggregate,view_schema,llm_chat,ai_assist,llm,insight_read,insight_manage,evidence_read,evidence_manage,signal_read,task_read,task_manage - Commander (adds):
edition_read,edition_manage,edition_attest,signal_manage,governance_read - Principal (adds):
export_data(and removesedition_manage)
Rules: frontend normalizes capabilities to string[], checks via .includes(); selectCanAttest accepts legacy aliases (can_attest, attest, admin) — new code MUST use edition_attest. Known gap: profiles.yaml uses edition_attest but decision_templates.yaml uses decision_attest. Canonical: edition_attest.
Session and Profile Rules
| # | Rule |
|---|---|
| S-01 | MCP initialize MUST be called with profile_id before any chat or tool call |
| S-02 | Failure to initialize → "LLM chat capability not enabled". DO NOT add fallback profiles. |
| S-03 | Profile stored in localStorage['beacon_profile'] on frontend |
| S-04 | Cortex stores profile_id in Redis session keyed by JWT session_state/sid |
| S-05 | Every request MUST include: Authorization, X-Session-ID, X-Profile-ID headers |
| S-06 | Use profile_id and profile_name. Never id or name. |
Vocabulary Rules
| # | Rule |
|---|---|
| V-01 | VocabularyService maps internal keys to display terms ('insight' → configured display) |
| V-02 | VocabularyService uses Angular computed signals: vocab.investigation(), not vocab.investigation |
| V-03 | All user-facing text MUST go through VocabularyService |
| V-04 | Wire protocol uses insight. UI uses VocabularyService output. Route params use insightId. |
| V-05 | Experience packs MUST cover ALL user-facing terms (partial overrides create mixed terminology) |
Allowed Events by Surface
A frontend correctness contract. Cortex does NOT currently enforce surface boundaries (see component.cortex.platform-architecture#surfaces.gap).
| Surface | Allowed Events | Forbidden |
|---|---|---|
| Home | None | ALL mutations |
| Monitor | signal_acknowledged, signal_disposition_set, implicit entry_intent_set |
block_created, text_updated, edition_created |
| Explore | entry_intent_set, signal_linked, signal_disposition_set, block_created, block_pinned, edition_created (caveats), revision_committed |
attested, task_completed |
| Investigations: Narrative | text_updated, rationale_added, comment_added, revision_committed |
block_created |
| Investigations: Evidence | block_pinned, block_unpinned, block_frozen |
text_updated |
| Investigations: Edition | edition_created, review_requested, task_created, attested, decision_tagged |
block_created |
| Investigations: Timeline | None (read-only) | ALL mutations |
| Edition (standalone) | attested, decision_tagged |
ALL content mutations |
| Tasks | task_completed, review_closed, signal_acknowledged |
block_created, edition_created |
Depends on: component.cortex.decision-evidence, component.cortex.platform-architecture