PUBLIC PROJECTS

Projects

A selection of public projects where I build solutions around Data Governance, automation and data architecture. Each case summarizes the problem it addresses, the approach taken and the main design decisions, with the repository available for reviewing the implementation in detail.

collibra-governance-automation

v1.2.0

Collibra Governance Automation

Automates the journey from technical metadata coming from multiple sources to a common governance model that can be reviewed, analyzed and synchronized with Collibra in a controlled way.

Problem it solves

PostgreSQL, ODCS, dbt and OpenLineage describe different parts of the same ecosystem. The challenge is not simply collecting that metadata, but giving it a common identity, preserving where it came from and understanding how it relates before sending it to a governance platform.

How I approached it

The project first builds a neutral governance model that is independent of Collibra. That model can then be used to check rules, analyze the impact of changes and prepare reviewable actions. Collibra remains at the end of the flow as the synchronization target rather than the source of truth for the model.

See how the project works

How the project works

This project automates two different workflows that share principles of governance, reviewability and determinism, but not the same internal model. The first starts from PostgreSQL, builds a GovernanceModel and controls which changes can be prepared and synchronized with Collibra. The second composes ODCS, dbt and OpenLineage into a GovernanceGraph to preserve provenance, build lineage and analyze which assets may be affected by a change.

Keeping both workflows separate is an important part of the current architecture: PostgreSQL does not feed the impact graph, and the multi-source graph does not feed Collibra synchronization. The portfolio must show that separation exactly as it exists in the code rather than turning it into a single pipeline that does not exist today.

POSTGRESQL → GOVERNANCEMODEL → COLLIBRA

ODCS + DBT + OPENLINEAGE → GOVERNANCEGRAPH → IMPACT

Two workflows, two models

GovernanceModel and GovernanceGraph are two different vendor-neutral cores. GovernanceModel represents physical metadata discovered from PostgreSQL and is the basis for the policy and Collibra synchronization path. GovernanceGraph represents nodes, relationships and provenance coming from ODCS, dbt and OpenLineage and is the basis for impact analysis.

There is currently no GovernanceModel → GovernanceGraph conversion. Keeping that boundary visible avoids attributing an end-to-end integration to the project that is not implemented yet and makes it possible to explain precisely what problem each workflow solves.

ROOT

Control and synchronization with Collibra

GovernanceModel

Context, lineage and impact

GovernanceGraph

WORKFLOW A

Control and synchronization with Collibra

This workflow answers an operational question: what physical metadata exists in PostgreSQL, whether it satisfies a small set of governance checks and which changes would need to be prepared for the managed Collibra state to represent it without applying writes by default.

RUNNING EXAMPLE · commerce.orders

A1

PostgreSQL discovery

The workflow starts by observing PostgreSQL catalogs directly. The scanner works inside a REPEATABLE READ, READ ONLY transaction to obtain a consistent view of the structure without modifying the database.

WHAT GOES IN

A PostgreSQL connection and the catalogs of the configured database.

WHAT PYTHON DOES

Python executes five catalog queries and reconstructs databases, user schemas, tables, columns, types, nullability, primary keys, foreign keys, comments and ownership. Views, indexes and CHECK constraints are not part of the discovery currently implemented.

RESULT

A GovernanceModel with a Data Source → Database → Schema → Table → Column hierarchy and structural relationships derived from foreign keys.

CODE EVIDENCE

PostgresMetadataScanner.scan · build_governance_model

commerce

orders

  • order_id

  • customer_id

orders.customer_idcustomers.customer_id

In the commerce demo, Python observes the orders table and the orders.customer_id → customers.customer_id foreign key. The relationship is preserved inside the GovernanceModel as structural metadata.

A2

Model and stable identities

Discovered metadata is not kept as loose catalog rows. Python turns it into domain objects with stable identities so the same asset can be recognized reproducibly across executions.

WHAT GOES IN

The normalized rows obtained by the PostgreSQL scanner.

WHAT PYTHON DOES

