Skip to Content
ArchitectureReasoning serviceAgent accountability
Architecture · Reasoning

Agent evidence, checked on intake and shown as cases.

A batch is refused at the first failed check. Storage is the last step, and it is not acceptance.

What it is for

An organisation’s agentsAgentA program that takes actions for an organisation. NovusLens records what it is allowed to do and what its activity reports show. act on systems the organisation owns. NovusLens keeps a record of what each agent was authorised to do, what it was observed doing, and who answers for its work. A steward can then ask about one case and see the evidence behind the answer. The modules on this page belong to the reasoning service. They receive signed agent evidence and show case files and remitRemitA written list of an agent’s allowed actions, resources and destinations for information. The list states whether it is complete. comparisons. They answer ownership questions from records and generate policy exportsPolicy exportA file of rules generated from an agent’s recorded permissions, in Cedar or Rego format. NovusLens generates the file. The customer decides whether to use it. for the customer.

AuthorityAuthorityWhat a team or agent is allowed to decide or do. For an agent, this comes from a named person or system that grants permission. (what an agent is permitted to do) and ResponsibilityResponsibilityThe work or result that a team or agent answers for. NovusLens records the person answerable for it. (who answers for its work) are recorded as separate things. Both are kept apart from what the agent was observed doing. A record that names an owner is shown as a record. A missing owner is shown as a gap in the record, not as proof that nobody answers for the work.

How it works

Intake

agent_evidence.ingest, behind POST /agent-evidence/ingest, takes one signed batch. The caller must be an operator with write access. The service resolves the active policy with agent_policy.resolve, and stage then runs its checks in a fixed order before anything is stored:

  1. The envelopeEnvelopeThe surrounding fields that identify a message, its sender, its type and its time, alongside the message's data. signatureDigital signatureA check calculated with a signing key that can detect whether a record has changed. Identifying the signer also requires a trusted link between that key and its owner. is verified with federation.verify_signature, and the batch’s org must match the request.
  2. The source must be enrolled and enabled, and the envelope must be signed with that source’s enrolled key. The public keyPublic keyA value used to check a digital signature. Sharing it lets others check signatures but does not let them create new signatures. that ships with the demonstration fixturesFixtureA prepared set of records used for a test or demonstration. A fixture is sample data, not a live customer's records. is refused for authenticated intake.
  3. Each record must pass common_py.agent_evidence.validate, name a record type the source may publish, and name a subject that the enrolmentEnrolmentThe operator's recorded permission for a source to send specified record types about named agents, using an identified signing key. links to an existing cellCellA box on the map that stands for a team, service, supplier or AI agent. It is a unit you can inspect, not necessarily a department or a person.. Its timestamp may be at most five seconds ahead of the server clock.
  4. Grant issuers, authorisers and acceptors must appear on the source’s enrolled lists. A remit’s issuer is checked when reads are assembled, not at intake.
  5. Only then are the signed bytes stored as an artifactArtifactA stored source file or evidence body that a record can cite. Keeping the exact content lets a reader check what supported the record., and the batch is queued in the outboxOutboxA database list of saved messages waiting to be published. A message stays on the list until its progress is recorded. with an admission record. That record holds the enrolled key, the subject bindings, the environment and the policy revision in force.

Batches are bounded at 2 MiBKiB and MiBBinary size units: one KiB is 1,024 bytes; one MiB is 1,048,576 bytes. Evidence limits use these units. in canonical formCanonical JSONA fixed way to write data: sort the field names and omit spaces between fields. Do not use infinity or invalid numbers. Sender and receiver can then sign and check identical content. and 1,000 records. Retries are idempotentIdempotentRepeating the same operation has the same effect as doing it once: it creates no extra copies or repeated changes. on the organisation and batch_id. A retry with the same signed envelope returns the original receiptReceiptA recorded acknowledgement of a request or action, with its identity, time and result. An evidence intake receipt confirms storage. It does not establish acceptance or prove that an agent acted. with duplicate: true. The same batch ID with different content, a different source or a different cursorCursorA saved position in a sequence of records. A program uses it to continue from where it stopped. is refused.

