Event log library with Lamport clocks and systematic error tracking
Project description
spec-kitty-events
Canonical event contracts for Spec Kitty mission state, mission runtime, conformance, and replay.
Package Version: 5.0.0 | Cutover Contract: 3.0.0 | Python: >=3.10
What Changed In 5.0.0
5.0.0 is a fail-closed TeamSpace migration contract release. The package
major version is 5.0.0; the on-wire envelope schema remains
schema_version="3.0.0".
- Mission identity fields are canonicalized to
mission_slug,mission_number, andmission_type. - Event envelopes require
build_idand use the cutover signalschema_version="3.0.0". - Live ingestion is fail-closed. There are no runtime compatibility aliases for legacy mission-domain fields.
- Legacy mission-domain keys and names such as
feature_slug,feature_number,mission_key,legacy_aggregate_id,FeatureCreated, andFeatureClosedare rejected on live paths. in_reviewis part of the canonical lane vocabulary.- The conformance package includes historical-shape fixtures for TeamSpace migration dry-runs.
See COMPATIBILITY.md for the exact fail-closed rollout policy.
Installation
From PyPI:
pip install "spec-kitty-events==5.0.0"
With conformance validation support:
pip install "spec-kitty-events[conformance]==5.0.0"
Development install:
git clone https://github.com/Priivacy-ai/spec-kitty-events.git
cd spec-kitty-events
pip install -e ".[dev,conformance]"
Contract Highlights
Eventis the canonical top-level envelope.build_ididentifies the build that emitted the envelope.node_ididentifies the emitting node within that build.schema_versionis the on-wire compatibility signal. Live envelopes must use3.0.0for this release.StatusTransitionPayloadusesmission_slugfor mission identity and acceptsin_review.- Mission catalog payloads use
mission_slug,mission_number, andmission_type. - Mission runtime payloads use
mission_type; they do not acceptmission_key.
Quick Start
Emit a Canonical Event Envelope
import uuid
from datetime import datetime
from spec_kitty_events import Event
event = Event(
event_id="01ARZ3NDEKTSV4RRFFQ69G5FAV",
event_type="WPStatusChanged",
aggregate_id="mission/WP01",
payload={
"mission_slug": "mission-001",
"wp_id": "WP01",
"from_lane": "planned",
"to_lane": "claimed",
"actor": "ci-bot",
"execution_mode": "worktree",
},
timestamp=datetime.now(),
build_id="build-2026-04-05",
node_id="runner-01",
lamport_clock=1,
project_uuid=uuid.uuid4(),
correlation_id="01ARZ3NDEKTSV4RRFFQ69G5FAV",
schema_version="3.0.0",
)
Validate a Payload Against the Canonical Contract
from spec_kitty_events.conformance import validate_event
payload = {
"mission_slug": "mission-001",
"wp_id": "WP01",
"from_lane": "planned",
"to_lane": "claimed",
"actor": "ci-bot",
"execution_mode": "worktree",
}
result = validate_event(payload, "WPStatusChanged")
assert result.valid
Validate a Full Envelope With Fail-Closed Cutover Checks
from spec_kitty_events.conformance import validate_event
envelope = {
"event_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
"event_type": "WPStatusChanged",
"aggregate_id": "mission/WP01",
"timestamp": "2026-04-05T12:00:00Z",
"build_id": "build-2026-04-05",
"node_id": "runner-01",
"lamport_clock": 1,
"project_uuid": "12345678-1234-5678-1234-567812345678",
"correlation_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
"schema_version": "3.0.0",
"payload": {
"mission_slug": "mission-001",
"wp_id": "WP01",
"from_lane": "planned",
"to_lane": "claimed",
"actor": "ci-bot",
"execution_mode": "worktree",
},
}
result = validate_event(envelope, "WPStatusChanged", strict=True)
assert result.valid
Schemas And Conformance
- Committed JSON Schemas are generated from the canonical Pydantic models.
- Replay streams and golden reducer outputs ship in the package.
- Conformance validation combines Pydantic validation, committed JSON Schemas, and cutover artifact checks.
Run the drift and conformance gates:
python -m spec_kitty_events.schemas.generate --check
pytest --pyargs spec_kitty_events.conformance -v
Public Guidance
- Use
mission_slug,mission_number, andmission_typein public mission-domain payloads. - Use
build_idto identify the emitting build andnode_idto identify the emitting node. - Do not rely on runtime translation of legacy mission-domain fields.
- Use offline rewrite or migration jobs if you need to transform historical pre-cutover data.
Legacy Envelope Normalization (legacy_envelope_v1)
spec_kitty_events.legacy publishes a named, frozen contract for promoting
known legacy event shapes to canonical 3.x envelopes. Three legacy shapes are
recognized in v1: pre_3_0_envelope, feature_keys_envelope, and
awaiting_review_synonym.
from spec_kitty_events.legacy import (
LegacyEnvelopeNormalizer,
NormalizedEnvelope,
UnnormalizableLegacyDiagnostic,
)
from spec_kitty_events.conformance.validators import validate_event
result = LegacyEnvelopeNormalizer().normalize(stored_legacy_row)
match result:
case NormalizedEnvelope(canonical=canonical, raw=raw, legacy_shape=shape):
conformance = validate_event(canonical, canonical["event_type"], strict=True)
# ship to materializer, retain raw for audit
case UnnormalizableLegacyDiagnostic(reason=reason, shape_hints=hints, raw=raw):
# classify as legacy / business-rule diagnostic; never silent
Guarantees:
- Audit preservation: both result variants carry the original
rawdict. - Determinism: same input always yields the same output (including the
minted
project_uuidvia UUID5 over(node_id, build_id)). - No silent aliases: every field-name change is captured by the
legacy_shapeidentifier; un-normalizable rows surface as structured diagnostics, never silent passes. - Idempotency: calling
normalize()on an already-canonical envelope returnsUnnormalizableLegacyDiagnostic(reason="unrecognized_legacy_shape").
The contract is named legacy_envelope_v1 and frozen. Future legacy shapes
ship as legacy_envelope_v2 alongside v1 for a deprecation window.
Mission: canonical-producer-contracts-legacy-envelope-01KS7JM3.
Local-Only Event Classification (LOCAL_ONLY_EVENT_TYPES)
spec_kitty_events.LOCAL_ONLY_EVENT_TYPES is a machine-readable
frozenset[str] published so downstream consumers (CLI canonical-producer
lint, SaaS adapter) can identify event types that are NOT routed through
the SaaS-bound producer path.
from spec_kitty_events import LOCAL_ONLY_EVENT_TYPES
# Currently empty: every CLI-emitted event audited as of spec-kitty 43305c12c
# routes through SpecKittyEventEmitter._emit() (the SaaS-bound central path).
assert LOCAL_ONLY_EVENT_TYPES == frozenset()
Future event types that don't cross the SaaS boundary can be classified by adding them to this set; consumers do not need to re-ship a contract or update their lint exemption files.
Mission: canonical-producer-contracts-legacy-envelope-01KS7JM3.
Identity-Boundary CI Gate
The cross-repo-harness-tests required check runs the
spec-kitty-end-to-end-testing
harness's identity-boundary unit tests on every PR. The harness is checked
out at a pinned commit SHA and the PR's HEAD copy of
spec_kitty_events is installed over the harness's frozen lockfile via
uv pip install -e ../events. If a PR breaks SaaS-side resolution
assumptions (envelope shape, identity field names, recognition rules), the
unit suite turns red and merge is blocked. Workflow file:
.github/workflows/cross-repo-harness-tests.yml.
Pinned e2e SHA: 193f5c0eb07c8fdb6943d91d205ab892b98d6dfc
SHA-bump procedure
When an intentional, breaking contract change ships in this repo that requires a matching harness update:
- Get the new e2e SHA after the harness update lands:
unset GITHUB_TOKEN gh api repos/Priivacy-ai/spec-kitty-end-to-end-testing/commits/main --jq .sha
- Verify the new SHA still contains
tests/unit/identity_boundary/andtests/identity_boundary/unit/:gh api repos/Priivacy-ai/spec-kitty-end-to-end-testing/contents/tests/unit/identity_boundary --ref <NEW_SHA> gh api repos/Priivacy-ai/spec-kitty-end-to-end-testing/contents/tests/identity_boundary/unit --ref <NEW_SHA>
- Update the
ref:field in.github/workflows/cross-repo-harness-tests.yml. - Open the bump PR; CI will exercise the new SHA against the new contract before merge.
Sibling gates
This is one of three coordinated CI gates tracked under
Priivacy-ai/spec-kitty#1247:
cross-repo-harness-testshere (this repo).drift-detectorinspec-kitty— workflow.github/workflows/drift-detector.yml.identity-boundary-canaryinspec-kitty-saas— workflow.github/workflows/canary-gate.yml.
Admin action required (one-time)
After this gate merges, a repo admin must register the check as required on
main:
- Open https://github.com/Priivacy-ai/spec-kitty-events/settings/branches.
- Edit the rule for
main. - Under "Require status checks to pass before merging", add the exact name
cross-repo-harness-tests. - Save.
Until that step is done, the workflow still runs on every PR but its red status does not block merge.
Versioning
This package now publishes the TeamSpace migration release as package 5.0.0.
2.xdocumentation and mixed-field operation are no longer the public contract.- Consumers should treat the cutover artifact, recursive forbidden-key helper, and committed fixtures as the authoritative compatibility surface.
- The envelope schema version intentionally remains
3.0.0.
License
All rights reserved. This repository is owned by Priivacy AI.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spec_kitty_events-5.2.0.tar.gz.
File metadata
- Download URL: spec_kitty_events-5.2.0.tar.gz
- Upload date:
- Size: 252.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a045e4164942d9857438a5a901a6e3a794215d678fc590d982dc82abe8b3755f
|
|
| MD5 |
cd4b4205950bf96d6c616acdb814e780
|
|
| BLAKE2b-256 |
115c10926f0989e9b0d769ce23d0b1ddc0ae18d0df573bcbb7cbcd776bb0ee46
|
Provenance
The following attestation bundles were made for spec_kitty_events-5.2.0.tar.gz:
Publisher:
publish-pypi.yml on Priivacy-ai/spec-kitty-events
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spec_kitty_events-5.2.0.tar.gz -
Subject digest:
a045e4164942d9857438a5a901a6e3a794215d678fc590d982dc82abe8b3755f - Sigstore transparency entry: 1603295235
- Sigstore integration time:
-
Permalink:
Priivacy-ai/spec-kitty-events@657b14736356c5418b6121a1220af03dd6a74fa5 -
Branch / Tag:
refs/tags/v5.2.0 - Owner: https://github.com/Priivacy-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@657b14736356c5418b6121a1220af03dd6a74fa5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file spec_kitty_events-5.2.0-py3-none-any.whl.
File metadata
- Download URL: spec_kitty_events-5.2.0-py3-none-any.whl
- Upload date:
- Size: 372.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84ea41ec792957e7c825d96d299f8d890bbb7407f1d6f9e8b1294acd7f6848e3
|
|
| MD5 |
67e35eb54d9f9560763f3240283c863f
|
|
| BLAKE2b-256 |
0fe05ab534d87428e62645e9be0450fb03f2559c2023cc4addd7b29343234411
|
Provenance
The following attestation bundles were made for spec_kitty_events-5.2.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on Priivacy-ai/spec-kitty-events
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spec_kitty_events-5.2.0-py3-none-any.whl -
Subject digest:
84ea41ec792957e7c825d96d299f8d890bbb7407f1d6f9e8b1294acd7f6848e3 - Sigstore transparency entry: 1603295477
- Sigstore integration time:
-
Permalink:
Priivacy-ai/spec-kitty-events@657b14736356c5418b6121a1220af03dd6a74fa5 -
Branch / Tag:
refs/tags/v5.2.0 - Owner: https://github.com/Priivacy-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@657b14736356c5418b6121a1220af03dd6a74fa5 -
Trigger Event:
push
-
Statement type: