AI Wikis / Agentic Web

Executive Summary

Report summary

We propose a rigorous governance and lifecycle-management framework to ensure that any graph-derived memory pattern proposed for an AI agent is fully validated, reviewed, and safely executable before affecting agent behavior. Core to our design is human oversight at critical junctures and machine-ex

Status
Research archive item
Category
AI Wikis / Agentic Web
Length
4,126 words
Reading time
19 minutes
Report type
evaluation

Key topics

  • AI Wikis / Agentic Web
  • AI Wikis
  • Agentic Web
  • AI
  • .NET
  • C#
  • SQL
  • Python
  • Runtime

Research provenance

Archive status
Research archive item
Content identity
sha256:535b4b12bbf2de9d5d71c16d78f8284dd3925ed737da4042e24ab11306a811b8

For citation, use the report title and canonical URL. Archival presence does not establish authorship or promote report statements into portfolio evidence.

This page renders the archived Markdown as safe, formatted HTML. It is background research and does not become a portfolio claim without evidence review.

Full report

On this page

We propose a rigorous governance and lifecycle-management framework to ensure that any graph-derived memory pattern proposed for an AI agent is fully validated, reviewed, and safely executable before affecting agent behavior. Core to our design is human oversight at critical junctures and machine-executable falsification checks to automatically disable patterns when their assumptions break. This follows established AI-governance principles (e.g. UNESCO’s AI Ethics Guidelines emphasize transparency, fairness, and human oversight) and emerging best practices for agent safety. Our system treats analytical outputs as untrusted by default: every CrossTaskAnalyticalFinding (a generalized pattern inferred from one or more agent trajectories) must pass automated validation and a qualified human review before being committed. Each approved pattern carries executable falsification rules — concrete, testable conditions that, if met in runtime, immediately suspend or quarantine the pattern (e.g. “target object absent” or “confidence below threshold”). This is directly inspired by Popperian falsifiability applied to AI: as noted by recent agent-engineering experts, “no claim is accepted without explicit falsification conditions”.

Our solution includes: a detailed JSON Schema for the pattern artifact, a safe expression language for falsification logic (we recommend using Google’s CEL for its safety and performance), a finite-state lifecycle machine with enforced transitions and audit logging, automated validation rules, secure ASP.NET Core APIs (with EF Core and SQL Server persistence), atomic commit/rollback workflows, a runtime enforcement layer, and a review-dashboard contract. We enforce strict separation of duties (no LLM or automated process has final approval authority) and end-to-end traceability (all decisions, hashes, and attestations are recorded). The design uses UTC for all timestamps, concurrency tokens for safe updates, ETags for HTTP concurrency, and [Display(Name="…")] attributes for clear UI labels. We include code examples with XML documentation and comprehensive test scenarios.

Governance Principles

Our approach embodies established AI governance and software-quality principles:

  • Human-in-the-Loop for High-Stakes Decisions: High-risk patterns must be approved by qualified reviewers. AI safety research emphasizes that even capable agents need meaningful human oversight on consequential actions. For example, we gate any cross-task memory pattern that could alter agent behavior with a human review step, akin to “second-agent reviewer” patterns in multi-agent systems.
  • Accountability & Auditability: All artifacts, decisions, and pattern activations are logged. We require a complete audit trail (“who reviewed/approved what, when”) and immutable versioning. This aligns with governance recommendations to maintain an auditable memory of what the agent knew and when.
  • Transparency & Explainability: Every approved pattern includes its context – matching subgraph, edit plan, and evidence – so reviewers understand why it was inferred. Falsification rules are stored in structured form (not just text) to make their logic explicit. We also record feature and structural scores and a risk classification to quantify uncertainty.
  • Reliability & Consistency: No pattern can be modified silently after approval. Any material change requires a new artifact and review. Patterns have expiration dates to force re-validation. These controls prevent drift and stale knowledge.
  • Security & Integrity: We store evidence references (URIs and content hashes) rather than raw data to protect privacy and enable integrity checks. Each artifact includes a content hash and digital signature/attestation to detect tampering. This follows best practices in supply-chain security.
  • Least Privilege and Role Separation: Authorization is required for every action. Reviewer roles and qualifications are enforced (e.g. domain experts vs. junior reviewers). This is similar to financial workflows where approval limits vary by role.
  • Fail-Safe by Default: Unless explicitly approved, patterns are inactive in agent memory. At runtime, failing a falsification check will disable the pattern (fail-closed) or degrade functionality safely. This conservative stance is standard in safety-critical systems.

Together, these principles ensure that agent memory evolves under strict governance: automated pattern detection is leveraged, but no unvetted insight can directly change agent behavior without passing a robust, multi-layered review process. (See Mermaid diagram below for the pattern review lifecycle.)

CrossTaskAnalyticalFinding JSON Schema