Python builds canonical IDs for each model level, validates reference integrity and orders collections deterministically. The PostgreSQL host and port are not part of table and column identity, so moving the connection does not by itself change the logical identity of an asset.

RESULT

A stable, reviewable vendor-neutral GovernanceModel that can be used without depending on Collibra yet.

CODE EVIDENCE

GovernanceModel · make_table_id · make_column_id · make_relationship_id

  1. RAW CATALOG ROWS

  2. CANONICAL IDS

  3. GOVERNANCEMODEL

The example table is identified as tbl:governance-demo/governance_demo/commerce/orders and the customer_id column as col:governance-demo/governance_demo/commerce/orders/customer_id.

A3

Governance checks

Before preparing changes for Collibra, the project can apply a small and explicit set of rules to the GovernanceModel. This is not a general-purpose policy engine: the project currently defines three check types.

WHAT GOES IN

The GovernanceModel and the rules declared in the Governance-as-Code configuration.

WHAT PYTHON DOES

Python evaluates whether selected assets have an owner, a description and relationships when require_owner, require_description or require_relationship demand them. Violations are sorted and reported; an error-severity violation can block check or plan generation.

RESULT

A violation report that separates governance issues from the synchronization phase.

CODE EVIDENCE

evaluate_policies · NormalizedPolicySet

GovernanceModel

  • require_owner · requires ownership

  • require_description · requires a description

  • require_relationship · requires at least one relationship

report

A4

Desired state and reviewable plan

Collibra appears at the end of the model, not at the beginning. Python translates the neutral GovernanceModel into a Collibra-specific representation and compares that desired state with the managed remote state before deciding which operations would be necessary.

WHAT GOES IN

GovernanceModel + Collibra mapping + managed remote state.

WHAT PYTHON DOES

Python transforms databases, schemas, tables, columns and FK relationships into CollibraAssetSpec and CollibraRelationshipSpec, including configured domain, type and attribute references. It then calculates a SyncPlan with CREATE, UPDATE, UNCHANGED and REMOTE_ONLY, and can save the actions in a .gplan together with identities for configuration, snapshot, policies, mapping, target context and remote state.

RESULT

A reviewable plan combining an ordered list of operations with an integrity contract. REMOTE_ONLY is reported but does not become a delete operation.

The .gplan is more than a description: it preserves the actions and identities required to detect whether the context has changed before applying.

CODE EVIDENCE

map_to_desired_state · build_sync_plan · build_saved_plan · SavedGovernancePlan

  1. 01

    GovernanceModel

  2. 02

    CollibraDesiredState

    + managed remote

  3. 03

    SyncPlan

  4. 04

    .gplan

  • CREATE

  • UPDATE

  • UNCHANGED

The .gplan is more than a description: it preserves the actions and identities required to detect whether the context has changed before applying.

A5

Safe synchronization

Having a plan does not authorize a write. The workflow keeps dry-run as the default behaviour, requires explicit opt-in to apply and adds further checks before allowing operations against a live adapter.

WHAT GOES IN

A reviewed SyncPlan or .gplan, the current configuration and either a mock or live Collibra adapter.

WHAT PYTHON DOES

Python executes dry-run with no writes by default. Applying requires --apply and, when the adapter is live, an additional --confirm-live confirmation. Before writing, the .gplan flow checks that the relevant identities still match; if the plan is stale, it is blocked before the first write. During apply, write errors stop the sequence.

RESULT

CREATE and UPDATE can be executed when explicitly requested. The project does not implement DELETE, automatic deletion, rollback or a proven retry engine.

LiveCollibraAdapter is contract-tested against simulated HTTP. The repository does not demonstrate validation against a real commercial Collibra tenant.

CODE EVIDENCE

execute_sync_plan · plans/stale.py · MockCollibraAdapter · LiveCollibraAdapter

.gplan

DRY-RUN · DEFAULT

--apply ?

NO → 0 WRITES

YES

LIVE ADAPTER ?

NO → continue

YES → --confirm-live

STALE ?

NO → CREATE / UPDATE

RESULT

In the local lifecycle using MockCollibraAdapter, an empty remote state produces creates and a second synchronization against the new state does not create the same assets again.

