← 全体レポートに戻る

局所トレーサビリティビュー グループ: SERIAL

生成日時: 2026-03-11 00:06:09

対象アイテム

8

REQ

1

ARCH

1

SPEC

2

TST

2

IMPL

2

レビュー済

8/8

Suspect

0

グループ

SERIAL
アイテム: REQ005 ARCH005 SPEC012 SPEC013 TST012 TST013 IMPL012 IMPL013

トレーサビリティマトリクス

✓=レビュー済 ○=未レビュー ⚠=Suspect(複数同時表示あり。IDクリックで詳細へ)

グループREQARCHSPECTSTIMPL
SERIALREQ005
関数の戻り値を安全にシリアライズ・デシリアライズできること。ユーザー定義型のカスタムエンコーダ・デコーダを登録可能であること。
ARCH005
## コンポーネント構成 ```mermaid graph TD A[MsgpackSerializer] -->|Registry| B[TypeReg...
SPEC012
## インターフェース ```python class MsgpackSerializer(SerializerProtocol, TypeRegistryP...
TST012
## 目的 `MsgpackSerializer` はキャッシュデータの永続化形式を決定する。シリアライズの不具合はデータ消失(デシリアライズ不能)やサイレン...
IMPL012
## 実装概要 `MsgpackSerializer` クラスが `SerializerProtocol` と `TypeRegistryProtocol` ...
SERIALREQ005
関数の戻り値を安全にシリアライズ・デシリアライズできること。ユーザー定義型のカスタムエンコーダ・デコーダを登録可能であること。
ARCH005
## コンポーネント構成 ```mermaid graph TD A[MsgpackSerializer] -->|Registry| B[TypeReg...
SPEC013
## インターフェース ```python def register( code: int, encoder: Callable[[Any],...
TST013
## 目的 カスタム型登録はユーザー定義クラスのキャッシュを可能にする拡張ポイントである。登録の不備は `SerializationError` によるキャッ...
IMPL013
## 実装概要 2つのレイヤーで構成: - `MsgpackSerializer.register(type, code, encoder, decoder)...

カバレッジ(局所)

リンク方向カバー数カバー率未カバー
ARCH → REQ 1 / 1 100.0%
SPEC → ARCH 1 / 1 100.0%
TST → SPEC 2 / 2 100.0%
IMPL → SPEC 2 / 2 100.0%

アイテム詳細

REQ005 REQ {h(g)} ✓ レビュー済

関数の戻り値を安全にシリアライズ・デシリアライズできること。ユーザー定義型のカスタムエンコーダ・デコーダを登録可能であること。

親:

子: ARCH005

ARCH005 ARCH {h(g)} ✓ レビュー済

コンポーネント構成

graph TD
  A[MsgpackSerializer] -->|Registry| B[TypeRegistryProtocol]
  A -->|LRU Cache| C[Thread-Local Storage]
  A -->|Core| D[msgpack-python]

コンポーネント責務

コンポーネント 責務 インターフェース
MsgpackSerializer MessagePackベースの高速・コンパクトなバイナリ変換 dumps(), loads()
TypeRegistryProtocol ユーザー定義型(ExtType)のエンコーダ・デコーダ登録 register()
Thread-Local Cache free-threading環境でのロック競合を回避するMRO解決キャッシュ OrderedDict (LRU)

データフロー

sequenceDiagram
  participant User as ユーザーコード
  participant Ser as MsgpackSerializer
  participant Reg as TypeRegistry
  participant MP as msgpack

  User->>Ser: dumps(obj)
  Ser->>Ser: 型チェック & MRO解決
  opt カスタム型
    Ser->>Reg: エンコーダ取得
    Reg-->>Ser: encoder_fn
    Ser->>MP: ExtType(code, encoder_fn(obj))
  end
  MP-->>Ser: binary
  Ser-->>User: bytes

技術選定

技術領域 選定 理由
フォーマット MessagePack JSONより高速・コンパクト。バイナリをネイティブにサポート
スレッド安全 Copy-on-Write (CoW) 読み取りパスからロックを排除し、マルチスレッド性能を最大化
型拡張 ExtType (0-127) カスタム型を1バイトのオーバーヘッドで表現可能

非機能要件方針

親: REQ005

子: SPEC012, SPEC013

SPEC012 SPEC {h(g)} ✓ レビュー済

インターフェース

class MsgpackSerializer(SerializerProtocol, TypeRegistryProtocol):
    def dumps(self, obj: Any) -> bytes: ...
    def loads(self, data: bytes) -> Any: ...

振る舞い