We define a JSON Schema for the artifact we call CrossTaskAnalyticalFinding. This schema enforces structure and basic constraints on each field. For large or binary evidence, we require URIs or content hashes rather than embedding raw data, to support content-addressing and security checks. Key fields include artifact identifier, tenant/fleet scope, tasks and graph versions, the inferred subgraph pattern, scores, solver metadata, evidence refs, risk/confidence metrics, falsification rules, reviewer qualifications, lifecycle state, timestamps, content hash, and digital signature.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "CrossTaskAnalyticalFinding",
  "type": "object",
  "properties": {
    "ArtifactId": {
      "type": "string",
      "format": "uuid"
    },
    "Tenant": { "type": "string" },
    "Fleet": { "type": "string" },
    "SourceTask": { "type": "string" },
    "TargetTask": { "type": "string" },
    "SourceGraphVersion": { "type": "string" },
    "TargetGraphVersion": { "type": "string" },
    "MatchingSubgraph": {
      "type": "object",
      "description": "Graph structure or ID matching the pattern"
    },
    "ProposedGraphEditPath": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "Operation": { "type": "string" },
          "Parameters": { "type": "object" }
        },
        "required": ["Operation"]
      }
    },
    "ProposedActionLogic": {
      "type": "object",
      "description": "Universal action or rule logic (in domain-specific form)"
    },
    "AlignmentScore": { "type": "number", "minimum": 0 },
    "FeatureScore": { "type": "number", "minimum": 0 },
    "StructureScore": { "type": "number", "minimum": 0 },
    "SolverName": { "type": "string" },
    "SolverVersion": { "type": "string" },
    "SolverConfigHash": {
      "type": "string",
      "pattern": "^[A-Fa-f0-9]{64}$"
    },
    "EvidenceReferences": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "Uri": { "type": "string", "format": "uri" },
          "Hash": {
            "type": "string",
            "pattern": "^[A-Fa-f0-9]{64}$"
          },
          "Description": { "type": "string" }
        },
        "required": ["Uri"]
      }
    },
    "TopologySnapshotRefs": {
      "type": "array",
      "items": {
        "type": "string",
        "format": "uri"
      }
    },
    "FeatureModelVersion": { "type": "string" },
    "RiskLevel": {
      "type": "string",
      "enum": ["Low","Medium","High","Critical"]
    },
    "Confidence": {
      "type": "number",
      "minimum": 0,
      "maximum": 1
    },
    "KnownLimitations": {
      "type": "string",
      "maxLength": 1000
    },
    "FalsificationConditions": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "Expression": { "type": "string" },
          "Description": { "type": "string" }
        },
        "required": ["Expression"]
      }
    },
    "RequiredReviewerQualifications": {
      "type": "array",
      "items": { "type": "string" }
    },
    "Expiration": { "type": "string", "format": "date-time" },
    "State": {
      "type": "string",
      "enum": [
        "Proposed","ValidationFailed","ReadyForReview","UnderReview",
        "ChangesRequested","Rejected","Approved","Committing",
        "Committed","Suspended","Superseded","Revoked"
      ]
    },
    "CreatedAt": { "type": "string", "format": "date-time" },
    "ReviewedAt": { "type": "string", "format": "date-time" },
    "ContentHash": {
      "type": "string",
      "pattern": "^[A-Fa-f0-9]{64}$"
    },
    "Attestation": {
      "type": "object",
      "properties": {
        "Signature": { "type": "string" },
        "Signer": { "type": "string" },
        "Timestamp": { "type": "string", "format": "date-time" }
      },
      "required": ["Signature","Signer"]
    }
  },
  "required": [
    "ArtifactId","Tenant","SourceTask","TargetTask",
    "SourceGraphVersion","TargetGraphVersion",
    "MatchingSubgraph","ProposedGraphEditPath",
    "AlignmentScore","SolverName","SolverVersion",
    "EvidenceReferences","RiskLevel","Confidence",
    "FalsificationConditions","RequiredReviewerQualifications",
    "CreatedAt","ContentHash","Attestation"
  ],
  "additionalProperties": false
}
  • Example of a valid artifact:
{
  "ArtifactId": "d2f7f8ab-1234-45c6-b789-0123abcdef45",
  "Tenant": "tenantA",
  "Fleet": "fleet42",
  "SourceTask": "task_login",
  "TargetTask": "task_authenticate",
  "SourceGraphVersion": "graph-v1.2",
  "TargetGraphVersion": "graph-v1.3",
  "MatchingSubgraph": { "Nodes": ["A","B","C"], "Edges": [["A","B"],["B","C"]] },
  "ProposedGraphEditPath": [
    { "Operation": "AddEdge", "Parameters": {"from": "C", "to": "A"} }
  ],
  "ProposedActionLogic": {
    "Type": "Sequence",
    "Steps": ["Login","VerifyToken","CreateSession"]
  },
  "AlignmentScore": 0.87,
  "FeatureScore": 0.75,
  "StructureScore": 0.92,
  "SolverName": "GraphMatcher",
  "SolverVersion": "2.0",
  "SolverConfigHash": "9af3d9b8ae34c648feba1234567890abcdef1234567890abcdef1234567890ab",
  "EvidenceReferences": [
    {
      "Uri": "https://evidence.repo/logs/exec1234.json",
      "Hash": "7e57b6d9b2c10d34a36e8fa2545e0fe446c6f31883f4e9a2c4f7ff63d4eeb9f3",
      "Description": "Execution log from run 1234"
    }
  ],
  "TopologySnapshotRefs": [
    "https://graphs.repo/topology/v1.2/snapshot.json"
  ],
  "FeatureModelVersion": "v3.5",
  "RiskLevel": "Medium",
  "Confidence": 0.82,
  "KnownLimitations": "May not generalize to inactive user sessions.",
  "FalsificationConditions": [
    {
      "Expression": "not context.UserSessionActive",
      "Description": "Target session must be active"
    },
    {
      "Expression": "context.GraphVersion != 'graph-v1.3'",
      "Description": "Graph version changed"
    }
  ],
  "RequiredReviewerQualifications": ["SecurityEngineer","SoftwareArchitect"],
  "Expiration": "2027-07-01T00:00:00Z",
  "State": "ReadyForReview",
  "CreatedAt": "2026-07-20T08:00:00Z",
  "ReviewedAt": "2026-07-21T14:30:00Z",
  "ContentHash": "6fa459eaee8a5ca2772f08c8e0f26bbea1b1d553371f7e86c6b6ee1ba231bf79",
  "Attestation": {
    "Signature": "MEUCIQDn4...",
    "Signer": "ReviewBoard",
    "Timestamp": "2026-07-21T14:30:10Z"
  }
}
  • Example of an invalid artifact: (violates schema rules, errors annotated)
{
  "ArtifactId": "1234",                        // Invalid UUID
  "Tenant": "",                                // Empty tenant not allowed
  "SourceTask": "t1",
  "TargetTask": "t2",
  "SourceGraphVersion": "v1",
  "TargetGraphVersion": "v1",
  "MatchingSubgraph": "notAnObject",           // Should be an object
  "ProposedGraphEditPath": "[]",               // Should be an array of objects
  "AlignmentScore": 1.5,                      // Score > 1.0 (invalid if normalized)
  "SolverName": "Algo",
  "SolverVersion": "1.0",
  "EvidenceReferences": [],                   // Must include at least one reference (if required)
  "RiskLevel": "VeryHigh",                    // Not in enum
  "Confidence": -0.1,                         // Negative confidence
  "FalsificationConditions": [ { } ],         // Missing required 'Expression'
  "RequiredReviewerQualifications": [""],
  "CreatedAt": "not-a-date",
  "ContentHash": "XYZ",                       // Not hex SHA256
  "Attestation": {}                           // Missing required signature fields
}

