Phase A0.1 Implementation Plan — SSP system-implementation 結構重整補丁

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan. Steps use checkbox (- [ ]) syntax.

Goal:把 A0 ship 的 system_security_plan_system_implementations 表結構正確化 — rename 成 ssp_system_implementation_items、補上 OSCAL system-implementation block 主檔 ssp_system_implementations、補上 inventory-item ↔︎ component M:N join 表、改 column information_system_idsystem_characteristic_id

Architecture:DDD 嚴格分層擴充 — 1 個 SQL migration 完成所有 schema change(含 rename / new tables / column rename / backfill);jedi-oscal 套件 ORM rename + 新 main/join 完整 stack;主 BE caller 改寫;既有 A0 32 個測試 fix。dev 期續 poetry path dep,feature 完工才推 Nexus。

Tech Stack:Python 3.11 / SQLAlchemy 2.0 / PostgreSQL / pytest / poetry path dep / jedi-oscal local

Specdesign-A0.1.md 前置:A0 已 ship(commits c4804d7 / a1b80cc / e73b1aa / 60a4a2e / 5d8626e) Branchfeature/ssp-import-export-phase2


§1

全域實作規範(每個 task 都要遵守)

  1. TDD strict:先寫測試 → 確認 fail → 改實作 → 確認 pass → commit
  2. 顯式 git addgit add <file1> <file2>禁用 -am / -A
  3. commit 前必 git status --short 確認 staged 區只有自己 add 的檔案
  4. Co-Authored-By footerCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
  5. 不自動 publish jedi-oscal:保持 path dep
  6. SQL migration 用 cmmgr
  7. 改 BE service 後提醒 user 重啟

§2

File Structure

compliance-manager-be(主專案)

動作 路徑
已有(不動) scripts/sql/2026-05-19-ssp-system-implementation-restructure.sql ★ user 已自行執行
Modify app/oscal/service/ssp_versioning_service.py(既有 caller,import + clone main 流程)
Modify app/associations/service/project_device_mapping_service.py(既有 caller,upsert main 前置)
Modify di_containers/oscal/oscal_containers.py(wiring main + join service)
Modify tests/test_ssp_system_implementation_regression.py(A0 regression 更名)
Create tests/test_ssp_system_implementation_main_regression.py(main upsert smoke)
Create docs/changelog/2026-05-19-tweak-ssp-system-impl-restructure.md

jedi-oscal 套件

Rename 既有檔(class + 檔名改): | 既有 | 改後 | |------|-----| | infra/model/ssp/ssp_system_implementation.py (class OscalSystemSecurityPlanSystemImplementation) | infra/model/ssp/ssp_system_implementation_items.py (class OscalSspSystemImplementationItem) | | domain/entity/ssp/ssp_system_implementation_entity.py (class SystemImplementationEntity) | .../ssp_system_implementation_item_entity.py (class SspSystemImplementationItemEntity) | | domain/entity/ssp/ssp_system_implementation_query_entity.py | .../ssp_system_implementation_item_query_entity.py | | infra/repository/ssp/ssp_system_implementation_repo_impl.py (class SystemImplementationRepoImpl) | .../ssp_system_implementation_item_repo_impl.py (class SspSystemImplementationItemRepoImpl) | | domain/repository/ssp/system_implementation_repo.py (class ISystemImplementationRepo) | .../system_implementation_item_repo.py (class ISspSystemImplementationItemRepo) | | infra/mapper/ssp/system_implementation_mapper.py (class SystemImplementationMapper) | .../system_implementation_item_mapper.py (class SspSystemImplementationItemMapper) | | app/dto/ssp/ssp_system_implementation_dto.py (class SystemImplementationDTO) | .../ssp_system_implementation_item_dto.py (class SspSystemImplementationItemDTO) | | domain/services/ssp/system_implementation_domain_service.py (class SystemImplementationDomainService) | .../system_implementation_item_domain_service.py (class SspSystemImplementationItemDomainService) |

Modify(父層引用更新):

  • infra/model/ssp/ssp.py(relationship system_implementations
  • infra/mapper/ssp/system_security_plan_mapper.py
  • infra/mapper/ssp/ssp_yaml_mapper.py核心改動:從 main 出發 + 三分支 + implemented-components)
  • domain/entity/ssp/ssp_entity.py
  • app/dto/ssp/ssp_dto.py
  • infra/repository/ssp/__init__.py(export 改 class 名)
  • domain/repository/ssp/__init__.py
  • domain/services/ssp/__init__.py

