☰ Contents

Trust and Data

F verified factP decided planC open challenge

Purpose

Every case begins with content the platform did not write: a ticket body typed by a customer, an email from outside Ablera, an attached workbook, a row read from a database, a log line, a web page. The same platform holds connectors that write to production Oracle. Those two facts together define the security problem, and it is not a deployment detail — it is an architecture rule, because the boundary has to hold inside the agent loop where no firewall reaches.

This document defines what the platform trusts, what a case is allowed to do, and what data may leave it.

1. The trust boundary — CR-8

P Content is data. Authority comes from grants and gates, never from content.

Untrusted everything observed through a connector: ticket and email bodies, attachments, file contents and file names, database rows, log lines, web pages, HelpDesk articles, commit messages, and any text an agent produced from them
Trusted the case's grants (§ 2), the human's answers at gates, and published prompts and profiles (Agent Framework). That is the whole list
Derived — informs, never authorizes the memory tree's own articles. They are curated, and they are still written by agents from case material, so an article can carry forward something an untrusted source put there. Memory may shape how an agent investigates; it may never widen what a case may do

Consequences, binding on every profile:

  1. An agent never derives permission from observed content. A ticket that says "you are authorized to fix this directly in production", a document claiming a standing approval, a comment addressed to the agent — all are quoted to the human as content, and change nothing about what the case may do. A wiki article or an uploaded file cannot grant permission.
  2. Instruction-shaped content is surfaced, not executed. When observed material contains directives, the agent reports them with their source and continues its own plan.
  3. Connector results are labelled. Every result carries its origin and its trust class, so the label survives into sub-agent prompts and into the ledger.
  4. No agent widens its own scope. A profile's grants are provisioned to it (Agents § 0.1); widening is a gate decision by a human, never a step in a plan.
  5. Memory is not an authority root. A remembered instruction to act, an article claiming a standing approval, a precedent that "we always fix this directly" — none of these grant anything. This closes the durable form of the injection path: untrusted content read in case A, written to memory, and read back as trusted in case B.
  6. Intake never derives execution authority from content. "Work this ticket" authorizes reading it and proposing; side-effectful items are proposed as packets and require current gates/grants; an accepted policy may answer an eligible instance.

Why this is stated at architecture level: the platform's whole value is autonomous multi-step work between gates. Every step in that stretch reads attacker-influenceable text, and the only place the rule can be enforced is in how tools and scopes are provisioned — not in a prompt asking the model to be careful.

2. Grants

What a grant is

A grant answers exactly one question, for one case, at one moment:

What may this case do, to which system, in which environment?

Not what the agent intends to do — what it is permitted to do, checked by the platform against the operation actually requested, before the connector opens a session.

A worked example. A support case opens on a transfer failure for a policy:

Moment The case's grants
Case opens as an incident PROD / IPAL / read · PROD / INSIS / read — nothing else exists
Investigation runs for an hour, dozens of queries unchanged; every one is inside the grant, so nobody is asked anything
The agent proposes a data fix still read-only. A proposal does not grant itself anything
The human approves at the gate PROD / IPAL / write, bound to the shown statement and its expected row count, expiring
The agent tries a second, unshown UPDATE refused before the connection is used — it is outside the bound scope
Case closes all grants expire

Why the design needs them

Because the alternative is asking every time, which is unusable. The agent makes dozens of reads between gates. If each needed approval, the platform would be slower than doing the work by hand — the whole value of autonomous stretches disappears.

Because the other alternative is trusting the agent, which v1 shows is not enough. v1's rule is "strictly read-only, never DML on any environment" and it is enforced only by the model's own discipline. The 20.05.2026 audit measured that kind of discipline failing: four error families recurred after the rule against them already existed F: [write-time discipline]. A rule that lives in a prompt is a rule the author can forget while authoring.

A grant moves the boundary from the agent's judgement into the connector: it does not matter what the agent decided, because the operation is refused before it reaches the database.

Because "which environment" is where the expensive mistakes are. The estate has eleven database connections across PROD, TEST and QA. The v1 protection against acting on the wrong one is the operator noticing. A grant makes the environment part of what was authorised, so a case opened against TEST cannot reach PROD even if every other detail of the statement is right.

The properties