Falsification-Condition Expression Model

Each pattern carries one or more falsification conditions: executable predicates on runtime context that, if true, disqualify the pattern. We evaluated several options:

  • JSON Logic: A JSON-based logic format. Simple and readable, but lacks types and static validation. Cannot easily handle dates or precision arithmetic without extension.
  • Rego (Open Policy Agent): Powerful policy language, but heavier, with its own eval engine and potential I/O (imports). Possibly overkill for simple checks.
  • General scripting (C# Scripts, Python): Too rich; risk of nondeterminism or side-effects. Not easily sandboxed without complex measures.
  • Custom Expression Tree: Build a custom AST. Safe but reinventing a lot of functionality.
  • CEL (Common Expression Language): A mature language by Google, explicitly designed for safe, fast evaluation. CEL is non-Turing-complete and sandboxable, and only accesses host-provided data. It supports rich types (numbers, strings, booleans, lists, maps) and operations (arithmetic, comparisons, logic, date/time) with deterministic behavior. CEL expressions can be statically checked against a schema, and its evaluation cost is predictable. These qualities match our requirements: deterministic, bounded, versionable, no arbitrary I/O, and explainable.

Recommendation: Use CEL for falsification rules. Each rule is a CEL boolean expression over a given context object. The context supplies runtime facts (e.g. available tools, object states, versions). We can version the language runtime and preload schemas. On evaluation, missing data or type mismatches will be handled as errors (described below).

Expression Schema and Evaluation Interface

We define a simple schema for each condition in JSON (for storage) and a C# interface for evaluation:

// Falsification condition schema (for JSON storage)
{
  "type": "object",
  "properties": {
    "Expression": { "type": "string" },
    "Description": { "type": "string" }
  },
  "required": ["Expression"]
}

In C#, we create an evaluator that compiles CEL expressions and runs them against a context. For example:

public interface IFalsificationEvaluator
{
    /// <summary>
    /// Compiles the CEL expression. Throws FormatException if invalid.
    /// </summary>
    void Compile(string expressionText);

    /// <summary>
    /// Evaluates the compiled expression against the given context.
    /// Returns true if the condition is met (falsified), false otherwise.
    /// Evaluation errors are returned as false, and logged.
    /// </summary>
    bool Evaluate(IDictionary<string, object> contextVariables);
}

A C# implementation would use a CEL library (such as @@MKREPORTTOKEN0@@). The evaluator would:

  • Handle missing data: If contextVariables lacks a needed key, treat that as a false (not falsified) and log a warning. This errs on the side of not disabling patterns unless a clear falsifier is triggered.
  • Type mismatches: E.g. comparing a string to a number. We catch evaluation exceptions and return false. The unsafe condition is not triggered, but we also flag the pattern for review if many type errors occur.
  • Numeric precision: Use decimal internally or specify rounding as part of expressions. We require any numeric threshold to be explicit. (We do not use floating-point comparison without tolerance.)
  • Time comparisons: Date/time values should be in ISO 8601 strings and parsed into DateTime in the context. CEL supports datetime comparisons natively (e.g. timestamp type).
  • Evaluation errors: Any exception during eval is caught and treated as false, but an audit entry is made. This ensures safety but draws attention to faulty rules.

Thus, a falsification condition like "context.GraphVersion != 'graph-v1.3'" or "not context.RequiredToolAvailable" will be interpreted faithfully and deterministically.

Example Usage

  • Compiled expressions: At review time, approved conditions are compiled and stored (to catch syntax issues early).
  • Runtime context: The runtime gateway will supply a context dictionary per evaluation, e.g. { "GraphVersion": "graph-v1.4", "UserSessionActive": true }.
  • Explainable result: If a condition evaluates to true, we log which expression fired and why, aiding debugging.

This design meets all criteria: CEL is portable and versionable (we can pin a specific CEL release), expressions have bounded execution, and the evaluation code is straightforward to audit and test.

Lifecycle State Machine

We define a finite-state machine for artifact review. States include:

  • Proposed: Newly generated, awaiting validation.
  • ValidationFailed: Automatically rejected due to schema or data errors.
  • ReadyForReview: Passed validation, queued for human review.
  • UnderReview: A reviewer has claimed it.
  • ChangesRequested: Reviewer asked for modifications.
  • Rejected: Reviewer permanently rejected it.
  • Approved: Reviewer accepted it.
  • Committing: In process of promoting to active memory.
  • Committed: Successfully added to active memory.
  • Suspended: Pattern was temporarily disabled (e.g. due to a falsification hit).
  • Superseded: A newer version of this pattern exists.
  • Revoked: Permanently disabled post-commit.

Allowed transitions and triggers:

  • Proposed → ValidationFailed: by automated validation (role: system).
  • Proposed → ReadyForReview: if validation passes (system).
  • ReadyForReview → UnderReview: when a reviewer claims it.
  • UnderReview → ChangesRequested: if reviewer requests edits.
  • UnderReview → Rejected: if reviewer rejects outright.
  • UnderReview → Approved: if reviewer approves.
  • ChangesRequested → UnderReview: after author resubmits edits (requires re-validation).
  • Approved → Committing: when system begins commit (initiated by a service).
  • Committing → Committed: on successful commit.
  • Any → Revoked: by authorized admin (emergency).
  • Committed → Superseded: if a new version is approved later.
  • Any (except Committed) → Suspended: if a falsification or admin pause is needed.
  • Suspended → (previous state or Revoked): resumes or revoked by admin.

Each transition has guards and roles. For example, only a user with role Reviewer can move UnderReview→Approved, and only Administrator can Revoked. We record an idempotency key (e.g. a GUID per action) to allow safe retries. All operations update an audit log entry with user, timestamp, and reasons.

Below is a C# implementation sketch for the state machine logic. All public properties use [Display(Name="...")], omitting suffixes (e.g. ArtifactId displays as “Artifact”).

using System;
using System.ComponentModel.DataAnnotations;

namespace AgentMemoryGovernance.Models
{
    /// <summary>
    /// Represents the state of a cross-task analytical finding in its review lifecycle.
    /// </summary>
    public enum FindingState
    {
        Proposed,
        ValidationFailed,
        ReadyForReview,
        UnderReview,
        ChangesRequested,
        Rejected,
        Approved,
        Committing,
        Committed,
        Suspended,
        Superseded,
        Revoked
    }

    /// <summary>
    /// Core entity for a proposed memory pattern (cross-task finding).
    /// </summary>
    public class CrossTaskAnalyticalFinding
    {
        /// <summary>Unique artifact identifier (UUID).</summary>
        [Display(Name = "Artifact")]
        public Guid ArtifactId { get; set; }

        /// <summary>Responsible tenant for this artifact.</summary>
        [Display(Name = "Tenant")]
        public string Tenant { get; set; }

        /// <summary>Scope or fleet identifier within the tenant.</summary>
        [Display(Name = "Fleet")]
        public string Fleet { get; set; }

        // ... (other fields from schema) ...

        /// <summary>Current lifecycle state of this finding.</summary>
        [Display(Name = "State")]
        public FindingState State { get; set; }

        /// <summary>Timestamp of creation (UTC).</summary>
        [Display(Name = "Created At")]
        public DateTime CreatedAt { get; set; }

        /// <summary>Timestamp of the latest decision (UTC).</summary>
        [Display(Name = "Reviewed At")]
        public DateTime? ReviewedAt { get; set; }

        /// <summary>Concurrency token for optimistic locking (rowversion).</summary>
        [Timestamp]
        public byte[] Version { get; set; }
    }

    /// <summary>
    /// State machine logic for CrossTaskAnalyticalFinding.
    /// </summary>
    public static class FindingStateMachine
    {
        /// <summary>
        /// Attempts to transition the finding to a new state under the specified action.
        /// Throws InvalidOperationException for disallowed transitions or unauthorized roles.
        /// </summary>
        /// <param name="finding">The finding to transition.</param>
        /// <param name="action">The action being performed (e.g. "Claim", "Approve").</param>
        /// <param name="actorRole">Role of the user performing the action.</param>
        /// <param name="idempotencyKey">Client-generated idempotency key to prevent duplicates.</param>
        public static void Transition(
            CrossTaskAnalyticalFinding finding,
            string action,
            string actorRole,
            string idempotencyKey)
        {
            // Example guards (simplified):
            switch (finding.State)
            {
                case FindingState.Proposed:
                    if (action == "ValidateSuccess")
                        finding.State = FindingState.ReadyForReview;
                    else if (action == "ValidateFail")
                        finding.State = FindingState.ValidationFailed;
                    else
                        throw new InvalidOperationException("Invalid action from Proposed");
                    break;

                case FindingState.ReadyForReview:
                    if (action == "Claim" && actorRole == "Reviewer")
                        finding.State = FindingState.UnderReview;
                    else
                        throw new InvalidOperationException("Only a Reviewer can claim.");
                    break;

                case FindingState.UnderReview:
                    if (action == "RequestChanges")
                    {
                        if (actorRole != "Reviewer") throw new InvalidOperationException("Only a Reviewer can request changes.");
                        finding.State = FindingState.ChangesRequested;
                    }
                    else if (action == "Reject")
                    {
                        if (actorRole != "Reviewer") throw new InvalidOperationException("Only a Reviewer can reject.");
                        finding.State = FindingState.Rejected;
                    }
                    else if (action == "Approve")
                    {
                        if (actorRole != "Reviewer") throw new InvalidOperationException("Only a Reviewer can approve.");
                        finding.State = FindingState.Approved;
                    }
                    else
                        throw new InvalidOperationException($"Invalid action '{action}' in UnderReview.");
                    break;

                case FindingState.ChangesRequested:
                    if (action == "Resubmit" && actorRole == "Contributor")
                        finding.State = FindingState.ReadyForReview;
                    else
                        throw new InvalidOperationException("Only contributor can resubmit after changes.");
                    break;

                case FindingState.Approved:
                    if (action == "Commit")
                        finding.State = FindingState.Committing;
                    else if (action == "Suspend" && actorRole == "Admin")
                        finding.State = FindingState.Suspended;
                    else
                        throw new InvalidOperationException("Invalid action from Approved.");
                    break;

                case FindingState.Committing:
                    if (action == "CommitSuccess")
                        finding.State = FindingState.Committed;
                    else if (action == "CommitFail")
                        finding.State = FindingState.Revoked;
                    else
                        throw new InvalidOperationException("Invalid commit transition.");
                    break;

                case FindingState.Committed:
                    if (action == "Supersede")
                        finding.State = FindingState.Superseded;
                    else if (action == "Revoke" && actorRole == "Admin")
                        finding.State = FindingState.Revoked;
                    else
                        throw new InvalidOperationException("Invalid action from Committed.");
                    break;

                case FindingState.Suspended:
                    if (action == "Resume" && actorRole == "Admin")
                        finding.State = FindingState.ReadyForReview;
                    else if (action == "Revoke" && actorRole == "Admin")
                        finding.State = FindingState.Revoked;
                    else
                        throw new InvalidOperationException("Invalid action from Suspended.");
                    break;

                default:
                    // Allow Revocation from most states by Admin
                    if (action == "Revoke" && actorRole == "Admin")
                    {
                        finding.State = FindingState.Revoked;
                        break;
                    }
                    throw new InvalidOperationException($"No transitions allowed from state {finding.State}.");
            }

            // Side effects: update ReviewedAt timestamp
            finding.ReviewedAt = DateTime.UtcNow;
            // TODO: log audit event with idempotencyKey
        }
    }
}

Mermaid State Diagram: (visualizing key transitions)

stateDiagram-v2
    [*] --> Proposed
    Proposed --> ValidationFailed : validation fails
    Proposed --> ReadyForReview : validation passes
    ReadyForReview --> UnderReview : reviewer claims
    UnderReview --> ChangesRequested : request changes
    UnderReview --> Rejected : reject
    UnderReview --> Approved : approve
    ChangesRequested --> ReadyForReview : resubmit
    Approved --> Committing : commit
    Committing --> Committed : success
    Committing --> Revoked : fail
    Committed --> Superseded : new version
    * --> Revoked : revoke (Admin)
    * --> Suspended : suspend (Admin or falsifier)
    Suspended --> Revoked : revoke
    Suspended --> ReadyForReview : resume

This design ensures idempotency by using an idempotencyKey (e.g. GUID) for each user action; duplicate requests with the same key have no additional effect. We rely on EF Core optimistic concurrency ([Timestamp] token) and ETags in HTTP to handle race conditions and detect concurrent edits. Every valid transition is logged as an audit event with details (by a separate logging service), so we have full traceability.

Automated Validation

Before any artifact reaches human review, we perform automated checks to catch obvious errors. The validation pipeline includes:

  • Schema Validation: Use the above JSON Schema to check required fields, types, formats (e.g. UUIDs, date-times). Failure here blocks the artifact (state → ValidationFailed).
  • Provenance Hashes: Verify any referenced graph versions or solver configs exist. For instance, check that SolverConfigHash matches the actual solver code version used, and that ContentHash equals the hash of the stored JSON. Mismatch is blocking.
  • Graph References: Ensure SourceGraphVersion and TargetGraphVersion correspond to known graphs. If a graph ID is unknown or deleted, flag as error. (Non-existent graph = blocking error.)
  • Solver Version Check: Compare SolverName and SolverVersion to approved versions. If an outdated or unauthorized solver version was used, fail validation.
  • Score Ranges: Confirm that AlignmentScore, FeatureScore, and StructureScore are between 0 and 1. Values outside indicate a processing bug (block).
  • Edit-Path Consistency: The ProposedGraphEditPath list of operations should be valid graph-edit steps (we can validate format and basic semantics). Inconsistencies here (e.g. invalid operation names) block.
  • Falsification Syntax: Each falsification Expression is compiled to ensure syntactic correctness. Compilation failures cause ValidationFailed.
  • Scope Authorization: Check that the artifact’s Tenant and Fleet match the identity of the requestor or system (prevent submitting for someone else). Blocking error if mismatch.
  • Duplicate Check: Compare (SourceTask, TargetTask, MatchingSubgraph) to existing approved findings in the same scope. Exact duplicates are turned into warnings or automatically superseded, not blocking if intentional.
  • Evidence Availability: For each URI in EvidenceReferences, check accessibility (e.g. HTTP HEAD) and validate the hash if retrievable. Missing evidence logs a warning; critical missing evidence (if policy requires it) may block.
  • Reproducibility Metadata: Ensure timestamps and evidence cover the inference time. For example, require that evidence dates overlap with task executions.
  • Risk-Specific Fields: If RiskLevel is “Critical”, require additional justification fields (e.g. a signed risk assessment). Absence is a blocking error.

We categorize failures as blocking (artifact is invalid) or warning (artifact may still proceed but reviewer sees a warning flag). For example, missing evidence could be a warning, whereas schema errors or hash mismatches are blocking. All validation outcomes are recorded in an automated review log.

ASP.NET Core Minimal API Design

We expose secure endpoints for managing artifacts. Key endpoints include:

  • GET /api/review/queue – list artifacts in queue (by state or assignment).
  • GET /api/review/{id} – get one artifact’s full details (read-only).
  • GET /api/graphs/{graphId} – retrieve graph topology (subgraph) by version or snapshot ref.
  • GET /api/evidence/{evidenceId} – retrieve evidence metadata (URI, description, hash).
  • POST /api/review/{id}/claim – claim artifact for review.
  • POST /api/review/{id}/request-changes – requester asks for changes (Reviewer only).
  • POST /api/review/{id}/approve – approve artifact (Reviewer only).
  • POST /api/review/{id}/reject – reject artifact (Reviewer only).
  • POST /api/review/{id}/suspend – admin suspends pattern.
  • POST /api/review/{id}/revoke – admin revokes pattern.
  • GET /api/audit/{id} – get audit history for artifact.
  • POST /api/falsifier/evaluate – supply a runtime context to evaluate falsification conditions.
  • POST /api/review/{id}/promote – commit approved artifact into active memory (system only).

These are implemented using ASP.NET Core Minimal APIs. We use JWT or cookie authentication with role-based checks (.RequireAuthorization(), policies like "Reviewer", "Admin"). We include ETag support for GET and use If-Match on write endpoints. Validation of request bodies uses [FromBody] with Data Annotations.

Example minimal API endpoints (Program.cs):

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(...);
// Add EF DbContext, etc.
var app = builder.Build();

// JSON responses for errors, using Problem Details:
app.MapGet("/api/review/queue", async (ReviewDbContext db, HttpContext ctx) =>
{
    // Optional filtering, pagination
    return Results.Ok(await db.Findings
        .Where(f => f.State == FindingState.ReadyForReview)
        .Select(f => new { f.ArtifactId, f.Tenant, f.State })
        .ToListAsync());
}).RequireAuthorization();

app.MapGet("/api/review/{id}", async (Guid id, ReviewDbContext db) =>
{
    var finding = await db.Findings.FindAsync(id);
    if (finding == null)
        return Results.NotFound(new { Message = "Artifact not found." });
    return Results.Ok(finding);
}).RequireAuthorization();

app.MapPost("/api/review/{id}/claim", async (Guid id, HttpContext ctx, ReviewDbContext db) =>
{
    var user = ctx.User;
    if (!user.IsInRole("Reviewer"))
        return Results.Forbid();
    var finding = await db.Findings.FindAsync(id);
    if (finding == null) return Results.NotFound();
    try
    {
        FindingStateMachine.Transition(finding, "Claim", "Reviewer", ctx.Request.Headers["Idempotency-Key"]);
        await db.SaveChangesAsync();
    }
    catch (InvalidOperationException ex)
    {
        return Results.BadRequest(new { Message = ex.Message });
    }
    return Results.Ok();
});

app.MapPost("/api/review/{id}/approve", async (Guid id, HttpContext ctx, ReviewDbContext db) =>
{
    var user = ctx.User;
    if (!user.IsInRole("Reviewer"))
        return Results.Forbid();
    var finding = await db.Findings.FindAsync(id);
    if (finding == null) return Results.NotFound();
    try
    {
        FindingStateMachine.Transition(finding, "Approve", "Reviewer", ctx.Request.Headers["Idempotency-Key"]);
        await db.SaveChangesAsync();
    }
    catch (InvalidOperationException ex)
    {
        return Results.Conflict(new { Message = ex.Message });
    }
    return Results.Ok();
});

// ... Similarly for reject, request-changes, suspend, revoke ...

// Evaluate falsification rules:
app.MapPost("/api/falsifier/evaluate", (EvaluationRequest req, IFalsificationEvaluator evaluator) =>
{
    // req: { Conditions: [...], Context: { ... } }
    var results = new List<object>();
    foreach (var cond in req.Conditions)
    {
        try {
            evaluator.Compile(cond.Expression);
            bool fired = evaluator.Evaluate(req.Context);
            results.Add(new { cond.Description, Fired = fired });
        }
        catch (Exception ex) {
            results.Add(new { cond.Description, Error = ex.Message });
        }
    }
    return Results.Ok(results);
}).RequireAuthorization();

// Promote to active memory:
app.MapPost("/api/review/{id}/promote", async (Guid id, HttpContext ctx, ReviewDbContext db, IAgentMemoryService memSvc) =>
{
    var finding = await db.Findings.FindAsync(id);
    if (finding == null) return Results.NotFound();
    if (finding.State != FindingState.Approved)
        return Results.BadRequest(new { Message = "Only approved artifacts can be promoted." });
    // Re-validate hashes, check for superseding version, etc.
    await memSvc.PromotePatternAsync(finding, ctx.Request.Headers["Idempotency-Key"]);
    return Results.Ok();
}).RequireAuthorization("System");

app.Run();
  • Authentication/Authorization: Every endpoint calls .RequireAuthorization() or specific roles. E.g. only users in role "Reviewer" can call approve/reject endpoints. In Minimal APIs, one adds builder.Services.AddAuthorization() and sets up policies as needed.
  • Concurrency/Etag: We attach a [Timestamp] Version property to our entity. On GET, we can include an ETag header (e.g. the base64 of the Version). On PUT/POST that modify state, we check the If-Match header against the current token to enforce optimistic concurrency. If mismatch, return 412 Precondition Failed. This follows the pattern in EF Core (which uses a rowversion token).
  • Validation: ASP.NET Core model binding automatically checks required fields and formats for our request DTOs (decorated with DataAnnotations). Additional checks (like valid enum values) return HTTP 400 with ProblemDetails.
  • Pagination/Filtering: List endpoints (like review queue) support query parameters for page size and filters (e.g. by risk level).
  • Audit Logging: Each handler records an audit event (e.g. “User X claimed artifact Y”) via a logging service.
  • Error Handling: We use Results.Problem with appropriate status codes for errors. Validation and concurrency exceptions produce 400/409. Unauthorized or forbidden produce 401/403.

This API surface gives full control over the review workflow and associated data. All data is transferred in UTC (ISO 8601 strings) and endpoints use consistent C# and JSON contracts.

Persistence Model

We use EF Core with SQL Server to persist artifacts and related entities. Key entities:

public class ReviewDbContext : DbContext
{
    public DbSet<CrossTaskAnalyticalFinding> Findings { get; set; }
    public DbSet<AuditEvent> AuditEvents { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Use rowversion for concurrency token
        modelBuilder.Entity<CrossTaskAnalyticalFinding>()
            .Property(f => f.Version)
            .IsRowVersion();
        // Additional configuration (indexes, table names)...
    }
}

/// <summary>
/// Records an audit event (state change, user action, error).
/// </summary>
public class AuditEvent
{
    [Key]
    public int Id { get; set; }

    [Display(Name = "Artifact")]
    public Guid ArtifactId { get; set; }

    [Display(Name = "Timestamp")]
    public DateTime Timestamp { get; set; }

    [Display(Name = "Event Type")]
    public string EventType { get; set; }

    [Display(Name = "Performed By")]
    public string PerformedBy { get; set; }

    [Display(Name = "Details")]
    public string Details { get; set; }
}

All updates to a CrossTaskAnalyticalFinding (state transitions, content changes) are encapsulated in a transactional SaveChanges. The Version property with [Timestamp] attribute ensures EF includes it in the SQL WHERE clause. If a conflict occurs, EF throws DbUpdateConcurrencyException, which we catch at the API layer and return 409 to the client, prompting a retry. We also support explicit ETag logic for Web API clients.

The falsification rules themselves could be stored either as text or as a precompiled form. For simplicity, each CrossTaskAnalyticalFinding may have a JSON column FalsificationConditions (array of expressions). Alternatively, we use a child table if queries are needed.

Commit and Rollback Workflow

Promoting an approved artifact into active memory is an atomic workflow:

  1. Check Current State: Verify the artifact is still Approved. (If it changed, abort.)
  2. Re-verify Hashes: Re-compute content hash and confirm evidence/graph versions haven’t changed. If mismatch, abort.
  3. Supersedence Check: Confirm no newer artifact with equal intent has been committed in the meantime. (E.g. same source/target tasks.) If found, mark this as Superseded and abort promotion.
  4. Begin Transaction: Start a DB transaction.
  5. Write Active Memory: Insert the pattern into the ActiveMemory table (or however agent memory is represented). This may involve adding nodes/edges to a live graph store.
  6. Record Source: Log the source artifact ID and version in an audit log or a link table.
  7. Publish Event: Emit an outbox event/message like { "PatternCommitted": { "ArtifactId": ..., "ApprovedBy": ..., "Timestamp": ... }} for downstream systems.
  8. Update State: Set artifact.State = Committed. Save transaction.
  9. End Transaction: Commit.

If any step fails, roll back the transaction and leave the artifact in Approved state (not lost). The API returns an error. Clients should retry or require manual intervention. We also implement an emergency rollback by setting State = Revoked and issuing a compensating message or deleting the active memory entry if already written. Since the artifact is immutable once approved, any change means creating a new artifact version.

For revocation/suspension after commit, the system will:

Material revision of a pattern requires a fresh artifact and review (no direct edits).

  • Remove or disable the active memory pattern.
  • Emit an event "PatternRevoked": {artifactId, reason}.
  • Update artifact.State to Suspended/Revoked.

Runtime Enforcement

At agent runtime, before using an active pattern, the system must check falsification conditions. We propose an in-process gateway that:

  • Retrieves all currently Active patterns for an agent request (filtered by fleet, task, etc.).
  • For each pattern, checks its falsification expressions against the runtime context (e.g. current environment, user, tools).
  • If any falsifier is true, the pattern is disabled for that invocation (and a log entry is emitted). The normal behavior is fail-closed: the agent will act as if the pattern did not exist.
  • If some data needed by an expression is missing from context, we treat the condition as false (do not disable) but log a warning.
  • Patterns can cache their compiled expressions in memory for speed. We invalidate caches if the pattern version changes (e.g. pattern was updated with new rules).
  • We avoid introducing any I/O in this hot path. All context data must be in-memory or passed in. This ensures low-latency checks.
  • In case of conflicting conditions (one says disable, another says ok), any disable wins (conservative).
  • We may sample audit logs of pattern usage or falsification hits for offline review.

Example interface:

public interface IPatternEnforcer
{
    /// <summary>
    /// Evaluates the pattern against the given runtime context.
    /// Returns true if the pattern is **still valid**; false if it should be disabled.
    /// </summary>
    bool IsPatternValid(string artifactId, IDictionary<string, object> context);
}

/// <summary>
/// Implementation uses precompiled CEL expressions for each pattern.
/// </summary>
public class PatternEnforcer : IPatternEnforcer
{
    private readonly IPatternRepository _repo; // provides patterns & rules
    private readonly IFalsificationEvaluator _evaluator;

    /// <summary>
    /// Checks all falsification conditions for the given pattern.
    /// If any condition evaluates true, returns false.
    /// </summary>
    public bool IsPatternValid(string artifactId, IDictionary<string, object> context)
    {
        var conditions = _repo.GetFalsificationExpressions(artifactId);
        foreach (var expr in conditions)
        {
            try
            {
                if (_evaluator.Evaluate(context))
                {
                    // Log disqualification
                    return false;
                }
            }
            catch
            {
                // On error, conservatively return true (do not disable)
            }
        }
        return true;
    }
}

We might cache per-artifact evaluation delegates so we only parse/compile CEL once when loading the pattern. Version pinning is intrinsic: once an artifact is approved and published, its content (including rules) is immutable.

Review Interface Contract

The internal review dashboard needs structured data to show details and context. We define a contract (C# classes or JSON) for what the UI will render:

  • Before/After Graph Views: The subgraph matching (before edit) and the proposed graph edit path (after). We can export these as adjacency lists or edge lists. For example:
  {
    "beforeGraph": { "nodes": [...], "edges": [[...],[...]] },
    "editOperations": [ {"type":"AddEdge","params":{"from":"C","to":"A"}}, ... ]
  }
  • Matched vs Unmatched Nodes: The UI should highlight which nodes/edges are in the matched subgraph and which are proposed changes. We include lists: MatchedNodes, UnmatchedNodes, etc.
  • Scores: Provide numeric scores and individual feature/structure component breakdown, along with histograms or thresholds. The UI can label each score.
  • Evidence: List of evidence refs (URI, description). The UI can link to or display metadata. We provide metadata like timestamp, author.
  • Warnings/Validation Errors: Any validation warnings (e.g. missing evidence, out-of-range score) should be a list of messages in the artifact payload (ValidationWarnings array).
  • Falsification Rules: The UI displays each rule expression and description. Ideally, also allow testing the rule against sample contexts.
  • Impacted Fleets: A list of fleet identifiers and agent versions that would be affected by this pattern (we can infer this from the scopes in the artifact).
  • Side-by-side diffs: If possible, show the subgraph difference (before vs after). This requires exporting two graph snapshots.

We ensure the API returns these in JSON so the UI can deterministically render charts and graphs. For example, the review endpoint might return:

{
  "ArtifactId": "...",
  "SourceTask": "...", "TargetTask": "...",
  "State": "ReadyForReview",
  "GraphDiff": {
    "Before": { "nodes": [...], "edges": [...] },
    "After":  { "nodes": [...], "edges": [...] }
  },
  "Scores": {
    "Alignment": 0.87,
    "Feature": 0.75,
    "Structure": 0.92
  },
  "Evidence": [
    {"Uri": "...", "Description": "...", "Timestamp": "2026-07-19T21:00:00Z"}
  ],
  "FalsificationRules": [
    {"Expression": "...", "Description": "..."}
  ],
  "Warnings": [
    "Source graph version graph-v1.2 is marked deprecated."
  ],
  "ImpactedFleets": ["fleet42","fleet99"]
}

With this contract, the dashboard can show a diff graph, color matched nodes, list scores and evidence, and allow the reviewer to approve/reject via API calls.

Tests

We provide a comprehensive test suite (e.g. using xUnit or NUnit) to cover key behaviors:

  • Invalid Artifacts: Submit artifacts with schema violations (e.g. missing fields, invalid score ranges) and assert validation blocks them (state = ValidationFailed).
  • Authorization: Ensure unauthorized users (roles mismatch) cannot claim/review artifacts (403 Forbidden).
  • Duplicate Decisions: Ensure repeated approval attempts with the same idempotency key do not change state or cause errors.
  • Concurrent Approvals: Simulate two reviewers trying to approve the same artifact concurrently (one should succeed, the other should get a concurrency exception or 409).
  • Approval After Source Change: Approving an artifact, then changing its underlying graph versions externally, and attempting to promote: should detect the inconsistency and fail.
  • Tampered Evidence: If the evidence URI is changed or hash mismatches after approval, the falsification evaluator should catch it (either at validation or runtime).
  • Invalid Falsification Expression: Include a syntactically invalid rule in an artifact; validation should fail with a clear error.
  • Runtime Falsification: Simulate the runtime gateway with a pattern that has a falsifier, provide a context that triggers it, and assert the pattern is disabled.
  • Commit Failure & Retry: Simulate a failure during the commit step (e.g. DB error after writing active memory but before marking state Committed). On retry, ensure no double-commit and artifact stays Approved or is Revoked according to policy.
  • Revocation Propagation: After committing a pattern, issue a revoke; ensure the active memory store removes it and state moves to Revoked.
  • Immutable Artifact: Attempt to modify a pattern after approval (e.g. edit scores); assert it must be treated as a new version, not altering the existing record.
  • Superseding: Approve a new pattern for the same tasks; ensure the older committed pattern moves to Superseded automatically or via admin action.

Each test asserts the correct state transitions, database contents, and any side effects (audit events, memory state, exceptions).

Threat and Failure Analysis

We have conducted a threat analysis on the system. Key concerns include:

  • Data Tampering: An attacker might try to modify an approved artifact to subvert the pattern. We mitigate by storing a content hash and signature. Any mismatch triggers an alert.
  • Spoofed Falsification: If the falsification logic is corrupted, patterns might not disable when needed. We code-sign the falsification expressions and restrict editing (only via the review API).
  • Replay Attacks: Old commit requests replayed could double-add patterns. We require idempotency keys and check artifact state. DB locks (via concurrency token) also prevent race conditions.
  • Race Conditions: Concurrent reviewers or commits could corrupt state. We use optimistic concurrency and atomic transactions to handle conflicts gracefully.
  • Unauthorized Access: Weak auth could let unauthorized users approve patterns. We enforce role checks on every endpoint; without valid JWT roles, actions are forbidden.
  • Supply-Chain Risks: The solver or analysis that generates patterns might produce biased or malicious patterns. We treat all analytic outputs as untrusted and require full review.
  • System Reliability: If the review service crashes mid-commit, we must handle partial commits. Our workflow is transactional: either all or nothing, plus logging for manual recovery.
  • Falsifier Evasion: Complex conditions might be hard to fully simulate at review time. We enforce that falsifiers are concrete (no free text). At runtime, we frequently re-evaluate conditions to catch changes (e.g. updated rules).
  • Denial-of-Service: An attacker flooding with spurious pattern proposals could overwhelm reviewers. We include rate limits and require puzzles/caps to submit artifacts.
  • Drift & Staleness: Even approved patterns may become invalid as the environment changes (e.g. API versions). We handle this via expiration dates and require periodic re-validation for long-lived patterns.

By design, we never auto-approve anything and always log every step. The review process itself is auditable, and alerts are raised on any suspicious condition (e.g. mismatched hashes). We also plan periodic audits of the pattern database to detect anomalies (multiple patterns with contradictory logic, etc.).

Unresolved Governance Questions

Several governance issues remain under review:

  • Reviewer Expertise: How to quantify the required expertise (qualifications) for different pattern types? We include a free-form RequiredReviewerQualifications list, but mapping roles to real-world certificates or training is open-ended.
  • Liability and Trust: If a human reviewer misses a critical flaw, who is liable? Our system logs the evidence basis, but organizational policies must define accountability (beyond our technical control).
  • Pattern Privacy: Some patterns may implicitly leak information about tasks or data. We must enforce privacy controls on what evidence can be linked to patterns (outside scope here).
  • Complex Patterns: Some cross-task relationships may not fit easily into our schema (e.g. temporal sequences). Extending the schema for new pattern types may require future reviews.
  • Regulatory Alignment: If jurisdictional regulations require explainability or fairness checks, we need to integrate those reviews. For now, we assume patterns are technical and subject to internal policy only.
  • Standards Evolution: As AI governance standards evolve (e.g. new legislation on AI), we may need to add compliance checks. Our architecture should accommodate new “qualification” requirements or data residency rules without redesign.

These open questions will guide future policy work, but our system provides the hooks (qualifications field, risk levels, audit logs) to incorporate new governance rules as they emerge.

Sources: We relied on AI-safety industry articles, official ASP.NET/EF Core documentation, and AI-memory architecture best practices. Guidelines like UNESCO’s AI ethics recommendation and AI governance frameworks inform our emphasis on oversight and accountability. The Popper-inspired falsifiability rules directly shaped our falsification design. All technical claims (e.g. EF Core concurrency) cite Microsoft docs or language specifications.