Skip to main content

plm-shared

Standalone repo since 2026-06-30 (FTR-924). Extracted from plm-engine-core/shared/ into github.com/plm-engine/plm-shared. See docs/POST-SPLIT.md for the split context, India onboarding pointer, and PRD §6.1 cross-reference.

Integrating against plm-shared? Start with the consumer guide at docs/federation-contract-guide.md and the runnable e2e example at examples/consume_plm_shared.py. For the ratified FR ⇄ India usage conventions (tenancy, RLS boundary, ownership, cross-pin, error taxonomy) and the consumer conformance checklist, see docs/fr-india-contract-conventions.md.

Frozen contracts shared across TracePulse PLM product lines (Core, Skill Kernel, Skill Packages, Knowledge, Workbench, Studio, Connectors). Owned by US-W1.0; consumed by US-W1.1 → US-W1.13 and US-CR.0 → US-CR.13 without modification.

The Wave 1 origin story (7 PRs that built US-W1.0 pre-extraction) is preserved in this repo's commit history + the retrospective RELEASE-NOTES-v1.0.0.md. Post-extraction (FTR-924, 2026-06-30) the shipping model is release-please + PyPI: see CHANGELOG.md for every published version.

Surface

Module Purpose
kernel_api Pydantic args + KernelEmitter Protocol (frozen)
sqlalchemy_kernel_emitter Concrete SqlAlchemyKernelEmitter impl (PR-6)
idempotency IdempotencyKey + compute_content_hash
capabilities Capability enum + YAML loader
knowledge_envelope KnowledgeEnvelopeV1 frozen schema
trace_context TraceContext ContextVar + W0.6 bridge
pricing compute_cost + CostStatus + PricingSnapshot dataclass
artifact_store ArtifactStorageBackend Protocol + LocalFilesystemBackend + ObjectStoreBackend
middleware PlmTenantMiddleware (ASGI) + parse_core_caller + cors_allowed_headers
db SQLAlchemy 2.0 ORM models + tenant_scoped_session

Kernel API (US-W1.0 / AC-2)

plm_shared.kernel_api.KernelEmitter is the frozen 4-method Protocol that every product line uses to record events. The authorised emitter boundary is Core: product lines submit decisions to Core (e.g. Workbench routes HITL approvals), and Core is the authorised emitter through plm-shared.

Protocol

from plm_shared.kernel_api import KernelEmitter
from plm_shared.kernel_api import (
    EmitTelemetryArgs,
    EmitGovernanceArgs,
    EmitLlmCallArgs,
    EmitConnectorCallArgs,
)

class KernelEmitter(Protocol):
    def emit_telemetry(self, args: EmitTelemetryArgs) -> None: ...
    def emit_governance(self, args: EmitGovernanceArgs) -> None: ...
    def record_llm_call(self, args: EmitLlmCallArgs) -> None: ...
    def record_connector_call(self, args: EmitConnectorCallArgs) -> None: ...

Every method returns None on success — including the silent replay path (200 OK: same key + same content). A logical-key collision (same identity, different content) raises plm_shared.sqlalchemy_kernel_emitter.IdempotencyConflict.

Args

EmitTelemetryArgs(
    event_type:      str,                  # e.g. "knowledge_call"
    span_id:         str,
    capability:      str,                  # capability tag for the event
    payload:         Dict[str, Any] = {},  # event-specific shape
    idempotency_key: IdempotencyKey,
)

EmitGovernanceArgs(
    governance_event_type: str,            # e.g. "hitl_resolved"
    span_id:               str,
    payload:               Dict[str, Any] = {},
    idempotency_key:       IdempotencyKey,
)

EmitLlmCallArgs(
    span_id:           str,
    model:             str,
    prompt_tokens:     int,
    completion_tokens: int,
    pricing_version:   str,                 # "litellm-live" | "overrides-static" | "unavailable"
    cost_eur:          Optional[float] = None,
    cost_status:       str,                 # "pending" | "calculated" | "unavailable"
    idempotency_key:   IdempotencyKey,
)

EmitConnectorCallArgs(
    span_id:         str,
    connector_id:    str,                   # e.g. "3dx-rest"
    capability:      str,                   # e.g. "read.parts"
    envelope:        Dict[str, Any] = {},
    pricing_version: str,
    cost_eur:        Optional[float] = None,
    cost_status:     str,
    idempotency_key: IdempotencyKey,
)