Create 新檔(main 完整 stack — 8 個)

  • infra/model/ssp/ssp_system_implementation.py(class OscalSspSystemImplementation,main table ORM)
  • domain/entity/ssp/ssp_system_implementation_entity.py(class SspSystemImplementationEntity,main entity)
  • domain/entity/ssp/ssp_system_implementation_query_entity.py
  • domain/repository/ssp/system_implementation_repo.py(class ISspSystemImplementationRepo
  • infra/repository/ssp/ssp_system_implementation_repo_impl.py(class SspSystemImplementationRepoImpl
  • infra/mapper/ssp/system_implementation_mapper.py(class SspSystemImplementationMapper
  • app/dto/ssp/ssp_system_implementation_dto.py(class SspSystemImplementationDTO
  • domain/services/ssp/system_implementation_domain_service.py(class SspSystemImplementationDomainService,含 upsert_by_scope

Create 新檔(join 完整 stack — 8 個)

  • infra/model/ssp/ssp_inventory_item_component.py(class OscalSspInventoryItemComponent
  • domain/entity/ssp/ssp_inventory_item_component_entity.py
  • domain/entity/ssp/ssp_inventory_item_component_query_entity.py
  • domain/repository/ssp/inventory_item_component_repo.py
  • infra/repository/ssp/ssp_inventory_item_component_repo_impl.py
  • infra/mapper/ssp/inventory_item_component_mapper.py
  • app/dto/ssp/ssp_inventory_item_component_dto.py
  • domain/services/ssp/inventory_item_component_domain_service.py

Modify 測試

  • tests/test_ssp_system_implementation_extension.py(A0 32 個測試 — import / class 名 / column 名)

Create 新測試

  • tests/test_ssp_system_implementation_main.py(main 表 CRUD + UNIQUE + upsert_by_scope)
  • tests/test_ssp_inventory_item_component.py(join 表 CRUD + M:N relationship)

§3

Task 0 — Pre-Flight Verification(第一個 task,必跑

開工前確認:

  1. SQL migration 已 user 自行執行於 dev DB
  2. 既有 14 個 jedi-oscal 檔結構與 design 預期相符
  3. 主 BE branch 正確
PGPASSWORD='jedi@123!' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev <<'EOF'
\dt oscal.ssp_system_implementations
\dt oscal.ssp_system_implementation_items
\dt oscal.ssp_inventory_item_components
SELECT COUNT(*) FROM oscal.ssp_system_implementation_items WHERE system_implementation_id IS NULL;
EOF

Expected: 3 個表都存在、items.system_implementation_id 全部不 null。

若 SQL 未執行,STOP 並通知 user 先跑 scripts/sql/2026-05-19-ssp-system-implementation-restructure.sql

grep "jedi-oscal" ~/Projects/Billows/Audit-Manager/compliance-manager-be/pyproject.toml

Expected: 看到 jedi-oscal = { path = "...", develop = true } active。若否,先 uncomment 並 poetry update jedi-oscal

cd ~/Projects/Billows/Audit-Manager/compliance-manager-be && git branch --show-current

Expected: feature/ssp-import-export-phase2

ls ~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal/jedi_oscal/infra/model/ssp/ssp_system_implementation.py
ls ~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal/jedi_oscal/domain/entity/ssp/ssp_system_implementation_entity.py
ls ~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal/jedi_oscal/infra/mapper/ssp/system_implementation_mapper.py
ls ~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal/jedi_oscal/app/dto/ssp/ssp_system_implementation_dto.py

Expected: 全部存在。


§4

Task 1 — jedi-oscal 既有檔 rename(items 層 8 個 stack)

目的:把 items 表對應的 8 個 ORM/entity/repo/mapper/dto/domain_service 檔案 + class 名 rename 到 *_item* / Ssp*Item*

注意:先做檔名 rename + class rename,不改 column — column rename 在 Task 3 做(拆分減少單 commit 範圍)。

Step 1: ORM rename

mv ~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal/jedi_oscal/infra/model/ssp/ssp_system_implementation.py ssp_system_implementation_items.py

編輯內容:

  • class OscalSystemSecurityPlanSystemImplementationclass OscalSspSystemImplementationItem
  • __tablename__ = "system_security_plan_system_implementations"__tablename__ = "ssp_system_implementation_items"
  • 既有 __table_args__ index 名同步:ix_ssp_sys_impl_*ix_ssp_si_items_*
  • 既有所有 column 維持(含 information_system_id — Task 3 才改)
cd ~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal
poetry run python -c "from jedi_oscal.infra.model.ssp.ssp_system_implementation_items import OscalSspSystemImplementationItem; print('OK')"

Expected: OK

Step 2~8: Entity / Query Entity / Repo (interface+impl) / Mapper / DTO / Domain Service rename

對每個檔案重複類似步驟:

  • mv 改檔名
  • 改 class 名
  • 同步 __init__.py export
  • Verify import path

詳細 class rename 對照見 design-A0.1.md §4.1。

Step 9: 父層引用更新

更新 4 個父層檔案內的 import / class 名引用:

Step 10: 既有 32 個測試 fix(只改 import / class 名,column 不改)

    • from jedi_oscal.infra.model.ssp.ssp_system_implementation import OscalSystemSecurityPlanSystemImplementation... ssp_system_implementation_items import OscalSspSystemImplementationItem
    • 全文 SystemImplementationEntitySspSystemImplementationItemEntity(依此類推所有 class 名)

Step 11: Run tests + commit

cd ~/Projects/Jedicogy/module/jedi-python-package
git add jedi-oscal/jedi_oscal/infra/model/ssp/ \
        jedi-oscal/jedi_oscal/domain/entity/ssp/ \
        jedi-oscal/jedi_oscal/domain/repository/ssp/ \
        jedi-oscal/jedi_oscal/infra/repository/ssp/ \
        jedi-oscal/jedi_oscal/infra/mapper/ssp/ \
        jedi-oscal/jedi_oscal/app/dto/ssp/ \
        jedi-oscal/jedi_oscal/domain/services/ssp/ \
        jedi-oscal/tests/test_ssp_system_implementation_extension.py
git commit -m "$(cat <<'EOF'
refactor(ssp-system-impl): rename items stack to Ssp* + _items 後綴

Phase 2 A0.1:既有 items 表 ORM + entity + repo + mapper + DTO + domain service
全部 rename 對齊新表名 ssp_system_implementation_items。
功能不變、所有測試綠。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"

§5

Task 2 — jedi-oscal 新建 main 完整 stack(8 個檔)

目的:建立 oscal.ssp_system_implementations main 表對應的 DDD 完整 stack。

Step 1: ORM model

import uuid
from typing import Optional
from datetime import datetime
from sqlalchemy import String, Text, UUID, DateTime, Integer, JSON, UniqueConstraint, Index, func
from sqlalchemy.orm import Mapped, mapped_column
from jedi_common.session.database.declarative_base import Base


class OscalSspSystemImplementation(Base):
    """OSCAL system-implementation block 主檔,1:1 per (scope_type, scope_id)。

    對應 OSCAL spec system-implementation block(無 UUID,但 DB 規範保留 uid,
    OSCAL 匯出時 mapper 排除 uid)。
    """
    __tablename__ = "ssp_system_implementations"
    __table_args__ = (
        UniqueConstraint("scope_type", "scope_id", name="uq_ssp_system_implementations_scope"),
        Index("ix_ssp_system_implementations_scope", "scope_type", "scope_id"),
        {"schema": "oscal"},
    )

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    uid: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), default=uuid.uuid4, unique=True, nullable=False)
    scope_type: Mapped[str] = mapped_column(String(20), nullable=False,
        comment="'ssp' or 'module_frame'")
    scope_id: Mapped[int] = mapped_column(Integer, nullable=False,
        comment="對應 scope_type 指向的 id (soft FK)")
    remarks: Mapped[Optional[str]] = mapped_column(Text)
    props_jsonb: Mapped[Optional[dict]] = mapped_column(JSON)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=func.now(), nullable=False)
    updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=func.now(), onupdate=func.now(), nullable=False)
    created_user: Mapped[Optional[str]] = mapped_column(String(50))
    updated_user: Mapped[Optional[str]] = mapped_column(String(50))

Step 2~7: Entity / Query Entity / Repo / Mapper / DTO / Domain Service

依 pattern 建立。Domain service 需含特殊方法 upsert_by_scope:

def upsert_by_scope(self, scope_type: str, scope_id: int, **kwargs) -> SspSystemImplementationEntity:
    """找 (scope_type, scope_id) 對應 main row;不存在就建。"""
    existing = self._repo.find_by_scope(scope_type, scope_id)
    if existing:
        return existing
    new_entity = SspSystemImplementationEntity(scope_type=scope_type, scope_id=scope_id, **kwargs)
    return self._repo.add(new_entity)

Step 8: TDD 測試

def test_main_table_exists():
    from jedi_oscal.infra.model.ssp.ssp_system_implementation import OscalSspSystemImplementation
    assert OscalSspSystemImplementation.__tablename__ == "ssp_system_implementations"


def test_main_entity_has_required_attrs():
    from jedi_oscal.domain.entity.ssp.ssp_system_implementation_entity import SspSystemImplementationEntity
    e = SspSystemImplementationEntity(scope_type="ssp", scope_id=42, remarks="test")
    assert e.scope_type == "ssp" and e.scope_id == 42


def test_main_mapper_round_trip():
    # to_entity + to_model round-trip
    ...


def test_main_repo_has_find_by_scope_and_upsert():
    from jedi_oscal.infra.repository.ssp.ssp_system_implementation_repo_impl import SspSystemImplementationRepoImpl
    assert hasattr(SspSystemImplementationRepoImpl, "find_by_scope")


def test_main_domain_service_upsert_by_scope():
    # 確認 upsert 行為(mock repo)
    ...

Step 9: Run tests + commit

git add jedi-oscal/jedi_oscal/infra/model/ssp/ssp_system_implementation.py \
        jedi-oscal/jedi_oscal/domain/entity/ssp/ssp_system_implementation_entity.py \
        jedi-oscal/jedi_oscal/domain/entity/ssp/ssp_system_implementation_query_entity.py \
        jedi-oscal/jedi_oscal/domain/repository/ssp/system_implementation_repo.py \
        jedi-oscal/jedi_oscal/infra/repository/ssp/ssp_system_implementation_repo_impl.py \
        jedi-oscal/jedi_oscal/infra/mapper/ssp/system_implementation_mapper.py \
        jedi-oscal/jedi_oscal/app/dto/ssp/ssp_system_implementation_dto.py \
        jedi-oscal/jedi_oscal/domain/services/ssp/system_implementation_domain_service.py \
        jedi-oscal/tests/test_ssp_system_implementation_main.py

git commit -m "$(cat <<'EOF'
feat(ssp-system-impl): 新增 main 表 OscalSspSystemImplementation 完整 stack

Phase 2 A0.1:OSCAL system-implementation block 鏡像主檔 (1:1 per scope)。
含 ORM + entity + repo + mapper + DTO + domain service(含 upsert_by_scope)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"

§6

Task 3 — Column rename: information_system_id → system_characteristic_id

目的:把 items 表的 information_system_id column 在 ORM / entity / repo / mapper / DTO 全層 rename 為 system_characteristic_id

注意:DB schema 已在 SQL migration rename,這 task 只動 jedi-oscal 程式碼層。

jedi_oscal/infra/model/ssp/ssp_system_implementation_items.py

# 將
information_system_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True, ...)
# 改成
system_characteristic_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True,
    comment="soft FK → oscal.system_security_plans_system_characteristics.id")

ssp_system_implementation_item_entity.py

# Constructor 參數 + self.X 賦值
information_system_id → system_characteristic_id

system_implementation_item_mapper.pyto_entityto_model 兩個 method 內所有 information_system_id 字串改 system_characteristic_id

SspSystemImplementationItemRepoImpl + interface:

  • find_by_information_system_id(information_system_id)find_by_system_characteristic_id(system_characteristic_id)

tests/test_ssp_system_implementation_extension.py:搜尋 information_system_id 全部換 system_characteristic_id

cd jedi-oscal && poetry run pytest tests/test_ssp_system_implementation_extension.py -v

Expected: 32 passed。

git add jedi-oscal/jedi_oscal/infra/model/ssp/ssp_system_implementation_items.py \
        jedi-oscal/jedi_oscal/domain/entity/ssp/ssp_system_implementation_item_entity.py \
        jedi-oscal/jedi_oscal/domain/entity/ssp/ssp_system_implementation_item_query_entity.py \
        jedi-oscal/jedi_oscal/infra/mapper/ssp/system_implementation_item_mapper.py \
        jedi-oscal/jedi_oscal/app/dto/ssp/ssp_system_implementation_item_dto.py \
        jedi-oscal/jedi_oscal/infra/repository/ssp/ssp_system_implementation_item_repo_impl.py \
        jedi-oscal/jedi_oscal/domain/repository/ssp/system_implementation_item_repo.py \
        jedi-oscal/tests/test_ssp_system_implementation_extension.py
git commit -m "refactor(ssp-system-impl): items column rename information_system_id → system_characteristic_id ..."

§7

Task 4 — items 表加 system_implementation_id FK + relationship

目的:items ORM 加 FK column + relationship 到 main。

# ssp_system_implementation_items.py
system_implementation_id: Mapped[int] = mapped_column(
    Integer,
    ForeignKey("oscal.ssp_system_implementations.id", ondelete="CASCADE"),
    nullable=False,
    comment="FK → ssp_system_implementations.id"
)
system_implementation: Mapped["OscalSspSystemImplementation"] = relationship(...)

Tests 內既有測試構造 OscalSspSystemImplementationItem(...) 時要補 system_implementation_id(用 fixture 先建 main row)。


§8

Task 5 — 新建 join 表完整 stack

目的:建 oscal.ssp_inventory_item_components M:N join 表的 8 層 stack。

[Step 1~9 同 Task 2 pattern,建立 ORM + entity + repo + mapper + DTO + domain service + 測試]

詳細 column 規格見 design-A0.1.md §3.3。

關鍵:domain service 內加 application 層驗證:

def add_link(self, inventory_item_id: int, component_id: int):
    inv = self._items_repo.get_by_id(inventory_item_id)
    comp = self._items_repo.get_by_id(component_id)
    if inv.implementation_type != "hardware":
        raise BadRequestError("inventory_item_id 必須指向 type=hardware")
    if comp.implementation_type not in ("component", "system", "subsystem", "service", "software"):
        raise BadRequestError("component_id 必須指向 type IN component family")
    # ... add link

§9

Task 6 — yaml_mapper 三分支 + implemented-components 整合

目的ssp_yaml_mapper.py 從 main 出發、items 三分支、加 implemented-components join 輸出。

def test_yaml_mapper_uses_main_block_level_fields():
    # main 有 remarks → output 含 "remarks"
    ...

def test_yaml_mapper_inventory_item_implemented_components():
    # join 表有資料 → inventory-item 輸出含 "implemented-components": [...]
    ...
@staticmethod
def _system_implementation_to_dict(main_entity, items_list, join_links) -> Dict:
    out = {}
    if main_entity:
        if main_entity.remarks: out["remarks"] = main_entity.remarks
        if main_entity.props_jsonb: out["props"] = main_entity.props_jsonb
    # 三分支 items(既有邏輯)
    ...
    # implemented-components 從 join_links 填入
    ...

§10

Task 7 — 主 BE caller 改寫

目的:兩個既有 caller 改用新 class + main upsert pattern。

Task 7a: project_device_mapping_service.py

main = self._main_domain_service.upsert_by_scope(scope_type="ssp", scope_id=int(ssp_id))
item_entity = SspSystemImplementationItemEntity(
    system_implementation_id=main.id,  # ← 新
    system_security_plan_id=int(ssp_id),
    scope_type="ssp",
    scope_id=int(ssp_id),
    name=device_entity.name,
    description=device_entity.description,
    implementation_type=SystemImplementationType.HARDWARE,
)

Task 7b: ssp_versioning_service.py

def _clone_system_implementations(self, session, old_ssp, new_ssp, curr_user):
    # 1. 先 clone main (1 row)
    old_main = session.query(OscalSspSystemImplementation).filter_by(
        scope_type="ssp", scope_id=old_ssp.id
    ).first()
    if old_main:
        new_main = OscalSspSystemImplementation(
            uid=uuid.uuid4(),
            scope_type="ssp",
            scope_id=new_ssp.id,
            remarks=old_main.remarks,
            props_jsonb=old_main.props_jsonb,
            created_user=curr_user,
            updated_user=curr_user,
        )
        session.add(new_main)
        session.flush()
        # 2. clone items with new main_id
        for old_item in old_main.items:  # via relationship
            new_item = OscalSspSystemImplementationItem(
                system_implementation_id=new_main.id,
                ...
            )
            session.add(new_item)
    session.flush()

Task 7c: DI container update

di_containers/oscal/oscal_containers.py

  • 加 main + join domain service / repo wiring
  • 既有 system_implementation 改用新 class 名

Task 7d: 既有 A0 regression test fix

tests/test_ssp_system_implementation_regression.py:所有 import / class 名 / column 名同步改。

Task 7e: 新 regression test for main upsert

tests/test_ssp_system_implementation_main_regression.py

def test_caller_upsert_main_idempotent():
    # 重複 upsert 同 scope 不會建多筆 main
    ...
poetry run pytest tests/test_ssp_system_implementation_regression.py tests/test_ssp_system_implementation_main_regression.py -v

Expected: All pass。


§11

Task 8 — BE Smoke Boot + Caller Integration

lsof -ti:8000 | xargs kill -9 2>/dev/null
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
set -a; source .env; set +a
nohup poetry run python main_app.py > /tmp/be_boot_a01.log 2>&1 &
sleep 8
tail -50 log/app.log

Expected: 無 schema mismatch / IntegrityError。

# manual API call or pytest integration test
# 確認 main + item 雙 row 寫入
PGPASSWORD='jedi@123!' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev <<'EOF'
SELECT COUNT(*) FROM oscal.ssp_system_implementations;
SELECT COUNT(*) FROM oscal.ssp_system_implementation_items WHERE system_implementation_id IS NOT NULL;
EOF

§12

Task 9 — Changelog + Tracker 更新

    • A0 row 標 A0.1 follow-up shipped
    • 加 A0.1 commit hash 清單

§13

Task 10 — 通知 user 重啟 BE + 收口

提供 user 通知文字:

A0.1 完工。改動範圍:

  • SQL schema rename + 新建 main / join 表(user 已執行)
  • jedi-oscal 全 stack rename + 新 main/join + column rename
  • 主 BE 兩個 caller 改寫
  • 測試全綠

請 restart BE

lsof -ti:8000 | xargs kill -9
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
set -a; source .env; set +a
nohup poetry run python main_app.py > /dev/null 2>&1 &

§14

Acceptance Criteria


§15

風險與緩解

風險 緩解
jedi-oscal rename 破壞既有 import path Task 1 完成立刻跑 32 個既有測試,破了立即發現
caller upsert main 漏處理 → INSERT items 失敗(NOT NULL system_implementation_id) Task 8 smoke 階段先測
yaml_mapper 改簽章破壞其他 caller grep caller 確認;Task 6 開頭先盤點
既有 32 個測試大量 fix 引入新 bug TDD 每 task 跑全測試確認
jedi-oscal 父層引用沒改全(ssp.py / mapper 父層) Task 1 Step 9 顯式列 4 個父層檔案

§16

不在 A0.1 範圍

  • system_characteristics 改 1:1(未來評估)
  • system-implementation.users[] 表(客戶有需求才做)
  • hardware enum 改 inventory-item(最後統整優化清單)
  • ❌ Phase 2 後續 A1~B6 phase

§17

接手指引(給下個 session)

  1. 先讀 SUMMARYdocs/conversation-history/2026-05-19/ssp-import-export-phase2-A0.1/SUMMARY.md
  2. 執行順序
    • Step 1: User 已執行 SQL(或 user 通知執行完)
    • Step 2: 跑 Task 0 pre-flight 驗證
    • Step 3: 按 Task 1~10 順序執行(建議用 subagent-driven)
  3. 重型 Tasks:Task 1 / Task 6 / Task 7 屬於高風險,subagent 完成後務必 spec + code review 雙 reviewer
  4. commit 規矩:每 task ship 一個 commit;commit 前必跑 git status --short 確認 staged 區乾淨