metaspn-schemas 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,46 @@
1
+ from metaspn_schemas.core import (
2
+ EmissionEnvelope,
3
+ EntityRef,
4
+ SchemaVersion,
5
+ SignalEnvelope,
6
+ TraceContext,
7
+ )
8
+ from metaspn_schemas.entities import EntityAliasAdded, EntityMerged, EntityResolved
9
+ from metaspn_schemas.features import (
10
+ GameClassified,
11
+ PlaybookRouted,
12
+ ProfileEnriched,
13
+ ScoresComputed,
14
+ )
15
+ from metaspn_schemas.outcomes import MeetingBooked, MessageSent, ReplyReceived, RevenueEvent
16
+ from metaspn_schemas.social import ProfileSnapshotSeen, SocialPostSeen
17
+ from metaspn_schemas.state_fragments import Attempts, Cooldowns, Evidence, Identity, Scores
18
+ from metaspn_schemas.tasks import Result, Task
19
+
20
+ __all__ = [
21
+ "Attempts",
22
+ "Cooldowns",
23
+ "EmissionEnvelope",
24
+ "EntityAliasAdded",
25
+ "EntityMerged",
26
+ "EntityRef",
27
+ "EntityResolved",
28
+ "Evidence",
29
+ "GameClassified",
30
+ "Identity",
31
+ "MeetingBooked",
32
+ "MessageSent",
33
+ "PlaybookRouted",
34
+ "ProfileEnriched",
35
+ "ProfileSnapshotSeen",
36
+ "ReplyReceived",
37
+ "Result",
38
+ "RevenueEvent",
39
+ "SchemaVersion",
40
+ "Scores",
41
+ "ScoresComputed",
42
+ "SignalEnvelope",
43
+ "SocialPostSeen",
44
+ "Task",
45
+ "TraceContext",
46
+ ]
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ from metaspn_schemas.utils.serde import Serializable
8
+ from metaspn_schemas.utils.time import ensure_utc
9
+
10
+ DEFAULT_SCHEMA_VERSION = "0.1"
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class SchemaVersion(Serializable):
15
+ package: str = "metaspn-schemas"
16
+ version: str = DEFAULT_SCHEMA_VERSION
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class EntityRef(Serializable):
21
+ ref_type: str
22
+ value: str
23
+ platform: str | None = None
24
+ label: str | None = None
25
+ schema_version: str = DEFAULT_SCHEMA_VERSION
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class TraceContext(Serializable):
30
+ trace_id: str
31
+ caused_by: tuple[str, ...] = field(default_factory=tuple)
32
+ provenance: str | None = None
33
+ redactions: tuple[str, ...] = field(default_factory=tuple)
34
+ metadata: dict[str, str] = field(default_factory=dict)
35
+ privacy_mode: bool = False
36
+ schema_version: str = DEFAULT_SCHEMA_VERSION
37
+
38
+
39
+ @dataclass(frozen=True)
40
+ class SignalEnvelope(Serializable):
41
+ signal_id: str
42
+ timestamp: datetime
43
+ source: str
44
+ payload_type: str
45
+ payload: Any
46
+ schema_version: str = DEFAULT_SCHEMA_VERSION
47
+ entity_refs: tuple[EntityRef, ...] = field(default_factory=tuple)
48
+ trace: TraceContext | None = None
49
+ raw: dict[str, Any] | None = field(default=None, metadata={"omit_in_privacy_mode": True})
50
+
51
+ def __post_init__(self) -> None:
52
+ object.__setattr__(self, "timestamp", ensure_utc(self.timestamp))
53
+
54
+
55
+ @dataclass(frozen=True)
56
+ class EmissionEnvelope(Serializable):
57
+ emission_id: str
58
+ timestamp: datetime
59
+ emission_type: str
60
+ payload: Any
61
+ caused_by: str
62
+ schema_version: str = DEFAULT_SCHEMA_VERSION
63
+ trace: TraceContext | None = None
64
+ entity_refs: tuple[EntityRef, ...] = field(default_factory=tuple)
65
+
66
+ def __post_init__(self) -> None:
67
+ object.__setattr__(self, "timestamp", ensure_utc(self.timestamp))
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+
6
+ from metaspn_schemas.core import DEFAULT_SCHEMA_VERSION
7
+ from metaspn_schemas.utils.serde import Serializable
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class EntityResolved(Serializable):
12
+ entity_id: str
13
+ resolver: str
14
+ resolved_at: datetime
15
+ confidence: float
16
+ schema_version: str = DEFAULT_SCHEMA_VERSION
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class EntityMerged(Serializable):
21
+ entity_id: str
22
+ merged_from: tuple[str, ...]
23
+ merged_at: datetime
24
+ reason: str | None = None
25
+ schema_version: str = DEFAULT_SCHEMA_VERSION
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class EntityAliasAdded(Serializable):
30
+ entity_id: str
31
+ alias: str
32
+ alias_type: str
33
+ added_at: datetime
34
+ schema_version: str = DEFAULT_SCHEMA_VERSION
@@ -0,0 +1,46 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+
6
+ from metaspn_schemas.core import DEFAULT_SCHEMA_VERSION
7
+ from metaspn_schemas.utils.serde import Serializable
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class ProfileEnriched(Serializable):
12
+ entity_id: str
13
+ enriched_at: datetime
14
+ summary: str
15
+ topics: tuple[str, ...] = field(default_factory=tuple)
16
+ schema_version: str = DEFAULT_SCHEMA_VERSION
17
+
18
+ def __post_init__(self) -> None:
19
+ object.__setattr__(self, "topics", tuple(sorted(self.topics)))
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class ScoresComputed(Serializable):
24
+ entity_id: str
25
+ computed_at: datetime
26
+ scores: dict[str, float]
27
+ scorer: str
28
+ schema_version: str = DEFAULT_SCHEMA_VERSION
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class PlaybookRouted(Serializable):
33
+ task_id: str
34
+ routed_at: datetime
35
+ playbook: str
36
+ rationale: str | None = None
37
+ schema_version: str = DEFAULT_SCHEMA_VERSION
38
+
39
+
40
+ @dataclass(frozen=True)
41
+ class GameClassified(Serializable):
42
+ entity_id: str
43
+ classified_at: datetime
44
+ label: str
45
+ confidence: float
46
+ schema_version: str = DEFAULT_SCHEMA_VERSION
@@ -0,0 +1,47 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+
6
+ from metaspn_schemas.core import DEFAULT_SCHEMA_VERSION
7
+ from metaspn_schemas.utils.serde import Serializable
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class MessageSent(Serializable):
12
+ message_id: str
13
+ channel: str
14
+ recipient: str
15
+ sent_at: datetime
16
+ subject: str | None = None
17
+ schema_version: str = DEFAULT_SCHEMA_VERSION
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class ReplyReceived(Serializable):
22
+ reply_id: str
23
+ message_id: str
24
+ sender: str
25
+ received_at: datetime
26
+ sentiment: str | None = None
27
+ schema_version: str = DEFAULT_SCHEMA_VERSION
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class MeetingBooked(Serializable):
32
+ meeting_id: str
33
+ organizer: str
34
+ booked_at: datetime
35
+ starts_at: datetime
36
+ attendees: tuple[str, ...]
37
+ schema_version: str = DEFAULT_SCHEMA_VERSION
38
+
39
+
40
+ @dataclass(frozen=True)
41
+ class RevenueEvent(Serializable):
42
+ revenue_id: str
43
+ amount: float
44
+ currency: str
45
+ recognized_at: datetime
46
+ source: str
47
+ schema_version: str = DEFAULT_SCHEMA_VERSION
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+
6
+ from metaspn_schemas.core import DEFAULT_SCHEMA_VERSION
7
+ from metaspn_schemas.utils.serde import Serializable
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class SocialPostSeen(Serializable):
12
+ post_id: str
13
+ platform: str
14
+ author_handle: str
15
+ content: str
16
+ seen_at: datetime
17
+ url: str | None = None
18
+ topics: tuple[str, ...] = field(default_factory=tuple)
19
+ schema_version: str = DEFAULT_SCHEMA_VERSION
20
+
21
+ def __post_init__(self) -> None:
22
+ object.__setattr__(self, "topics", tuple(sorted(self.topics)))
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class ProfileSnapshotSeen(Serializable):
27
+ profile_id: str
28
+ platform: str
29
+ handle: str
30
+ display_name: str | None
31
+ bio: str | None
32
+ seen_at: datetime
33
+ followers_count: int | None = None
34
+ topics: tuple[str, ...] = field(default_factory=tuple)
35
+ schema_version: str = DEFAULT_SCHEMA_VERSION
36
+
37
+ def __post_init__(self) -> None:
38
+ object.__setattr__(self, "topics", tuple(sorted(self.topics)))
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+
6
+ from metaspn_schemas.core import DEFAULT_SCHEMA_VERSION
7
+ from metaspn_schemas.utils.serde import Serializable
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class Identity(Serializable):
12
+ entity_id: str
13
+ canonical_name: str | None = None
14
+ aliases: tuple[str, ...] = field(default_factory=tuple)
15
+ schema_version: str = DEFAULT_SCHEMA_VERSION
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class Evidence(Serializable):
20
+ evidence_id: str
21
+ entity_id: str
22
+ source: str
23
+ collected_at: datetime
24
+ attributes: dict[str, str] = field(default_factory=dict)
25
+ schema_version: str = DEFAULT_SCHEMA_VERSION
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class Scores(Serializable):
30
+ entity_id: str
31
+ values: dict[str, float]
32
+ updated_at: datetime
33
+ schema_version: str = DEFAULT_SCHEMA_VERSION
34
+
35
+
36
+ @dataclass(frozen=True)
37
+ class Cooldowns(Serializable):
38
+ entity_id: str
39
+ channel: str
40
+ until: datetime
41
+ reason: str | None = None
42
+ schema_version: str = DEFAULT_SCHEMA_VERSION
43
+
44
+
45
+ @dataclass(frozen=True)
46
+ class Attempts(Serializable):
47
+ entity_id: str
48
+ count: int
49
+ last_attempt_at: datetime | None = None
50
+ schema_version: str = DEFAULT_SCHEMA_VERSION
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ from metaspn_schemas.core import DEFAULT_SCHEMA_VERSION, EntityRef
8
+ from metaspn_schemas.utils.serde import Serializable
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class Task(Serializable):
13
+ task_id: str
14
+ task_type: str
15
+ created_at: datetime
16
+ priority: int
17
+ entity_ref: EntityRef
18
+ inputs: dict[str, Any] = field(default_factory=dict)
19
+ context: dict[str, Any] = field(default_factory=dict)
20
+ schema_version: str = DEFAULT_SCHEMA_VERSION
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class Result(Serializable):
25
+ result_id: str
26
+ task_id: str
27
+ status: str
28
+ completed_at: datetime
29
+ outputs: dict[str, Any] = field(default_factory=dict)
30
+ errors: tuple[str, ...] = field(default_factory=tuple)
31
+ schema_version: str = DEFAULT_SCHEMA_VERSION
@@ -0,0 +1,14 @@
1
+ from metaspn_schemas.utils.ids import generate_id
2
+ from metaspn_schemas.utils.serde import Serializable, dataclass_from_dict, dataclass_to_dict
3
+ from metaspn_schemas.utils.time import datetime_to_str, ensure_utc, str_to_datetime, utc_now
4
+
5
+ __all__ = [
6
+ "Serializable",
7
+ "dataclass_from_dict",
8
+ "dataclass_to_dict",
9
+ "datetime_to_str",
10
+ "ensure_utc",
11
+ "generate_id",
12
+ "str_to_datetime",
13
+ "utc_now",
14
+ ]
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ import uuid
4
+
5
+
6
+ VALID_PREFIXES = {
7
+ "signal": "s",
8
+ "emission": "e",
9
+ "task": "t",
10
+ "result": "r",
11
+ "entity": "ent",
12
+ }
13
+
14
+
15
+ def generate_id(prefix: str | None = None) -> str:
16
+ token = uuid.uuid4().hex
17
+ if prefix is None:
18
+ return token
19
+ normalized = prefix.strip().lower()
20
+ mapped = VALID_PREFIXES.get(normalized, normalized)
21
+ return f"{mapped}_{token}"
@@ -0,0 +1,130 @@
1
+ from __future__ import annotations
2
+
3
+ import types
4
+ from dataclasses import MISSING, fields, is_dataclass
5
+ from datetime import datetime
6
+ from typing import Any, TypeVar, Union, get_args, get_origin, get_type_hints
7
+
8
+ from metaspn_schemas.utils.time import datetime_to_str, str_to_datetime
9
+
10
+ T = TypeVar("T")
11
+
12
+
13
+ class Serializable:
14
+ def to_dict(self, *, privacy_mode: bool = False) -> dict[str, Any]:
15
+ return dataclass_to_dict(self, privacy_mode=privacy_mode)
16
+
17
+ @classmethod
18
+ def from_dict(cls: type[T], data: dict[str, Any]) -> T:
19
+ return dataclass_from_dict(cls, data)
20
+
21
+
22
+ def dataclass_to_dict(obj: Any, *, privacy_mode: bool = False) -> dict[str, Any]:
23
+ if not is_dataclass(obj):
24
+ raise TypeError("dataclass_to_dict expects a dataclass instance")
25
+
26
+ output: dict[str, Any] = {}
27
+ for f in fields(obj):
28
+ if privacy_mode and f.metadata.get("omit_in_privacy_mode"):
29
+ continue
30
+ value = getattr(obj, f.name)
31
+ output[f.name] = _to_primitive(value, privacy_mode=privacy_mode)
32
+ return output
33
+
34
+
35
+ def _to_primitive(value: Any, *, privacy_mode: bool) -> Any:
36
+ if is_dataclass(value):
37
+ return dataclass_to_dict(value, privacy_mode=privacy_mode)
38
+ if isinstance(value, datetime):
39
+ return datetime_to_str(value)
40
+ if isinstance(value, tuple):
41
+ return [_to_primitive(v, privacy_mode=privacy_mode) for v in value]
42
+ if isinstance(value, list):
43
+ return [_to_primitive(v, privacy_mode=privacy_mode) for v in value]
44
+ if isinstance(value, dict):
45
+ return {k: _to_primitive(v, privacy_mode=privacy_mode) for k, v in sorted(value.items())}
46
+ return value
47
+
48
+
49
+ def dataclass_from_dict(cls: type[T], data: dict[str, Any]) -> T:
50
+ if not is_dataclass(cls):
51
+ raise TypeError("dataclass_from_dict expects a dataclass type")
52
+
53
+ hints = get_type_hints(cls)
54
+ kwargs: dict[str, Any] = {}
55
+
56
+ for f in fields(cls):
57
+ hint = hints.get(f.name, Any)
58
+ if f.name in data:
59
+ kwargs[f.name] = _coerce_value(hint, data[f.name])
60
+ continue
61
+
62
+ if f.default is not MISSING:
63
+ kwargs[f.name] = f.default
64
+ continue
65
+
66
+ if f.default_factory is not MISSING: # type: ignore[attr-defined]
67
+ kwargs[f.name] = f.default_factory() # type: ignore[misc]
68
+ continue
69
+
70
+ raise ValueError(f"Missing required field: {f.name}")
71
+
72
+ return cls(**kwargs)
73
+
74
+
75
+ def _coerce_value(hint: Any, value: Any) -> Any:
76
+ if value is None:
77
+ return None
78
+
79
+ origin = get_origin(hint)
80
+ args = get_args(hint)
81
+
82
+ if hint is Any:
83
+ return value
84
+
85
+ if hint is datetime:
86
+ if isinstance(value, datetime):
87
+ return value
88
+ if isinstance(value, str):
89
+ return str_to_datetime(value)
90
+ raise TypeError(f"Cannot parse datetime from {type(value)!r}")
91
+
92
+ if origin in (Union, types.UnionType):
93
+ last_error: Exception | None = None
94
+ for option in args:
95
+ if option is type(None):
96
+ continue
97
+ try:
98
+ return _coerce_value(option, value)
99
+ except Exception as err: # noqa: BLE001
100
+ last_error = err
101
+ if last_error is not None:
102
+ raise last_error
103
+ return value
104
+
105
+ if origin is tuple:
106
+ item_type = args[0] if args else Any
107
+ return tuple(_coerce_value(item_type, item) for item in value)
108
+
109
+ if origin is list:
110
+ item_type = args[0] if args else Any
111
+ return [_coerce_value(item_type, item) for item in value]
112
+
113
+ if origin is dict:
114
+ key_type = args[0] if len(args) > 0 else Any
115
+ value_type = args[1] if len(args) > 1 else Any
116
+ return {
117
+ _coerce_value(key_type, k): _coerce_value(value_type, v)
118
+ for k, v in value.items()
119
+ }
120
+
121
+ if is_dataclass(hint):
122
+ if isinstance(value, hint):
123
+ return value
124
+ if isinstance(value, dict):
125
+ return dataclass_from_dict(hint, value)
126
+
127
+ if hint in (str, int, float, bool):
128
+ return hint(value)
129
+
130
+ return value
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime, timezone
4
+
5
+
6
+ def utc_now() -> datetime:
7
+ return datetime.now(timezone.utc)
8
+
9
+
10
+ def ensure_utc(value: datetime) -> datetime:
11
+ if value.tzinfo is None:
12
+ return value.replace(tzinfo=timezone.utc)
13
+ return value.astimezone(timezone.utc)
14
+
15
+
16
+ def datetime_to_str(value: datetime) -> str:
17
+ utc_value = ensure_utc(value)
18
+ return utc_value.isoformat().replace("+00:00", "Z")
19
+
20
+
21
+ def str_to_datetime(value: str) -> datetime:
22
+ text = value[:-1] + "+00:00" if value.endswith("Z") else value
23
+ parsed = datetime.fromisoformat(text)
24
+ return ensure_utc(parsed)
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: metaspn-schemas
3
+ Version: 0.1.0
4
+ Summary: Canonical schemas for MetaSPN-compatible signal processing systems
5
+ Author: MetaSPN
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/MetaSPN/metaspn-schemas
8
+ Project-URL: Repository, https://github.com/MetaSPN/metaspn-schemas
9
+ Project-URL: Issues, https://github.com/MetaSPN/metaspn-schemas/issues
10
+ Keywords: schemas,signal-processing,events,dataclasses,metaspn
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest>=8; extra == "dev"
19
+ Requires-Dist: build>=1.2.0; extra == "dev"
20
+ Requires-Dist: twine>=5.0.0; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # metaspn-schemas
24
+
25
+ Canonical, stdlib-only schema package for MetaSPN-compatible systems.
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pip install metaspn-schemas
31
+ ```
32
+
33
+ ## Development
34
+
35
+ ```bash
36
+ python -m pip install -e .[dev]
37
+ pytest -q
38
+ python -m build
39
+ python -m twine check dist/*
40
+ ```
41
+
42
+ ## Design constraints
43
+
44
+ - Tiny and dependency-light (stdlib only)
45
+ - Frozen dataclasses for immutable-by-default objects
46
+ - Explicit `schema_version` on all public objects
47
+ - `to_dict()` / `from_dict()` on every schema
48
+ - UTC ISO-8601 datetime serialization
49
+ - Traceability metadata (`trace_id`, `caused_by`, provenance)
50
+ - Privacy mode support (`to_dict(privacy_mode=True)` omits raw blobs)
51
+
52
+ ## Example
53
+
54
+ ```python
55
+ from datetime import timezone, datetime
56
+
57
+ from metaspn_schemas import SignalEnvelope
58
+ from metaspn_schemas.utils.ids import generate_id
59
+
60
+ signal = SignalEnvelope(
61
+ signal_id=generate_id("signal"),
62
+ timestamp=datetime.now(timezone.utc),
63
+ source="linkedin.webhook",
64
+ payload_type="SocialPostSeen",
65
+ payload={"post_id": "123", "platform": "linkedin"},
66
+ schema_version="0.1",
67
+ )
68
+
69
+ as_dict = signal.to_dict()
70
+ round_trip = SignalEnvelope.from_dict(as_dict)
71
+ ```
72
+
73
+ ## Public imports
74
+
75
+ ```python
76
+ from metaspn_schemas import (
77
+ SignalEnvelope,
78
+ EmissionEnvelope,
79
+ Task,
80
+ Result,
81
+ SocialPostSeen,
82
+ ProfileEnriched,
83
+ ScoresComputed,
84
+ )
85
+ ```
86
+
87
+ ## Package layout
88
+
89
+ ```text
90
+ metaspn-schemas/
91
+ pyproject.toml
92
+ README.md
93
+ src/metaspn_schemas/
94
+ __init__.py
95
+ core.py
96
+ tasks.py
97
+ entities.py
98
+ social.py
99
+ outcomes.py
100
+ features.py
101
+ state_fragments.py
102
+ utils/
103
+ ids.py
104
+ time.py
105
+ serde.py
106
+ test/
107
+ test_serde.py
108
+ test_ids.py
109
+ test_backcompat.py
110
+ ```
111
+
112
+ ## Release
113
+
114
+ Release automation is configured in:
115
+
116
+ - `.github/workflows/ci.yml`
117
+ - `.github/workflows/publish.yml`
118
+
119
+ See `RELEASE.md` for the end-to-end push + PyPI release flow.
@@ -0,0 +1,17 @@
1
+ metaspn_schemas/__init__.py,sha256=zAryvrNvDBXXWOokiizwpQmpr3Orxp5VcvWMmCIJX08,1149
2
+ metaspn_schemas/core.py,sha256=ERkkWxnMVZ0P6_g3qruEOwxU2i59UvlDZUBKiSEnZoc,1942
3
+ metaspn_schemas/entities.py,sha256=jl_3Ie8vyaF1En2mcDHPGU0Sszz-oQu4OmYtWBak0Vg,811
4
+ metaspn_schemas/features.py,sha256=Z9Nh-o_At1e3UETelHidGm44R3P2T7WuybQikUi6F5A,1158
5
+ metaspn_schemas/outcomes.py,sha256=-t7S-Rn75INcIMMrxZNFnyYcDg804AP2aOQEEJm2P3U,1087
6
+ metaspn_schemas/social.py,sha256=r-2t0z35bRNUo0MqNMTuh2Tt7DuouKFo0XGnn0grFxY,1068
7
+ metaspn_schemas/state_fragments.py,sha256=YzHmyAdcpWQL-ALwDQezVSFEu4mQAmbqc6cNtqZaBg8,1239
8
+ metaspn_schemas/tasks.py,sha256=ZXHJl6kWq6l1B47hRxN80QXdVSgWDcTuDC-mJitnsbY,871
9
+ metaspn_schemas/utils/__init__.py,sha256=Vz4fl0V2Gwpjq3tGsFSLNSbihZUyUMN_f6UIHRuKKiY,421
10
+ metaspn_schemas/utils/ids.py,sha256=avUMruGrC0rKxPspmJgFk9eGa2BvUsFAYA-NkSyuKK4,421
11
+ metaspn_schemas/utils/serde.py,sha256=f-lhqGCXEtOeAP_Ea5nJT5Dsho-EhQghMnJA7hVWGhY,4065
12
+ metaspn_schemas/utils/time.py,sha256=U5l8_ZXIKgAIzvGB8wOkCewzhjKI5ygfCCzTLFu-_3A,634
13
+ metaspn_schemas-0.1.0.dist-info/licenses/LICENSE,sha256=a9HFx7YHIoXQV8KLxqBH1uEJ6Ok6-yGkFu0_4fi2Zu0,1064
14
+ metaspn_schemas-0.1.0.dist-info/METADATA,sha256=yHv_y7EVqAgi4WctNkP-KPo_3wTkwLwOCkpVdvE-wwE,2700
15
+ metaspn_schemas-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
16
+ metaspn_schemas-0.1.0.dist-info/top_level.txt,sha256=Vqx4EYfSXtLghSiLIlorpPnFPNJg7YBgGvO1ZQyW6WM,16
17
+ metaspn_schemas-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MetaSPN
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ metaspn_schemas