Skip to content

How to create an audit-ready change record for an Exstream PUB deployment

Classic Exstream Design and Production deployments using compiled PUB packages · Published 2026-08-21

By Tomas Hajek, working with Exstream since 2008

An enterprise change record can say that an Exstream application was deployed without proving what reached production. The workflow ran. A ticket changed state. Someone approved a release. None of those facts identifies the bytes that the engine will execute.

For a compiled Exstream application, an audit-ready record should connect four facts:

  1. The source revision from which the package was built.
  2. The SHA-256 digest of the exact PUB file.
  3. The production deployment event that succeeded.
  4. The person or automation identity that initiated the deployment.

Package inspection adds a fifth fact: what the deployed artifact contains. The same record works across change-management products, CI systems, and deployment orchestrators.

Register at the production boundary

The system that knows the deployment succeeded should create the deployment record.

A merge is too early. A build can succeed without being deployed. A package can be generated, rejected, regenerated, or sent to another environment. Registering any of those events as a production deployment produces a clean dashboard with unreliable data.

The registration point belongs after the final production action:

source revision
  -> build or package
  -> approval
  -> production deployment
  -> successful deployment result
  -> change registration

Platform-managed deployments may already report this event. Do not add a second registration path just because another team is standardising the legacy estate. The objective is one truthful event per deployment, not one event per participating system.

Preserve three forms of identity

Source identity, artifact identity, and deployment identity answer different questions.

The source revision answers, "Which repository state was selected?"

The package digest answers, "Which exact bytes did the engine receive?"

The deployment identifier answers, "Which production operation moved those bytes, and did it finish?"

Keep all three. A source SHA alone is insufficient when packaging depends on approval selection, environment settings, or a packaging tool outside the source repository. A filename alone is worse. CustomerLetters.pub can name hundreds of different files over its lifetime.

A small deployment manifest is enough:

{
  "schemaVersion": 1,
  "environment": "prod",
  "applicationName": "CustomerLetters",
  "sourceRepository": "communications/customer-letters",
  "sourceSha": "6d934e8...",
  "packageFileName": "CustomerLetters.pub",
  "packageSha256": "ad9f5ab...",
  "packageSizeBytes": 1234567,
  "deployedAt": "2026-08-21T14:32:00Z",
  "deploymentId": "deploy-18472",
  "initiatedBy": "operator@example.com",
  "message": "Release approved wording and tariff changes"
}

Store the manifest only after deployment succeeds. If deployment fails, retain the operational failure record, but do not publish a successful production change.

Resolve the source revision before reporting

Repository-based resource deployments often know their source SHA directly. Binary artifact deployments are harder.

A mutable snapshot version does not identify one build. Even a release version only works as identity when the artifact repository enforces immutability. The reliable pattern is to publish build metadata beside the artifact:

{
  "sourceRepository": "communications/customer-letters",
  "sourceSha": "6d934e8...",
  "sourceRef": "refs/heads/main",
  "artifactVersion": "4.7.2",
  "buildRunId": "98117"
}

The deployment system reads metadata for the exact artifact it selected. If it cannot resolve the deployed artifact to a source revision, it should expose that gap instead of substituting the current branch head.

Add package evidence with Inspect

The base deployment record proves what file was deployed. CCMForge Inspect can describe that file.

After packaging, run the Package CLI against the exact PUB that may be deployed:

exstream-package-cli CustomerLetters.pub \
  --format json --out CustomerLetters.package.json

The package report can record application identity, package and Design Manager versions, approval information, object counts, mappings, rules, variables, and wording where the package generation and decoder support them.

Before operator confirmation, the Design CLI can compare the selected repository application with the package currently deployed in the target environment:

exstream-package-cli state deployed/CustomerLetters.pub \
  --depth detailed > deployed-state.json

exstream-design-cli app diff CustomerLetters \
  --config ./inspect.yaml --profile production-design \
  --left-mode approved --right-state deployed-state.json \
  --output html > proposed-change.html

That comparison answers a different question from the deployment manifest. The manifest says what was deployed. The comparison says what was expected to change.

Keep those records separate. Copying every package fact into the deployment manifest creates two sources of truth that will eventually disagree.

State what the inspection could compare

Package formats change across Exstream generations. A decoder may support an object inventory while lacking full access to one kind of formatted text or property.

The report must state its coverage. "No difference found" is valid only for fields that both sides could compare. An unavailable field is not unchanged.

If inspection is optional for the deployment, record its result explicitly:

{
  "inspectionStatus": "partial",
  "inspectionReport": "CustomerLetters.package.json",
  "inspectionCoverage": "Package inventory complete; formatted text partial"
}

If package inspection fails but deployment policy permits the release, the deployment can continue with inspectionStatus: failed. The change record still carries the package digest, so the artifact remains identifiable.

If inspection is a mandatory release gate, fail before deployment. Do not deploy successfully and then rewrite the deployment as failed because an optional reporting step broke.

Keep ownership clear

Inspect provides design and package evidence. It does not own the production deployment event.

The deployment system should own:

  • the target environment;
  • the successful or failed deployment result;
  • the operator and approval context;
  • the deployed package digest;
  • the call to the central change-registration service.

Inspect should own:

  • the package manifest;
  • the repository state document;
  • the repository-to-package or package-to-package comparison;
  • the coverage statement for what could be decoded and compared.

That split keeps the audit trail useful when either system changes.

A practical adoption order

Start with the minimum truthful record:

  1. Register only successful production deployments.
  2. Record application, environment, time, operator, and deployment ID.
  3. Calculate the PUB digest and size from the deployed file.
  4. Resolve the source revision from build metadata.
  5. Add a package manifest.
  6. Add a pre-deployment repository or package comparison where it helps the reviewer.

The first four steps establish traceability. The last two make the change understandable.

See how CCMForge Inspect reads and compares Exstream packages.

Read the repository or package as structured data.

Inspect inventories the Design repository and compiled PUB package, extracts supported content, and compares any two states. Start with a free package overview or discuss a repository inventory.

These articles describe field experience and identify the Exstream versions they cover. They are not official vendor guidance. CCMForge is independent and is not affiliated with or endorsed by OpenText. OpenText and Exstream are trademarks of their respective owner.