Intake returns a receipt, described under receipts. A successful intake means the evidence is stored. It does not mean the evidence has been accepted, or that any runtime acted on it.

Projection, refresh and fencing

A stored batch is pending projectionProjectionThe regular pass that brings the read model up to date with the canonical log. It runs every 30 seconds by default. until it has been published to the twinTwinNovusLens’s model of one organisation, built from records about its teams, services and how they rely on one another. It is only as current as those records. and materialised. agent_evidence.refresh (POST /agent-evidence/refresh) publishes pending batches in rounds of up to 20, for at most 50 rounds. It then runs the materialiserMaterialiserThe component that reads recorded changes in order and updates the database. It records its place so it can continue after a restart. and derives the fleet-incident and remit-drift findingsFindingA difference in the records that needs a decision. It includes its sources and can describe a slow handoff, disputed fact or missing owner.. It reports projected, or projection-incomplete with the number of batches still waiting.

Until projection catches up, reads do not make a current claim. A case read reports updating when pending evidence in the viewer’s scopeScopeThe work, data, activity or access that a rule, statement or calculation covers. For access, it names the records an account can see. For team measures, “Own operations” covers the selected unit. “Including descendants” adds the units beneath it. could change its answer, and it withholds the operation list. The organisation-wide views return empty lists while any admitted batch is pending.

The delivery worker

When CONWAY_AGENT_EVIDENCE_CONFIG is set, the reasoning service starts agent_delivery.run as a daemon thread, named agent-evidence-delivery, from its lifespan. The thread moves stored batches through publication and projection without a request waiting on it.

The worker is bounded at every step. A pass selects at most 20 organisations that are due. For each one it publishes at most 20 batches, then runs the materialiser. A session advisory lockAdvisory lockA database lock that cooperating programs take to prevent conflicting work at the same time. They must explicitly use the lock. per organisation stops two workers from processing the same organisation at once, and a lost connection releases the lock. A completed pass leaves the organisation due again two seconds later while batches remain. A failed pass stores the error class, not the message, because transport errors can contain secrets. Its wait doubles from two seconds and is capped at 60 seconds, and the attempt count stops at ten. The batch stays in the outbox until it is projected.

The worker is restartable because its state is in the database. The outbox holds the batches, and the agent_evidence_delivery table holds each organisation’s retry state. A restarted service reads the due organisations from there and carries on. The worker’s only dependenciesDependencyA link where one unit needs something from another. A dependency is not a reporting line: it shows where work relies on something else. are the database, the twin writer and the materialiser. It sends nothing to the customer’s systems or agents. On shutdown the service sets the stop flag and waits up to three seconds for the thread to finish.

GET /agent-evidence/delivery reports pending batch counts and the oldest pending time. Status is pending, projected, retrying or idle. It includes attempts, the last attempt and the error class.

On a customer host, the projection worker delivers pending evidence after each successful materialisation. CONWAY_AGENT_EVIDENCE_CONFIG is a development setting. See projection.

Case reading

agent_evidence.read (GET /agent-evidence/case) assesses one intervention request. It returns authorisation, execution, outcome and the subject’s operations. An explain block adds the triggers, mandate and any corrections alongside those results. It runs in a repeatable-readRepeatable readA database mode that lets a group of reads use the same saved picture, even if another program changes the records while those reads run. transactionTransactionA group of database changes that is saved together. If the group fails, its changes are not saved..

An assessed record must be within the viewer’s cell scope. Its source must remain enrolled and unchanged, and its signed artifact must still exist. Purging the source therefore removes the support. The result carries a revision digestHashA fixed-length fingerprint calculated from content. Comparing fingerprints helps detect changes and match records., so a consumer can tell when the answer has changed. With policy_mode=current, the active policy is used. With policy_mode=recorded and a known_at cutoff, the policy and evidence known at that time are used.

