Context Platform
Documentation

Version Latest

Classification and deny rules

How classification levels are inherited across the organisation, which DLP action each level applies, who may read a space, and how organisation deny rules refuse Context actions.

Classification levels

Every space and source has an effective classification, from least to most sensitive: public, internal, confidential, restricted.

  • Own values. A project's classification is set on the project; other nodes (organisation, department, team, group) have a value on their Context space. The organisation root always has one (default internal) and cannot be cleared.
  • Inheritance. A node's inherited value is the strictest of its own value and all its ancestors': project, owning team, department, organisation; a group continues at its parent groups and team.
  • A source's value is the strictest of the inherited value, the source's own value and the .keystone.yaml declaration in its repository.
  • Tighten only. A space or source can only raise its level. A value below what it inherits, or a weaker DLP action, is refused with context.classification.loosening.

DLP action per level

Effective classificationDLP action
public, internalredact: findings of the organisation's DLP patterns are replaced by markers
confidentialdrop: chunks with a finding are left out
restrictedblock_source: one finding withholds every chunk of that source from the response

A source of a regulated project (a project with at least one compliance framework) gets at least drop. A source's own dlpAction (redact, drop or block_source) can only make it stricter.

Fail closed: a missing organisation root, an unknown stored value, a source with an unsupported dlp_policy_id or any lookup error drops the source's chunks.

Set a classification

Both routes need context:space:admin, enforced:

PUT /api/v1/context/spaces/{spaceId}/classification
{"classification": "confidential"}

PUT /api/v1/context/spaces/{spaceId}/sources/{sourceId}/policy
{"classification": "restricted", "dlpAction": "block_source"}

null clears an own value. A project space is classified on the project, not here.

Raising a level takes effect in the same request: vectors the new level no longer permits are removed, the affected sources are marked stale (full-text only) and re-indexed. A level raised outside the Context API (a project's classification or compliance frameworks, a hierarchy move) is applied by the 15-minute maintenance scan.

Frozen lenses and snapshots are re-scanned with the stricter of their captured level and the source's current level: a raised level applies to them, a lowered one never loosens frozen content.

Who may read a space

Besides the role grant, reading or searching a non-personal space needs a membership path to its node, by the node's inherited classification:

ClassificationWho may read
public, internalMembers of the node; for a project space also members of its owning team; administrators of the node or an ancestor; super admins and holders of an explicit context:space:admin grant on the space (own organisation only)
confidentialMembers of the node; for a project space also members of its owning team. Administrator roles and permissions do not grant read
restrictedMembers of the node itself only: no inherited read, not even the owning team, and no administrator override, super admins included
  • Membership: organisation membership for the organisation space; a team of a department for the department; a Directory team membership (direct or through groups, with nesting) for a team; group membership for a group; project membership for a project.
  • Administrators of a node are people with a role binding that grants context:space:admin on that node or above it. Members of a department do not read its team spaces, and teams do not see each other's spaces.
  • Personal spaces are owner-only in every case.
  • A space whose node no longer exists, or whose classification cannot be resolved, is not readable. A database error answers 503 context.authz.unavailable.

The model applies everywhere a space is read: retrieval (lenses, frozen lenses, pair sessions, the MCP endpoint and the agent routes included), the space and source API, project context, snapshots and handoffs, and other people's attribution records.

Organisation deny rules

Deny rules refuse Context actions on chosen nodes for everyone in the organisation, super admins included. They are checked before every retrieval and in every rollout mode. They are written as context_platform_deny on an organisation-level policy:

PUT /api/v1/hierarchy/policies
{
  "level": "org",
  "entity_id": "<org id>",
  "policy": {
    "context_platform_deny": [
      {"actions": ["context:space:search"], "node_kinds": ["team"], "node_ids": ["<team id>"], "reason": "legal hold"}
    ]
  }
}
KeyTypeMeaning
actionsstring array, requiredcontext:space:read, context:space:search, context:space:write, context:space:admin, context:space:*, context:* or *
node_kindsstring arrayorg, department, team, group, project, user; empty or absent means every kind
node_idsstring arrayEmpty or absent means every node
reasonstringShown in denial logs

Any other key, a value that is not an array, or a non-string entry makes the rule invalid. Rules are validated when they are proposed (through PUT /api/v1/hierarchy/policies or POST/PUT /api/v1/policies), and an invalid rule is refused with 400 validation_error naming the rule; nothing is stored.

A stored document that does not parse (written before validation existed) makes every Context authorisation fail closed with 503 context.authz.unavailable until it is fixed. GET /api/v1/context/deny-rules (organisation administrators) shows the effective rules as authorisation parses them, and valid: false with the parser's message when they do not parse.

Last reviewed 17 October 2026View as Markdown

Classification and deny rules · Docs · Neural Inverse