Concrete emitter — SqlAlchemyKernelEmitter

from plm_shared.sqlalchemy_kernel_emitter import (
    IdempotencyConflict,
    SqlAlchemyKernelEmitter,
)
from plm_shared.idempotency import IdempotencyKey, compute_content_hash
from plm_shared.kernel_api import EmitLlmCallArgs

tenant_id = "00000000-0000-0000-0000-000000000000"
emitter = SqlAlchemyKernelEmitter(tenant_id=tenant_id)

payload = {"model": "gpt-4o", "prompt_tokens": 100}
key = IdempotencyKey(
    tenant_id=tenant_id,
    trace_id="trace-X",
    span_id="span-1",
    event_type="llm_call",
    content_hash=compute_content_hash(payload),
)

try:
    emitter.record_llm_call(EmitLlmCallArgs(
        span_id="span-1",
        model="gpt-4o",
        prompt_tokens=100,
        completion_tokens=50,
        pricing_version="litellm-live",
        cost_eur=0.0042,
        cost_status="calculated",
        idempotency_key=key,
    ))
    # 200 — inserted, OR 200 — silent replay (same key + same content)
except IdempotencyConflict:
    # 409 — same logical identity, different content
    raise

The emitter:

  • Opens a tenant_scoped_session(tenant_id) so RLS engages on INSERT (migration 0009 — fail-closed for an unset GUC).
  • Stamps the idempotency_key UNIQUE; on collision, dispatches by constraint name (<table>_idempotency_key_key → 200 silent replay, uq_<table>_logical → 409 raise).
  • For LLM and connector calls, upserts a pricing_snapshots row keyed on (tenant_id, model, snapshot_date) (migration 0011) and stores the FK on the call row. pricing_version="unavailable" skips the snapshot — the cost_status column carries the authoritative signal.

Backend wiring (deferred to US-CR.0)

PlmTenantMiddleware is published in plm_shared.middleware but is NOT yet installed in 02_App/backend/main.py. US-CR.0 owns the ordering — it adds IdentityMiddleware first, then plumbs PlmTenantMiddleware behind it, then wires CORS so that CORSMiddleware wraps both (failure responses still carry CORS headers). Conv D leaves the middleware available-but-unwired so US-CR.0 lands the full ordering in one place.

Migration chain

Frozen head: 0024. Full chain:

Rev Subject
0001 foundational tables tenants, runs + quality_level ENUM + actor_kind ENUM
0002 telemetry_events + composite index + UNIQUE idempotency_key
0003 llm_calls + cost_* columns + UNIQUE idempotency_key
0004 connector_calls + connector-specific fields
0005 artifacts + storage_uri + retention_until
0006 quality_level + cost_status transition triggers
0007 mcrc_v1_view (§1-§8 projection)
0008 Postgres roles plm_kernel_writer + plm_migrator
0009 Row-Level Security on the 5 tenant-scoped tables + plm_migrator BYPASSRLS
0010 logical UNIQUE constraints (backs the 200/409 IdempotencyKey contract)
0011 pricing_snapshots dedup table + nullable FKs
0012 plm_migrator table privileges — SELECT/INSERT/UPDATE/DELETE on the 7 tenant-scoped tables (BYPASSRLS alone does not grant table access)
0013 audit_log table for identity events (US-CR.0 PR-2)
0014 cost-canonicalisation columns on LLM + connector calls (US-W1.12 Conv H)
0015 artifact offload schema extension — prompt/completion refs (US-W1.5 Conv I)
0016 promote Wave 0 metadata to typed columns on telemetry_events (US-W1.13 Conv I)
0017 hitl_tickets HITL Control Plane persistence (US-CR.13)
0018 hitl_ticket_comments HITL comment persistence (US-CR.13)
0019 connector_access_index Knowledge curation index (FTR-603 Wave 5 Conv C)
0020 mcrc_v1_view widening — pricing + rate source projections (Wave 5 Conv D / FTR-605)
0021 widen runs.outcome enum to include awaiting_hitl (US-DC.2 Wave 6 Conv B)
0022 realised-baseline correction — DC-3 telemetry columns (US-DC.3 Wave 6 Conv D)
0023 telemetry workload indexes for DC-5 read-path (US-DC.5 Wave 6 Conv D)
0024 agent-invocations rename + realised-baseline correction (US-DC.4 Wave 6 Conv E)