The remit panel (agent_evidence.activities, GET /agent-evidence/activities) shows each subject in scope with its recorded remits. Each observed activity is compared with those remits by agent_authority.evaluate_activity. The panel shows the comparator’s status, the attribution (individual where an execution identity is present, otherwise group), the coverageCoverageWhat the available records cover, and what is missing. A count such as “3 of 5 dependencies measured” names the measured portion and the gap., and any deployment reports. Its own note says that the detector classifies, NovusLens does not, and that an incomplete remit never proves prohibition.

Ownership questions in Ask

Before the model is consulted, accountability.answer_from_records is tried. compass.run_loop calls it, so Compass and the Strategy agent share it. It answers from the authority records and the open findings, and it runs three routes in order:

  • an inventory of capabilitiesCapabilityWhat a team can provide or an agent can do. NovusLens records the claim and the evidence that supports it. with no owner, which reports four results that are never merged: recorded as unowned, accountable ownerAccountable ownerThe person recorded as answerable for a team, service or agent. NovusLens does not assume that this person is also the one who runs it day to day. not recorded, operational ownerOperational ownerThe person who runs a team or service day to day. This is not automatically the accountable owner, and NovusLens records the two separately. not recorded, and conflicting assignments;
  • a key-person question, answered from key-person findings only, with no count and no name in the answer;
  • a named-topic lookup, such as who is accountable for a given cell.

For a named topic, owner status is recorded, recorded as unowned, in dispute, or not recorded. Unowned needs a finding naming the absence. A dispute keeps both accounts without choosing one. Documents that say “is accountable for” are quoted as recorded statements, not as independent verification. Compound questions, and questions whose topic is a pronoun, fall through to the model.

Remits: declared in the product

A remit states what an agent may do for one subject. It lists allowed and excluded operations, resources and destinations. It records validity dates, responsible role, optional document reference and whether the allowed list is complete. Remit authoring in remit_authoring runs in five steps.

  1. Draft. A writer records a draft with declare. Nothing is signed. Catalogue warnings are attached to the draft.
  2. Approve. approve runs two recorded checks. The approver must be on the product source’s enrolled remit_issuers list. The approver must also cover the subject’s cell: a cxo covers every cell, and a bu-owner covers the cells in their scope. An operator approves only on a named responsible person’s behalf, through on_behalf_of, and that person must pass both checks. A refusal returns approved: false with the reasons in words. It is not an error.
  3. Publish. On approval, the installation’s Ed25519Ed25519The digital-signature method used to sign evidence. The private key signs the exact content; the public key checks that signature. product key signs the remit. The key is kept in the database. The record then passes the normal stage intake check. A later declaration for the same subject replaces the earlier one by correctionCorrectionA change to a recorded value or record. The earlier version stays in the history, and any conclusion that depended on it is checked again., so no two live remits overlap.
  4. Withdraw. withdraw publishes a signed withdrawalWithdrawalA source’s removal of a value or record from current use. Its history stays, and NovusLens checks conclusions that depended on it again. with a stated reason.
  5. Templates. template records a draft revision for a set of member subjects. approve_template then issues, corrects or withdraws one record per member against the previous revision. An exception on a member stands until it is withdrawn.
The shaded step is where a person decides. Export is generated text for the customer to deploy at their own enforcement point.

Approval, withdrawal and template approval each take an advisory lock per subject, or per template, so two decisions cannot race.

export (GET /remits/export) renders an approved declaration as CedarCedarA language for writing rules about who may perform an action on a resource. NovusLens can generate files in this format for the customer to review. or RegoRegoA language for writing rules that a control system can check. NovusLens can generate files in this format for the customer to review. text and records its digest. The header of the artifact says that it is generated and not deployed. A Cedar export carries no validity dates, so the renderer lists them as clauses the target cannot carry. The Rego renderer does carry them. Each export lists every clause the target cannot carry, and no export is described as lossless. The customer deploys the artifact at its own enforcement point. A deployment report that names the digest is recorded as deployment reported.