LiveCollibraAdapter is contract-tested against simulated HTTP. The repository does not demonstrate validation against a real commercial Collibra tenant.

Collibra does not have a single fixture that joins PostgreSQL, ODCS, dbt and OpenLineage in one end-to-end execution. The PostgreSQL → Collibra workflow and the ODCS/dbt/OpenLineage → impact workflow are shown with different real examples so the project is not credited with an integration that does not exist yet.

WORKFLOW B

Context, lineage and impact

This workflow answers a different question: if an asset changes, which dependencies, contracts and consumers fall within its blast radius. To answer it, Python composes declared, transformational and observed metadata coming from ODCS, dbt and OpenLineage.

RUNNING EXAMPLE · orders → downstream

B1

Context sources

The three sources do not contribute the same information. ODCS describes contracts and declared context, dbt describes models and transformation dependencies, and OpenLineage contributes execution observations and lineage. The value comes from preserving those differences rather than collapsing them into one format without provenance.

WHAT GOES IN

ODCS v3.1.0 documents, a subset of dbt Manifest v12 and OpenLineage core 2-0-2 events.

WHAT PYTHON DOES

Python validates and maps each source specifically. ODCS creates contract, dataset and column nodes with governs and contains relationships. dbt turns models, sources, columns and parent_map into physical structure and depends_on relationships. OpenLineage composes RunEvent, JobEvent and DatasetEvent, input and output datasets and, when present, columnLineage.

RESULT

Three sets of nodes, relationships and provenance ready to be composed into a GovernanceGraph.

ODCS can express quality, SLA and servers in the standard, but this project does not currently map them into the GovernanceGraph.

CODE EVIDENCE

load_odcs_graph · load_dbt_graph · load_openlineage_graph

  • ODCS · contract and declared context

    contract → governs → dataset → contains → column

  • dbt · models and declared dependencies

    source/model → depends_on

  • OpenLineage · observed execution and column lineage

    input → run/job → output

    + columnLineage

ODCS can express quality, SLA and servers in the standard, but this project does not currently map them into the GovernanceGraph.

B2

Identity and provenance

To compose multiple sources, the project needs to decide when two observations may represent the same asset and preserve where each fact came from. That merge is not based on silently choosing a winning source.

WHAT GOES IN

Nodes and relationships produced by the ODCS, dbt and OpenLineage mappers.

WHAT PYTHON DOES

Python builds GraphNodeIdentity from namespace, kind, logical_id and, where applicable, parent. Observations with the same identity and the same material payload can merge their ProvenanceRecord. If two observations with the same identity contain incompatible material attributes, composition fails instead of choosing a source arbitrarily.

RESULT

Assets with canonical identity and declared, observed or derived provenance, ready to participate in the same graph when their identities are compatible.

dbt and OpenLineage can converge on the same physical identity when namespace, database, schema and table match.

ODCS only converges automatically with other assets when its logical IDs have been aligned. PostgreSQL does not participate in this identity scheme because it belongs to the GovernanceModel workflow.

The project preserves provenance, but it does not yet implement an authority or conflict-resolution engine. A material conflict is rejected.

CODE EVIDENCE

GraphNodeIdentity · ProvenanceRecord · GovernanceGraph.from_parts

dbt observation

OpenLineage observation

SAME IDENTITY

ONE NODE

TWO PROVENANCE RECORDS

dbt and OpenLineage can converge on the same physical identity when namespace, database, schema and table match.

ODCS only converges automatically with other assets when its logical IDs have been aligned. PostgreSQL does not participate in this identity scheme because it belongs to the GovernanceModel workflow.

The project preserves provenance, but it does not yet implement an authority or conflict-resolution engine. A material conflict is rejected.

B3

GovernanceGraph

Composition produces an in-memory governance graph built from immutable dataclasses. It does not use a graph database or NetworkX: the domain itself defines how nodes and relationships are normalized, validated and ordered.

WHAT GOES IN

Nodes, relationships and provenance information already normalized by each integration.

WHAT PYTHON DOES