Property
Scope environment × system × schema/target × mode (read, dry-run, write)
Issued at case open, from the case type and the operator's own authority; widened only at a gate
Bound where approval was given for a specific change, the grant is tied to that artefact and its preconditions. A material change to payload, environment, scope or preconditions re-opens the gate — the approval was for the thing that was shown, not for the intention behind it
Expiring at case close or a fixed wall-clock, whichever comes first (decision 01.09.2026; the wall-clock is configuration, grants.expiryWhitelabel Catalogue). An expired grant is a refusal, not a warning — a long-running case re-asks rather than holding a production write open for days
Enforced at the connector refusal happens before contact — the connector will not open a session it may not use [F: the PC environment lock]

P The case's current grants are part of every agent's prompt (decision 01.09.2026). An agent is told what it may do rather than discovering it by being refused: the grant set is rendered into the per-case prompt, so planning happens inside the boundary instead of against it. The connector check remains the enforcement — the prompt is how the agent knows, not how it is held.

P Routine work covered by a grant proceeds without asking the human to approve every tool call — that is the point. What is not covered does not proceed at all: undefined or ambiguous authority never permits execution.

P Policies, customer roles, case types, stage outcomes and operation catalogues are versioned data. The engine keeps a closed, versioned set of primitive modes and state transitions so it can enforce their semantics. A customer role maps to those capabilities; adding a primitive effect or message is a software-contract change. Defining policy remains trusted administration, never an action a case can authorise for itself.

P Preflight runs immediately before execution wherever stale state could change the effect, and the connector reports what actually ran, not what was requested.

Two credentials per environment, never one

P A grant is a decision the platform makes about itself; a credential is what the estate will actually let it do. They are separate defences and the second one is only real if the write cannot be taken by the account doing the reading. So a connected environment holds two accounts, never one: a read account that only selects — the one every prober, sweep and investigation uses — and a write account granted only on the targets an approved write shape can name. A credential that could do both makes every read a write away from an accident, and makes an over-broad grant sufficient rather than merely necessary.

P The write account is granted per environment. Connecting a working environment for writes while a customer-facing one stays read-only is a supported configuration, not a degradation, and it is the normal state for a new customer.

P And no connection at all is a first-class mode. With no target credential, a module may finish an explicitly agreed plan/script-only assignment — it emits its script sets, the case reports what it could not prove, and the verification rung it could not reach is named rather than assumed (Quote Verification § 1 says the same thing for the rating gateway: numeric verification unavailable is not the product is broken). A missing connection caps proof. A case whose agreed outcome includes live delivery remains held until the obligation is met or explicitly changed.

Side effects under control

Database writes · stored procedures with effects · configuration APIs · file changes · Git publication · deployments · queue messages · workflow actions · account changes · customer-visible sends · browser interactions that change state.

P A grant says what a case may do; the write-gating protocol says what a particular write needs before it happens (Gating, D72). The two are independent and both are required: an instance inside a grant still needs its gate, and an approved shape still needs a grant covering the environment, system and target. The connector remains the enforcement point for the grant; the write auditor (D73) is the enforcement point for exactness, boundedness and reversibility, and it runs before the gate rather than after it.

3. Roles and approver separation

P Five platform roles plus the Customer-representative role. The roles are delivered by the platform, not by a directory (decision Vladimir, 04.09.2026 — D134, closing A-10): each role is a row of the estate's SRD_SYS.LT_USER_ROLES, assigned to a user in SRD_SYS.USER_ROLES, and Authority issues one role claim per assignment in the token; the mapping from platform role to estate role id is plug-in configuration (roles.estate_role_idsWhitelabel Catalogue) F: [identity chain; UserAccountIdentityFacade.GetRolesClaimsAsync in Authority's Plugin.Standard emits ClaimTypes.Role per USER_ROLES row — serdica-backend master, read 04.09.2026]:

Role May
Viewer open and read any session they are entitled to see
Operator control a session, answer H1–H3 and H6, run read and dry-run work
Approver answer H4/H5/H7 and HW-approve/HW-instance/HW-shared/HW-irreversible/HW-ddl/H5-send for the scoped target; full role matrix: Gating § 3.1
Prompt publisher make a tested prompt, profile or skill version live; roll one back. Held per stage or module, not once across all of them, so no single holder becomes the queue; independent of the other roles — an author may or may not hold it (decision 01.09.2026)
Administrator define profiles, policies, grants and connector scopes
Customer representative confirm business scope/results explicitly assigned by the case type, and accept preview/delivery; no technical write/release permission is implied

