perceptkit 0.2.3__tar.gz → 0.2.4__tar.gz
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.
- {perceptkit-0.2.3 → perceptkit-0.2.4}/CHANGELOG.md +15 -1
- {perceptkit-0.2.3 → perceptkit-0.2.4}/PKG-INFO +1 -1
- {perceptkit-0.2.3 → perceptkit-0.2.4}/pyproject.toml +1 -1
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/manifest/minimal.py +9 -1
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_regressions.py +31 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/uv.lock +1 -1
- {perceptkit-0.2.3 → perceptkit-0.2.4}/.github/workflows/release.yml +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/.gitignore +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/LICENSE +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/NOTES-packaging.md +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/NOTES-quickstart.md +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/README.md +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/docs/PerceptKit-/344/272/247/345/223/201/347/233/256/346/240/207/344/270/216/345/275/223/345/211/215/345/256/236/347/216/260/345/267/256/350/267/235/345/217/215/351/246/210.md" +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/docs/PerceptKit-/346/204/237/347/237/245/345/255/227/346/256/265/344/270/216/345/255/230/345/202/250-/345/267/245/347/250/213/345/257/271/351/275/220/350/241/245/345/205/205/350/256/250/350/256/272.md" +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/docs/reference-storage-mapping.md +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/examples/end_to_end.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/examples/ios_adapter.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/examples/quickstart.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/__init__.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/algorithms/__init__.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/algorithms/attribution.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/algorithms/glance.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/algorithms/history.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/algorithms/identity.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/algorithms/observation.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/algorithms/streaks.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/algorithms/trend_models.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/algorithms/wake.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/catalog.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/conformance/__init__.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/conformance/memory.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/conformance/report.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/conformance/suite.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/conformance/wake.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/__init__.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/_time.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/availability.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/context.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/delivery.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/errors.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/event.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/observation.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/receipt.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/records.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/report.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/contracts/versioning.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/fields.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/kit.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/manifest/__init__.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/manifest/checks.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/manifest/mapping.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/manifest/types.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/manifest/units.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/ports/__init__.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/ports/storage.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/ports/wake.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/processing/__init__.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/processing/aggregate.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/processing/dispatch.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/processing/normalize.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/processing/pipeline.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/processing/recompute.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/processing/recurrence.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/processing/scheduled.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/prompts.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/queries/__init__.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/queries/api.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/retention.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/rules/__init__.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/rules/engine.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/rules/evaluators.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/src/perceptkit/rules/types.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/fixtures/README.md +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/fixtures/ios_snapshot_no_data.json +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/fixtures/ios_snapshot_normal.json +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/fixtures/ios_snapshot_unauthorized.json +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_attribution.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_catalog.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_conformance.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_conformance_wake_report.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_contracts.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_delivery_and_records.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_edge_cases.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_end_to_end.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_event_envelope.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_examples.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_export.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_identity.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_ios_fixture.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_isolation.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_manifest.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_no_host_leakage.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_observation.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_pipeline.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_projection.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_purity.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_queries.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_recompute.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_recurrence.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_retention.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_rules.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_scheduled.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_source_mirror.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_streaks.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_trend_models.py +0 -0
- {perceptkit-0.2.3 → perceptkit-0.2.4}/tests/test_wake.py +0 -0
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# 变更记录
|
|
2
2
|
|
|
3
|
-
## 0.2.
|
|
3
|
+
## 0.2.4 — 未发布
|
|
4
|
+
|
|
5
|
+
**第一批真机数据跑出来的。** 4052 次比对里三处不一致,这是其中属于内核的那一处。
|
|
6
|
+
|
|
7
|
+
### 修复
|
|
8
|
+
|
|
9
|
+
- **「音乐停了」这个状态进不了系统。** `track_key` 声明成必填,而播放器停着的
|
|
10
|
+
时候没有曲目 —— 于是那条观测因「缺必填字段」被**整条拒掉**:在放什么记得住,
|
|
11
|
+
停了永远记不住。而「他刚把音乐关了」恰恰是这个信号最有用的那一半。
|
|
12
|
+
真机上 83 次上报,83 次都是这个。
|
|
13
|
+
|
|
14
|
+
规范 §5.3 把 `track_id` 列为字段,没说它任何时候都必须有值。
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## 0.2.3 — 2026-09-01
|
|
4
18
|
|
|
5
19
|
**七个「声明了、但没有代码做」的修复。** 都是拿规范逐条跑代码跑出来的,
|
|
6
20
|
不是照着清单打勾 —— 清单把这七条全判成了成立,因为它核的是 manifest 怎么写的。
|
|
@@ -1093,7 +1093,15 @@ MUSIC_PLAYBACK = SignalDefinition(
|
|
|
1093
1093
|
key="track_key",
|
|
1094
1094
|
value_type="string",
|
|
1095
1095
|
privacy_class="sensitive",
|
|
1096
|
-
nullable=
|
|
1096
|
+
nullable=True,
|
|
1097
|
+
# ★ 「什么都没在放」是一个**正常状态**,而它没有曲目。
|
|
1098
|
+
#
|
|
1099
|
+
# 非空的话,播放器停着的那条观测因为缺必填字段被整条拒掉 ——
|
|
1100
|
+
# 于是 kit 永远不知道「音乐停了」,只知道「在放什么」。
|
|
1101
|
+
# 真机上这条占了 83 次差异里的 83 次:老路记着 stopped,
|
|
1102
|
+
# kit 那边一片空白。
|
|
1103
|
+
#
|
|
1104
|
+
# 规范 §5.3 把 track_id 列为字段,没说它任何时候都必须有值。,
|
|
1097
1105
|
comparison_strategy="exact",
|
|
1098
1106
|
wake_eligible=True,
|
|
1099
1107
|
query_visibility="on_demand",
|
|
@@ -823,3 +823,34 @@ def test_every_signal_with_a_permanent_aggregate_marks_its_identity():
|
|
|
823
823
|
if s.keeps_aggregates_forever and not s.keeps_history_forever]
|
|
824
824
|
assert set(at_risk) == {"focus_state", "motion_state",
|
|
825
825
|
"music_playback", "photo_library_added"}
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
# ---------------------------------------------------------------------------
|
|
829
|
+
# I11 —— 「音乐停了」这个状态进不了系统
|
|
830
|
+
#
|
|
831
|
+
# 真机上跑出来的:老路 83 次记着 stopped,kit 那边一片空白。
|
|
832
|
+
# ---------------------------------------------------------------------------
|
|
833
|
+
|
|
834
|
+
def test_a_stopped_player_is_a_state_the_system_can_hold():
|
|
835
|
+
"""播放器停着的时候没有曲目 —— 那是正常的,不是数据缺失。
|
|
836
|
+
|
|
837
|
+
`track_key` 非空的话,这条观测因为缺必填字段被**整条拒掉**:于是
|
|
838
|
+
「在放什么」记得住,「停了」永远记不住。而「他刚把音乐关了」恰恰是
|
|
839
|
+
这个信号最有用的那一半。
|
|
840
|
+
"""
|
|
841
|
+
storage = InMemoryStorage()
|
|
842
|
+
kit = PerceptionKit(storage=storage, signals=MINIMAL_SIGNALS)
|
|
843
|
+
at = datetime(2026, 9, 1, 9, 0, tzinfo=timezone.utc)
|
|
844
|
+
outcome = kit.ingest({
|
|
845
|
+
"schema_version": 1, "report_id": "m1", "producer": "ios",
|
|
846
|
+
"observations": [{
|
|
847
|
+
"signal": "music_playback", "signal_schema_version": 1,
|
|
848
|
+
"occurred_at": at.isoformat(), "availability": "observed",
|
|
849
|
+
"timezone": "Asia/Shanghai",
|
|
850
|
+
"value": {"playback_state": "stopped", "edge_quality": "estimated"},
|
|
851
|
+
}],
|
|
852
|
+
}, context=IngestContext("u", at))
|
|
853
|
+
assert not outcome.rejected, list(outcome.rejected)
|
|
854
|
+
current = storage.get_current(subject_id="u", signals=["music_playback"]
|
|
855
|
+
)["music_playback"][0]
|
|
856
|
+
assert current.typed_value["playback_state"] == "stopped"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|