Python merges compatible observations, checks that parents exist, rejects dangling edges, canonicalizes attributes and orders nodes and relationships. The graph uses contains for hierarchy, depends_on for dependencies and governs to associate contracts with the assets they govern.

RESULT

A deterministic GovernanceGraph with its own content identity and enough structure to build lineage and traverse dependencies.

depends_on is stored as derived → dependency. To calculate downstream impact, traversal uses that relationship in reverse.

CODE EVIDENCE

GovernanceGraph · GraphNode · GraphEdge · canonical_json_bytes

GovernanceGraph

in-memory

  • contains

  • depends_on

  • governs

depends_on is stored as derived → dependency. To calculate downstream impact, traversal uses that relationship in reverse.

B4

Lineage and contracts

Inside the graph, dependencies may come from different sources and preserve different levels of detail. dbt contributes declared dependencies between models and sources; OpenLineage contributes dependencies observed at runtime and can materialize column-to-column lineage; ODCS contributes contracts associated with datasets.

WHAT GOES IN

dbt parent_map, OpenLineage inputs/outputs and columnLineage, and ODCS governs relationships.

WHAT PYTHON DOES

Python materializes depends_on relationships with derived → dependency direction. In dbt those relationships are at table or transformation level. In OpenLineage they may also exist between columns through ColumnLineageAssertion. ODCS contracts remain contract nodes connected through governs and are included as context for impact analysis.

RESULT

A graph capable of representing dataset-level and column-level dependencies together with the available contract context.

dbt does not generate column-level lineage in this project. That capability is demonstrated through OpenLineage.

ODCS contracts are informational context inside impact analysis; they do not currently block changes or replace the require_* rules from the PostgreSQL workflow.

CODE EVIDENCE

materialize_column_lineage_edges · ColumnLineageAssertion · GraphEdge

  • DATASETdownstreamorders
  • COLUMNoutput columninput column
  • CONTRACTcontractdataset

dbt does not generate column-level lineage in this project. That capability is demonstrated through OpenLineage.

ODCS contracts are informational context inside impact analysis; they do not currently block changes or replace the require_* rules from the PostgreSQL workflow.

Tests demonstrate that a physical identity built from OpenLineage can be compatible with the equivalent physical dbt asset and that column lineage is materialized as output column → depends_on → input column.

B5

Impact analysis

When an asset is declared as changed, the project uses the GovernanceGraph to calculate which consumers sit downstream. The analysis is completely read-only and does not execute policies or perform remote writes.

WHAT GOES IN

GovernanceGraph + one or more changed roots defined through governance-impact-changes/v1.

WHAT PYTHON DOES

Python validates the roots, builds an effective adjacency, traverses depends_on in reverse and runs a multi-source BFS by distance. It distinguishes direct and transitive impact, avoids cycling back into roots, selects a canonical shortest path when equivalent routes exist and collects relationships, contracts and governance context inside the affected closure.

RESULT

A deterministic governance-impact-result/v1 containing affected assets, distances, paths and relevant context. The governance impact command reports an impacted state when affected consumers are found and performs no remote mutation.

The main CLI example is dataset-level. Column-level lineage is demonstrated by specific OpenLineage tests and must be shown as complementary technical evidence rather than as if it belonged to the same CLI fixture.

CODE EVIDENCE

analyze_downstream_impact · GovernanceImpactResult · _path_sort_key

orders

↓ reverse traversal over depends_on

downstream

DIRECT · distance 1

TRANSITIVE · distance ≥2

READ ONLY0 REMOTE WRITES

In the real fixture used by governance impact, orders is the changed root and downstream appears as an affected consumer. That traversal is proven by both the CLI and the read-only GitHub Action.

The main CLI example is dataset-level. Column-level lineage is demonstrated by specific OpenLineage tests and must be shown as complementary technical evidence rather than as if it belonged to the same CLI fixture.

What Python actually automates