シリアライズ (dumps)

  1. オブジェクトの型を type(obj) で取得
  2. 登録済み型またはそのサブクラス(MRO順)を探索
  3. ヒットした場合、カスタムエンコーダを実行し ExtType としてパック
  4. ヒットしない場合、MessagePack のデフォルト処理(または SerializationError

デシリアライズ (loads)

  1. MessagePack ストリームをパース
  2. ExtType を発見した場合、コードに対応するカスタムデコーダを呼び出す

パラメータ詳細

設定 デフォルト 説明
max_cache_size 1024 スレッドごとの型解決LRUキャッシュの最大サイズ

エラーハンドリング

エッジケース

親: ARCH005

子: IMPL012, TST012

SPEC013 SPEC {h(g)} ✓ レビュー済

インターフェース

def register(
    code: int,
    encoder: Callable[[Any], Any],
    decoder: Callable[[Any], Any],
) -> Callable: ... # デコレータ形式

def register_type(
    type_class: Type,
    code: int,
    encoder: Callable[[Any], Any],
    decoder: Callable[[Any], Any],
) -> None: ...

振る舞い

  1. 重複チェック: 同一コードまたは同一クラスが既に登録されていないか確認
  2. CoW更新: 現在のレジストリ辞書をコピーし、新しいエントリを追加した後に参照を差し替える
  3. 世代更新: _registry_generation をインクリメントし、全スレッドのLRUキャッシュを無効化対象とする

パラメータ詳細

パラメータ 制限 説明
code 0127 MessagePack ExtType のユーザー定義領域コード
encoder 引数1、戻り値シリアライズ可能 オブジェクトをプリミティブ構造へ変換する関数
decoder 引数1、戻り値オブジェクト プリミティブ構造からオブジェクトを復元する関数

エラーハンドリング

エッジケース

親: ARCH005

子: IMPL013, TST013

TST012 TST {h(g)} ✓ レビュー済

目的

MsgpackSerializer はキャッシュデータの永続化形式を決定する。シリアライズの不具合はデータ消失(デシリアライズ不能)やサイレントなデータ劣化(精度低下等)に直結する。スレッドセーフ性の欠如はマルチスレッド環境での競合状態を引き起こす。

検証観点

references: tests/unit/test_serializer.py

親: SPEC012

子:

TST013 TST {h(g)} ✓ レビュー済

目的

カスタム型登録はユーザー定義クラスのキャッシュを可能にする拡張ポイントである。登録の不備は SerializationError によるキャッシュ保存失敗を引き起こし、ユーザーの既存コードとの統合を阻害する。デコレータ方式と命令方式の両方の登録パスを検証する。

検証観点

references: tests/unit/test_type_registry.py

親: SPEC013

子:

IMPL012 IMPL {h(g)} ✓ レビュー済

実装概要

MsgpackSerializer クラスが SerializerProtocolTypeRegistryProtocol を実装。 dumps(obj) -> bytes / loads(data) -> Any が主要 API。 カスタム型は msgpack の ExtType(code, payload) で拡張する。 _default_packer() がエンコード時のカスタム型ディスパッチ、 _ext_hook() がデコード時の型復元を行う。

設計判断

Copy-on-Write レジストリ

_encoders / _decoders 辞書は register() 時に新しい辞書を作成して アトミックに差し替える(CoW)。読み取り側はスナップショットを参照するため、 ロックなしで安全に読める。GIL に依存せず、PEP 703(free-threading)にも 対応できる設計。世代カウンタ _registry_generationレジストリ差し替えの前に インクリメントすることで、読み取り側が古いキャッシュを使い続けることを防ぐ。

スレッドローカル LRU キャッシュ

MRO スキャンの結果(サブクラス→登録済み親クラスの解決)を threading.local()OrderedDict にキャッシュする。_cache_generation_registry_generation を比較し、 世代が変わったらキャッシュを破棄する。LRU のサイズ上限は max_cache_size で制御。

MRO スキャンによるサブクラス自動解決

Pydantic モデルのサブクラスのように、親クラスが登録済みなら サブクラスも自動的に同じエンコーダで処理できる。type(obj).__mro__ を走査し、 最初にマッチした登録型のエンコーダを使用する。

実装メモ

references: src/beautyspot/serializer.py

親: SPEC012

子:

IMPL013 IMPL {h(g)} ✓ レビュー済

実装概要

2つのレイヤーで構成: - MsgpackSerializer.register(type, code, encoder, decoder): 低レベルの型登録 API - Spot.register() / Spot.register_type(): ユーザー向けの高レベル API

Spot.register() はデコレータ形式、Spot.register_type() は命令形式で、 いずれも内部で serializer.register() に委譲する(TypeRegistryProtocol 準拠時のみ)。

設計判断

二層 API の提供

デコレータ形式 @spot.register(code=1, ...) はクラス定義と同時に登録でき、 宣言的で読みやすい。命令形式 spot.register_type(MyClass, code=1, ...) は 外部ライブラリのクラスなどデコレートできない場合に使用する。

TypeRegistryProtocol による条件分岐

シリアライザが TypeRegistryProtocol を実装していない場合(カスタムシリアライザ)、 register() / register_type()ConfigurationError を送出する。 これにより、型登録非対応のシリアライザを使用する場合のエラーメッセージが明確になる。

実装メモ

references: src/beautyspot/serializer.py, src/beautyspot/core.py

親: SPEC013

子: