{ "planPath": "archreview/plans/R2-07-surgical-pure-adds-plan.md", "lastUpdated": "2026-07-12", "tasks": [ { "id": "T1", "subject": "Phase 1: AddressSpaceChangeClassifier + table-driven tests (move TagDeltaIsSurgicalEligible/VtagDeltaIsNodeIrrelevant)", "status": "pending", "blockedBy": [] }, { "id": "T2", "subject": "Phase 1: route AddressSpaceApplier.Apply through the classifier — PureAdd skips rebuild (high-risk)", "status": "pending", "blockedBy": ["T1"] }, { "id": "T3", "subject": "Phase 1: ComputeAddAnnouncements + AnnounceAddedNodes on the applier (dedup parent NodeAdded announces)", "status": "pending", "blockedBy": ["T1"] }, { "id": "T4a", "subject": "Phase 1: idempotent MaterialiseAlarmCondition (skip-if-present-and-same-kind) (high-risk)", "status": "pending", "blockedBy": ["T1"] }, { "id": "T4b", "subject": "Phase 1: OpcUaPublishActor calls AnnounceAddedNodes after the Materialise passes on non-rebuild applies (high-risk)", "status": "pending", "blockedBy": ["T2", "T3", "T4a"] }, { "id": "T5", "subject": "Phase 1: over-the-wire SubscriptionSurvivalTests — subscribe, pure-add, item survives + new node browsable", "status": "pending", "blockedBy": ["T4b"] }, { "id": "T6", "subject": "Phase 1: MANDATORY live-/run gate on docker-dev (rebuild BOTH centrals; Client.CLI subscribe survives +1-tag deploy; kind=PureAdd rebuild=False) — Phase 1 shippable boundary", "status": "pending", "blockedBy": ["T5"] }, { "id": "T7", "subject": "Phase 2: add RemoveVariableNode/RemoveAlarmConditionNode/RemoveEquipmentSubtree to ISurgicalAddressSpaceSink + DeferredAddressSpaceSink forwarding — guard-first with observed negative control (high-risk)", "status": "pending", "blockedBy": ["T6"] }, { "id": "T8", "subject": "Phase 2: OtOpcUaNodeManager.RemoveVariableNode + BuildNodesRemovedModelChange (NodeDeleted) (high-risk)", "status": "pending", "blockedBy": ["T7"] }, { "id": "T9", "subject": "Phase 2: OtOpcUaNodeManager.RemoveAlarmConditionNode (+ native-flag cleanup) (high-risk)", "status": "pending", "blockedBy": ["T7"] }, { "id": "T10", "subject": "Phase 2: OtOpcUaNodeManager.RemoveEquipmentSubtree (descendants + notifier demotion) + SdkAddressSpaceSink forwards (high-risk)", "status": "pending", "blockedBy": ["T8", "T9"] }, { "id": "T11", "subject": "Phase 2: applier PureRemove arm — terminal Bad/RemovedConditionState writes, equipment subsumption, false-to-rebuild ratchet (high-risk)", "status": "pending", "blockedBy": ["T10"] }, { "id": "T12", "subject": "Phase 2: remove-side subscription-survival integration test + live-/run remove gate (kind=PureRemove rebuild=False) — Phase 2 shippable boundary", "status": "pending", "blockedBy": ["T11"] }, { "id": "T13", "subject": "Phase 3: AddRemoveMix routing — removes-then-adds surgically, same-NodeId remove-then-recreate ordering test (high-risk)", "status": "pending", "blockedBy": ["T12"] }, { "id": "T14", "subject": "Phase 3: mixed-deploy integration test + live-/run mixed gate + STATUS.md/P1 close-out — plan complete", "status": "pending", "blockedBy": ["T13"] } ] }