Python does not act here as a single chain of scripts. In the operational workflow it discovers PostgreSQL metadata, builds stable identities, evaluates checks, translates the model to Collibra and prepares reviewable plans with dry-run and stale-plan protection. In the impact workflow it ingests ODCS, dbt and OpenLineage, composes identities and provenance, materializes lineage and traverses the GovernanceGraph to calculate downstream impact deterministically.

  1. DISCOVERPostgresMetadataScanner.scan
  2. IDENTIFYGovernanceModel
  3. CHECKevaluate_policies
  4. MAPmap_to_desired_state
  5. PLANbuild_saved_plan
  6. PROTECTexecute_sync_plan
  7. COMPOSEGovernanceGraph.from_parts
  8. TRACE LINEAGEmaterialize_column_lineage_edges
  9. CALCULATE IMPACTanalyze_downstream_impact
  10. EVIDENCEContentIdentity

Identities, ordering, artifacts and impact paths are canonicalized so the same input produces a reviewable and reproducible representation.

Complete architecture

COLLIBRA GOVERNANCE AUTOMATION

TWO MODELS · NO CURRENT DIRECT CONVERSION

  1. POSTGRESQL

  2. GOVERNANCEMODEL

  3. CHECKSCOLLIBRA DESIRED STATE
  4. SYNCPLAN / .GPLAN

  5. DRY-RUN

  6. APPLY

  7. COLLIBRA

  1. ODCSDBTOPENLINEAGE
  2. GOVERNANCEGRAPH

  3. PROVENANCELINEAGECONTRACTSIMPACT ANALYSIS
  4. IMPACT RESULT

  5. PR / REVIEW

Maturity and evolution

The polygon reflects documented functional state. The outer ring represents the full profile.

  • Most consolidated

    Read-only PostgreSQL discovery, the GovernanceModel, ODCS/dbt/OpenLineage composition, the GovernanceGraph, OpenLineage-based column-level lineage, deterministic impact analysis and safe planning toward Collibra are capabilities demonstrated by code and tests.

  • Still evolving

    The live Collibra integration is contract-tested but has not been validated against a real commercial tenant. PostgreSQL and the GovernanceGraph remain separate workflows, and the project does not yet implement an authority or source-conflict resolution engine.

  • Next areas

    The repository documents Collibra integration hardening, authority, conflict and drift management, and greater provider extensibility as pending areas. They are presented as future evolution, not as implemented capabilities or as a closed versioned roadmap.

Maturity and evolution

  1. CURRENT · v1.2.0
  2. NEXT AREASCollibra hardeningFUTURE
  3. NEXT AREASAuthority / conflicts / driftFUTURE
  4. NEXT AREASProvider extensibilityFUTURE

What you can review on GitHub

The repository lets you inspect PostgreSQL discovery and Collibra synchronization separately from multi-source GovernanceGraph composition, lineage, impact analysis and plan safety controls.

purview-governance-automation

v1.1.0

Microsoft Purview Governance Automation

Automates Microsoft Purview configuration as a reviewable desired state: it observes the live environment, detects differences, prepares a plan and only executes changes that pass the safety checks.

What problem it solves

When Purview configuration is maintained through manual operations or direct scripts, it becomes difficult to know what should exist, what has actually changed and what will be modified in each execution.

How I approached it

The project starts from a desired configuration, observes the live Purview state, classifies the differences and generates a deterministic plan. Before writing, it queries the environment again and blocks execution if the state no longer matches the context for which the plan was created.

See how the project works

How the project works

This project turns Microsoft Purview Scanning configuration into a declarative, reviewable and safe process. Python validates how the environment should be configured, observes how it is actually configured, calculates the differences, prepares an executable plan and checks the remote state again immediately before any write. The goal is not to automate changes blindly, but to make every decision explicit, reproducible and auditable.

  1. CONFIGURATION
  2. VALIDATION
  3. REMOTE STATE
  4. COMPARISON
  5. PLAN
  6. SAFE EXECUTION
  7. RESULT

The example traced through these seven stages is reproduced against the repository's offline contract server. It demonstrates the pipeline behaviour and its contracts, but it does not constitute validation against a live Microsoft Purview tenant.

01

Desired configuration