Run the chain with alembic upgrade head from this repo root (needs PG_DSN exported).

Install (developer)

In a workspace context (uv workspace at c:\AIxPLM\plm-engine\), uv sync resolves plm-shared editable as a workspace member. As an external consumer:

pip install plm-shared          # base install — from PyPI
pip install 'plm-shared[db]'    # + SQLAlchemy / psycopg / alembic
pip install 'plm-shared[s3]'    # + boto3 (ObjectStoreBackend)
pip install 'plm-shared[db,s3]' # combined

Pin per D3 = Option A (additive→minor, breaking→major): plm-shared = "^1.0" in your sibling's pyproject.toml. See docs/POST-SPLIT.md.

Tests

cd plm-shared
python -m pytest tests/ -v

Audit + migration suites under tests/audit/ and tests/migrations/ are gated on PG_DSN. CI brings up the matching Postgres service in .github/workflows/audit-pg.yml (postgres:15.7-alpine, tracepulse_ci DB). Locally, bring Postgres up with plain docker run (the workspace also provides dev/postgres.yml, but the compose file is only present inside the plm-engine workspace clone, not this standalone repo):

# tracepulse_ci is the canonical DB name — matches CI (audit-pg.yml
# + example-smoke) and the local dev-compose file. Keeping one name
# means reproducing a CI failure locally needs no path translation.
docker run -d --name plm-shared-pg \
  -e POSTGRES_USER=tracepulse \
  -e POSTGRES_PASSWORD=tracepulse \
  -e POSTGRES_DB=tracepulse_ci \
  -p 5432:5432 \
  postgres:15.7-alpine
export PG_DSN=postgresql+psycopg://tracepulse:tracepulse@localhost:5432/tracepulse_ci
alembic upgrade head
python -m pytest tests/audit/ tests/migrations/ -v

S3-protocol live tests under tests/test_object_store_backend.py gate on S3_ENDPOINT_URL (skip-when-unset). Bring up minio (or any S3-protocol endpoint) and export S3_ENDPOINT_URL, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET.

Architecture conformance gate (US-W1.0 / AC-4)

pyproject.toml declares one [tool.importlinter] Forbidden contract banning sqlalchemy from every plm-shared module except db and sqlalchemy_kernel_emitter. Run it from the repo root:

cd plm-shared
lint-imports --config pyproject.toml

The companion BL5 rule in 02_App/backend/scripts/architecture_guardrails.py (warn-only at launch) regex-scans for INSERT INTO {telemetry_events|llm_calls|connector_calls|pricing_snapshots} outside kernel_api / sqlalchemy_kernel_emitter / migrations.

Metadata

Release files for plm-shared 1.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for plm-shared 1.6.0
File Size Uploaded Provenance Actions
plm_shared-1.6.0.tar.gz 457.8 kB With provenance Details for plm_shared-1.6.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for plm-shared 1.6.0
File Interpreter ABI Platform Actions
plm_shared-1.6.0-py3-none-any.whl Python 3 none any Details for plm_shared-1.6.0-py3-none-any.whl

Total release size: 859.4 kB

Release files / plm_shared-1.6.0.tar.gz

Download URL plm_shared-1.6.0.tar.gz
Size 457.8 kB
Tags Source
SHA-256 checksum
How to use checksums
076fea82f6aa7ec691dbf09a7a268bb41c7b9c09c6fd800a20ab4d74e7fedaee
BLAKE2b-256 checksum
How to use checksums
0a7edb2e798146f562067e165067ab2ec2bf2cf6e5144a7cf34a77baf26f1259
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / plm_shared-1.6.0-py3-none-any.whl

Download URL plm_shared-1.6.0-py3-none-any.whl
Size 401.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
16e4b46232807b0104ab924746d4941586eec8c890b1b5a577678ecebdef0146
BLAKE2b-256 checksum
How to use checksums
9d9477a8cb2b9bf96cb8d687af30a83a81ec0ec812f0798ed958e936a5ecc8ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Security for plm-shared 1.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for plm_shared-1.6.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page