F The estate's own login is already an OIDC server — an Ablera component publishing the discovery document and the standard endpoints, federating the password check to the customer's directory with a failover tier behind it F: [the identity-server chain — the /identity-server microservice owns the OIDC endpoints and federates to the customer's LDAP first, its directory second]. P That is what keeps this section short: the platform registers as a client of it rather than growing an identity of its own, and an operator already signed in to the estate reaches the platform without a second login — authorization code with PKCE against an issuer the browser already holds a session for, and silent renewal, so only a genuinely absent session shows a form. Where a customer runs no such server, any OIDC provider it does run takes the same seam; nothing in the platform assumes the estate's.

P Resolved 04.09.2026 (D134). The two facts this rested on were read from the estate's source rather than asked: the identity server does issue client registrations — clients are rows of SRD_SYS.OIDC_APPLICATIONS (or RegisteredClients in oidc-settings.json), with client_credentials for services and the roles scope for users — and it does carry role claims in the token, one standard role claim per USER_ROLES row; the directory (Bulstrad_LDAPBulstrad_AD) checks the password only, though the LDAP plug-in can also surface a bstRole attribute as a role where the estate already maintains it. The platform's endpoints are gated the way every Serdica endpoint is: SRD_SYS.Routes.AllowedRoles (;-delimited) enforced by the JWT-with-session middleware, which re-reads the roles from the Redis session so a revoked assignment takes effect at the next request, not at token expiry. So: no Bulstrad IT directory request — six LT_USER_ROLES rows, an OIDC client registration and Routes.AllowedRoles for the platform's routes are Ablera's own Serdica configuration (Software Architecture § 10.7 row 1); ROLE_ASSIGNMENTS.source = platform_row records the origin. What remains a customer conversation is unchanged in kind: whether the write and deploy roles are acceptable as estate roles at all, since they grant a power no existing role grants — the customer's security owner says so deliberately when the first AISA_APPROVER row is created.

P Approval is a permission, not a second person (decision 02.09.2026). Whoever answers a gate must hold the role for that gate and that target — deployment, write, reversal, publishing, or taking over another person's session. An operator who holds the role approves their own case in one action; one who does not sees the gate become a task in the gate inbox of those who do, and the case parks until one of them decides. No extra staff is implied: the control is the role check and the audit record naming who held it, not a mandatory four-eyes rule. Where the organisation wants four eyes on a specific target, it withholds the approver role for that target from its operators — a role-set decision, not a platform rule.

P The write-identity path: human in the loop now, the agent's own rights as the target (decision Vladimir, 02.09.2026 — D65). Write authority moves along a staged path, per environment and system, and the stage a target is on is configuration (connectors.identities):

Stage Who executes a write The human's position
1 — now the existing privileged support identity (ABLERA_SUPPORT on INSIS — which today holds far wider rights than the work needs), used by the write executor under the HW-ddl gate with the identity of the current D65 stage where estate DDL is applied (D104) in the loop: approves at the gate; execution is by the gated write executor, not an implied DBA step
2 — hardened a dedicated least-privilege platform identity per environment — named object grants, no ANY privileges, no shared accounts across environments — under a unified-audit policy in the loop: the gate authorizes, the platform executes under its own identity, every statement attributable
3 — target the same identity, with the gate auto-confirming the write shapes whose risk class the organisation has accepted (Gating § 1 auto-confirm, D70) on the loop: supervises through the ledger, the metrics and the exception queue

The platform is built so stage 3 needs no redesign — grants, binding, audit and the connector's refusal-before-contact are stage-independent; only the identity rows and the auto-confirm policy change.

3b. Who may start what — initiation rights

P A role says what a person may decide; initiation says what they may begin (D97). The two are separate because they fail differently: a missing decision right stops a gate, a missing initiation right must stop the requested work from starting — otherwise the platform does work nobody authorised and asks for approval afterwards.

Role May start May request May not start
Operator support, configuration — (development is opened by handover from a case they control)
Approver as their operator role
Administrator any module
Customer representative support configuration — an approver grants development
Prompt publisher — (it is a publishing role, not a case role) every module

P Every cell is a default in the customer plug-in (intake.initiation per customer × role × module, Whitelabel Catalogue § 5b), not a rule of the architecture: a customer who wants their representatives to open configuration work directly changes a value, and a customer who wants no client-initiated work at all sets every module to may not start, at which point the client's start a request screen is not rendered for their people. The router enforces it (Agents § 5c); the check is a ledger record whether it passes or fails, because a refusal is evidence too.

4. Data classes and where they may go

P Customer-owned data is the customer's (D127). The operator (Ablera) and the client sign a data-administration agreement under local legislation that governs how the platform holds, moves, retains and erases it; the production-simulation criteria (D42) and the two-role gate (D107) are clauses of that agreement, and the retention policy (D109) is administered within it.

P The boundary is drawn per module (Platform Details PG-7, decision 01.09.2026) and enforced at governed route selection plus a per-deployment endpoint — not at adapter construction, which does not exist per request (Agents § 0.3).

Class Examples May reach
Public / internal product structure, tariffs, catalogues, rating grids, schema, code an estate-approved adapter whose data policy covers this material
Customer-identifying ЕГН/ЕИК, names, addresses, policy and claim numbers tied to a person EU-resident, GDPR-compliant adapters only
Special category health data — product 8000 / ДЗО, provider reports EU-resident, GDPR-compliant adapters only, and handle-substituted wherever the task does not need the individual (D33)
Secrets credentials, tokens, keys never to any model; Vault via make prepare_files, never in the repo F: [branch/env rules]

Module consequences:

Handles, not redaction

P Blanket redaction does not work, and saying so is the point: a support case about this policy for this person cannot be investigated once the identifier is gone. The mechanism is therefore substitution, not deletion.

At the connector boundary, each personal datum — recognised by the customer plug-in's identifier patterns (pii.identifier_patterns, Whitelabel Catalogue; ЕГН and ЕИК for Bulgaria) — is replaced by a case-local handle«ph-3» for a person, «pol-1» for a policy number — and the mapping lives in the case, never in a prompt, a paper, a transcript or the ledger.

The agent sees «ph-3» throughout. It can reason, plan and write about «ph-3» freely, and two mentions of «ph-3» are the same person
Connectors take handles calls are parameterised: policy_by_holder(«ph-3»), never a literal ЕГН assembled by the agent. The connector resolves the handle inside its own boundary and the value never travels back up
Re-identification is an action, not a lookup resolving «ph-3» to a real identity happens only for a customer-visible draft or an operator's screen, is a distinct audited operation, and appears in the gate packet as what will be revealed to whom
The ledger stores handles so an audit record is readable years later without holding the data it describes
Handles die with the case the map is destroyed when the customer closes the case (D49); retention for every artefact class is a controllable retention.* policy with manual erase, anonymise, extend and export actions as gated writes (D109) — rows deleted and the per-case key destroyed in Vault, so backup copies are unreadable too (crypto-shredding, Software Architecture § Challenges); afterwards the case is legible and no longer identifying

P Handles are the mechanism; redaction is not used (decision 02.09.2026). Structured identifiers — ЕГН/ЕИК, policy, claim, VIN, account ids — are substituted deterministically at the connector; free-text personal data is detected and substituted the same way; whatever detection misses reaches only the EU-resident, DPA-covered model, which is the legal basis for Support anyway. The handles are defence in depth and what keeps papers, memory and ledger clean; re-identification stays a distinct audited action.

Why this beats redaction: the investigation keeps its precision — the agent can follow one person across four systems — while no model call, no memory write and no audit row ever carries the identifier. It also removes the judgement call redaction requires, since nothing decides how much to remove.

P Free-text is the hard part: an ЕГН inside a customer's own sentence, or a name in an attachment, has to be detected before substitution. Detection is imperfect, so the boundary is defence-in-depth, not a guarantee — the module-level rule (Configuration handles no personal data at all) stays the primary control. P No stable pseudonym for natural persons (decision Vladimir, 02.09.2026 — D44). Two cases about the same person get different handles; the experience index records the pattern, never the person; joining two cases about one person is re-identification as an audited action on the live systems while both are open. For business objects — a policy, a framework, a claim — a saga entry may carry a keyed hash of the object number (HMAC with a platform key in Vault, rotated yearly, old keys retained for lookup), so cases about one contract can be joined without the number being readable in memory. Never for ЕГН, names or addresses.

Rules added from the Support case studies (02.09.2026)

P Handles carry structure, not only identity (Support Case Studies G-1). A handle is issued by value, so two occurrences of the same ЕИК in two systems resolve to the same handle whatever the field name; and the connector exposes structural facets on a handle — length, prefix, checksum validity, equality with another handle, edit distance to another handle — so an agent can still find a one-digit ЕИК malformation or recognise that a POLICY_NO equals a foreign SR_POLICY_ID without ever seeing the value. Comparison is a connector operation on handles; it is never done by the model on values.

P Re-identification is itemised in the gate packet (G-2). A customer-visible draft stays in handle space until approval; the packet lists each datum that will be resolved and its audience (customer portal, internal note, mail recipient); approving the send is approving that list. A public comment that would carry an ЕГН is refused by the connector unless that datum is on the approved list — the SD-1729 pattern (an operator posting an ЕГН publicly) cannot recur.

P Iteration grants (G-17). A correction series on one logical object inside one case and one day — the SD-1554 shape, four UI rounds in an afternoon — runs under one grant bound to the object set and the day, with a per-iteration preflight and expected counts; a new object, a new environment or a new day re-opens the gate. Binding to a single statement hash stays the rule for one-shot writes.

P One atomic artefact, two schemas (SD-1757). A grant may name several targets when the approved artefact is one atomic block spanning them (IPAL SRD_INTEGR + SRD_CUST); the connector executes the block as one shape-A call and the write log records every statement with its target.

P Browser evidence and worktree secrets (Development Module § 5 G14, G21; D116). A screenshot is a customer-identifying artefact — it bypasses the handle boundary — so verification prefers DOM text passed through the connector's substitution, and a screenshot that must exist is stored as an artefact under the evidence retention, never sent to a model. Files read from a worktree (appsettings*.json, .env, connection strings) are scrubbed before the model sees them — keys, secrets, tokens and passwords replaced by a marker — the same rule the DeepSeek harness (dsh) applies to child-process environments (Agent Runtime § 9.2 pattern 20).

5. What the ledger may hold

F The v1 convention, generalized to every connector: log the statement, target, environment, role, mode and row count — never the result rows (the PC agent's queries.jsonl, artifact).

P An audit record carries: actor and case/task ancestry · profile, prompt and adapter versions · plan revision and the parent decision · applicable policy and grant · the exact requested action · what actually ran · the verification result · payload hash, not payload. Artefact hashes and timestamps are preserved so a reviewer can identify the material used at the time.

P The ledger is append-only and tamper-evident. A mistake is corrected by a linked correction record; history is never silently rewritten when a plan or an interpretation changes. Search indexes and the evidence graph are projections over it.

P No customer PII in the memory tree — record the pattern, never the incident F: [rule].

6. The write path

P Agent Runtime § 5 is the single sequence: proposal → isolated auditor → required decisions → fresh authority/preflight → deterministic executor → connector → recorded/reconciled effect → external-surface proof. No stage holds a mutating connector. Gate decisions bind the proposal hash; grants are materialised for execution, not invented inside an unauthorised proposal.

P Identity, mode and scope are rejected before unauthorised contact. Checking live preconditions necessarily uses an authorised read connection. A stale-state check is not permission to use the write credential, and passing it is not protection against an uncoordinated external author; Planning § 3b defines that limit for DDL.

P An iteration grant covers the approved object set, period, template family and bounds, not arbitrary new statements. Every changed semantic packet still passes the auditor and applicable effect requirements. Accepted policy can answer eligible iterations without repeating the human decision.

P A case key is destroyed by the key service, not by setting a database timestamp. CASE_KEYS.TRANSIT_KEY_REF must identify a case-specific destruction boundary; retaining a shared wrapping key able to decrypt a backed-up wrapped key would not shred that case. Restore tests must prove that a destroyed case remains unreadable from database/paper backups under the configured key-retention policy. Do not claim cryptographic erasure until that test passes.

Challenges