The starting point is a versioned document describing how Purview should be configured. It contains no credentials and does not assume that those resources already exist: it expresses an intention that the rest of the flow must validate, compare and, when appropriate, execute.

WHAT GOES IN

A YAML or JSON file containing the Purview target and the resources we want to manage. In v2 the project supports Azure Storage Data Sources, Custom Classification Rules, Custom Azure Storage Scan Rule Sets and AzureStorageMsi Scans.

WHAT PYTHON DOES

Python loads the YAML or JSON using safe, strict parsing, detects duplicate keys and identifies the contract version declared by the document. At this point it does not query Purview or decide which changes to perform: it turns the input declaration into a structure that can pass through the next checks.

RESULT

A parsed and versioned desired-configuration document, ready to pass through validation and normalization.

CODE EVIDENCE

load_config_file · purview-governance-config/v1|v2

ds-a

custom-rule

custom-srs

DailyScan @ ds-a

(ds-a, DailyScan)

ds-b

DailyScan @ ds-b

(ds-b, DailyScan)

Two scans can share the same name without representing the same resource. The project identifies each scan through the combination of its parent Data Source and its name: (dataSourceName, name).

02

Validation and normalization

Before anything is compared with Purview, the project checks that the configuration has a valid shape and then converts it into a canonical representation. Validation and normalization are separate responsibilities: validation decides whether the document is acceptable; normalization removes representational differences that should not change its meaning.

WHAT GOES IN

The parsed document, its versioned schemas and the resources declared by the user.

WHAT PYTHON DOES

Python validates the document with JSON Schema, rejects unknown or sensitive properties, checks types and duplicate identities, and requires a valid HTTPS endpoint. It then canonicalizes the endpoint, sorts resources and lists, normalizes finite numeric values and builds a typed, immutable GovernanceConfig. When the plan is created, desired_state_from_config projects from that configuration only the material fields that will actually participate in comparison.

RESULT

A canonical and deterministic GovernanceConfig and, during planning, a DesiredState representing only the material part of that intention. Two documents that mean the same thing can converge on the same representation even if their original ordering differs.

CODE EVIDENCE

validate_document · normalize_document · GovernanceConfig · desired_state_from_config · DesiredState

INPUT

  • https://a.blob.core.windows.net/
  • [CSV, JSON]
  • 80.0
  • DailyScan @ ds-a

CANONICAL

  • canonical endpoint
  • sorted lists
  • normalized finite double
  • stable identity

Normalization does not change the intention. It makes the system compare meaning rather than accidental differences in formatting or ordering.

03

Observing the remote state

The desired configuration only explains how we want the environment to look. To know whether anything needs to change, Python must observe how Purview is configured at that moment and convert that observation into a comparable representation.

WHAT GOES IN

An authenticated Microsoft Purview Scanning Data Plane client and LIST/GET responses from API version 2023-09-01.

WHAT PYTHON DOES

Python discovers remote resources, sorts their identities, retrieves the required detail, rejects unsafe or sensitive shapes and normalizes each supported resource. It then builds a RemoteStateV2 and calculates a materialStateIdentity using SHA-256 over a canonical representation of the material state.

RESULT

A versioned remote snapshot describing what actually exists, plus a stable identity that can later be used to determine whether that state has changed.

The manual remote-state capture command exists for auditing. plan create does not reuse that file: it performs its own fresh capture before calculating differences.

CODE EVIDENCE

capture_remote_state_v2 · compute_material_state_identity · PurviewScanningClient

DESIRED

6 resources

REMOTE

0 resources

RemoteStateV2

materialStateIdentity = sha256:…

04

Comparison

Once the desired and remote states have been normalized, Python matches each resource by identity and classifies the difference. This stage is still read-only: it decides what each discrepancy means, but it does not execute any change.

WHAT GOES IN

DesiredState + RemoteStateV2.

WHAT PYTHON DOES

Python matches Data Sources, Classification Rules and Scan Rule Sets by name, and Scans through the composite identity (dataSourceName, name). It then compares only material fields, applies safety rules and produces deterministically ordered outcomes and reasons.