Policy: versioned and activated by the operator

CONWAY_AGENT_EVIDENCE_CONFIG names a server-owned JSONJSONJavaScript Object Notation: a text format for data, using named fields, lists and values. Configuration files and service messages use it. file. It has version: 1 and an organisations map, and each organisation has sources and criteria. Intake and reads do not read that file directly. They read the activated copy.

FieldHolds
sourcesPer source: enabled, public_key_b64, subject_cells, record_types, grant_issuers, authorisers, acceptors, remit_issuers and environment (unknown, production or simulated).
criteriaPer intervention case: name, unit, window_start, window_end and expected_value.
boundary_sourcesPer legacy boundary feedBoundary feedRecords supplied by the customer’s own systems about activity at the edge of an agent or service. NovusLens reads those records; it does not watch the agent.: the endpointEndpointA particular address on a service that accepts a defined kind of request., the public keys, the subjects, the mode (demo or production), and the refresh and clock-skew bounds.
settingsfleet_window_ms (one minute to one day) and evidence_horizon_ms (one hour to 366 days). The horizon defaults to 30 days for the organisation-wide views. Grants and remits are read whatever their age.

POST /agent-evidence/policy/activate is operator-only. It reads the file, merges it into the current activated policy, checks the result against the policy bounds and writes a new epochEpochFor timestamps, the starting point is 1 January 1970 at midnight in the shared world time reference. For evidence policy, it is the recorded version number.. Activation is additive by default, so activating one source does not withdraw the others. The policy is stored as an artifact with its epoch, its recorded time and its digest. Activating an unchanged policy writes nothing. A recorded time may not precede the last activation.

Before the first activation, the file is the current configuration but it is not versioned, and there is no history for it. A historical cutoff earlier than the first activation is refused, because historical policy cannot be inferred. After activation, a file edit has no effect until it is activated. POST /agent-evidence/criteria records one case’s outcome criterion as an activation of its own.

Legacy boundary feeds

A boundary feed carries records published by the customer’s systems, including signed agent declarations and reported activity. NovusLens reads those records to form evidence; it does not operate the customer’s agents.

boundary_policy.allowed decides whether a stored boundary comparison may count as support. The comparison must carry an enrolment that matches the current boundary_sources entry exactly, and the endpoint must match the entry’s host and port. Both the envelope and the facts must verify against their keys, and the refresh interval must be within the bound. When the profile is customer, the entry must be in production mode, and no key may be the public fixture key. checker refuses everything unless the active policy is a current, activated one, so an unversioned file does not qualify. finding_support consults this check when it reads boundary findings. Disabling a source, rotating its key or changing its bindings therefore withdraws support, and the original artifacts are kept.

Receipts and cursors

agent_receipts.receipt (GET /agent-evidence/receipt) reports the stored artifact, the document digest, the stored time and the cursor for one source and batch. Its status is one of four values. projected means the batch is in the read modelRead modelThe database tables used by the map, Ask and Find. NovusLens rebuilds these tables from its history of recorded changes.. published-pending-projection means it has been published to the twin but not yet acknowledged. stored-pending-projection means it is in the outbox only. evidence-unavailable means the signed evidence cannot be resolved. Every receipt carries the sentence “Durable intake receipt; not evidence acceptance or runtime execution.”

agent_receipts.checkpoint (GET /agent-evidence/checkpoint) returns the latest cursor for one source’s stream, with the receipt of the batch that set it. A producer that loses a response can use the receipt to recover. Cursor positions are validated at intake, a stale previous position is refused, and a reused position with different content is refused. Both receipt routes are operator-only.

Interfaces

Evidence intake, reads and policy:

