feat(P6): IHF Phase 6 complete — agent-assisted distillation

T08 gate: integration tests for all Phase 6 artifacts (EnvelopeEmissionContract,
InteractionReportingContract, WidgetAdapterSpec, adapter assignment, dashboard
coverage logic); SCOPE.md updated to Phase 6 complete; docs/phase6-summary.md
written (contract model, adapter pattern, known limitations, Phase 7 readiness);
workplan IHUB-WP-0006 marked done.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-29 21:27:10 +00:00
parent ae81dfd484
commit b1d1f5066b
4 changed files with 217 additions and 6 deletions

View File

@@ -1090,3 +1090,117 @@ main = do
length pending `shouldBe` 1
length accepted `shouldBe` 1
deleteRecord hub
-- ----------------------------------------------------------------
-- Phase 6 — Cross-Framework UI Adaptation Layer
-- ----------------------------------------------------------------
describe "EnvelopeEmissionContract" do
it "can create and fetch with required attributes" do
contract <- newRecord @EnvelopeEmissionContract
|> set #contractVersion "test-1.0"
|> set #requiredAttributes (toJSON (["data-widget-id","data-hub-id"] :: [Text]))
|> set #optionalAttributes (toJSON ([] :: [Text]))
|> set #validationRules (toJSON (object []))
|> set #status "active"
|> createRecord
contract.contractVersion `shouldBe` "test-1.0"
contract.status `shouldBe` "active"
fetched <- fetch contract.id
fetched.requiredAttributes `shouldBe` contract.requiredAttributes
deleteRecord contract
describe "InteractionReportingContract" do
it "can create and fetch" do
rc <- newRecord @InteractionReportingContract
|> set #contractVersion "test-1.0"
|> set #endpointPath "/api/v1/interaction-events"
|> set #acceptedEventTypes (toJSON (["clicked","viewed"] :: [Text]))
|> set #requiredFields (toJSON (["widget_id","hub_id"] :: [Text]))
|> set #authScheme "bearer"
|> set #status "active"
|> createRecord
rc.endpointPath `shouldBe` "/api/v1/interaction-events"
rc.authScheme `shouldBe` "bearer"
fetched <- fetch rc.id
fetched.contractVersion `shouldBe` "test-1.0"
deleteRecord rc
describe "WidgetAdapterSpec" do
it "can create with draft status and transition to active" do
ec <- newRecord @EnvelopeEmissionContract
|> set #contractVersion "test-env-1.0"
|> set #requiredAttributes (toJSON ([] :: [Text]))
|> set #status "active"
|> createRecord
rc <- newRecord @InteractionReportingContract
|> set #contractVersion "test-rep-1.0"
|> set #endpointPath "/api/v1/interaction-events"
|> set #acceptedEventTypes (toJSON ([] :: [Text]))
|> set #requiredFields (toJSON ([] :: [Text]))
|> set #status "active"
|> createRecord
spec <- newRecord @WidgetAdapterSpec
|> set #name "test-react-18"
|> set #framework "react"
|> set #version "1.0"
|> set #envelopeContractId (Just ec.id)
|> set #reportingContractId (Just rc.id)
|> set #status "draft"
|> createRecord
spec.status `shouldBe` "draft"
spec.framework `shouldBe` "react"
-- Transition to active
spec |> set #status "active" |> updateRecord
fetched <- fetch spec.id
fetched.status `shouldBe` "active"
deleteRecord spec
deleteRecord ec
deleteRecord rc
describe "Widget adapter assignment" do
it "widget can be assigned to an adapter spec and badge resolves" do
hub <- newRecord @Hub |> set #name "AdapterHub" |> createRecord
spec <- newRecord @WidgetAdapterSpec
|> set #name "badge-test-adapter" |> set #framework "vue"
|> set #version "1.0" |> set #status "active"
|> createRecord
widget <- newRecord @Widget
|> set #hubId hub.id
|> set #name "AdapterWidget"
|> set #widgetType "chart"
|> set #adapterSpecId (Just spec.id)
|> createRecord
widget.adapterSpecId `shouldBe` Just spec.id
mSpec <- case widget.adapterSpecId of
Nothing -> pure Nothing
Just sid -> fetchOneOrNothing sid
fmap (.name) mSpec `shouldBe` Just "badge-test-adapter"
deleteRecord widget
deleteRecord spec
deleteRecord hub
describe "Adapter compatibility dashboard data" do
it "correctly categorises native vs adapter-backed widgets" do
hub <- newRecord @Hub |> set #name "CompatHub" |> createRecord
spec <- newRecord @WidgetAdapterSpec
|> set #name "compat-test" |> set #framework "react"
|> set #version "1.0" |> set #status "active"
|> createRecord
w1 <- newRecord @Widget
|> set #hubId hub.id |> set #name "Native"
|> set #widgetType "chart"
|> createRecord
w2 <- newRecord @Widget
|> set #hubId hub.id |> set #name "Adapted"
|> set #widgetType "form" |> set #adapterSpecId (Just spec.id)
|> createRecord
hubWidgets <- query @Widget |> filterWhere (#hubId, hub.id) |> fetch
let adapted = length (filter (\w -> isJust w.adapterSpecId) hubWidgets)
native = length (filter (\w -> isNothing w.adapterSpecId) hubWidgets)
adapted `shouldBe` 1
native `shouldBe` 1
deleteRecord w1
deleteRecord w2
deleteRecord spec
deleteRecord hub