RESULT

A DiffDocument containing an outcome and its reasons for every resource. That document is not persisted as a standalone artifact: it becomes part of the plan changeSet.

CODE EVIDENCE

diff_desired_vs_remote · DiffDocument

DiffDocument

  • CREATE

    It exists in the desired configuration but not in Purview. It can become a create operation.

  • REPLACE

    It exists on both sides, but there is a material difference that the project considers safe to update.

  • NO-OP

    The relevant configuration already matches. There is nothing to write.

  • REMOTE-ONLY

    It exists in Purview but is not part of the desired state. The difference is reported, but the project does not delete it.

  • BLOCKED

    The difference cannot be handled safely or falls outside the supported contract. The plan becomes ineligible for writes.

In the real example, all six resources exist in desired and none exists in remote yet. The result is CREATE for all six.

05

Change plan

Detecting a difference does not authorize a write. The project turns the comparison into a versioned, reviewable artifact that preserves the full context, separates informational differences from executable ones and fixes exactly which operations could eventually be performed.

WHAT GOES IN

The validated configuration, the captured remote state and the DiffDocument calculated from both.

WHAT PYTHON DOES

Python includes the complete changeSet, selects only CREATE and REPLACE as executable operations, orders operations by resource type, embeds the desiredState that will be authoritative for payload construction and stores identities for the target, configuration and remote state. It then calculates a planIdentity and validates the plan contract again.

RESULT

A purview-governance-plan/v2 that acts at the same time as an explanation of the differences, an executable contract and an ordered list of operations.

CODE EVIDENCE

build_governance_plan_v2 · GovernancePlan · planIdentity

  1. 01

    CREATE · dataSource · ds-a

  2. 02

    CREATE · dataSource · ds-b

  3. 03

    CREATE · classificationRule · custom-rule

  4. 04

    CREATE · scanRuleSet · custom-srs

  5. 05

    CREATE · scan · DailyScan @ ds-a

  6. 06

    CREATE · scan · DailyScan @ ds-b

The order is deterministic and respects the model dependencies: Data Sources first, then classification rules, Scan Rule Sets and, finally, Scans.

06

Safe execution

A plan does not gain permission to write merely because it exists. Before the first PUT, Python checks the contract, execution mode, eligibility, target, payloads and remote state again. If any of those conditions is no longer safe, execution stops before writing.

WHAT GOES IN

A validated GovernancePlan, a client bound to the target and an ExecutionMode that defaults to DRY_RUN.

WHAT PYTHON DOES

Python moves through a fail-closed sequence of checks. Only if every check passes can execution reach the write boundary. Dry-run performs the same pre-write checks as apply, including a fresh remote capture and exact staleness validation, but finishes without issuing any PUT.

RESULT

dry-run-ready when everything is safe and writes were not requested; applied when APPLY was enabled and the operations completed successfully; or a blocking status explaining why no write was reached or why execution stopped.

CODE EVIDENCE

execute_governance_plan · materialize_mutation_intents_v2 · ExecutionMode

  1. 01Revalidate the plan

    Checks the GovernancePlan schema and semantic integrity again.

  2. 02Confirm the mode

    Only execution modes defined by ExecutionMode are accepted.

  3. 03Check eligibility

    If the plan is blocked, execution finishes with zero writes.

  4. 04Validate operations

    Only create or replace actions and resource types supported by the plan version are accepted.

  5. 05Bind the target

    The client endpoint and identity must match the target stored in the plan.

  6. 06Materialize payloads

    Mutation bodies are built from the desiredState embedded in the plan, not from external state that may have changed.

  7. 07Capture Purview again

    Python performs a fresh full read of the remote state immediately before the write boundary.

  8. 08Check that the plan is still current

    The observed state identity must exactly match the remote identity stored when the plan was created.

DRY-RUN

dry-run-ready · 0 PUT

APPLY

sequential PUTs

Dry-run is not a superficial simulation: it passes through every pre-write gate, materializes the payloads and reads Purview again. The only difference is that it stops before writing.