RouteCallerWhat it does
POST /agent-evidence/ingestOperatorAdmits one signed batch and returns its receipt.
POST /agent-evidence/refreshOperatorPublishes pending batches, materialises them and derives findings.
GET /agent-evidence/caseViewer, scopedAssesses one intervention request. Optional known_at and policy_mode (current or recorded).
GET /agent-evidence/requestsViewer, scopedLists the intervention requests in the viewer’s scope.
GET /agent-evidence/activitiesViewer, scopedThe remit panel: remits and comparator results per subject.
GET /agent-evidence/deliveryOperatorBacklog and worker state for the organisation.
GET /agent-evidence/receiptOperatorThe receipt for source and batch_id.
GET /agent-evidence/checkpointOperatorThe latest cursor for source and stream, with its receipt.
POST /agent-evidence/policy/activateOperatorActivates the policy file as a new epoch.
POST /agent-evidence/criteriaOperatorRecords one case’s outcome criterion as an activation.

Remits:

RouteCallerWhat it does
GET /remits/product-sourceViewerReports the product source, its enrolment problems and the subjects it binds. The operator’s call creates the key if none exists.
POST /remits/product-source/rotateOperatorReplaces the product key.
GET /remits/declarationsViewer, scopedDeclarations and template revisions in scope.
POST /remits/declareWriterRecords a draft. Nothing is signed.
POST /remits/approveWriter with an approval role, or the operator on on_behalf_ofApproves a draft and publishes a signed remit, or refuses with reasons.
POST /remits/withdrawWriter, scope checkedPublishes a signed withdrawal of an approved declaration.
POST /remits/templateWriterRecords a template revision as a draft.
POST /remits/approve-templateWriter with an approval roleIssues, corrects or withdraws one record per member.
GET /remits/exportWriterRenders an approved declaration as Cedar or Rego, by format (default cedar).

The modules call PostgresPostgresThe database software that stores the tables read by the NovusLens screens, along with document bodies, access records and protected personnel records., the meshMeshA set of connected Mycelium services that exchange updates and keep the NovusLens log. writer and materialiser, and the federationFederationSharing selected signed facts and summaries between separate regional twins, while their detailed records stay in their own regions. signature check. They use the policy file named by CONWAY_AGENT_EVIDENCE_CONFIG. Enrolment is done with the connectorsConnectorSoftware that reads records from a source system, such as an incident tool. A customer-written file connects those records to teams or services in NovusLens. command agent-source, as described on the agent evidence sources page. The full route list is on the HTTP endpoints page.

Invariants and failure behaviour

Every check in intake runs before anything is stored. A batch with a bad signature, an unenrolled or disabled source, a foreign tenant or an unbound subject is refused, and nothing is queued.

Intake, refresh, policy activation, receipts, checkpoints and delivery status are operator-only. Drafting requires a writer role, and the board role is read-only under guards.require_writer. Scope is enforced on every object route. The cxo and the operator see unscoped views. Other viewers see the cells in their scope. An out-of-scope object returns a 403 with the generic access message, not a description of what exists.

Approval refusals are answers. Nothing is written when a refusal is returned. Approval, withdrawal and template approval are processed one at a time per subject, and the approval is rechecked under the lock.

Policy history is append-only. Each epoch’s digest is checked when it is read, and a mismatch fails the read. Key rotation does not rewrite history. Records signed with the old key stay admitted under the enrolment that held it, and they lose eligibility once the new key is activated.

Failures behave as follows:

  • A storage outage returns 503 with the message that no new assessment is available, and the caller retries once the database recovers.
  • A batch that has been stored but not projected keeps the affected reads at updating. Nothing is marked as supported in the meantime.
  • A failed delivery leaves its batch in the outbox. The next attempt happens after the backoffBackoffA delay before retrying a failed operation. The delay usually grows after repeated failures to avoid making an outage worse., and no runtime authority is granted in the meantime.
  • After a restart, the outbox and the retry state are read back from the database, and an abandoned lock is released with its connection.
  • A backdated activation is refused, and so is a historical cutoff before the first activation.

Signed evidence in, the outbox and delivery worker, the read model, case reading, and the remit declaration, approval and export path.

Last updated