The plan was prepared while the remote state was empty. Before applying it, Python queries Purview again and detects that remote inventory now exists. Because the material identity no longer matches the identity fixed in the plan, the entire execution is blocked before any write.

This protects against a stale plan. It is not a complete drift engine.

APPLY is opt-in. It only allows create/replace, executes operations in plan order and stops on the first write failure. The project does not implement automatic deletes, automatic retries or rollback.

07

Result and evidence

The flow does not end with an HTTP call. Python builds a versioned result that relates what had been planned to what actually happened, so a successful, blocked or failed execution can be reviewed afterwards.

WHAT GOES IN

The plan, execution mode, identities observed during preflight and the result of every operation that was attempted.

WHAT PYTHON DOES

Python records the planIdentity, planned and execution targets, planned and observed remote states, mode, global status, write counters and the status of each operation. If a failure exists, it preserves its classification as well. The contract does not add execution timestamps.

RESULT

A purview-execution-result/v2 with its own resultIdentity and enough context to distinguish what was intended from what actually happened.

CODE EVIDENCE

build_execution_result_v2_from_parts · ExecutionResultV2 · resultIdentity

  • DRY-RUN

    status: dry-run-ready

    writesAttempted: 0

    operations: not-run

  • APPLY

    status: applied

    writesPerformed: 6

    operations: 6 succeeded

  • After applying

    RE-PLAN

    When the project is planned again against the new remote state, desired and remote now match. The plan contains no operations and a new execution attempts no writes.

What Python actually automates

Python does not act here as a simple API client. The project uses it to turn a declarative intention into a reproducible process: validate and normalize configuration, project the material state that actually matters, observe Purview, compare resources, build a deterministic plan, materialize payloads from that plan, block executions that no longer represent the current state and record the result. Writing sits at the end of the system and is only enabled after all of those conditions have been satisfied.

  1. VALIDATEvalidate_config_file
  2. NORMALIZEnormalize_document
  3. OBSERVEcapture_remote_state_v2
  4. COMPAREdiff_desired_vs_remote
  5. PLANbuild_governance_plan_v2
  6. PROTECTexecute_governance_plan
  7. EVIDENCEbuild_execution_result_v2_from_parts

Complete flow

  1. DESIRED CONFIGURATION
  2. VALIDATION + NORMALIZATION
  3. REMOTE STATE
  4. COMPARISON
  5. PLAN
  6. FRESH CAPTURE
  7. STILL CURRENT?
  8. NO →STALE · 0 WRITES
  9. YES →DRY-RUN · 0 WRITESAPPLY · CREATE/REPLACE
  10. EXECUTION RESULT

Maturity and evolution

The polygon reflects documented functional state. The outer ring represents the full profile.

  • Most consolidated

    Desired configuration, remote-state capture, deterministic comparison, change planning and pre-execution checks already form a coherent core proven through offline contracts.

  • Still evolving

    Current coverage is focused on Scanning and Classification within the supported Azure Storage slice. Validation against a live tenant and prolonged operation in a production environment remain outside the capabilities currently demonstrated.

  • Next

    The planned evolution expands the scope toward Unified Catalog, drift operations and greater enterprise extensibility and scale, without presenting them as implemented capabilities yet.

Roadmap

  1. Current · v1.1Scanning & Classification as CodeConfiguration, remote state, plan and apply for the AzureStorage slice.
  2. Next · v1.2Unified Catalog GovernancePublic Preview API isolated from the stable core.FUTURE
  3. Then · v1.3Drift and operationsDrift, retry/backoff, rate limits and telemetry.FUTURE
  4. Target · v2.0Extensibility and scaleScale, concurrency and extension contracts.FUTURE

What you can review on GitHub

Implementation

Lets you review how desired state is modeled, Purview is observed and the plan is built.

Contracts

Lets you review the versioned representations that make the cycle reproducible.

Safety and tests

Lets you verify that dry-run, staleness and fail-closed are covered without depending on a live tenant.

Documentation and examples

Lets you follow the review flow and examples without reconstructing context from the code.