System test cases

Canonical specifications at the system verification level. Each case retains its own Need ID, requirement links and execution history. See Test-case specification for classification and evidence semantics.

ID

Title

Status

Verifies

Last Result

Executed By

STV_TC_SY_001

usability smoke

accepted

STV_SHR_015; STV_SHR_049; STV_SWR_050; STV_SWR_054; STV_SYS_006

passed

STV_TE_4C69746CC553D7A0; STV_TE_4E59CF2773313BBA; STV_TE_09C5B5C0E3162718; STV_TE_21EC36CA6CCE8591; STV_TE_3715FF748298BF10; STV_TE_8791048E05CC01B1; STV_TE_A665E29D25CE8904; STV_TE_B5A1346E2B834D74; STV_TE_C6A8BF692AE392F8; STV_TE_D68BBA2BC672A957; STV_TE_E5E1E0786213B6DF; STV_TE_E61ABF83926193AC; STV_TE_EDDA1B963CE797B3; STV_TE_FA148C6483A7987B

STV_TC_SY_002

control order smoke

accepted

STV_SHR_051; STV_SWR_055

passed

STV_TE_0ED306D2D082CD2A; STV_TE_2E552F667F047742; STV_TE_3EA3780EE4C691D4; STV_TE_05F532BCAA9F91FA; STV_TE_9DF8D53E0264122D; STV_TE_42F89514387F2644; STV_TE_48E662C1225F4525; STV_TE_68DEC3FFAD82756F; STV_TE_592C60F7DBAE2635; STV_TE_BDC8A354E2C4DC86; STV_TE_D5B9A638927DFF25; STV_TE_E9DF4EB84C2C809D

STV_TC_SY_003

missing placeholder and detail error

accepted

STV_SHR_027; STV_SHR_028; STV_SHR_029; STV_SWR_027; STV_SWR_028; STV_SWR_029; STV_SYS_004

passed

STV_TE_0B004B872559B017; STV_TE_0F414A54C03A4E46; STV_TE_1E7C90AF591203FD; STV_TE_6AA25FA7CA5F5192; STV_TE_8F9660805C1BF3D1; STV_TE_9D6123D898988719; STV_TE_10D8C741EA634C01; STV_TE_98FA5AFD1CF5BE75; STV_TE_01014AFFA8103E08; STV_TE_ABB5CA4103F3FDF3; STV_TE_B71B51810DD8B805; STV_TE_CECBFB91BF01D342; STV_TE_E49AF6AA3D709DC5; STV_TE_EDBA066210352B45; STV_TE_F7530E9CA9023217

STV_TC_SY_004

failed finalization retains pending page and previous assets

accepted

STV_SHR_015; STV_SHR_017; STV_SHR_027; STV_SWR_015; STV_SWR_017; STV_SWR_027

passed

STV_TE_2FE927B84AC573F5; STV_TE_3EC3329BC8AF8ADC; STV_TE_7B6CE5D5AA9DCA82; STV_TE_7EE3EFE1531FE505; STV_TE_35ACFC65C5B99B80; STV_TE_43EC581314FEB950; STV_TE_78CA1963DFC5C470; STV_TE_147E98E60DA06020; STV_TE_370A22653A3C61D1; STV_TE_644E38E89EF5303D; STV_TE_5428B57695F57556; STV_TE_7423FCB00FD2FB74; STV_TE_AB3AB31683DE7C64; STV_TE_D4FCDC8C50E1BDD7; STV_TE_EDBF887E42FFA00D; STV_TE_FB2A4E45E7928173

STV_TC_SY_005

seed layout replacement failure and staleness

accepted

STV_SHR_044; STV_SHR_053; STV_SWR_044; STV_SWR_057

passed

STV_TE_0EEADCA1406FD6ED; STV_TE_1DC0F35D41063248; STV_TE_3B3E61D7DFC99D73; STV_TE_98FB37EE8CFDD9F8; STV_TE_510EE3C618B9EA6C; STV_TE_776A0D0F470417C5; STV_TE_938B27916A316D0E; STV_TE_BFADF389F6A536A5; STV_TE_D8056F473116FDB6; STV_TE_DAA641048DC2DEA4; STV_TE_E929F4EC8065A6E8; STV_TE_FE386BE5427049F0

STV_TC_SY_006

alternate host schema external metadata and parts

accepted

STV_SHR_014; STV_SHR_015; STV_SHR_017; STV_SHR_026; STV_SHR_036; STV_SHR_045; STV_SHR_047; STV_SHR_048; STV_SWR_014; STV_SWR_036; STV_SWR_045; STV_SWR_047; STV_SWR_048; STV_SYS_002

passed

STV_TE_1DAC049D0A5D148A; STV_TE_1DEFDCD63760E5EB; STV_TE_4D22B3B6FFD3CE4C; STV_TE_19C8684FFE688A1D; STV_TE_3277FF16FB8DD82C; STV_TE_5878BEA6800904D7; STV_TE_8105F93F757B5B04; STV_TE_A57228DC70FF277F; STV_TE_AA534A6986BCE95B; STV_TE_CECCD71A1F7BD48C; STV_TE_D7B0F10CAD8EECF1; STV_TE_DCE1C4DC05374B2D; STV_TE_E4896463459663B7; STV_TE_F74CE1E256232699; STV_TE_FF1EC92330C20220

STV_TC_SY_007

documentation visuals

accepted

STV_SHR_017; STV_SHR_018; STV_SYS_003

passed

STV_TE_6E2481C9D9B7D366; STV_TE_8BA9F97053CDDB86; STV_TE_8D236D778E5397B0; STV_TE_8DE4DA01E32EBBEC; STV_TE_9D507F344CAFCA21; STV_TE_22DE49BBDDE7EC3B; STV_TE_80BB18ED0F7DCA3F; STV_TE_281E939E541ADC21; STV_TE_A068479E3F7C1674; STV_TE_AC6CFB631FC13A26; STV_TE_BAD1E81D14E6A792; STV_TE_C9B10F63B52B82BE

STV_TC_SY_008

invalid seed source location

accepted

STV_SHR_014; STV_SHR_026; STV_SHR_047; STV_SHR_048; STV_SWR_026; STV_SWR_048; STV_SYS_001

passed

STV_TE_4CA68E5E713B77CF; STV_TE_7ECA7E344B860974; STV_TE_23C04073B4F916E7; STV_TE_55AFED6304CFE81F; STV_TE_93AFE98F3EE60BE8; STV_TE_98C1FD50055BD13A; STV_TE_693FD96917368D8D; STV_TE_785BF58793290B0E; STV_TE_562442171556608D; STV_TE_AE9A6D175B070252; STV_TE_AF5B476EEA5DFA00; STV_TE_B23ED4BAF8B4ACAC; STV_TE_B541FAAB192B3BBE; STV_TE_C6840C674379E70A; STV_TE_DC1671A02F1BF34C

STV_TC_SY_009

control order smoke

accepted

STV_SHR_051; STV_SWR_055

passed

STV_TE_7EA1E9B64E0256BD; STV_TE_9A8EA01D9A7898BA; STV_TE_60E832B730CEF95E; STV_TE_89DA2BE17EC0FB60; STV_TE_97A2EA6B2A2DFFD8; STV_TE_183C1C7ED8127FB9; STV_TE_193BABCE01804ECD; STV_TE_463EAF1F5A2DBCA9; STV_TE_7866D2386D1B82BA; STV_TE_D54F9EC1B8C3DC2D; STV_TE_F7CB285B655300F4; STV_TE_FD3CB24029F71B7D

STV_TC_SY_010

interactive seed smoke

accepted

STV_SHR_038; STV_SHR_052; STV_SHR_053; STV_SWR_038; STV_SWR_056; STV_SWR_057

passed

STV_TE_4EF5692B22CAD5BB; STV_TE_5F5882C224B3CDF5; STV_TE_28A980B4D13444E8; STV_TE_69F7D85B922D326A; STV_TE_542E4BF583AB9821; STV_TE_9043AB9378286E9A; STV_TE_62167E711ACEA294; STV_TE_4640159F9F5A68EF; STV_TE_2305068297D4DE1F; STV_TE_BC32CB88DE8FEAB6; STV_TE_E7F31A178D716764; STV_TE_E5587901B2158B26

STV_TC_SY_011

seed capacity at directive

accepted

STV_SHR_001; STV_SHR_026; STV_SHR_043; STV_SHR_048; STV_SWR_001; STV_SWR_026; STV_SWR_043

passed

STV_TE_2C1C26AE520E7580; STV_TE_6D696303432BC7C8; STV_TE_10B3E6446E94D385; STV_TE_15D0BD9F9CF33DA9; STV_TE_1653F853EF6BA9A5; STV_TE_9752C0214F03C7B6; STV_TE_A5B37D2B297444D4; STV_TE_A15052A1362D4FBC; STV_TE_AD334071180DF0AC; STV_TE_AECE97EF99A0CFD6; STV_TE_B88FABBBBA1DB23F; STV_TE_BE6098AB231764A5; STV_TE_C7A76049793288AA; STV_TE_D470B949B372D93E; STV_TE_FE7FDC9A6AB9C219

STV_TC_SY_012

missing placeholder and detail error

accepted

STV_SHR_027; STV_SHR_028; STV_SHR_029; STV_SWR_027; STV_SWR_028; STV_SWR_029; STV_SYS_004

passed

STV_TE_06BD1CDDE6262850; STV_TE_7FB8F491ACEA8640; STV_TE_9EE2D06816C8EA7C; STV_TE_64C890A655FDC0CE; STV_TE_69D0670DBA913348; STV_TE_134FB6EFA234AE0A; STV_TE_04395F65C2DC7521; STV_TE_720279BBD09277C1; STV_TE_3214827A289CE1D9; STV_TE_07748973EFBEE7AF; STV_TE_B3EF025C32FD0BBD; STV_TE_C907D3DAAB33A698; STV_TE_D5E9A4491730BF22; STV_TE_F9FF69F5AF8B80F1; STV_TE_F460306704A9DB56

STV_TC_SY_013

cross page bundle

accepted

STV_SHR_001; STV_SHR_002; STV_SHR_013; STV_SHR_026; STV_SHR_048; STV_SWR_001; STV_SWR_002; STV_SWR_013; STV_SWR_026; STV_SYS_001

passed

STV_TE_3E778A3C5CF09B0C; STV_TE_4B3E601321BA8924; STV_TE_6B9128D591CDF82B; STV_TE_7BF04875B87C2A7D; STV_TE_7FBEE6C61DCE1FC8; STV_TE_18FC22178525A93E; STV_TE_24EDC6D2A0B2BE77; STV_TE_226A0A5469B1E2C8; STV_TE_91450CBE45F118C0; STV_TE_764956AD4834A5CE; STV_TE_2663333BEDD0993E; STV_TE_766806520A73D7D5; STV_TE_819761153322682B; STV_TE_BCFF8322B90078E6; STV_TE_E3E662FC79CD1503

STV_TC_SY_014

invalid seed source location

accepted

STV_SHR_014; STV_SHR_026; STV_SHR_047; STV_SHR_048; STV_SWR_026; STV_SWR_048; STV_SYS_001

passed

STV_TE_1C3AE7E9B5E53605; STV_TE_4B035E2310E4BEDD; STV_TE_5EF3536A7D0C8E21; STV_TE_5F20F75886471936; STV_TE_8E740204118C54D9; STV_TE_9EBE4F77A19E95FE; STV_TE_065C6FD1FB610C20; STV_TE_97AA7EB41C45F077; STV_TE_5794F3DB1152BA1E; STV_TE_39301A83113F7C7D; STV_TE_A247DA8C0E04955C; STV_TE_BDE8AC2E7AF70D1A; STV_TE_BF82FCAAF05F967E; STV_TE_D18E0A7F3567D77B; STV_TE_F573520D32C946D7

STV_TC_SY_015

alternate model geometry details and external

accepted

STV_SHR_008; STV_SHR_012; STV_SHR_014; STV_SHR_015; STV_SHR_017; STV_SHR_026; STV_SHR_029; STV_SHR_031; STV_SHR_033; STV_SHR_037; STV_SHR_041; STV_SHR_047; STV_SHR_048; STV_SWR_008; STV_SWR_012; STV_SWR_015; STV_SWR_029; STV_SWR_031; STV_SWR_033; STV_SWR_037; STV_SWR_041; STV_SWR_047; STV_SWR_048; STV_SWR_049; STV_SWR_050; STV_SYS_004; STV_SYS_005; STV_SYS_006; STV_SYS_010

passed

STV_TE_2FC3770F257B1187; STV_TE_6B426B0AF668C4A5; STV_TE_6C0CA12C41B4B075; STV_TE_8B8C5753AB0D6BEB; STV_TE_9CE6E38ECB5EEAE5; STV_TE_35FB54BAAB756A5E; STV_TE_80B3F0B64A8C7517; STV_TE_95F0B44A5100699E; STV_TE_887B981489E09587; STV_TE_61313CFB6F4999CF; STV_TE_092393FE8521A18E; STV_TE_885907CB7C9BE957; STV_TE_F3C4E90AA84CED2E; STV_TE_FFFF8323BE7629F1

STV_TC_SY_016

usability smoke

accepted

STV_SHR_015; STV_SHR_049; STV_SWR_050; STV_SWR_054; STV_SYS_006

passed

STV_TE_2DD4D61CC1768AC7; STV_TE_3EE36C9CEB398919; STV_TE_5A3DAC2CD84CDE46; STV_TE_8D4A42C5790D2EC3; STV_TE_34B5AD4D60F216D2; STV_TE_259F9577440EEA71; STV_TE_708DE94151BCBBEA; STV_TE_8944DFBBE4F32C4F; STV_TE_9497AD07336A96B3; STV_TE_28071DAEB935E86B; STV_TE_281973898519845F; STV_TE_A92CAC9AEFDF41DE; STV_TE_D2D7FD0068CA7959; STV_TE_DED28A82ABE8E598

STV_TC_SY_017

large project at visible capacity

accepted

STV_SHR_043; STV_SHR_044; STV_SWR_043; STV_SWR_044; STV_SYS_008

passed

STV_TE_3A0908374B1E6391; STV_TE_5FEC76D970E683E5; STV_TE_010F955390602276; STV_TE_20B0861FE4CAF0C7; STV_TE_809C40B6FBEA4FF9; STV_TE_844554C54799C655; STV_TE_B9F860BD0657B89B; STV_TE_BCAD7509AA5BF000; STV_TE_D938868A58E75A99; STV_TE_EE6AEB1775FD54B0; STV_TE_FC0887B66F8AAE1A

STV_TC_SY_018

invalid mapping has entry path and location

accepted

STV_SHR_036; STV_SWR_036

passed

STV_TE_1BA15C05B4E308DA; STV_TE_1F42B7F8907C33A9; STV_TE_2AB9CFA572A3DF86; STV_TE_2AB9279CD710B2D6; STV_TE_6B318ECBD0F9E0A6; STV_TE_58E1DD12F4CEDA35; STV_TE_62AC4B0AB9B248F8; STV_TE_386D5C547F786FC8; STV_TE_04003BC62A11DADD; STV_TE_25353B9B728085D0; STV_TE_B1B8242C880AB7CE; STV_TE_BEB0736CCC12C0B6; STV_TE_BF4F7F2714720616; STV_TE_EAD577B1E7E3D4BA; STV_TE_F56B7DAF30DD1E7B

STV_TC_SY_019

seed selection release

accepted

STV_SHR_003; STV_SHR_014; STV_SHR_026; STV_SHR_038; STV_SHR_047; STV_SHR_048; STV_SHR_052; STV_SHR_053; STV_SWR_003; STV_SWR_038; STV_SWR_048; STV_SWR_051; STV_SWR_052; STV_SWR_056; STV_SWR_057

passed

STV_TE_0DECE0E8697DFBED; STV_TE_0F35184C42BADC8C; STV_TE_04E3FD1C4E20AEF7; STV_TE_86BFB02CC6BF31E3; STV_TE_6251FD2EBF141AEC; STV_TE_56729CA066D02CA9; STV_TE_B1856276067DD5FD; STV_TE_BF6793A3D27A2835; STV_TE_DFBF01DD6EFAC659; STV_TE_E78BA064DCE82BD6; STV_TE_EA142C83B0548AF5; STV_TE_FD08039E2FB58CC9

STV_TC_SY_020

async layout failure and stale completion

accepted

STV_SHR_044; STV_SHR_047; STV_SWR_044; STV_SWR_052

passed

STV_TE_05CD890A08061442; STV_TE_5DCC25155978FEA9; STV_TE_130B12AAC46E91FD; STV_TE_04649C30DC0167D7; STV_TE_74238165C37854A2; STV_TE_AF637C92878F7D57; STV_TE_B72094ADA2795468; STV_TE_D3F32F1A7B2C808E; STV_TE_D099D363BCFCAD31; STV_TE_DDA147A234F1EB90; STV_TE_DDF31A56AF9D68A5; STV_TE_E779106639A88BD6

STV_TC_SY_021

interactive seed smoke

accepted

STV_SHR_038; STV_SHR_052; STV_SHR_053; STV_SWR_038; STV_SWR_056; STV_SWR_057

passed

STV_TE_4C07297DF2CE4C54; STV_TE_633C7D44A74AC0EC; STV_TE_23223A8584B5C6B5; STV_TE_30779BF2349D192A; STV_TE_63082524BD2D8904; STV_TE_671083236DF393C2; STV_TE_A84D8ECC1014B0EE; STV_TE_AC2B99B3F04883E0; STV_TE_B31D3899B67AB2C0; STV_TE_CA289414E87D6ACE; STV_TE_D5A008B344DB0388; STV_TE_F35ECDA0945BF860

STV_TC_SY_022

invalid seed source location

accepted

STV_SHR_014; STV_SHR_026; STV_SHR_047; STV_SHR_048; STV_SWR_026; STV_SWR_048; STV_SYS_001

passed

STV_TE_2CDA237388E56731; STV_TE_3ECB5894059D4525; STV_TE_5C39DBEB8DDD7692; STV_TE_06A072906D5A03D1; STV_TE_8B0700DC00B39515; STV_TE_36E150FE90219288; STV_TE_72C2FBE6E1A2D120; STV_TE_96307E8E50F8092F; STV_TE_0898010E7C9AF0A4; STV_TE_971193CC70E48D46; STV_TE_D8999C6A3B3720F5; STV_TE_DA7D6F5E8EF93887; STV_TE_F8F0B0D11A680D82; STV_TE_F3789E9A81CEF0BE; STV_TE_FE11303CE3990960

STV_TC_SY_023

seed capacity at directive

accepted

STV_SHR_001; STV_SHR_026; STV_SHR_043; STV_SHR_048; STV_SWR_001; STV_SWR_026; STV_SWR_043

passed

STV_TE_2EABE1B34FE7C16D; STV_TE_2ED0C4098318A308; STV_TE_5EBB8A15272B4D9F; STV_TE_7CA638873EC75B4A; STV_TE_8F17CFA55BF7EBA1; STV_TE_9E2B134E8B2D88AF; STV_TE_19BECE77146BA374; STV_TE_23A84EBE529860DF; STV_TE_87D3CFA80A551B52; STV_TE_2236E7195FD9816E; STV_TE_37235BA0631DE3C2; STV_TE_82912A60F66BB94C; STV_TE_649684CCAC6F8A53; STV_TE_686277C8A7C1D863; STV_TE_F3BA1217F938D9A8

STV_TC_SY_024

prior fatal exception is not replaced by bundle generation

accepted

STV_SHR_027; STV_SWR_027

passed

STV_TE_01DFB0CB521A0316; STV_TE_05C8C8194E3C5F0D; STV_TE_13B11B8AE03CF870; STV_TE_16A66D205D4A455E; STV_TE_49AC08F58BB7959E; STV_TE_95BAD407570E981E; STV_TE_244B1C037AA3C732; STV_TE_4225679A0D77B25E; STV_TE_10081046B1450184; STV_TE_A7F928DB9206E151; STV_TE_B273D034597B28B8; STV_TE_BD57BEDA18552973; STV_TE_C9F5F024FD54FD79; STV_TE_D2AD87B422D36273; STV_TE_E6D08074BE5F60AD; STV_TE_E80573F84DC22684

STV_TC_SY_025

project paging

accepted

STV_SHR_047; STV_SWR_051; STV_SWR_052

passed

STV_TE_0BE55BC5BDF3AC65; STV_TE_6D24EE4E3DD64FC8; STV_TE_8A63E99187C976E3; STV_TE_21BB65233C33EB7E; STV_TE_22F4D540350790A3; STV_TE_356D0AA693768685; STV_TE_9092D8E50E28B340; STV_TE_6723673D161CA9BA; STV_TE_A45D91EBCD47189C; STV_TE_B5BE8E6CC3A97EBC; STV_TE_BE1FC0B9DB1BF352; STV_TE_F08F8491A3B8F26E

STV_TC_SY_026

incremental body change hidden and deleted objects

accepted

STV_SHR_014; STV_SHR_015; STV_SHR_018; STV_SHR_026; STV_SHR_047; STV_SHR_048; STV_SWR_015; STV_SWR_018; STV_SWR_048

passed

STV_TE_1FEF2B44838D4155; STV_TE_5D129E706050ED4A; STV_TE_6F44E4DAFCBC42DE; STV_TE_8D5E02C06160CC48; STV_TE_010FFE0C52956BBD; STV_TE_55D1143DA9DE27A7; STV_TE_65AC63D67AFA6334; STV_TE_81C9D01E889ACCD1; STV_TE_99A255B5C7BF621D; STV_TE_656E30080137AC26; STV_TE_662FFE1D5E60218E; STV_TE_8447E3E24802A7A4; STV_TE_A7840F205B45812E; STV_TE_AD072603469BA90E; STV_TE_F5233640F6DF867D

STV_TC_SY_027

host owns broken trace failure

accepted

STV_SHR_027; STV_SHR_028; STV_SWR_027; STV_SWR_028

passed

STV_TE_1DADCCE77BA8F1AA; STV_TE_1E1AE11AF532DD50; STV_TE_5BD3D06F689A4099; STV_TE_6CB95C3B5678BACE; STV_TE_54E20F597A26F24F; STV_TE_71A42A22CDFDE17A; STV_TE_89DB9F0DFA6EBD36; STV_TE_93C0D8BF6B430F32; STV_TE_094A7E0FA6FEF0E2; STV_TE_348BA477EA1FE9E0; STV_TE_630A3D3547812370; STV_TE_929A6D4A3145B1C4; STV_TE_C22DE139B2E5DF52; STV_TE_DC50B0D40735701B; STV_TE_F75BB11AA22CCBEA

STV_TC_SY_028

seed selection release

accepted

STV_SHR_003; STV_SHR_014; STV_SHR_026; STV_SHR_038; STV_SHR_047; STV_SHR_048; STV_SHR_052; STV_SHR_053; STV_SWR_003; STV_SWR_038; STV_SWR_048; STV_SWR_051; STV_SWR_052; STV_SWR_056; STV_SWR_057

passed

STV_TE_0EF09DDE354057C3; STV_TE_2BE1C4B126B18F38; STV_TE_2DD310F24F67C848; STV_TE_7E7D403D4FC776CA; STV_TE_9D583239BE7DB40C; STV_TE_24B707D287D02B0A; STV_TE_56BF0F252E2B0681; STV_TE_379A3FC426E17AE7; STV_TE_AD1513DB7BEF1B53; STV_TE_AF7BF6EFED698380; STV_TE_BB04E44583D97C0D; STV_TE_F3E1482ECEAD8334

STV_TC_SY_029

host default directional labels are used

accepted

STV_SHR_045; STV_SWR_045

passed

STV_TE_4C39FAAE619D9350; STV_TE_26C2A9F82B271223; STV_TE_45E5FFF9B4722E84; STV_TE_71DC30F5DFDF60F0; STV_TE_445D4DCBA570FB1E; STV_TE_5947EEBE87470746; STV_TE_379307EDD1A87108; STV_TE_580685ED94D01FB9; STV_TE_ACE9C1B0730B1F80; STV_TE_B8467BD319FACA48; STV_TE_C1E476628B443676; STV_TE_C1EDE9A31DFDC3A9; STV_TE_CFF8782DE1D60572; STV_TE_E4CC915CE4DE97F6; STV_TE_FFE6C24FE4E05F95

STV_TC_SY_030

offline exploration

accepted

STV_SHR_004; STV_SHR_008; STV_SHR_015; STV_SHR_016; STV_SHR_017; STV_SHR_018; STV_SHR_029; STV_SHR_031; STV_SHR_033; STV_SHR_034; STV_SHR_035; STV_SHR_038; STV_SHR_039; STV_SHR_040; STV_SWR_004; STV_SWR_008; STV_SWR_015; STV_SWR_016; STV_SWR_017; STV_SWR_018; STV_SWR_029; STV_SWR_031; STV_SWR_033; STV_SWR_034; STV_SWR_035; STV_SWR_038; STV_SWR_039; STV_SWR_040; STV_SWR_050; STV_SYS_003; STV_SYS_007

passed

STV_TE_1DFB3F3B10BB7640; STV_TE_4A72E96BA6DE2E1E; STV_TE_08F343031032CCDA; STV_TE_11AFE68FC4D2ADED; STV_TE_36AF6C6B39F1B4F5; STV_TE_46D683A2FBB94ACF; STV_TE_174B9C66EB0119E6; STV_TE_536E631428F4AA4A; STV_TE_387407E224540198; STV_TE_99656696793F848A; STV_TE_CFC88A8408D563AF; STV_TE_D7F753F8D4FD8294; STV_TE_E5F510CB6F23FE4E; STV_TE_FF3A07585B18457D

STV_TC_SY_031

project paging

accepted

STV_SHR_047; STV_SWR_051; STV_SWR_052

passed

STV_TE_8C8006872295E8D3; STV_TE_8F519B08D780D32F; STV_TE_9C2EF2AAB951A88F; STV_TE_9C8894EBD9225C91; STV_TE_54F374C6AC0C66B2; STV_TE_68E579755FF433AE; STV_TE_77A4405F2A5366B4; STV_TE_92C56796616E739A; STV_TE_2522C6ACB028F1A4; STV_TE_63692B5AF5018FDE; STV_TE_CBBC2FACA177EA6A; STV_TE_E3A97E937014C6FB

STV_TC_SY_032

async layout failure and stale completion

accepted

STV_SHR_044; STV_SHR_047; STV_SWR_044; STV_SWR_052

passed

STV_TE_3A7FDDC0E8DA0DCC; STV_TE_3D82AD70B58BFCB9; STV_TE_9D6EBF6A6F0743F7; STV_TE_9DEB9C844A02AF74; STV_TE_41E221457D96AB22; STV_TE_913CC158B364F38A; STV_TE_80574D51B50F80B0; STV_TE_BC7B47354D524871; STV_TE_D69BCBFE6F8CCA03; STV_TE_EECA1AE0C4A89B68; STV_TE_F9BBC268A452F033; STV_TE_F9969FB7D90A4D29

STV_TC_SY_033

alternate model geometry details and external

accepted

STV_SHR_008; STV_SHR_012; STV_SHR_014; STV_SHR_015; STV_SHR_017; STV_SHR_026; STV_SHR_029; STV_SHR_031; STV_SHR_033; STV_SHR_037; STV_SHR_041; STV_SHR_047; STV_SHR_048; STV_SWR_008; STV_SWR_012; STV_SWR_015; STV_SWR_029; STV_SWR_031; STV_SWR_033; STV_SWR_037; STV_SWR_041; STV_SWR_047; STV_SWR_048; STV_SWR_049; STV_SWR_050; STV_SYS_004; STV_SYS_005; STV_SYS_006; STV_SYS_010

passed

STV_TE_0B94DF5EA07D94A1; STV_TE_3F3AC5EDBDFD9D32; STV_TE_4BC4C1C6145FF78B; STV_TE_5F59ABA5113CD6C4; STV_TE_82B77D01320C4E9B; STV_TE_84741E6A453CC99C; STV_TE_5479348C2D1ACE13; STV_TE_A7749A458DE50DB9; STV_TE_A92276531D812B43; STV_TE_B2BF070074AED94F; STV_TE_BC1CFE6CF644D38B; STV_TE_C45BE36EF5E5D893; STV_TE_D1B802D9FAC62D16; STV_TE_F227E7F8F64E9942

STV_TC_SY_034

empty seed catalog

accepted

STV_SHR_047; STV_SHR_053; STV_SWR_051; STV_SWR_052; STV_SWR_057

passed

STV_TE_1D0AB7290C45AD8F; STV_TE_1DC1F9096040F112; STV_TE_2AC7B06424B73B9D; STV_TE_4F13B65C7988E6F4; STV_TE_6513DAB610F6BAE5; STV_TE_BF048477E71EFA16; STV_TE_CA503BDB2E45A2A8; STV_TE_CD508D01E393339D; STV_TE_DA00E9FE56E5A125; STV_TE_E3F0D2EE903C0D79; STV_TE_EAB2D41B5168D79C; STV_TE_F4B5B1B6C6055FE4

STV_TC_SY_035

large project at visible capacity

accepted

STV_SHR_043; STV_SHR_044; STV_SWR_043; STV_SWR_044; STV_SYS_008

passed

STV_TE_0C05C6C932469EDB; STV_TE_1B0FA04DA16E3401; STV_TE_8DB38CDB318CBFBD; STV_TE_26F6C864C1112908; STV_TE_43B6FB7759209B3D; STV_TE_3232344A59C0F9C0; STV_TE_A62ED5B70EFE8DD0; STV_TE_CDFD772A1134C279; STV_TE_D536922AB4044FDB; STV_TE_E2401329A9EBEB27; STV_TE_EA4C3D20E892A129

STV_TC_SY_036

seed layout replacement failure and staleness

accepted

STV_SHR_044; STV_SHR_053; STV_SWR_044; STV_SWR_057

passed

STV_TE_0A999588B6A1920C; STV_TE_8A56A1800E4EA5B1; STV_TE_031D77745B96D6B3; STV_TE_82A872882A01D6B9; STV_TE_268F75A16FC25867; STV_TE_351FD1E3C6BE094F; STV_TE_B197F3B233A1FC46; STV_TE_B65229E135C87272; STV_TE_CDCABD8ACB9C2964; STV_TE_CDDA5867728E9B15; STV_TE_D7F50F82479AC0C8; STV_TE_F0A444E2D30EB34A

STV_TC_SY_037

offline exploration

accepted

STV_SHR_004; STV_SHR_008; STV_SHR_015; STV_SHR_016; STV_SHR_017; STV_SHR_018; STV_SHR_029; STV_SHR_031; STV_SHR_033; STV_SHR_034; STV_SHR_035; STV_SHR_038; STV_SHR_039; STV_SHR_040; STV_SWR_004; STV_SWR_008; STV_SWR_015; STV_SWR_016; STV_SWR_017; STV_SWR_018; STV_SWR_029; STV_SWR_031; STV_SWR_033; STV_SWR_034; STV_SWR_035; STV_SWR_038; STV_SWR_039; STV_SWR_040; STV_SWR_050; STV_SYS_003; STV_SYS_007

passed

STV_TE_0BFDF79B6E8658DB; STV_TE_2FF9EA5FEF88B39F; STV_TE_6E5FDBC73C036919; STV_TE_9A8AFF0DB6451958; STV_TE_9DBA576C3AF1FFF3; STV_TE_381A684E64CE327D; STV_TE_6360FE728FDA103F; STV_TE_5616686CDB8D1B9C; STV_TE_CC11AD7C6E64725A; STV_TE_CD6E815F9CAC0F7F; STV_TE_CE60972C9269D472; STV_TE_D21D12BEAAE35E74; STV_TE_F0C2845AEA49F292; STV_TE_F9676FBC315DBFF5

STV_TC_SY_038

clean wheel host

accepted

STV_SHR_042; STV_SHR_046; STV_SWR_042; STV_SWR_046; STV_SYS_009

passed

STV_TE_1BF73FA2457D90D8; STV_TE_01F92BEF833F1EDE; STV_TE_7BEB3B1B6625A5DC; STV_TE_8C0DFF558A66DCA0; STV_TE_8C81216F00482ADD; STV_TE_9AFC30AFCB2544CA; STV_TE_23CFB2E2F59258A0; STV_TE_46FCDBE70FFEE8BD; STV_TE_61BD7D777495C79E; STV_TE_63EC86E2AE3E28DD; STV_TE_74C98DE9CE271275; STV_TE_78A7F282F37C6E00; STV_TE_221C02233B7C1762; STV_TE_276AE256DA132001; STV_TE_582AFC5A3B0D6CD4; STV_TE_B0F93EF8DDAA2A15; STV_TE_B4CE34E817E66D0A; STV_TE_E9C945EDF4A0769F; STV_TE_F750E6633DE4056D

STV_TC_SY_039

empty seed catalog

accepted

STV_SHR_047; STV_SHR_053; STV_SWR_051; STV_SWR_052; STV_SWR_057

passed

STV_TE_0FF12FF96A021A26; STV_TE_23C70B5CADFE85F6; STV_TE_52CF8B9BF7AA0812; STV_TE_0055C4B135295D6D; STV_TE_265D5327A72D2EC1; STV_TE_2006E17586AC3CE7; STV_TE_48559F4CECA001AD; STV_TE_723306A23F12F53A; STV_TE_75640254413F6888; STV_TE_B5530BDE44AA3DBF; STV_TE_C419E178B9EBDAC3; STV_TE_F0A3E069E2F6967C

STV_TC_SY_040

unsupported builder fails clearly

accepted

STV_SHR_001; STV_SWR_001

passed

STV_TE_1BFE396F1328BC93; STV_TE_5D5D6764322F0A1B; STV_TE_09A2807578D5A808; STV_TE_029A3FD82C43AE6D; STV_TE_040D9CA2437EA3D8; STV_TE_41D713508BF4AACB; STV_TE_AF301C9173BE297C; STV_TE_B4A4DD22BA6B72F8; STV_TE_B17272C4602B2A77; STV_TE_BA73A0873DEDC23D; STV_TE_BE1ACFDE9841CB9D; STV_TE_C5624120CB94333D; STV_TE_DB3A63198D744D1A; STV_TE_E4C2AC7C086ACDB6; STV_TE_F6C5F1F06B8C8442

STV_TC_SY_041

Select separate occurrences

accepted

STV_SHR_019; STV_SWR_019

not_run

STV_TC_SY_042

Restore occurrence exploration

accepted

STV_SHR_021; STV_SWR_021

not_run

STV_TC_SY_043

Isolate occurrence expansion

accepted

STV_SHR_022; STV_SWR_022

not_run

STV_TC_SY_044

Merge shared expansion sets

accepted

STV_SHR_023; STV_SWR_023

not_run

STV_TC_SY_045

Inspect details from a nested Windows checkout

accepted

STV_SHR_015; STV_SHR_017; STV_SHR_018; STV_SWR_015; STV_SWR_017; STV_SWR_018; STV_SYS_003; STV_SYS_006

passed

STV_TE_0CBA56C2D1B16D6F; STV_TE_0D4744C556ABA23B; STV_TE_1EA0D25151D74A7C; STV_TE_3E9F0CC9AE6D1527; STV_TE_5EA591226543E09E; STV_TE_50AA9174F28AE924; STV_TE_610BEE40C54D1DA7; STV_TE_1416F5875342DB33; STV_TE_8022ED96D359D61B; STV_TE_8691313C00B21F3E; STV_TE_ADB1B05CE41E118B; STV_TE_BE98DA9EEED13EDA; STV_TE_E6F98C2085D7A915

STV_TC_SY_046

Reject unaudited distribution inputs

accepted

STV_SWR_042; STV_SYS_009

passed

STV_TE_7F0E0FAA905ACCA8; STV_TE_9CD44AB8FBFD9395; STV_TE_506DA5166F4226E8; STV_TE_1074CEBE7559F606; STV_TE_9315CB8A6BAFB14A; STV_TE_A74A579CBD8A43DE; STV_TE_B143FA7927D35E75; STV_TE_C6F4E2EFCEBE9659; STV_TE_C9C0DD4F8282FBED; STV_TE_D888A42739229DD1; STV_TE_D4686F09B0D54AA5; STV_TE_DB8B40103708320D; STV_TE_EE13FB7DE2E2F1CD; STV_TE_EF7E4DAFEAFBC4FA; STV_TE_FA10CBBD5A653BBA

STV_TC_SY_047

Authored transport markers remain inert over file

accepted

STV_SWR_015; STV_SWR_017; STV_SWR_018; STV_SWR_049

passed

STV_TE_0A29394EF7EFB513; STV_TE_2CFA057649D4219D; STV_TE_2D0224E188572853; STV_TE_04F7EDED17CC043F; STV_TE_5A9D6B8DC1AB49AC; STV_TE_55377E9CDFC887DC; STV_TE_A562EDC3ECD1FAAA; STV_TE_B4680757B5EBD9B6; STV_TE_C1F038C26B75641F; STV_TE_CBBD1EEEBE243AEB

STV_TC_SY_048

Authored transport markers remain inert over HTTP

accepted

STV_SWR_015; STV_SWR_017; STV_SWR_018; STV_SWR_049

passed

STV_TE_4FC31631AC32AD39; STV_TE_5DD66163012116DE; STV_TE_7F806DC9A3DFF8AA; STV_TE_3813E6D27511E313; STV_TE_8226DEA4BD51290F; STV_TE_073124C33BD1B11A; STV_TE_A5995580EE4A745C; STV_TE_C878CB13D878C95C; STV_TE_E8C533F33F0B37B7; STV_TE_FFCA3F00A628A9C9

STV_TC_SY_049

Retained historical archives carry a complete licensing supplement

accepted

STV_SWR_042; STV_SWR_046; STV_SYS_009

passed

STV_TE_18C9BA971B0CE338; STV_TE_89D9283C4480C51F; STV_TE_383CF38713FF256B; STV_TE_472FA68626CCD96B; STV_TE_A0D4D6BC54AE39C9; STV_TE_D8B1B640D6940F1F

STV_TC_SY_050

Patched offline distribution remains usable on Python 3.10

accepted

STV_SWR_042; STV_SWR_046; STV_SYS_009

passed

STV_TE_63B6EBE88E472425; STV_TE_69B541A0F8037DB4; STV_TE_30042ECC9414E101; STV_TE_3784740026DBAEE3; STV_TE_A097E5958A89160A; STV_TE_BF2C08B633BD00D3

STV_TC_SY_051

Actual source archive respects the distribution boundary

accepted

STV_SWR_042; STV_SWR_046; STV_SYS_009

passed

STV_TE_1DDD21C8F37EF5DC; STV_TE_1E2008932F39C18B; STV_TE_3F0DEB05F990600D; STV_TE_5E5DF9E1DE3F1E68; STV_TE_053E27C9576BC49A; STV_TE_0062C61AC4ED5ABE; STV_TE_74B1E2689D5AA322; STV_TE_85B5ACEA5A1F0B46; STV_TE_698569DEB206A355; STV_TE_BDAB8C896C5B7922; STV_TE_C45E10E22EF0B80D; STV_TE_D1DB8D156DF73A64

STV_TC_SY_052

Clean rebuild retires obsolete publication files

accepted

STV_SWR_042; STV_SYS_009

passed

STV_TE_0BA0673DB0572C62; STV_TE_00DF8B8564A416AA; STV_TE_2BA56671E0E0DD64; STV_TE_5EF6D34693B5EA29; STV_TE_9A991F5CD63BFC3C; STV_TE_67C5F33620631412; STV_TE_95CD54454268526C; STV_TE_3194E0C00D5E5120; STV_TE_5282B7B96CC1E0C6; STV_TE_7109C2FF8B1787D4; STV_TE_D5D5C30CB3605726; STV_TE_D23981CC1C16F468; STV_TE_DF5D6826958881EC

STV_TC_SY_053

Failed documentation build preserves published bytes

accepted

STV_SWR_042; STV_SYS_009

passed

STV_TE_003E6BDD6E3816A3; STV_TE_4B16C75492B3457D; STV_TE_04F65BAA6CDB685B; STV_TE_8DAE1FCE2789C9F8; STV_TE_09D9C2A6E1936B4F; STV_TE_9D8704D758FD0921; STV_TE_37C71B72B4C9EB26; STV_TE_55FA0354073DF3AF; STV_TE_057BEBB8A33EC7E4; STV_TE_739298E2F0564C1A; STV_TE_BE516BF1862781FE; STV_TE_CCE8E0DCF3719A06; STV_TE_E7E6E350F5543A43

STV_TC_SY_054

Failed directory promotion restores previous publication

accepted

STV_SWR_042; STV_SYS_009

passed

STV_TE_2CBD01AF2B417364; STV_TE_257F51CA54DE5456; STV_TE_378DA6459376DA86; STV_TE_4658E397071ACF9C; STV_TE_343809F516DE6145; STV_TE_3094558686816C3D; STV_TE_BF63FCCA7228006C; STV_TE_C71A70B3E5D75446; STV_TE_D03C25CCCCEF8DF9; STV_TE_D90868BD589779C5; STV_TE_E0C20537B8E451DF; STV_TE_EC8765117EE3C76C; STV_TE_F6254BF26D0A4601

STV_TC_SY_055

CI policy rejects privilege and provenance drift

draft

STV_SWR_042; STV_SYS_009

passed

STV_TE_4E407028E958FA48; STV_TE_22D8A9E190DED8AD; STV_TE_136F9269B7351A90; STV_TE_2114AE5490730B19; STV_TE_2145D7E34A337FF0; STV_TE_3742A83C2E3FAE19; STV_TE_30562D2F63C7ED1A; STV_TE_7613765B219D4B6C; STV_TE_A0B0212F491B4997; STV_TE_C3AEE3D9833820A7; STV_TE_F0ACADE4EC2AE522; STV_TE_F2713590E26C7C17

STV_TC_SY_056

Candidate checksums detect changed artifact bytes

draft

STV_SWR_042; STV_SYS_009

passed

STV_TE_72D4DF66DF6B2B7D; STV_TE_0086C904AA50BF6E; STV_TE_344E841C199397BF; STV_TE_0858F185CEC1A735; STV_TE_A76A3D71F5EBFA5C; STV_TE_A465F6AC125E6A0F; STV_TE_BF44BCF7A5BAB8D0; STV_TE_D0BFD3B60852DD51; STV_TE_E3EDB778980FE51E; STV_TE_E9EE225771AB4968; STV_TE_EAC633983360B5F2; STV_TE_F46E8734D73CCD1D

STV_TC_SY_057

CI runtime command imports the installed Python 3.10 package

draft

STV_SWR_042; STV_SYS_009

passed

STV_TE_499D35C386BF239A; STV_TE_A552051FBF6ABD96; STV_TE_B5A2DB777F66970D; STV_TE_BA4FCAA2A46146AA; STV_TE_EBE31340A9BBCC87; STV_TE_EF9CF01D208E1305

STV_TC_SY_058

Stable keyboard navigation and project root toggles

accepted

STV_SHR_054; STV_SWR_058

passed

STV_TE_05BC66F63ACA5FF3; STV_TE_320E931965C15242; STV_TE_3528C30AC31D2177; STV_TE_39616CB95E67378D; STV_TE_BFC00DA35F1B2273; STV_TE_C0356AC4349BC096; STV_TE_CA1B48292193F71A; STV_TE_F5373865A628182C

STV_TC_SY_059

Negative route rendering and viewport reset

accepted

STV_SHR_054; STV_SWR_059

passed

STV_TE_3C534C28AE70CDDE; STV_TE_27AEFBC714B71032; STV_TE_788FBAA9E5D4DAEB; STV_TE_10057DCD1058B2C7; STV_TE_D733514232D9B3A0; STV_TE_DD4AA0D380BDF0C3; STV_TE_E018DFA57A2EB582; STV_TE_F108B1B11E6A70F1

STV_TC_SY_060

Natural seeded order survives expansion

accepted

STV_SHR_055; STV_SWR_060

passed

STV_TE_4B887AA38AE3E45C; STV_TE_4F603EC22B0D3432; STV_TE_17E96786E19C26CB; STV_TE_58E6337840098442; STV_TE_358C84E3287B376E; STV_TE_361A3EFE750F6E42; STV_TE_873F1D2F001CA837; STV_TE_105487D5F40F1890

STV_TC_SY_061

Published nine-row evidence navigation

accepted

STV_SHR_009; STV_SHR_010; STV_SHR_011; STV_SHR_012; STV_SHR_054; STV_SWR_012; STV_SWR_037; STV_SWR_055; STV_SWR_058; STV_SWR_061; STV_SYS_002; STV_SYS_005

passed

STV_TE_05A2833E373574A8; STV_TE_471F081A1E795BE6; STV_TE_17192149B6D99989; STV_TE_575799773B1DCCEC; STV_TE_A6902518F42BAF11; STV_TE_BAA88F7F4D7239D5; STV_TE_BB9B90F7B18046A2; STV_TE_F0A242FBBBDC350A

STV_TC_SY_062

Visible viewport boundary during graph navigation

accepted

STV_SHR_056; STV_SWR_062

passed

STV_TE_3B2EEB2B638C7B71; STV_TE_7F7FF76154519BAE; STV_TE_13CB015D758DFB0E; STV_TE_58DC3797C13AF162; STV_TE_67ADF36ED5EF6CB3; STV_TE_848DFD9863AE8365; STV_TE_BCF4CA8DCA71F916; STV_TE_D09F0F6E8D4D6F7C; STV_TE_DC9753FC471984A4; STV_TE_EF56B6D683147340

STV_TC_SY_063

Persistent details across navigation and capacity

accepted

STV_SHR_034; STV_SHR_057; STV_SWR_050; STV_SWR_063; STV_SWR_064; STV_SWR_065

passed

STV_TE_2A89BBF5F2390AA1; STV_TE_6A21DAFE7005869A; STV_TE_80F2BB3C2A369802; STV_TE_3560C9D93E7D77F1; STV_TE_6629368094D691E7; STV_TE_A3A11EF15BFC0A39; STV_TE_B863F8A01DCA8556; STV_TE_C0D48B92F4736549; STV_TE_CA52AC7B132F8E75; STV_TE_D592F86831942182; STV_TE_FFD62C605C0585C1

STV_TC_SY_064

Persistent loading cancellation and shared content safety

accepted

STV_SHR_057; STV_SWR_063; STV_SWR_064

passed

STV_TE_0FAB92819C2C6B5E; STV_TE_3B3D244CA3DF9D0B; STV_TE_5DAD06625FF240A3; STV_TE_6E717D50D8A45C92; STV_TE_18BA7B73F4987A95; STV_TE_44FC2520374671F3; STV_TE_49E022039A715E29; STV_TE_658077BE86E61947; STV_TE_913550FBD6B5445C

STV_TC_SY_065

Readable details, metadata disclosure and artifact-ID navigation

accepted

STV_SHR_057; STV_SWR_016; STV_SWR_018; STV_SWR_064

passed

STV_TE_04D19E7C66068621; STV_TE_9A90B66E37D26235; STV_TE_21D8D7E0E61848CF; STV_TE_587EE20025A702C6; STV_TE_836F6E0063EB6DBD; STV_TE_B105AA527FA40C29; STV_TE_B42030594D71B57E; STV_TE_D3CF5B1D4C095CC3; STV_TE_F1877BF68A7C887D; STV_TE_FCB0443B199D51BC

STV_TC_SY_066

Reset exploration without losing current roots or cards

accepted

STV_SHR_058; STV_SWR_066

passed

STV_TE_1F3D9A05677CDFA3; STV_TE_223F00B3F57FF9F8; STV_TE_5762940D0A9F6514; STV_TE_22816527CBAE39E9; STV_TE_EB9700F6E06019BD

STV_TC_SY_067

Export and save the visible graph and details offline

accepted

STV_SHR_059; STV_SWR_070; STV_SWR_071; STV_SWR_072; STV_SYS_011

passed

STV_TE_69D5C15A79F78E08; STV_TE_1727CFEADD67393A; STV_TE_3893F5FF7471EF7E; STV_TE_6059D5F8703764AF; STV_TE_F94B92BCB22B9EC2

STV_TC_SY_068

Configure and read both detail text presentations

accepted

STV_SHR_060; STV_SWR_067; STV_SWR_068

passed

STV_TE_773C3738146D3326; STV_TE_975D95E25D67690D; STV_TE_AB3F15769187326B; STV_TE_D2778F6079356CB2; STV_TE_E0767DE46808FBFF

STV_TC_SY_069

Bulk-fold host attributes without changing embedded views

accepted

STV_SHR_061; STV_SWR_069

passed

STV_TE_234E8CF136742890; STV_TE_255830AF37EC9FD8; STV_TE_B5884B4F6DAC0D54; STV_TE_E2E294FCBF4A129C; STV_TE_F80092425DBB0B9E

STV_TC_SY_070

Remember and restore a real browser view

accepted

STV_SHR_003; STV_SHR_057; STV_SHR_062; STV_SHR_063; STV_SHR_064; STV_SHR_065; STV_SWR_003; STV_SWR_063; STV_SWR_073; STV_SWR_074; STV_SWR_075

passed

STV_TE_1669814EA3AAFF11

STV_TC_SY_001: usability smoke

Test case: usability smoke STV_TC_SY_001
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_usability_smoke[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_usability_smoke[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_usability_smoke[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_usability_smoke(browser, short_output, protocol):
    """Viewport, hover lifecycle and explicit activation on both transports."""
    output = short_output / 'usability'
    result = build(FIXTURE, output)
    assert result.returncode == 0, result.stderr
    with published_url(output,protocol) as url:
        browser.get(url)
        _exercise_usability(browser)

Interaction procedure and observable outcomes:

def _exercise_usability(browser):
    wait = WebDriverWait(browser, 10)
    wait.until(lambda d: d.find_elements(By.CSS_SELECTOR, '.stv-view[data-stv-revision="0"]'))
    root = browser.find_element(By.CSS_SELECTOR, '.stv-view')
    viewport = root.find_element(By.CSS_SELECTOR, '.stv-viewport')
    assert browser.execute_script('return getComputedStyle(arguments[0]).height', viewport) == '975px'
    node = root.find_element(By.CSS_SELECTOR, '.stv-node')
    details = node.find_element(By.CSS_SELECTOR, '[data-focus="details"]')
    toolbar = root.find_element(By.CSS_SELECTOR, '.stv-toolbar button')
    ActionChains(browser).move_to_element(node).perform()
    time.sleep(.3)
    assert not browser.find_elements(By.CSS_SELECTOR, '.stv-detail')
    ActionChains(browser).move_to_element(toolbar).perform()
    time.sleep(1.1)
    assert not browser.find_elements(By.CSS_SELECTOR, '.stv-detail')
    # Measure the actual deadline, independently of WebDriver command latency.
    browser.execute_script("""
      window.hoverTimes={};
      arguments[0].addEventListener('mouseenter',()=>{hoverTimes.node=performance.now()},{once:true});
      arguments[1].addEventListener('mouseenter',()=>{hoverTimes.button=performance.now()},{once:true});
      const observer=new MutationObserver(()=>{if(document.querySelector('.stv-detail')){
        hoverTimes.open=performance.now();observer.disconnect();}});
      observer.observe(document.body,{childList:true});
    """,node,details)
    ActionChains(browser).move_to_element_with_offset(node,-node.size['width']/2+8,-node.size['height']/2+8).perform()
    time.sleep(.5)
    ActionChains(browser).move_to_element(details).perform()
    wait.until(lambda d: d.find_elements(By.CSS_SELECTOR, '.stv-detail'))
    times=browser.execute_script('return hoverTimes')
    assert 950 <= times['open']-times['node'] < 1500, times
    assert 0 <= times['open']-times['button'] < 850, times
    # Hover did not focus the view: real Escape must still dismiss it.
    browser.execute_script('document.body.tabIndex=-1;document.body.focus()')
    browser.switch_to.active_element.send_keys(Keys.ESCAPE)
    assert not browser.find_elements(By.CSS_SELECTOR,'.stv-detail')
    ActionChains(browser).move_to_element(toolbar).perform()
    ActionChains(browser).move_to_element(node).perform()
    time.sleep(.2)
    browser.switch_to.active_element.send_keys(Keys.ESCAPE)
    time.sleep(1.1)
    assert not browser.find_elements(By.CSS_SELECTOR,'.stv-detail')
    browser.execute_script('arguments[0].focus()', details)
    details.send_keys(Keys.ENTER)
    assert browser.find_elements(By.CSS_SELECTOR, '.stv-persistent-detail')
    browser.switch_to.active_element.send_keys(Keys.ESCAPE)
    assert browser.find_elements(By.CSS_SELECTOR, '.stv-persistent-detail')
    browser.find_element(By.CSS_SELECTOR,'.stv-persistent-detail button').send_keys(Keys.ENTER)
    assert not browser.find_elements(By.CSS_SELECTOR, '.stv-detail')
    assert browser.switch_to.active_element == details
    # Last, test each cancellation from the same reset viewport, with no
    # pointer departure after the action masking whether it cancels the timer.
    for selector in ('[aria-label="Pan right"]','.stv-groups button'):
        browser.execute_script("arguments[0].querySelector('[aria-label=\"Reset viewport\"]').click()",root)
        ActionChains(browser).move_to_element(toolbar).perform()
        ActionChains(browser).move_to_element(node).perform()
        time.sleep(.2)
        browser.execute_script('arguments[0].querySelector(arguments[1]).click()',root,selector)
        wait.until(lambda d:root.get_attribute('aria-busy')=='false')
        time.sleep(1.1)
        assert not browser.find_elements(By.CSS_SELECTOR,'.stv-detail')

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_002: control order smoke

Test case: control order smoke STV_TC_SY_002
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_control_order_smoke[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_control_order_smoke[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_control_order_smoke[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_control_order_smoke(browser,protocol):
    published=Path(__file__).parents[1]/'docs/_build/html'
    with published_url(published,protocol) as url:
        browser.get(url.rsplit('/',1)[0]+'/demo.html')
        _exercise_control_order(browser)

Interaction procedure and observable outcomes:

def _exercise_control_order(browser):
    wait=WebDriverWait(browser,20)
    wait.until(lambda d:len(d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))==2)
    root=browser.find_elements(By.CSS_SELECTOR,'.stv-view')[1]
    def buttons():
        node=next(n for n in root.find_elements(By.CSS_SELECTOR,'.stv-node')
                  if n.find_element(By.CSS_SELECTOR,'.stv-id').text=='STV_SWR_001')
        return node.find_elements(By.CSS_SELECTOR,'.stv-groups button')
    def identities():
        return [json.loads(b.get_attribute('data-focus'))[1:] for b in buttons()]
    expected=[['derives_from','outgoing'],['verifies','incoming'],['allocated_to','outgoing']]
    assert identities()==expected
    buttons()[0].click()
    wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
    assert identities()==expected
    assert buttons()[0].get_attribute('aria-expanded')=='true'
    buttons()[0].click()
    wait.until(lambda d:root.get_attribute('data-stv-revision')=='2')
    assert identities()==expected
    assert buttons()[0].get_attribute('aria-expanded')=='false'

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_003: missing placeholder and detail error

Test case: missing placeholder and detail error STV_TC_SY_003
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_missing_placeholder_and_detail_error[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_missing_placeholder_and_detail_error[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_missing_placeholder_and_detail_error[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_missing_placeholder_and_detail_error(browser,short_output,protocol):
    import shutil
    source=short_output/'source';shutil.copytree(FIXTURE,source)
    path=source/'requirements.rst';path.write_text(path.read_text(encoding='utf-8').replace(':traces: LEAF_B',':traces: MISSING_A'),encoding='utf-8')
    output=short_output/'html';result=build(source,output)
    assert result.returncode!=0 and 'MISSING_A' in result.stderr
    saved={script:script.read_bytes() for script in (output/'_static/stv/details').glob('*.js')}
    for script in saved:script.unlink()
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,20)
        wait.until(lambda d:d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))
        root=browser.find_element(By.CSS_SELECTOR,'.stv-view')
        control=root.find_element(By.CSS_SELECTOR,'[aria-label="Expand Traces (outgoing) for ROOT_A"]')
        browser.execute_script('arguments[0].focus()',control);control.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        missing=root.find_element(By.CSS_SELECTOR,'.stv-missing')
        # Stable navigation can discover a node left of the current viewport.
        # Check its identity, then explicitly fit before testing visible content.
        assert 'MISSING_A' in missing.get_attribute('textContent')
        geometry=browser.execute_script('return [...arguments[0].querySelectorAll(".stv-node")].map(n=>[n.dataset.key,n.style.left,n.style.top])',root)
        browser.execute_script('[...arguments[0].querySelectorAll(".stv-toolbar button")].find(b=>b.textContent==="Reset viewport").click()',root)
        assert browser.execute_script('return [...arguments[0].querySelectorAll(".stv-node")].map(n=>[n.dataset.key,n.style.left,n.style.top])',root)==geometry
        assert 'MISSING_A' in missing.text and 'Missing object' in missing.text
        assert not missing.find_elements(By.CSS_SELECTOR,'a,button')
        inspect=root.find_element(By.CSS_SELECTOR,'[aria-label="Details for ROOT_A"]')
        browser.execute_script('arguments[0].focus()',inspect);inspect.send_keys(Keys.ENTER)
        wait.until(lambda d:'Local detail asset unavailable' in d.find_element(By.CSS_SELECTOR,'.stv-detail').text)
        browser.find_element(By.CSS_SELECTOR,'.stv-persistent-detail button').send_keys(Keys.ENTER)
        wait.until(lambda d:not d.find_elements(By.CSS_SELECTOR,'.stv-detail'))
        for script,content in saved.items():script.write_bytes(content)
        inspect.send_keys(Keys.ENTER)
        wait.until(lambda d:'formatted body' in d.find_element(By.CSS_SELECTOR,'.stv-detail').text)

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_004: failed finalization retains pending page and previous assets

Test case: failed finalization retains pending page and previous assets STV_TC_SY_004
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: src/sphinx_traceability_view/directive/tests/test_lifecycle.py::test_failed_finalization_retains_pending_page_and_previous_assets
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: src/sphinx_traceability_view/directive/tests/test_lifecycle.py::test_failed_finalization_retains_pending_page_and_previous_assets.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "src/sphinx_traceability_view/directive/tests/test_lifecycle.py::test_failed_finalization_retains_pending_page_and_previous_assets" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_failed_finalization_retains_pending_page_and_previous_assets(tmp_path):
    from types import SimpleNamespace
    from sphinx.errors import SphinxError
    from sphinx_traceability_view.directive.lifecycle import finish
    pending='<section data-stv-build="STV_PENDING"></section>'
    (tmp_path/'index.html').write_text(pending,encoding='utf-8')
    (tmp_path/'requirements.html').write_text('<p>Expected Need body missing</p>',encoding='utf-8')
    previous=tmp_path/'_static/stv/graph-old.js';previous.parent.mkdir(parents=True);previous.write_text('previous complete asset',encoding='utf-8')
    graph={'model':{'relations':{}},'objects':{'A':{'url':'requirements.html#A','external':False,'parent':None}}}
    app=SimpleNamespace(_stv_graph=graph,_stv_hidden=set(),outdir=str(tmp_path),env=SimpleNamespace(stv_views={'index':[{}]}))
    with pytest.raises(SphinxError,match='Rendered Need.*missing'):
        finish(app,None)
    assert (tmp_path/'index.html').read_text(encoding='utf-8')==pending
    assert previous.read_text(encoding='utf-8')=='previous complete asset'
    assert list(previous.parent.glob('graph-*.js'))==[previous]

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_005: seed layout replacement failure and staleness

Test case: seed layout replacement failure and staleness STV_TC_SY_005
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_release_seeds.py :: docs/test-scripts/test_release_seeds.py::test_seed_layout_replacement_failure_and_staleness[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_release_seeds.py::test_seed_layout_replacement_failure_and_staleness[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_release_seeds.py::test_seed_layout_replacement_failure_and_staleness[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_seed_layout_replacement_failure_and_staleness(browser,short_output,protocol):
    from pathlib import Path
    project=Path(__file__).parents[1]
    script="import{build}from'esbuild';await build({entryPoints:[process.argv[1]],bundle:true,format:'iife',outfile:process.argv[2]})"
    result=subprocess.run(['node','--input-type=module','-e',script,str(project/'docs/test-scripts/fixtures/browser-harness.js'),str(short_output/'harness.js')],cwd=project/'frontend',capture_output=True,text=True)
    assert result.returncode==0,result.stderr
    (short_output/'index.html').write_text('<link rel="stylesheet" href="'+(project/'src/sphinx_traceability_view/static/stv.css').as_uri()+'"><div class="stv-view" id="test-view" data-stv-seeds=\'["A"]\'></div><script src="harness.js"></script>',encoding='utf-8')
    with published_url(short_output,protocol) as url:
        browser.get(url);_assert_async_layout(browser)
        wait=WebDriverWait(browser,20);root=browser.find_element(By.CSS_SELECTOR,'.stv-view')
        field=root.find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        previous=root.find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style')
        field.send_keys('B');field.send_keys(Keys.ENTER)
        wait.until(lambda d:d.execute_script('return calls.length')==7)
        browser.execute_script('calls[6].reject(Error("Seed layout failure"))')
        wait.until(lambda d:'Seed layout failure' in root.find_element(By.CSS_SELECTOR,'.stv-status').text)
        assert root.get_attribute('data-stv-revision')=='2'
        assert root.find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style')==previous
        assert browser.switch_to.active_element==field
        for identity,count in [('A',8),('B',9)]:
            field.send_keys(Keys.CONTROL,'a');field.send_keys(Keys.BACKSPACE);field.send_keys(identity);field.send_keys(Keys.ENTER)
            wait.until(lambda d:d.execute_script('return calls.length')==count)
        browser.execute_script('stvHarness.compute(...calls[8].args).then(calls[8].resolve)')
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='3')
        browser.execute_script('stvHarness.compute(...calls[7].args).then(calls[7].resolve)')
        wait.until(lambda d:d.execute_script('return document.querySelectorAll(".stv-measure").length')==0)
        assert root.get_attribute('data-stv-revision')=='3'
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['B']
        assert browser.switch_to.active_element==field

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_006: alternate host schema external metadata and parts

Test case: alternate host schema external metadata and parts STV_TC_SY_006
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_alternate_host_schema_external_metadata_and_parts
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_alternate_host_schema_external_metadata_and_parts.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_alternate_host_schema_external_metadata_and_parts" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_alternate_host_schema_external_metadata_and_parts(tmp_path):
    result=build(FIXTURE.parent/'alternate_model',tmp_path)
    assert result.returncode==0,result.stdout+result.stderr
    data=manifest(tmp_path)
    assert data['model']['types']['hardware']['level']=='hardware'
    assert data['model']['relations']['traces']['outgoing']=='Traces to'
    assert data['objects']['EXTERNAL_A']['metadata']['owner']=='External owner'
    assert data['objects']['EXTERNAL_A']['docname'] is None
    assert 'GOAL_A.fragment' in data['objects']
    assert 'GOAL_A.fragment' not in data['entries']
    assert 'HIDDEN_A' not in data['objects']
    assert not any('HIDDEN_A' in edge for edge in data['edges'])

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_007: documentation visuals

Test case: documentation visuals STV_TC_SY_007
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_documentation_visuals
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_documentation_visuals.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_documentation_visuals" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_documentation_visuals(browser):
    published=Path(__file__).parents[1]/'docs/_build/html'
    assert (published/'demo.html').is_file(),'Build project documentation before publication checks'
    browser.set_window_size(1500,1300)
    browser.get((published/'demo.html').as_uri())
    wait=WebDriverWait(browser,20)
    wait.until(lambda d:len(d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))==2)
    assert 'Traceability view failed' not in browser.find_element(By.TAG_NAME,'body').text
    screenshots=Path(os.environ.get('STV_SCREENSHOTS','docs/_build/browser'));screenshots.mkdir(parents=True,exist_ok=True)
    browser.save_screenshot(str(screenshots/'project-demo.png'))
    browser.get((published/'state-machine.html').as_uri())
    assert browser.find_element(By.CSS_SELECTOR,'object[type="image/svg+xml"]').get_attribute('data').endswith('state-machine.svg')
    browser.save_screenshot(str(screenshots/'state-page.png'))
    browser.get((published/'state-machine.svg').as_uri())
    assert browser.find_elements(By.TAG_NAME,'svg')
    assert len(browser.find_elements(By.TAG_NAME,'a'))>=10
    browser.save_screenshot(str(screenshots/'state-diagram.png'))
    for name in ('system-architecture','software-architecture'):
        browser.get((published/(name+'.svg')).as_uri())
        assert browser.find_elements(By.TAG_NAME,'svg')
        assert browser.find_elements(By.TAG_NAME,'a')
        browser.save_screenshot(str(screenshots/(name+'.png')))
        page='architecture-system' if name.startswith('system') else 'architecture-software'
        browser.get((published/(page+'.html')).as_uri())
        assert browser.find_element(By.CSS_SELECTOR,'object[type="image/svg+xml"]')
        browser.save_screenshot(str(screenshots/(page+'-page.png')))

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_008: invalid seed source location

Test case: invalid seed source location STV_TC_SY_008
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_invalid_seed_source_location[UNKNOWN]
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_invalid_seed_source_location[UNKNOWN].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_invalid_seed_source_location[UNKNOWN]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_invalid_seed_source_location(tmp_path, seed):
    source = tmp_path / "source"
    shutil.copytree(FIXTURE, source)
    (source / "index.rst").write_text(f"Invalid\n=======\n\n.. toctree::\n\n   requirements\n\n.. traceability-view:: {seed}\n", encoding="utf-8")
    with (source / "requirements.rst").open("a", encoding="utf-8") as stream:
        stream.write("\n.. shr:: Hidden\n   :id: HIDDEN_A\n   :hide:\n")
    result = build(source, tmp_path / "html")
    assert result.returncode != 0
    assert "index.rst:8" in result.stderr
    assert "unknown or hidden starting ID" in result.stderr

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_009: control order smoke

Test case: control order smoke STV_TC_SY_009
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_control_order_smoke[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_control_order_smoke[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_control_order_smoke[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_control_order_smoke(browser,protocol):
    published=Path(__file__).parents[1]/'docs/_build/html'
    with published_url(published,protocol) as url:
        browser.get(url.rsplit('/',1)[0]+'/demo.html')
        _exercise_control_order(browser)

Interaction procedure and observable outcomes:

def _exercise_control_order(browser):
    wait=WebDriverWait(browser,20)
    wait.until(lambda d:len(d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))==2)
    root=browser.find_elements(By.CSS_SELECTOR,'.stv-view')[1]
    def buttons():
        node=next(n for n in root.find_elements(By.CSS_SELECTOR,'.stv-node')
                  if n.find_element(By.CSS_SELECTOR,'.stv-id').text=='STV_SWR_001')
        return node.find_elements(By.CSS_SELECTOR,'.stv-groups button')
    def identities():
        return [json.loads(b.get_attribute('data-focus'))[1:] for b in buttons()]
    expected=[['derives_from','outgoing'],['verifies','incoming'],['allocated_to','outgoing']]
    assert identities()==expected
    buttons()[0].click()
    wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
    assert identities()==expected
    assert buttons()[0].get_attribute('aria-expanded')=='true'
    buttons()[0].click()
    wait.until(lambda d:root.get_attribute('data-stv-revision')=='2')
    assert identities()==expected
    assert buttons()[0].get_attribute('aria-expanded')=='false'

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_010: interactive seed smoke

Test case: interactive seed smoke STV_TC_SY_010
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_interactive_seed_smoke[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_interactive_seed_smoke[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_interactive_seed_smoke[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_interactive_seed_smoke(browser,short_output,protocol):
    output=short_output/'seed-picker';result=build(FIXTURE,output)
    assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,20)
        wait.until(lambda d:len(d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))==2)
        roots=browser.find_elements(By.CSS_SELECTOR,'.stv-view');root=roots[0]
        field=root.find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        field.send_keys('missing');field.send_keys(Keys.ENTER)
        assert field.get_attribute('aria-invalid')=='true'
        assert root.get_attribute('data-stv-revision')=='0'
        field.clear();field.send_keys('software detail')
        wait.until(lambda d:root.find_element(By.CSS_SELECTOR,'.stv-seed-matches').is_displayed())
        assert 'LEAF_B' in root.find_element(By.CSS_SELECTOR,'.stv-seed-matches').text
        field.send_keys(Keys.ARROW_DOWN);field.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['LEAF_B']
        assert roots[1].get_attribute('data-stv-revision')=='0'
        root.find_element(By.XPATH,'.//button[text()="Project overview"]').click()
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='2')
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-project'))==1
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['ROOT_A']
        centers=browser.execute_script("return [...arguments[0].querySelectorAll('.stv-node')].map(n=>parseFloat(n.style.left)+n.offsetWidth/2)",root)
        assert abs(centers[0]-centers[1])<1

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_011: seed capacity at directive

Test case: seed capacity at directive STV_TC_SY_011
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_seed_capacity_at_directive[200-True]
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_seed_capacity_at_directive[200-True].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_seed_capacity_at_directive[200-True]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_seed_capacity_at_directive(tmp_path, count, success):
    source = tmp_path / "source"
    shutil.copytree(FIXTURE, source)
    ids = [f"NEED_{i:03}" for i in range(count)]
    (source / "requirements.rst").write_text("Requirements\n============\n\n" + "\n".join(f".. shr:: Item {i}\n   :id: {identity}\n" for i, identity in enumerate(ids)), encoding="utf-8")
    (source / "index.rst").write_text("Capacity\n========\n\n.. toctree::\n\n   requirements\n\n.. traceability-view:: " + " ".join(ids) + "\n", encoding="utf-8")
    result = build(source, tmp_path / "html")
    assert (result.returncode == 0) is success, result.stderr
    if not success:
        assert "index.rst:8" in result.stderr
        assert "200 distinct starting IDs" in result.stderr

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_012: missing placeholder and detail error

Test case: missing placeholder and detail error STV_TC_SY_012
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_missing_placeholder_and_detail_error[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_missing_placeholder_and_detail_error[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_missing_placeholder_and_detail_error[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_missing_placeholder_and_detail_error(browser,short_output,protocol):
    import shutil
    source=short_output/'source';shutil.copytree(FIXTURE,source)
    path=source/'requirements.rst';path.write_text(path.read_text(encoding='utf-8').replace(':traces: LEAF_B',':traces: MISSING_A'),encoding='utf-8')
    output=short_output/'html';result=build(source,output)
    assert result.returncode!=0 and 'MISSING_A' in result.stderr
    saved={script:script.read_bytes() for script in (output/'_static/stv/details').glob('*.js')}
    for script in saved:script.unlink()
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,20)
        wait.until(lambda d:d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))
        root=browser.find_element(By.CSS_SELECTOR,'.stv-view')
        control=root.find_element(By.CSS_SELECTOR,'[aria-label="Expand Traces (outgoing) for ROOT_A"]')
        browser.execute_script('arguments[0].focus()',control);control.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        missing=root.find_element(By.CSS_SELECTOR,'.stv-missing')
        # Stable navigation can discover a node left of the current viewport.
        # Check its identity, then explicitly fit before testing visible content.
        assert 'MISSING_A' in missing.get_attribute('textContent')
        geometry=browser.execute_script('return [...arguments[0].querySelectorAll(".stv-node")].map(n=>[n.dataset.key,n.style.left,n.style.top])',root)
        browser.execute_script('[...arguments[0].querySelectorAll(".stv-toolbar button")].find(b=>b.textContent==="Reset viewport").click()',root)
        assert browser.execute_script('return [...arguments[0].querySelectorAll(".stv-node")].map(n=>[n.dataset.key,n.style.left,n.style.top])',root)==geometry
        assert 'MISSING_A' in missing.text and 'Missing object' in missing.text
        assert not missing.find_elements(By.CSS_SELECTOR,'a,button')
        inspect=root.find_element(By.CSS_SELECTOR,'[aria-label="Details for ROOT_A"]')
        browser.execute_script('arguments[0].focus()',inspect);inspect.send_keys(Keys.ENTER)
        wait.until(lambda d:'Local detail asset unavailable' in d.find_element(By.CSS_SELECTOR,'.stv-detail').text)
        browser.find_element(By.CSS_SELECTOR,'.stv-persistent-detail button').send_keys(Keys.ENTER)
        wait.until(lambda d:not d.find_elements(By.CSS_SELECTOR,'.stv-detail'))
        for script,content in saved.items():script.write_bytes(content)
        inspect.send_keys(Keys.ENTER)
        wait.until(lambda d:'formatted body' in d.find_element(By.CSS_SELECTOR,'.stv-detail').text)

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_013: cross page bundle

Test case: cross page bundle STV_TC_SY_013
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_cross_page_bundle
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_cross_page_bundle.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_cross_page_bundle" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_cross_page_bundle(tmp_path):
    result = build(FIXTURE, tmp_path)
    assert result.returncode == 0, result.stdout + result.stderr
    html = (tmp_path / "index.html").read_text(encoding="utf-8")
    assert "STV_PENDING" not in html
    soup = BeautifulSoup(html, "html.parser")
    roots = soup.select(".stv-view")
    assert len(roots) == 2
    assert json.loads(roots[0]["data-stv-seeds"]) == ["ROOT_A", "LEAF_B"]
    assert json.loads(roots[1]["data-stv-seeds"]) == []
    script = soup.select_one("script[data-stv-graph]")
    assert (tmp_path / script["src"]).is_file()
    fragments = list((tmp_path / "_static/stv/details").glob("*.js"))
    assert len(fragments) == 2
    assert any("formatted body" in p.read_text() for p in fragments)

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_014: invalid seed source location

Test case: invalid seed source location STV_TC_SY_014
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_invalid_seed_source_location[ROOT_A UNKNOWN]
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_invalid_seed_source_location[ROOT_A UNKNOWN].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_invalid_seed_source_location[ROOT_A UNKNOWN]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_invalid_seed_source_location(tmp_path, seed):
    source = tmp_path / "source"
    shutil.copytree(FIXTURE, source)
    (source / "index.rst").write_text(f"Invalid\n=======\n\n.. toctree::\n\n   requirements\n\n.. traceability-view:: {seed}\n", encoding="utf-8")
    with (source / "requirements.rst").open("a", encoding="utf-8") as stream:
        stream.write("\n.. shr:: Hidden\n   :id: HIDDEN_A\n   :hide:\n")
    result = build(source, tmp_path / "html")
    assert result.returncode != 0
    assert "index.rst:8" in result.stderr
    assert "unknown or hidden starting ID" in result.stderr

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_015: alternate model geometry details and external

Test case: alternate model geometry details and external STV_TC_SY_015

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_alternate_model_geometry_details_and_external[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_alternate_model_geometry_details_and_external[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_alternate_model_geometry_details_and_external(browser,short_output,protocol):
    output=short_output/'html';result=build(FIXTURE.parent/'alternate_model',output);assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,30)
        wait.until(lambda d:len(d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))==3)
        roots=browser.find_elements(By.CSS_SELECTOR,'.stv-view');root=roots[0]
        assert browser.execute_script('''const n=arguments[0].querySelector('.stv-node').getBoundingClientRect(),v=arguments[0].querySelector('.stv-viewport').getBoundingClientRect();return n.top>=v.top&&n.bottom<=v.bottom''',root)
        def group(identity,direction):
            return root.find_element(By.CSS_SELECTOR,f'[aria-label="Expand Traces {"to" if direction=="outgoing" else "from"} ({direction}) for {identity}"]')
        control=group('SOFTWARE_A','outgoing');browser.execute_script('arguments[0].focus()',control);control.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        control=group('GOAL_A','outgoing');browser.execute_script('arguments[0].focus()',control);control.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='2')
        boxes=browser.execute_script('''return Object.fromEntries([...arguments[0].querySelectorAll('.stv-nodes>.stv-node')].map(n=>[n.querySelector('.stv-id').textContent,{x:parseFloat(n.style.left),y:parseFloat(n.style.top),width:n.offsetWidth,height:n.offsetHeight}]))''',root)
        assert len(boxes)==6
        assert 'HIDDEN_A' not in boxes
        for a,b in zip(['GOAL_A','HARDWARE_A','SYSTEM_A','SOFTWARE_A'],['HARDWARE_A','SYSTEM_A','SOFTWARE_A','MODULE_A']):assert boxes[a]['y']+boxes[a]['height']<boxes[b]['y']
        assert boxes['CHECK_A']['x']>=max(v['x']+v['width'] for k,v in boxes.items() if k!='CHECK_A')+96
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-edges polyline'))==7
        assert browser.execute_script('''const title=arguments[0].querySelector('[data-key*="GOAL_A"] .stv-title');return title.scrollHeight>title.clientHeight&&title.clientHeight<=2*parseFloat(getComputedStyle(title).lineHeight)+1''',root)
        long_id=roots[1].find_element(By.CSS_SELECTOR,'[data-key*=LONG_IDENTIFIER] .stv-id')
        assert long_id.get_attribute('textContent')=='LONG_IDENTIFIER_WITH_MANY_SEGMENTS_ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789'
        assert browser.execute_script('return arguments[0].scrollWidth<=arguments[0].clientWidth',long_id)
        assert len(roots[1].find_elements(By.CSS_SELECTOR,'.stv-unaccepted'))==2
        # A part seed inspects the complete published containing Need.
        part=roots[2].find_element(By.CSS_SELECTOR,'[aria-label="Details for GOAL_A.fragment"]')
        browser.execute_script('arguments[0].focus()',part);part.send_keys(Keys.ENTER)
        wait.until(lambda d:'Static widget text' in d.find_element(By.CSS_SELECTOR,'.stv-detail').text)
        panel=browser.find_element(By.CSS_SELECTOR,'.stv-detail')
        metadata=panel.find_element(By.CSS_SELECTOR,'.needs_collapse')
        assert metadata.get_attribute('aria-expanded')=='false'
        browser.execute_script('arguments[0].click()',metadata)
        assert 'Fixture owner' in panel.text
        assert 'Resource unavailable offline' in panel.text
        assert not panel.find_elements(By.CSS_SELECTOR,'script,iframe,object,[onerror]')
        assert not browser.execute_script('return window.STV_WIDGET_EXECUTED===true')
        assert panel.find_element(By.CSS_SELECTOR,'img[data-stv-src]').get_attribute('complete')=='true'
        assert browser.execute_script('return arguments[0].naturalWidth',panel.find_element(By.CSS_SELECTOR,'img[data-stv-src]'))>0
        assert browser.execute_script('return arguments[0].naturalWidth',panel.find_element(By.CSS_SELECTOR,'.fixture-widget img'))>0
        label=panel.find_element(By.CSS_SELECTOR,'label');field=panel.find_element(By.CSS_SELECTOR,'input')
        assert label.get_attribute('for')==field.get_attribute('id')
        assert field.get_attribute('id').startswith(panel.get_attribute('id'))
        assert 'HIDDEN_A' not in panel.text
        assert not browser.execute_script("return performance.getEntriesByType('resource').some(e=>e.name.includes('example.invalid'))")
        assert browser.execute_script('return arguments[0].scrollHeight>arguments[0].clientHeight',panel)
        browser.execute_script('arguments[0].focus()',panel);panel.send_keys(Keys.END)
        wait.until(lambda d:browser.execute_script('return arguments[0].scrollTop>0',panel))
        original=panel.find_element(By.CSS_SELECTOR,'a[href*="example.invalid/remote.png"]')
        assert original.text=='Original resource'
        panel.find_element(By.CSS_SELECTOR,'button').click()
        external=roots[1].find_element(By.CSS_SELECTOR,'[aria-label="Details for EXTERNAL_A"]')
        browser.execute_script('arguments[0].focus()',external);external.send_keys(Keys.ENTER)
        wait.until(lambda d:'External owner' in d.find_element(By.CSS_SELECTOR,'.stv-detail').text)
        assert 'full body unavailable offline' in browser.find_element(By.CSS_SELECTOR,'.stv-detail').text
        browser.find_element(By.CSS_SELECTOR,'.stv-detail button').click()
        isolated=roots[1].find_element(By.CSS_SELECTOR,'.stv-unaccepted')
        browser.execute_script('arguments[0].focus()',isolated.find_element(By.CSS_SELECTOR,'[data-focus="details"]'))
        wait.until(lambda d:isolated.find_element(By.CSS_SELECTOR,'.stv-id').text=='ISOLATED_A')
        assert isolated.find_element(By.CSS_SELECTOR,'.stv-id').text=='ISOLATED_A'
        assert 'No relationships' in isolated.text
        assert not isolated.find_elements(By.CSS_SELECTOR,'.stv-groups button')

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_016: usability smoke

Test case: usability smoke STV_TC_SY_016
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_usability_smoke[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_usability_smoke[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_usability_smoke[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_usability_smoke(browser, short_output, protocol):
    """Viewport, hover lifecycle and explicit activation on both transports."""
    output = short_output / 'usability'
    result = build(FIXTURE, output)
    assert result.returncode == 0, result.stderr
    with published_url(output,protocol) as url:
        browser.get(url)
        _exercise_usability(browser)

Interaction procedure and observable outcomes:

def _exercise_usability(browser):
    wait = WebDriverWait(browser, 10)
    wait.until(lambda d: d.find_elements(By.CSS_SELECTOR, '.stv-view[data-stv-revision="0"]'))
    root = browser.find_element(By.CSS_SELECTOR, '.stv-view')
    viewport = root.find_element(By.CSS_SELECTOR, '.stv-viewport')
    assert browser.execute_script('return getComputedStyle(arguments[0]).height', viewport) == '975px'
    node = root.find_element(By.CSS_SELECTOR, '.stv-node')
    details = node.find_element(By.CSS_SELECTOR, '[data-focus="details"]')
    toolbar = root.find_element(By.CSS_SELECTOR, '.stv-toolbar button')
    ActionChains(browser).move_to_element(node).perform()
    time.sleep(.3)
    assert not browser.find_elements(By.CSS_SELECTOR, '.stv-detail')
    ActionChains(browser).move_to_element(toolbar).perform()
    time.sleep(1.1)
    assert not browser.find_elements(By.CSS_SELECTOR, '.stv-detail')
    # Measure the actual deadline, independently of WebDriver command latency.
    browser.execute_script("""
      window.hoverTimes={};
      arguments[0].addEventListener('mouseenter',()=>{hoverTimes.node=performance.now()},{once:true});
      arguments[1].addEventListener('mouseenter',()=>{hoverTimes.button=performance.now()},{once:true});
      const observer=new MutationObserver(()=>{if(document.querySelector('.stv-detail')){
        hoverTimes.open=performance.now();observer.disconnect();}});
      observer.observe(document.body,{childList:true});
    """,node,details)
    ActionChains(browser).move_to_element_with_offset(node,-node.size['width']/2+8,-node.size['height']/2+8).perform()
    time.sleep(.5)
    ActionChains(browser).move_to_element(details).perform()
    wait.until(lambda d: d.find_elements(By.CSS_SELECTOR, '.stv-detail'))
    times=browser.execute_script('return hoverTimes')
    assert 950 <= times['open']-times['node'] < 1500, times
    assert 0 <= times['open']-times['button'] < 850, times
    # Hover did not focus the view: real Escape must still dismiss it.
    browser.execute_script('document.body.tabIndex=-1;document.body.focus()')
    browser.switch_to.active_element.send_keys(Keys.ESCAPE)
    assert not browser.find_elements(By.CSS_SELECTOR,'.stv-detail')
    ActionChains(browser).move_to_element(toolbar).perform()
    ActionChains(browser).move_to_element(node).perform()
    time.sleep(.2)
    browser.switch_to.active_element.send_keys(Keys.ESCAPE)
    time.sleep(1.1)
    assert not browser.find_elements(By.CSS_SELECTOR,'.stv-detail')
    browser.execute_script('arguments[0].focus()', details)
    details.send_keys(Keys.ENTER)
    assert browser.find_elements(By.CSS_SELECTOR, '.stv-persistent-detail')
    browser.switch_to.active_element.send_keys(Keys.ESCAPE)
    assert browser.find_elements(By.CSS_SELECTOR, '.stv-persistent-detail')
    browser.find_element(By.CSS_SELECTOR,'.stv-persistent-detail button').send_keys(Keys.ENTER)
    assert not browser.find_elements(By.CSS_SELECTOR, '.stv-detail')
    assert browser.switch_to.active_element == details
    # Last, test each cancellation from the same reset viewport, with no
    # pointer departure after the action masking whether it cancels the timer.
    for selector in ('[aria-label="Pan right"]','.stv-groups button'):
        browser.execute_script("arguments[0].querySelector('[aria-label=\"Reset viewport\"]').click()",root)
        ActionChains(browser).move_to_element(toolbar).perform()
        ActionChains(browser).move_to_element(node).perform()
        time.sleep(.2)
        browser.execute_script('arguments[0].querySelector(arguments[1]).click()',root,selector)
        wait.until(lambda d:root.get_attribute('aria-busy')=='false')
        time.sleep(1.1)
        assert not browser.find_elements(By.CSS_SELECTOR,'.stv-detail')

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_017: large project at visible capacity

Test case: large project at visible capacity STV_TC_SY_017
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_capacity.py :: docs/test-scripts/test_capacity.py::test_large_project_at_visible_capacity[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_capacity.py::test_large_project_at_visible_capacity[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_capacity.py::test_large_project_at_visible_capacity[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_large_project_at_visible_capacity(browser,protocol):
    output=Path(os.environ.get('STV_CAPACITY_OUTPUT','docs/_build/benchmark-v2/html')).resolve()
    assert (output/'index.html').is_file(),'Run scripts/benchmark.py before capacity verification'
    runs=[]
    browser.set_script_timeout(35)
    temporary=tempfile.TemporaryDirectory(prefix='stv-cap-') if protocol=='file' else None
    if temporary:
        assert Path(temporary.name).resolve().is_relative_to(Path(tempfile.gettempdir()).resolve())
        # Full hash names need a short physical output root in Windows Firefox.
        short=Path(temporary.name)/'html';shutil.copytree(output,short);output=short
    try:
        _measure_capacity(browser,output,protocol,runs)
    finally:
        if temporary:
            assert Path(temporary.name).resolve().is_relative_to(Path(tempfile.gettempdir()).resolve())
            temporary.cleanup()
    result={'browser':browser.capabilities['browserVersion'],'geckodriver':browser.capabilities.get('moz:geckodriverVersion'),
            'memory_scope':'Sum of working sets of the isolated Firefox process tree, including content/GPU helpers; shared pages may be counted more than once',
            'runs':runs,'startup_median_ms':statistics.median(r['startup_ms'] for r in runs),
            'startup_max_ms':max(r['startup_ms'] for r in runs),
            'expansion_median_ms':statistics.median(v for r in runs for v in r['expansion_ms']),
            'expansion_max_ms':max(v for r in runs for v in r['expansion_ms'])}
    target=Path(os.environ.get('STV_CAPACITY_METRICS','docs/_build/capacity-browser.json'));target.parent.mkdir(parents=True,exist_ok=True)
    aggregate=json.loads(target.read_text(encoding='utf-8')) if target.exists() else {}
    aggregate[protocol]=result
    target.write_text(json.dumps(aggregate,indent=2),encoding='utf-8')

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_018: invalid mapping has entry path and location

Test case: invalid mapping has entry path and location STV_TC_SY_018
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_invalid_mapping_has_entry_path_and_location
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_invalid_mapping_has_entry_path_and_location.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_invalid_mapping_has_entry_path_and_location" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_invalid_mapping_has_entry_path_and_location(tmp_path):
    source=tmp_path/'source';shutil.copytree(FIXTURE,source)
    with (source/'conf.py').open('a',encoding='utf-8') as stream:
        stream.write('\ntraceability_view_model["types"]["shr"]["level"]="unknown"\n')
    result=build(source,tmp_path/'html')
    assert result.returncode!=0
    assert 'index.rst:8' in result.stderr
    assert 'types.shr' in result.stderr

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_019: seed selection release

Test case: seed selection release STV_TC_SY_019
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_release_seeds.py :: docs/test-scripts/test_release_seeds.py::test_seed_selection_release[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_release_seeds.py::test_seed_selection_release[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_release_seeds.py::test_seed_selection_release[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_seed_selection_release(browser,short_output,protocol):
    source=short_output/'source';shutil.copytree(FIXTURE,source)
    requirements='Requirements\n============\n\n'
    for i in range(12):
        requirements+=f'.. shr:: Goal {i}\n   :id: GOAL_{i:03}\n'
        if i==0:
            requirements+='   :traces: '+', '.join(f'CHILD_{j}' for j in range(5))+'\n'
        requirements+='\n'
    requirements+='.. shr:: Secret hidden title\n   :id: HIDDEN_A\n   :hide:\n\n'
    requirements+='\n'.join(f'.. swr:: Software child {j}\n   :id: CHILD_{j}\n' for j in range(5))
    (source/'requirements.rst').write_text(requirements,encoding='utf-8')
    (source/'index.rst').write_text('Project\n=======\n\n.. toctree::\n\n   requirements\n\n.. traceability-view::\n\n.. traceability-view:: GOAL_000\n',encoding='utf-8')
    output=short_output/'html';result=build(source,output);assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,20)
        wait.until(lambda d:len(d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))==2)
        roots=browser.find_elements(By.CSS_SELECTOR,'.stv-view');root=roots[0]
        field=root.find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==[f'GOAL_{i:03}' for i in range(5)]
        field.send_keys('software child')
        assert root.get_attribute('data-stv-revision')=='0'
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-seed-matches [role="option"]'))==5
        field.send_keys(Keys.ESCAPE)
        assert field.get_attribute('aria-expanded')=='false'
        field.send_keys(Keys.CONTROL,'a');field.send_keys(Keys.BACKSPACE);field.send_keys('software child')
        root.find_elements(By.CSS_SELECTOR,'.stv-seed-matches [role="option"]')[2].click()
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['CHILD_2']
        assert browser.switch_to.active_element==field
        for invalid in ['', 'HIDDEN_A', 'Secret hidden', 'goal_000']:
            field.send_keys(Keys.CONTROL,'a');field.send_keys(Keys.BACKSPACE)
            if invalid:field.send_keys(invalid)
            if invalid!='goal_000':
                assert not root.find_elements(By.CSS_SELECTOR,'.stv-seed-matches [role="option"]')
            field.send_keys(Keys.ENTER)
            assert field.get_attribute('aria-invalid')=='true'
            assert root.get_attribute('data-stv-revision')=='1'
        field.send_keys(Keys.CONTROL,'a');field.send_keys(Keys.BACKSPACE);field.send_keys(' GOAL_000 ');field.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='2')
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['GOAL_000']
        control=root.find_element(By.CSS_SELECTOR,'[aria-label="Expand Traces (outgoing) for GOAL_000"]')
        browser.execute_script('arguments[0].click()',control)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='3')
        boxes=browser.execute_script("""return Object.fromEntries([...arguments[0].querySelectorAll('.stv-node')].map(n=>[n.querySelector('.stv-id').textContent,{x:parseFloat(n.style.left),w:n.offsetWidth}]))""",root)
        children=[boxes[f'CHILD_{i}'] for i in range(5)]
        midpoint=(min(n['x'] for n in children)+max(n['x']+n['w'] for n in children))/2
        assert abs(boxes['GOAL_000']['x']+boxes['GOAL_000']['w']/2-midpoint)<1
        root.find_element(By.XPATH,'.//button[text()="Project overview"]').click()
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='4')
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-node'))==6
        assert roots[1].get_attribute('data-stv-revision')=='0'
        other=roots[1].find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        other.send_keys('CHILD_4');other.send_keys(Keys.ENTER)
        wait.until(lambda d:roots[1].get_attribute('data-stv-revision')=='1')
        assert root.get_attribute('data-stv-revision')=='4'
        assert [n.text for n in roots[1].find_elements(By.CSS_SELECTOR,'.stv-id')]==['CHILD_4']

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_020: async layout failure and stale completion

Test case: async layout failure and stale completion STV_TC_SY_020
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_async_layout_failure_and_stale_completion[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_async_layout_failure_and_stale_completion[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_async_layout_failure_and_stale_completion[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_async_layout_failure_and_stale_completion(browser,short_output,protocol):
    project=Path(__file__).parents[1]
    script="import{build}from'esbuild';await build({entryPoints:[process.argv[1]],bundle:true,format:'iife',outfile:process.argv[2]})"
    result=subprocess.run(['node','--input-type=module','-e',script,str(project/'docs/test-scripts/fixtures/browser-harness.js'),str(short_output/'harness.js')],cwd=project/'frontend',capture_output=True,text=True)
    assert result.returncode==0,result.stderr
    (short_output/'index.html').write_text('<link rel="stylesheet" href="'+(project/'src/sphinx_traceability_view/static/stv.css').as_uri()+'"><div class="stv-view" id="test-view" data-stv-seeds=\'["A"]\'></div><script src="harness.js"></script>',encoding='utf-8')
    # Keep the host alive across all injected completions.
    with published_url(short_output,protocol) as url:
        browser.get(url)
        _assert_async_layout(browser)

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_021: interactive seed smoke

Test case: interactive seed smoke STV_TC_SY_021
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_interactive_seed_smoke[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_interactive_seed_smoke[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_interactive_seed_smoke[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_interactive_seed_smoke(browser,short_output,protocol):
    output=short_output/'seed-picker';result=build(FIXTURE,output)
    assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,20)
        wait.until(lambda d:len(d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))==2)
        roots=browser.find_elements(By.CSS_SELECTOR,'.stv-view');root=roots[0]
        field=root.find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        field.send_keys('missing');field.send_keys(Keys.ENTER)
        assert field.get_attribute('aria-invalid')=='true'
        assert root.get_attribute('data-stv-revision')=='0'
        field.clear();field.send_keys('software detail')
        wait.until(lambda d:root.find_element(By.CSS_SELECTOR,'.stv-seed-matches').is_displayed())
        assert 'LEAF_B' in root.find_element(By.CSS_SELECTOR,'.stv-seed-matches').text
        field.send_keys(Keys.ARROW_DOWN);field.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['LEAF_B']
        assert roots[1].get_attribute('data-stv-revision')=='0'
        root.find_element(By.XPATH,'.//button[text()="Project overview"]').click()
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='2')
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-project'))==1
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['ROOT_A']
        centers=browser.execute_script("return [...arguments[0].querySelectorAll('.stv-node')].map(n=>parseFloat(n.style.left)+n.offsetWidth/2)",root)
        assert abs(centers[0]-centers[1])<1

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_022: invalid seed source location

Test case: invalid seed source location STV_TC_SY_022
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_invalid_seed_source_location[HIDDEN_A]
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_invalid_seed_source_location[HIDDEN_A].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_invalid_seed_source_location[HIDDEN_A]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_invalid_seed_source_location(tmp_path, seed):
    source = tmp_path / "source"
    shutil.copytree(FIXTURE, source)
    (source / "index.rst").write_text(f"Invalid\n=======\n\n.. toctree::\n\n   requirements\n\n.. traceability-view:: {seed}\n", encoding="utf-8")
    with (source / "requirements.rst").open("a", encoding="utf-8") as stream:
        stream.write("\n.. shr:: Hidden\n   :id: HIDDEN_A\n   :hide:\n")
    result = build(source, tmp_path / "html")
    assert result.returncode != 0
    assert "index.rst:8" in result.stderr
    assert "unknown or hidden starting ID" in result.stderr

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_023: seed capacity at directive

Test case: seed capacity at directive STV_TC_SY_023
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_seed_capacity_at_directive[201-False]
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_seed_capacity_at_directive[201-False].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_seed_capacity_at_directive[201-False]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_seed_capacity_at_directive(tmp_path, count, success):
    source = tmp_path / "source"
    shutil.copytree(FIXTURE, source)
    ids = [f"NEED_{i:03}" for i in range(count)]
    (source / "requirements.rst").write_text("Requirements\n============\n\n" + "\n".join(f".. shr:: Item {i}\n   :id: {identity}\n" for i, identity in enumerate(ids)), encoding="utf-8")
    (source / "index.rst").write_text("Capacity\n========\n\n.. toctree::\n\n   requirements\n\n.. traceability-view:: " + " ".join(ids) + "\n", encoding="utf-8")
    result = build(source, tmp_path / "html")
    assert (result.returncode == 0) is success, result.stderr
    if not success:
        assert "index.rst:8" in result.stderr
        assert "200 distinct starting IDs" in result.stderr

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_024: prior fatal exception is not replaced by bundle generation

Test case: prior fatal exception is not replaced by bundle generation STV_TC_SY_024
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: src/sphinx_traceability_view/directive/tests/test_lifecycle.py::test_prior_fatal_exception_is_not_replaced_by_bundle_generation
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: src/sphinx_traceability_view/directive/tests/test_lifecycle.py::test_prior_fatal_exception_is_not_replaced_by_bundle_generation.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "src/sphinx_traceability_view/directive/tests/test_lifecycle.py::test_prior_fatal_exception_is_not_replaced_by_bundle_generation" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_prior_fatal_exception_is_not_replaced_by_bundle_generation(tmp_path):
    from types import SimpleNamespace
    from sphinx_traceability_view.directive.lifecycle import finish
    page=tmp_path/'index.html';page.write_text('previous complete page',encoding='utf-8')
    app=SimpleNamespace(_stv_graph={},outdir=str(tmp_path))
    finish(app,RuntimeError('Earlier fatal failure'))
    assert page.read_text(encoding='utf-8')=='previous complete page'
    assert not (tmp_path/'_static').exists()

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_025: project paging

Test case: project paging STV_TC_SY_025
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_project_paging[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_project_paging[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_project_paging[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_project_paging(browser,short_output,protocol):
    import shutil
    source=short_output/'source';shutil.copytree(FIXTURE,source)
    (source/'requirements.rst').write_text('Requirements\n============\n\n'+'\n'.join(f'.. shr:: Stakeholder {i}\n   :id: GOAL_{i:03}\n' for i in range(201)),encoding='utf-8')
    (source/'index.rst').write_text('Project\n=======\n\n.. toctree::\n\n   requirements\n\n.. traceability-view::\n',encoding='utf-8')
    output=short_output/'html';result=build(source,output);assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url)
        _assert_project_pages(browser)

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_026: incremental body change hidden and deleted objects

Test case: incremental body change hidden and deleted objects STV_TC_SY_026
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_incremental_body_change_hidden_and_deleted_objects
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_incremental_body_change_hidden_and_deleted_objects.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_incremental_body_change_hidden_and_deleted_objects" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_incremental_body_change_hidden_and_deleted_objects(tmp_path):
    source = tmp_path / "source"
    shutil.copytree(FIXTURE, source)
    with (source / "requirements.rst").open("a", encoding="utf-8") as stream:
        stream.write('\n.. shr:: Initially visible\n   :id: HIDDEN_LATER\n')
    output = tmp_path / "html"
    assert build(source, output).returncode == 0
    old = manifest(output)
    path = source / "requirements.rst"
    path.write_text(path.read_text(encoding="utf-8").replace("formatted body", "changed rich body").replace(":id: HIDDEN_LATER", ":id: HIDDEN_LATER\n   :hide:"), encoding="utf-8")
    assert build(source, output).returncode == 0
    new = manifest(output)
    assert new["identity"] != old["identity"]
    assert new["details"]["ROOT_A"]["digest"] != old["details"]["ROOT_A"]["digest"]
    assert "HIDDEN_LATER" not in new["objects"]
    assert "HIDDEN_LATER" not in new["details"]
    assert build(source, output).returncode == 0
    assert manifest(output)["identity"] == new["identity"]

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_027: host owns broken trace failure

Test case: host owns broken trace failure STV_TC_SY_027
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_host_owns_broken_trace_failure
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_host_owns_broken_trace_failure.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_host_owns_broken_trace_failure" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_host_owns_broken_trace_failure(tmp_path):
    source = tmp_path / "source"
    shutil.copytree(FIXTURE, source)
    with (source / "conf.py").open("a", encoding="utf-8") as stream:
        stream.write('\nneeds_report_dead_links = True\n')
    path = source / "requirements.rst"
    path.write_text(path.read_text(encoding="utf-8").replace(":traces: LEAF_B", ":traces: MISSING_A"), encoding="utf-8")
    output = tmp_path / "html"
    result = build(source, output)
    assert result.returncode != 0
    assert "MISSING_A" in result.stderr
    assert "STV_PENDING" not in (output / "index.html").read_text(encoding="utf-8")
    data = manifest(output)
    assert ["ROOT_A", "traces", "MISSING_A"] in data["edges"]
    assert "MISSING_A" not in data["objects"]

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_028: seed selection release

Test case: seed selection release STV_TC_SY_028
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_release_seeds.py :: docs/test-scripts/test_release_seeds.py::test_seed_selection_release[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_release_seeds.py::test_seed_selection_release[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_release_seeds.py::test_seed_selection_release[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_seed_selection_release(browser,short_output,protocol):
    source=short_output/'source';shutil.copytree(FIXTURE,source)
    requirements='Requirements\n============\n\n'
    for i in range(12):
        requirements+=f'.. shr:: Goal {i}\n   :id: GOAL_{i:03}\n'
        if i==0:
            requirements+='   :traces: '+', '.join(f'CHILD_{j}' for j in range(5))+'\n'
        requirements+='\n'
    requirements+='.. shr:: Secret hidden title\n   :id: HIDDEN_A\n   :hide:\n\n'
    requirements+='\n'.join(f'.. swr:: Software child {j}\n   :id: CHILD_{j}\n' for j in range(5))
    (source/'requirements.rst').write_text(requirements,encoding='utf-8')
    (source/'index.rst').write_text('Project\n=======\n\n.. toctree::\n\n   requirements\n\n.. traceability-view::\n\n.. traceability-view:: GOAL_000\n',encoding='utf-8')
    output=short_output/'html';result=build(source,output);assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,20)
        wait.until(lambda d:len(d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))==2)
        roots=browser.find_elements(By.CSS_SELECTOR,'.stv-view');root=roots[0]
        field=root.find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==[f'GOAL_{i:03}' for i in range(5)]
        field.send_keys('software child')
        assert root.get_attribute('data-stv-revision')=='0'
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-seed-matches [role="option"]'))==5
        field.send_keys(Keys.ESCAPE)
        assert field.get_attribute('aria-expanded')=='false'
        field.send_keys(Keys.CONTROL,'a');field.send_keys(Keys.BACKSPACE);field.send_keys('software child')
        root.find_elements(By.CSS_SELECTOR,'.stv-seed-matches [role="option"]')[2].click()
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['CHILD_2']
        assert browser.switch_to.active_element==field
        for invalid in ['', 'HIDDEN_A', 'Secret hidden', 'goal_000']:
            field.send_keys(Keys.CONTROL,'a');field.send_keys(Keys.BACKSPACE)
            if invalid:field.send_keys(invalid)
            if invalid!='goal_000':
                assert not root.find_elements(By.CSS_SELECTOR,'.stv-seed-matches [role="option"]')
            field.send_keys(Keys.ENTER)
            assert field.get_attribute('aria-invalid')=='true'
            assert root.get_attribute('data-stv-revision')=='1'
        field.send_keys(Keys.CONTROL,'a');field.send_keys(Keys.BACKSPACE);field.send_keys(' GOAL_000 ');field.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='2')
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['GOAL_000']
        control=root.find_element(By.CSS_SELECTOR,'[aria-label="Expand Traces (outgoing) for GOAL_000"]')
        browser.execute_script('arguments[0].click()',control)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='3')
        boxes=browser.execute_script("""return Object.fromEntries([...arguments[0].querySelectorAll('.stv-node')].map(n=>[n.querySelector('.stv-id').textContent,{x:parseFloat(n.style.left),w:n.offsetWidth}]))""",root)
        children=[boxes[f'CHILD_{i}'] for i in range(5)]
        midpoint=(min(n['x'] for n in children)+max(n['x']+n['w'] for n in children))/2
        assert abs(boxes['GOAL_000']['x']+boxes['GOAL_000']['w']/2-midpoint)<1
        root.find_element(By.XPATH,'.//button[text()="Project overview"]').click()
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='4')
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-node'))==6
        assert roots[1].get_attribute('data-stv-revision')=='0'
        other=roots[1].find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        other.send_keys('CHILD_4');other.send_keys(Keys.ENTER)
        wait.until(lambda d:roots[1].get_attribute('data-stv-revision')=='1')
        assert root.get_attribute('data-stv-revision')=='4'
        assert [n.text for n in roots[1].find_elements(By.CSS_SELECTOR,'.stv-id')]==['CHILD_4']

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_029: host default directional labels are used

Test case: host default directional labels are used STV_TC_SY_029
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_host_default_directional_labels_are_used
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_host_default_directional_labels_are_used.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_host_default_directional_labels_are_used" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_host_default_directional_labels_are_used(tmp_path):
    source=tmp_path/'source';shutil.copytree(FIXTURE,source)
    with (source/'conf.py').open('a',encoding='utf-8') as stream:
        stream.write('\nneeds_links={"traces":{}}\n')
    output=tmp_path/'html';result=build(source,output)
    assert result.returncode==0,result.stderr
    assert manifest(output)['model']['relations']['traces']=={'incoming':'traces incoming','outgoing':'traces'}

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_030: offline exploration

Test case: offline exploration STV_TC_SY_030

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_offline_exploration[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_offline_exploration[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_offline_exploration(browser, short_output, protocol):
    tmp_path = short_output
    output = tmp_path / "nested" / "documentation"
    result = build(FIXTURE, output)
    assert result.returncode == 0, result.stderr
    server = None
    try:
        if protocol == "http":
            server = ThreadingHTTPServer(("127.0.0.1", 0), partial(SimpleHTTPRequestHandler, directory=str(tmp_path)))
            threading.Thread(target=server.serve_forever, daemon=True).start()
            url = f"http://127.0.0.1:{server.server_port}/nested/documentation/index.html"
        else:
            url = (output / "index.html").as_uri()
        browser.get(url)
        wait = WebDriverWait(browser, 20)
        wait.until(lambda d: len(d.find_elements(By.CSS_SELECTOR, '.stv-view[data-stv-revision="0"]')) == 2)
        roots = browser.find_elements(By.CSS_SELECTOR, ".stv-view")
        assert len(roots[0].find_elements(By.CSS_SELECTOR, ".stv-node")) == 2
        assert len(roots[1].find_elements(By.CSS_SELECTOR, ".stv-node")) == 2
        root_button = roots[1].find_element(By.CSS_SELECTOR, '[data-focus="root"]')
        browser.execute_script("arguments[0].focus()", root_button)
        root_button.send_keys(Keys.ENTER)
        wait.until(lambda d: roots[1].get_attribute("data-stv-revision") == "1")
        assert len(roots[1].find_elements(By.CSS_SELECTOR, ".stv-node")) == 1
        assert roots[0].get_attribute("data-stv-revision") == "0"
        inspect = roots[0].find_element(By.CSS_SELECTOR, '[aria-label="Details for ROOT_A"]')
        browser.execute_script("arguments[0].focus()", inspect)
        inspect.send_keys(Keys.ENTER)
        try:
            wait.until(lambda d: "formatted body" in d.find_element(By.CSS_SELECTOR, ".stv-detail").text)
        except Exception:
            print(browser.find_element(By.CSS_SELECTOR, ".stv-detail").get_attribute("outerHTML"))
            raise
        assert browser.find_elements(By.CSS_SELECTOR, ".stv-detail table")
        browser.switch_to.active_element.send_keys(Keys.ESCAPE)
        assert browser.find_elements(By.CSS_SELECTOR,'.stv-persistent-detail')
        browser.find_element(By.CSS_SELECTOR,'.stv-persistent-detail button').send_keys(Keys.ENTER)
        wait.until(lambda d: not d.find_elements(By.CSS_SELECTOR, ".stv-detail"))
        assert browser.switch_to.active_element == inspect
        assert roots[0].find_element(By.CSS_SELECTOR, '.stv-node.stv-unaccepted .stv-id').text == 'LEAF_B'
        assert roots[0].find_element(By.CSS_SELECTOR, '.stv-node:not(.stv-unaccepted) .stv-id').text == 'ROOT_A'
        # Pointer hover presents the same final host fragment; pointer travel
        # into the interactive panel keeps it open beyond the dismissal grace.
        ActionChains(browser).move_to_element(inspect).perform()
        wait.until(lambda d: d.find_elements(By.CSS_SELECTOR, '.stv-detail'))
        panel=browser.find_element(By.CSS_SELECTOR,'.stv-detail')
        ActionChains(browser).move_to_element(panel).perform()
        wait.until(lambda d: 'formatted body' in panel.text)
        assert browser.execute_script('return arguments[0].getBoundingClientRect().right <= innerWidth',panel)
        assert browser.execute_script('return arguments[0].getBoundingClientRect().bottom <= innerHeight',panel)
        panel.find_element(By.CSS_SELECTOR,'button').click()
        # View-local transforms are shared by edge and node layers.
        other_transform=roots[1].find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style')
        for label in ['Zoom in','Pan right','Pan down']:
            control=roots[0].find_element(By.CSS_SELECTOR,f'[aria-label="{label}"]')
            browser.execute_script('arguments[0].focus()',control);control.send_keys(Keys.ENTER)
        assert roots[1].find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style') == other_transform
        roots[0].find_element(By.CSS_SELECTOR,'[aria-label="Reset viewport"]').click()
        viewport=roots[0].find_element(By.CSS_SELECTOR,'.stv-viewport')
        scene=roots[0].find_element(By.CSS_SELECTOR,'.stv-scene')
        before_drag=scene.get_attribute('style')
        x,y=browser.execute_script('const r=arguments[0].getBoundingClientRect();return [Math.min(r.right,innerWidth)-20,Math.min(r.bottom,innerHeight)-20]',viewport)
        drag=ActionChains(browser)
        drag.w3c_actions.pointer_action.move_to_location(x,y)
        drag.click_and_hold().move_by_offset(-80,-60).release().perform()
        wait.until(lambda d:scene.get_attribute('style')!=before_drag)
        before_wheel=scene.get_attribute('style')
        ActionChains(browser).scroll_from_origin(ScrollOrigin.from_element(viewport),0,-120).perform()
        wait.until(lambda d:scene.get_attribute('style')!=before_wheel)
        assert len(browser.window_handles)==1
        assert roots[1].find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style') == other_transform
        roots[0].find_element(By.CSS_SELECTOR,'[aria-label="Reset viewport"]').click()
        group=roots[0].find_element(By.CSS_SELECTOR,'[aria-label="Expand Traces (outgoing) for ROOT_A"]')
        browser.execute_script('arguments[0].focus()',group);group.send_keys(Keys.ENTER)
        wait.until(lambda d: roots[0].get_attribute('data-stv-revision')=='1')
        assert len(roots[0].find_elements(By.CSS_SELECTOR,'.stv-node'))==2
        assert len(roots[0].find_elements(By.CSS_SELECTOR,'.stv-edges polyline'))==1
        reverse=roots[0].find_element(By.CSS_SELECTOR,'[aria-label="Expand Traced by (incoming) for LEAF_B"]')
        browser.execute_script('arguments[0].focus()',reverse);reverse.send_keys(Keys.ENTER)
        wait.until(lambda d:roots[0].get_attribute('data-stv-revision')=='2')
        assert len(roots[0].find_elements(By.CSS_SELECTOR,'.stv-edges polyline'))==1
        original=roots[0].find_element(By.CSS_SELECTOR,'.stv-summary')
        before=browser.current_window_handle
        browser.execute_script('arguments[0].focus()',original);original.send_keys(Keys.ENTER)
        wait.until(lambda d: len(d.window_handles)==2)
        browser.switch_to.window(next(handle for handle in browser.window_handles if handle!=before))
        wait.until(lambda d:d.current_url.endswith('requirements.html#ROOT_A'))
        wait.until(lambda d:d.find_elements(By.ID,'ROOT_A'))
        assert browser.current_url.endswith('requirements.html#ROOT_A')
        browser.close();browser.switch_to.window(before)
        # The card background belongs to the original-object anchor; separate
        # group/detail controls remain above that stretched hit region.
        card=roots[0].find_element(By.CSS_SELECTOR,'[data-key*="ROOT_A"]')
        ActionChains(browser).move_to_element_with_offset(card,-card.size['width']/2+3,-card.size['height']/2+3).click().perform()
        wait.until(lambda d:len(d.window_handles)==2)
        browser.switch_to.window(next(handle for handle in browser.window_handles if handle!=before))
        wait.until(lambda d:d.current_url.endswith('requirements.html#ROOT_A'))
        wait.until(lambda d:d.find_elements(By.ID,'ROOT_A'))
        assert browser.current_url.endswith('requirements.html#ROOT_A')
        browser.close();browser.switch_to.window(before)
        artifact = os.environ.get("STV_SCREENSHOTS")
        if artifact:
            Path(artifact).mkdir(parents=True, exist_ok=True)
            browser.save_screenshot(str(Path(artifact) / f"{protocol}-example.png"))
    finally:
        if server:
            server.shutdown()
            server.server_close()

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_031: project paging

Test case: project paging STV_TC_SY_031
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_project_paging[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_project_paging[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_project_paging[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_project_paging(browser,short_output,protocol):
    import shutil
    source=short_output/'source';shutil.copytree(FIXTURE,source)
    (source/'requirements.rst').write_text('Requirements\n============\n\n'+'\n'.join(f'.. shr:: Stakeholder {i}\n   :id: GOAL_{i:03}\n' for i in range(201)),encoding='utf-8')
    (source/'index.rst').write_text('Project\n=======\n\n.. toctree::\n\n   requirements\n\n.. traceability-view::\n',encoding='utf-8')
    output=short_output/'html';result=build(source,output);assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url)
        _assert_project_pages(browser)

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_032: async layout failure and stale completion

Test case: async layout failure and stale completion STV_TC_SY_032
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_browser.py :: docs/test-scripts/test_browser.py::test_async_layout_failure_and_stale_completion[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_async_layout_failure_and_stale_completion[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_async_layout_failure_and_stale_completion[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_async_layout_failure_and_stale_completion(browser,short_output,protocol):
    project=Path(__file__).parents[1]
    script="import{build}from'esbuild';await build({entryPoints:[process.argv[1]],bundle:true,format:'iife',outfile:process.argv[2]})"
    result=subprocess.run(['node','--input-type=module','-e',script,str(project/'docs/test-scripts/fixtures/browser-harness.js'),str(short_output/'harness.js')],cwd=project/'frontend',capture_output=True,text=True)
    assert result.returncode==0,result.stderr
    (short_output/'index.html').write_text('<link rel="stylesheet" href="'+(project/'src/sphinx_traceability_view/static/stv.css').as_uri()+'"><div class="stv-view" id="test-view" data-stv-seeds=\'["A"]\'></div><script src="harness.js"></script>',encoding='utf-8')
    # Keep the host alive across all injected completions.
    with published_url(short_output,protocol) as url:
        browser.get(url)
        _assert_async_layout(browser)

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_033: alternate model geometry details and external

Test case: alternate model geometry details and external STV_TC_SY_033

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_alternate_model_geometry_details_and_external[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_alternate_model_geometry_details_and_external[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_alternate_model_geometry_details_and_external(browser,short_output,protocol):
    output=short_output/'html';result=build(FIXTURE.parent/'alternate_model',output);assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,30)
        wait.until(lambda d:len(d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))==3)
        roots=browser.find_elements(By.CSS_SELECTOR,'.stv-view');root=roots[0]
        assert browser.execute_script('''const n=arguments[0].querySelector('.stv-node').getBoundingClientRect(),v=arguments[0].querySelector('.stv-viewport').getBoundingClientRect();return n.top>=v.top&&n.bottom<=v.bottom''',root)
        def group(identity,direction):
            return root.find_element(By.CSS_SELECTOR,f'[aria-label="Expand Traces {"to" if direction=="outgoing" else "from"} ({direction}) for {identity}"]')
        control=group('SOFTWARE_A','outgoing');browser.execute_script('arguments[0].focus()',control);control.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        control=group('GOAL_A','outgoing');browser.execute_script('arguments[0].focus()',control);control.send_keys(Keys.ENTER)
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='2')
        boxes=browser.execute_script('''return Object.fromEntries([...arguments[0].querySelectorAll('.stv-nodes>.stv-node')].map(n=>[n.querySelector('.stv-id').textContent,{x:parseFloat(n.style.left),y:parseFloat(n.style.top),width:n.offsetWidth,height:n.offsetHeight}]))''',root)
        assert len(boxes)==6
        assert 'HIDDEN_A' not in boxes
        for a,b in zip(['GOAL_A','HARDWARE_A','SYSTEM_A','SOFTWARE_A'],['HARDWARE_A','SYSTEM_A','SOFTWARE_A','MODULE_A']):assert boxes[a]['y']+boxes[a]['height']<boxes[b]['y']
        assert boxes['CHECK_A']['x']>=max(v['x']+v['width'] for k,v in boxes.items() if k!='CHECK_A')+96
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-edges polyline'))==7
        assert browser.execute_script('''const title=arguments[0].querySelector('[data-key*="GOAL_A"] .stv-title');return title.scrollHeight>title.clientHeight&&title.clientHeight<=2*parseFloat(getComputedStyle(title).lineHeight)+1''',root)
        long_id=roots[1].find_element(By.CSS_SELECTOR,'[data-key*=LONG_IDENTIFIER] .stv-id')
        assert long_id.get_attribute('textContent')=='LONG_IDENTIFIER_WITH_MANY_SEGMENTS_ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789'
        assert browser.execute_script('return arguments[0].scrollWidth<=arguments[0].clientWidth',long_id)
        assert len(roots[1].find_elements(By.CSS_SELECTOR,'.stv-unaccepted'))==2
        # A part seed inspects the complete published containing Need.
        part=roots[2].find_element(By.CSS_SELECTOR,'[aria-label="Details for GOAL_A.fragment"]')
        browser.execute_script('arguments[0].focus()',part);part.send_keys(Keys.ENTER)
        wait.until(lambda d:'Static widget text' in d.find_element(By.CSS_SELECTOR,'.stv-detail').text)
        panel=browser.find_element(By.CSS_SELECTOR,'.stv-detail')
        metadata=panel.find_element(By.CSS_SELECTOR,'.needs_collapse')
        assert metadata.get_attribute('aria-expanded')=='false'
        browser.execute_script('arguments[0].click()',metadata)
        assert 'Fixture owner' in panel.text
        assert 'Resource unavailable offline' in panel.text
        assert not panel.find_elements(By.CSS_SELECTOR,'script,iframe,object,[onerror]')
        assert not browser.execute_script('return window.STV_WIDGET_EXECUTED===true')
        assert panel.find_element(By.CSS_SELECTOR,'img[data-stv-src]').get_attribute('complete')=='true'
        assert browser.execute_script('return arguments[0].naturalWidth',panel.find_element(By.CSS_SELECTOR,'img[data-stv-src]'))>0
        assert browser.execute_script('return arguments[0].naturalWidth',panel.find_element(By.CSS_SELECTOR,'.fixture-widget img'))>0
        label=panel.find_element(By.CSS_SELECTOR,'label');field=panel.find_element(By.CSS_SELECTOR,'input')
        assert label.get_attribute('for')==field.get_attribute('id')
        assert field.get_attribute('id').startswith(panel.get_attribute('id'))
        assert 'HIDDEN_A' not in panel.text
        assert not browser.execute_script("return performance.getEntriesByType('resource').some(e=>e.name.includes('example.invalid'))")
        assert browser.execute_script('return arguments[0].scrollHeight>arguments[0].clientHeight',panel)
        browser.execute_script('arguments[0].focus()',panel);panel.send_keys(Keys.END)
        wait.until(lambda d:browser.execute_script('return arguments[0].scrollTop>0',panel))
        original=panel.find_element(By.CSS_SELECTOR,'a[href*="example.invalid/remote.png"]')
        assert original.text=='Original resource'
        panel.find_element(By.CSS_SELECTOR,'button').click()
        external=roots[1].find_element(By.CSS_SELECTOR,'[aria-label="Details for EXTERNAL_A"]')
        browser.execute_script('arguments[0].focus()',external);external.send_keys(Keys.ENTER)
        wait.until(lambda d:'External owner' in d.find_element(By.CSS_SELECTOR,'.stv-detail').text)
        assert 'full body unavailable offline' in browser.find_element(By.CSS_SELECTOR,'.stv-detail').text
        browser.find_element(By.CSS_SELECTOR,'.stv-detail button').click()
        isolated=roots[1].find_element(By.CSS_SELECTOR,'.stv-unaccepted')
        browser.execute_script('arguments[0].focus()',isolated.find_element(By.CSS_SELECTOR,'[data-focus="details"]'))
        wait.until(lambda d:isolated.find_element(By.CSS_SELECTOR,'.stv-id').text=='ISOLATED_A')
        assert isolated.find_element(By.CSS_SELECTOR,'.stv-id').text=='ISOLATED_A'
        assert 'No relationships' in isolated.text
        assert not isolated.find_elements(By.CSS_SELECTOR,'.stv-groups button')

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_034: empty seed catalog

Test case: empty seed catalog STV_TC_SY_034
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_release_seeds.py :: docs/test-scripts/test_release_seeds.py::test_empty_seed_catalog[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_release_seeds.py::test_empty_seed_catalog[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_release_seeds.py::test_empty_seed_catalog[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_empty_seed_catalog(browser,short_output,protocol):
    source=short_output/'source';shutil.copytree(FIXTURE,source)
    (source/'requirements.rst').write_text('Requirements\n============\n',encoding='utf-8')
    (source/'index.rst').write_text('Project\n=======\n\n.. toctree::\n\n   requirements\n\n.. traceability-view::\n',encoding='utf-8')
    output=short_output/'html';result=build(source,output);assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,20)
        wait.until(lambda d:d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))
        root=browser.find_element(By.CSS_SELECTOR,'.stv-view')
        assert 'No stakeholder requirements.' in root.text
        assert not root.find_elements(By.CSS_SELECTOR,'[data-focus="root"],[data-focus="Next"]')
        field=root.find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        field.send_keys('anything');field.send_keys(Keys.ARROW_UP);field.send_keys(Keys.ENTER)
        assert field.get_attribute('aria-invalid')=='true'
        assert field.get_attribute('aria-expanded')=='false'
        assert root.get_attribute('data-stv-revision')=='0'
        root.find_element(By.XPATH,'.//button[text()="Project overview"]').click()
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-node'))==1

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_035: large project at visible capacity

Test case: large project at visible capacity STV_TC_SY_035
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_capacity.py :: docs/test-scripts/test_capacity.py::test_large_project_at_visible_capacity[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_capacity.py::test_large_project_at_visible_capacity[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_capacity.py::test_large_project_at_visible_capacity[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_large_project_at_visible_capacity(browser,protocol):
    output=Path(os.environ.get('STV_CAPACITY_OUTPUT','docs/_build/benchmark-v2/html')).resolve()
    assert (output/'index.html').is_file(),'Run scripts/benchmark.py before capacity verification'
    runs=[]
    browser.set_script_timeout(35)
    temporary=tempfile.TemporaryDirectory(prefix='stv-cap-') if protocol=='file' else None
    if temporary:
        assert Path(temporary.name).resolve().is_relative_to(Path(tempfile.gettempdir()).resolve())
        # Full hash names need a short physical output root in Windows Firefox.
        short=Path(temporary.name)/'html';shutil.copytree(output,short);output=short
    try:
        _measure_capacity(browser,output,protocol,runs)
    finally:
        if temporary:
            assert Path(temporary.name).resolve().is_relative_to(Path(tempfile.gettempdir()).resolve())
            temporary.cleanup()
    result={'browser':browser.capabilities['browserVersion'],'geckodriver':browser.capabilities.get('moz:geckodriverVersion'),
            'memory_scope':'Sum of working sets of the isolated Firefox process tree, including content/GPU helpers; shared pages may be counted more than once',
            'runs':runs,'startup_median_ms':statistics.median(r['startup_ms'] for r in runs),
            'startup_max_ms':max(r['startup_ms'] for r in runs),
            'expansion_median_ms':statistics.median(v for r in runs for v in r['expansion_ms']),
            'expansion_max_ms':max(v for r in runs for v in r['expansion_ms'])}
    target=Path(os.environ.get('STV_CAPACITY_METRICS','docs/_build/capacity-browser.json'));target.parent.mkdir(parents=True,exist_ok=True)
    aggregate=json.loads(target.read_text(encoding='utf-8')) if target.exists() else {}
    aggregate[protocol]=result
    target.write_text(json.dumps(aggregate,indent=2),encoding='utf-8')

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_036: seed layout replacement failure and staleness

Test case: seed layout replacement failure and staleness STV_TC_SY_036
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_release_seeds.py :: docs/test-scripts/test_release_seeds.py::test_seed_layout_replacement_failure_and_staleness[http]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_release_seeds.py::test_seed_layout_replacement_failure_and_staleness[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_release_seeds.py::test_seed_layout_replacement_failure_and_staleness[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_seed_layout_replacement_failure_and_staleness(browser,short_output,protocol):
    from pathlib import Path
    project=Path(__file__).parents[1]
    script="import{build}from'esbuild';await build({entryPoints:[process.argv[1]],bundle:true,format:'iife',outfile:process.argv[2]})"
    result=subprocess.run(['node','--input-type=module','-e',script,str(project/'docs/test-scripts/fixtures/browser-harness.js'),str(short_output/'harness.js')],cwd=project/'frontend',capture_output=True,text=True)
    assert result.returncode==0,result.stderr
    (short_output/'index.html').write_text('<link rel="stylesheet" href="'+(project/'src/sphinx_traceability_view/static/stv.css').as_uri()+'"><div class="stv-view" id="test-view" data-stv-seeds=\'["A"]\'></div><script src="harness.js"></script>',encoding='utf-8')
    with published_url(short_output,protocol) as url:
        browser.get(url);_assert_async_layout(browser)
        wait=WebDriverWait(browser,20);root=browser.find_element(By.CSS_SELECTOR,'.stv-view')
        field=root.find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        previous=root.find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style')
        field.send_keys('B');field.send_keys(Keys.ENTER)
        wait.until(lambda d:d.execute_script('return calls.length')==7)
        browser.execute_script('calls[6].reject(Error("Seed layout failure"))')
        wait.until(lambda d:'Seed layout failure' in root.find_element(By.CSS_SELECTOR,'.stv-status').text)
        assert root.get_attribute('data-stv-revision')=='2'
        assert root.find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style')==previous
        assert browser.switch_to.active_element==field
        for identity,count in [('A',8),('B',9)]:
            field.send_keys(Keys.CONTROL,'a');field.send_keys(Keys.BACKSPACE);field.send_keys(identity);field.send_keys(Keys.ENTER)
            wait.until(lambda d:d.execute_script('return calls.length')==count)
        browser.execute_script('stvHarness.compute(...calls[8].args).then(calls[8].resolve)')
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='3')
        browser.execute_script('stvHarness.compute(...calls[7].args).then(calls[7].resolve)')
        wait.until(lambda d:d.execute_script('return document.querySelectorAll(".stv-measure").length')==0)
        assert root.get_attribute('data-stv-revision')=='3'
        assert [n.text for n in root.find_elements(By.CSS_SELECTOR,'.stv-id')]==['B']
        assert browser.switch_to.active_element==field

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_037: offline exploration

Test case: offline exploration STV_TC_SY_037

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_browser.py::test_offline_exploration[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_browser.py::test_offline_exploration[http]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_offline_exploration(browser, short_output, protocol):
    tmp_path = short_output
    output = tmp_path / "nested" / "documentation"
    result = build(FIXTURE, output)
    assert result.returncode == 0, result.stderr
    server = None
    try:
        if protocol == "http":
            server = ThreadingHTTPServer(("127.0.0.1", 0), partial(SimpleHTTPRequestHandler, directory=str(tmp_path)))
            threading.Thread(target=server.serve_forever, daemon=True).start()
            url = f"http://127.0.0.1:{server.server_port}/nested/documentation/index.html"
        else:
            url = (output / "index.html").as_uri()
        browser.get(url)
        wait = WebDriverWait(browser, 20)
        wait.until(lambda d: len(d.find_elements(By.CSS_SELECTOR, '.stv-view[data-stv-revision="0"]')) == 2)
        roots = browser.find_elements(By.CSS_SELECTOR, ".stv-view")
        assert len(roots[0].find_elements(By.CSS_SELECTOR, ".stv-node")) == 2
        assert len(roots[1].find_elements(By.CSS_SELECTOR, ".stv-node")) == 2
        root_button = roots[1].find_element(By.CSS_SELECTOR, '[data-focus="root"]')
        browser.execute_script("arguments[0].focus()", root_button)
        root_button.send_keys(Keys.ENTER)
        wait.until(lambda d: roots[1].get_attribute("data-stv-revision") == "1")
        assert len(roots[1].find_elements(By.CSS_SELECTOR, ".stv-node")) == 1
        assert roots[0].get_attribute("data-stv-revision") == "0"
        inspect = roots[0].find_element(By.CSS_SELECTOR, '[aria-label="Details for ROOT_A"]')
        browser.execute_script("arguments[0].focus()", inspect)
        inspect.send_keys(Keys.ENTER)
        try:
            wait.until(lambda d: "formatted body" in d.find_element(By.CSS_SELECTOR, ".stv-detail").text)
        except Exception:
            print(browser.find_element(By.CSS_SELECTOR, ".stv-detail").get_attribute("outerHTML"))
            raise
        assert browser.find_elements(By.CSS_SELECTOR, ".stv-detail table")
        browser.switch_to.active_element.send_keys(Keys.ESCAPE)
        assert browser.find_elements(By.CSS_SELECTOR,'.stv-persistent-detail')
        browser.find_element(By.CSS_SELECTOR,'.stv-persistent-detail button').send_keys(Keys.ENTER)
        wait.until(lambda d: not d.find_elements(By.CSS_SELECTOR, ".stv-detail"))
        assert browser.switch_to.active_element == inspect
        assert roots[0].find_element(By.CSS_SELECTOR, '.stv-node.stv-unaccepted .stv-id').text == 'LEAF_B'
        assert roots[0].find_element(By.CSS_SELECTOR, '.stv-node:not(.stv-unaccepted) .stv-id').text == 'ROOT_A'
        # Pointer hover presents the same final host fragment; pointer travel
        # into the interactive panel keeps it open beyond the dismissal grace.
        ActionChains(browser).move_to_element(inspect).perform()
        wait.until(lambda d: d.find_elements(By.CSS_SELECTOR, '.stv-detail'))
        panel=browser.find_element(By.CSS_SELECTOR,'.stv-detail')
        ActionChains(browser).move_to_element(panel).perform()
        wait.until(lambda d: 'formatted body' in panel.text)
        assert browser.execute_script('return arguments[0].getBoundingClientRect().right <= innerWidth',panel)
        assert browser.execute_script('return arguments[0].getBoundingClientRect().bottom <= innerHeight',panel)
        panel.find_element(By.CSS_SELECTOR,'button').click()
        # View-local transforms are shared by edge and node layers.
        other_transform=roots[1].find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style')
        for label in ['Zoom in','Pan right','Pan down']:
            control=roots[0].find_element(By.CSS_SELECTOR,f'[aria-label="{label}"]')
            browser.execute_script('arguments[0].focus()',control);control.send_keys(Keys.ENTER)
        assert roots[1].find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style') == other_transform
        roots[0].find_element(By.CSS_SELECTOR,'[aria-label="Reset viewport"]').click()
        viewport=roots[0].find_element(By.CSS_SELECTOR,'.stv-viewport')
        scene=roots[0].find_element(By.CSS_SELECTOR,'.stv-scene')
        before_drag=scene.get_attribute('style')
        x,y=browser.execute_script('const r=arguments[0].getBoundingClientRect();return [Math.min(r.right,innerWidth)-20,Math.min(r.bottom,innerHeight)-20]',viewport)
        drag=ActionChains(browser)
        drag.w3c_actions.pointer_action.move_to_location(x,y)
        drag.click_and_hold().move_by_offset(-80,-60).release().perform()
        wait.until(lambda d:scene.get_attribute('style')!=before_drag)
        before_wheel=scene.get_attribute('style')
        ActionChains(browser).scroll_from_origin(ScrollOrigin.from_element(viewport),0,-120).perform()
        wait.until(lambda d:scene.get_attribute('style')!=before_wheel)
        assert len(browser.window_handles)==1
        assert roots[1].find_element(By.CSS_SELECTOR,'.stv-scene').get_attribute('style') == other_transform
        roots[0].find_element(By.CSS_SELECTOR,'[aria-label="Reset viewport"]').click()
        group=roots[0].find_element(By.CSS_SELECTOR,'[aria-label="Expand Traces (outgoing) for ROOT_A"]')
        browser.execute_script('arguments[0].focus()',group);group.send_keys(Keys.ENTER)
        wait.until(lambda d: roots[0].get_attribute('data-stv-revision')=='1')
        assert len(roots[0].find_elements(By.CSS_SELECTOR,'.stv-node'))==2
        assert len(roots[0].find_elements(By.CSS_SELECTOR,'.stv-edges polyline'))==1
        reverse=roots[0].find_element(By.CSS_SELECTOR,'[aria-label="Expand Traced by (incoming) for LEAF_B"]')
        browser.execute_script('arguments[0].focus()',reverse);reverse.send_keys(Keys.ENTER)
        wait.until(lambda d:roots[0].get_attribute('data-stv-revision')=='2')
        assert len(roots[0].find_elements(By.CSS_SELECTOR,'.stv-edges polyline'))==1
        original=roots[0].find_element(By.CSS_SELECTOR,'.stv-summary')
        before=browser.current_window_handle
        browser.execute_script('arguments[0].focus()',original);original.send_keys(Keys.ENTER)
        wait.until(lambda d: len(d.window_handles)==2)
        browser.switch_to.window(next(handle for handle in browser.window_handles if handle!=before))
        wait.until(lambda d:d.current_url.endswith('requirements.html#ROOT_A'))
        wait.until(lambda d:d.find_elements(By.ID,'ROOT_A'))
        assert browser.current_url.endswith('requirements.html#ROOT_A')
        browser.close();browser.switch_to.window(before)
        # The card background belongs to the original-object anchor; separate
        # group/detail controls remain above that stretched hit region.
        card=roots[0].find_element(By.CSS_SELECTOR,'[data-key*="ROOT_A"]')
        ActionChains(browser).move_to_element_with_offset(card,-card.size['width']/2+3,-card.size['height']/2+3).click().perform()
        wait.until(lambda d:len(d.window_handles)==2)
        browser.switch_to.window(next(handle for handle in browser.window_handles if handle!=before))
        wait.until(lambda d:d.current_url.endswith('requirements.html#ROOT_A'))
        wait.until(lambda d:d.find_elements(By.ID,'ROOT_A'))
        assert browser.current_url.endswith('requirements.html#ROOT_A')
        browser.close();browser.switch_to.window(before)
        artifact = os.environ.get("STV_SCREENSHOTS")
        if artifact:
            Path(artifact).mkdir(parents=True, exist_ok=True)
            browser.save_screenshot(str(Path(artifact) / f"{protocol}-example.png"))
    finally:
        if server:
            server.shutdown()
            server.server_close()

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_038: clean wheel host

Test case: clean wheel host STV_TC_SY_038

Level: System packaging integration.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_package.py::test_clean_wheel_host.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_package.py::test_clean_wheel_host" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

PRSA-003 refinement: Patch offline bootstrap tooling before installation. Prior design acceptance is preserved in historical reviews; the refined procedure is owner-accepted under Round 14: Owner acceptance for v1.0.0.

def test_clean_wheel_host():
    wheels=[Path(os.environ['STV_WHEEL'])] if os.environ.get('STV_WHEEL') else sorted((ROOT/'dist').glob('*.whl'))
    assert wheels,'Build the wheel before packaging verification'
    wheel=wheels[-1]
    wheelhouse=ROOT/'docs/_build/wheelhouse'
    assert wheelhouse.is_dir(),'Provision the runtime wheelhouse before offline packaging verification'
    with zipfile.ZipFile(wheel) as archive:
        names=archive.namelist()
        assert not any("/tests/" in name for name in names), "Unit tests must not ship in the runtime wheel"
        for asset in ('stv.js','stv.css','LICENSE.txt','THIRD_PARTY_NOTICES.txt','vendor/elk.bundled.js','vendor/ELK-SOURCE.txt','vendor/ELK-INVENTORY.json'):
            assert f'sphinx_traceability_view/static/{asset}' in names
        packaged_inventory=json.loads(archive.read('sphinx_traceability_view/static/vendor/ELK-INVENTORY.json'))
        assert hashlib.sha256(archive.read('sphinx_traceability_view/static/vendor/elk.bundled.js')).hexdigest()==packaged_inventory['elkjs']['sha256']
        metadata=archive.read(next(name for name in names if name.endswith('.dist-info/METADATA'))).decode()
        assert not any('Requires-Dist: '+name in metadata for name in ('pytest','selenium','esbuild'))
        assert 'License-Expression: MIT AND ISC AND BSD-3-Clause AND Apache-2.0 AND EPL-1.0 AND EPL-2.0' in metadata
        assert 'Copyright (c) 2026 Henning Heikes' in archive.read('sphinx_traceability_view/static/LICENSE.txt').decode()
        license_members=[name for name in names if '.dist-info/licenses/' in name]
        assert any(name.endswith('/LICENSE') for name in license_members)
        assert any(name.endswith('/THIRD_PARTY_NOTICES.txt') for name in license_members)
        assert any(name.endswith('/ELK-SOURCE.txt') for name in license_members)
    source_archive=wheel.parent/(wheel.name.split('-py3-')[0]+'.tar.gz')
    with tarfile.open(source_archive,'r:gz') as archive:
        names=archive.getnames()
        assert any(name.endswith('/LICENSE') for name in names)
        assert any(name.endswith('/static/THIRD_PARTY_NOTICES.txt') for name in names)
        assert any(name.endswith('/static/vendor/ELK-SOURCE.txt') for name in names)

    with tempfile.TemporaryDirectory(prefix='stv-wheel-') as directory:
        root=Path(directory);envpath=root/'env'
        assert root.resolve().is_relative_to(Path(tempfile.gettempdir()).resolve())
        subprocess.run([sys.executable,'-m','venv',str(envpath)],check=True,capture_output=True)
        python=envpath/'Scripts/python.exe'
        bootstrap=subprocess.run([str(python),'-m','pip','install','--no-index','--find-links',str(wheelhouse),'-r',str(ROOT/'requirements-tooling.txt')],capture_output=True,text=True)
        assert bootstrap.returncode==0,bootstrap.stdout+bootstrap.stderr
        result=subprocess.run([str(python),'-m','pip','install','--no-index','--find-links',str(wheelhouse),str(wheel)],capture_output=True,text=True)
        assert result.returncode==0,result.stdout+result.stderr
        source=root/'source';shutil.copytree(ROOT/'docs/test-scripts/fixtures/minimal',source)
        env=dict(os.environ);env.pop('PYTHONPATH',None)
        env['PATH']=str(envpath/'Scripts')+os.pathsep+str(Path(os.environ['SystemRoot'])/'System32')
        result=subprocess.run([str(python),'-m','sphinx','-b','html','-W',str(source),str(root/'html')],env=env,cwd=root,capture_output=True,text=True)
        assert result.returncode==0,result.stdout+result.stderr
        assert 'STV_PENDING' not in (root/'html/index.html').read_text(encoding='utf-8')
        static=root/'html/_static/stv'
        assert (static/'LICENSE.txt').read_bytes()==(ROOT/'LICENSE').read_bytes()
        assert 'https://github.com/kieler/elkjs/tree/0.10.0' in (static/'vendor/ELK-SOURCE.txt').read_text(encoding='utf-8')
        notices=(static/'THIRD_PARTY_NOTICES.txt').read_text(encoding='utf-8')
        assert 'Eclipse Public License' in notices
        assert 'Apache License' in notices
        assert 'EMF-GWT common/ecore' in notices
        inventory=json.loads((static/'vendor/ELK-INVENTORY.json').read_text())
        assert inventory==packaged_inventory
        assert {x['license'] for x in inventory['compiled_dependencies']} >= {'Apache-2.0','EPL-1.0','EPL-2.0','MIT'}
        assert 'https://github.com/eclipse-elk/elk/tree/v0.10.0' in notices

        probe=subprocess.run([str(python),'-c','import sphinx_traceability_view as s;from importlib.metadata import version;assert s.__version__==version("sphinx-traceability-view");print(s.__file__);print(s.__version__)'],env=env,cwd=root,capture_output=True,text=True,check=True)
        assert str(envpath).lower() in probe.stdout.lower()
        retained=os.environ.get('STV_CONSUMER_RECORD')
        if retained:
            destination=Path(retained);destination.mkdir(parents=True,exist_ok=True)
            (destination/'build.log').write_text(result.stdout+result.stderr,encoding='utf-8')
            frozen=subprocess.run([str(python),'-m','pip','freeze'],capture_output=True,text=True,check=True)
            (destination/'environment.txt').write_text(frozen.stdout,encoding='utf-8')
            (destination/'identity.txt').write_text(probe.stdout+'\nPATH='+env['PATH']+'\n',encoding='utf-8')

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_039: empty seed catalog

Test case: empty seed catalog STV_TC_SY_039
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_release_seeds.py :: docs/test-scripts/test_release_seeds.py::test_empty_seed_catalog[file]
priority: unassigned
verification_state: not_assessed

Level: System/browser acceptance.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_release_seeds.py::test_empty_seed_catalog[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_release_seeds.py::test_empty_seed_catalog[file]" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_empty_seed_catalog(browser,short_output,protocol):
    source=short_output/'source';shutil.copytree(FIXTURE,source)
    (source/'requirements.rst').write_text('Requirements\n============\n',encoding='utf-8')
    (source/'index.rst').write_text('Project\n=======\n\n.. toctree::\n\n   requirements\n\n.. traceability-view::\n',encoding='utf-8')
    output=short_output/'html';result=build(source,output);assert result.returncode==0,result.stderr
    with published_url(output,protocol) as url:
        browser.get(url);wait=WebDriverWait(browser,20)
        wait.until(lambda d:d.find_elements(By.CSS_SELECTOR,'.stv-view[data-stv-revision="0"]'))
        root=browser.find_element(By.CSS_SELECTOR,'.stv-view')
        assert 'No stakeholder requirements.' in root.text
        assert not root.find_elements(By.CSS_SELECTOR,'[data-focus="root"],[data-focus="Next"]')
        field=root.find_element(By.CSS_SELECTOR,'.stv-seed-picker input')
        field.send_keys('anything');field.send_keys(Keys.ARROW_UP);field.send_keys(Keys.ENTER)
        assert field.get_attribute('aria-invalid')=='true'
        assert field.get_attribute('aria-expanded')=='false'
        assert root.get_attribute('data-stv-revision')=='0'
        root.find_element(By.XPATH,'.//button[text()="Project overview"]').click()
        wait.until(lambda d:root.get_attribute('data-stv-revision')=='1')
        assert len(root.find_elements(By.CSS_SELECTOR,'.stv-node'))==1

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_040: unsupported builder fails clearly

Test case: unsupported builder fails clearly STV_TC_SY_040
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_build.py :: docs/test-scripts/test_build.py::test_unsupported_builder_fails_clearly
priority: unassigned
verification_state: not_assessed

Level: System integration through the public Sphinx build interface.

Preconditions and inputs: Use the pinned implementation environment, fixture setup and parameter variant identified by the executable selector. Browser cases require provisioned Firefox/geckodriver and both file/HTTP variants where parameterized. Capacity cases require a freshly generated 30,000-Need/90,000-edge fixture; packaging requires the candidate wheel and offline wheelhouse. The procedure below specifies test-specific inputs.

Executable selector: docs/test-scripts/test_build.py::test_unsupported_builder_fails_clearly.

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_build.py::test_unsupported_builder_fails_clearly" -q.

Procedure and expected outcomes: Execute the following existing test procedure with its fixture helpers. Every assertion is a required observable outcome; expected error cases must assert the specified diagnostic/state. Links identify criterion portions exercised by this case, not a claim that this individual case alone verifies every linked requirement in full. Review the full case set and the release criterion assessment together.

def test_unsupported_builder_fails_clearly(tmp_path):
    result=build(FIXTURE,tmp_path,'-b','text')
    assert result.returncode!=0
    assert 'supports only the html builder' in result.stderr

Evidence to retain: Per-case execution result and timestamp, candidate and test identities, environment, invocation and linked JUnit/log evidence.

STV_TC_SY_041: Select separate occurrences

Test case: Select separate occurrences STV_TC_SY_041
status: accepted
tags: release_later, test_system
last_result: not_run
basis: documented
evidence: docs/requirements-stakeholder.rst; docs/requirements-software.rst
priority: unassigned
verification_state: not_assessed

Level/environment: Planned browser acceptance, Windows/Firefox, file and nested static HTTP output, network blocked.

Preconditions/inputs: Future occurrence-mode implementation; two parents sharing one child with two disjoint nonempty relationship groups.

Procedure: Open a two-parent graph sharing one child. Select separate-occurrence mode, then shared mode.

Expected outcomes: Separate mode shows two child occurrences; shared mode shows one. The selector and visible mode agree.

Repeat with a cycle and a missing target to verify termination and visible placeholder identity. Start at 199 visible occurrences and request two more: the transition must be rejected atomically with the node-limit explanation. A transition to exactly 200 succeeds. Attempt a mode switch producing 201: retain mode, graph and exploration state and explain the limit.

Execution/evidence: No executable implementation exists in v0.2.0. Retain per-case results, candidate identity and file/HTTP screenshots when the future release implements this scope; no execution record is invented.

STV_TC_SY_042: Restore occurrence exploration

Test case: Restore occurrence exploration STV_TC_SY_042
status: accepted
tags: release_later, test_system
last_result: not_run
basis: documented
evidence: docs/requirements-stakeholder.rst; docs/requirements-software.rst
priority: unassigned
verification_state: not_assessed

Level/environment: Planned browser acceptance, Windows/Firefox, file and nested static HTTP output, network blocked.

Preconditions/inputs: Future occurrence-mode implementation; two parents sharing one child with two disjoint nonempty relationship groups.

Procedure: In separate mode expand different groups in each occurrence. Switch to shared mode and back.

Expected outcomes: Each occurrence recovers its own expanded and collapsed groups without losing prior exploration.

Repeat with a cycle and a missing target to verify termination and visible placeholder identity. Start at 199 visible occurrences and request two more: the transition must be rejected atomically with the node-limit explanation. A transition to exactly 200 succeeds. Attempt a mode switch producing 201: retain mode, graph and exploration state and explain the limit.

Execution/evidence: No executable implementation exists in v0.2.0. Retain per-case results, candidate identity and file/HTTP screenshots when the future release implements this scope; no execution record is invented.

STV_TC_SY_043: Isolate occurrence expansion

Test case: Isolate occurrence expansion STV_TC_SY_043
status: accepted
tags: release_later, test_system
last_result: not_run
basis: documented
evidence: docs/requirements-stakeholder.rst; docs/requirements-software.rst
priority: unassigned
verification_state: not_assessed

Level/environment: Planned browser acceptance, Windows/Firefox, file and nested static HTTP output, network blocked.

Preconditions/inputs: Future occurrence-mode implementation; two parents sharing one child with two disjoint nonempty relationship groups.

Procedure: In separate mode show two occurrences of one child through different parents. Expand a group on only the first.

Expected outcomes: Only the first occurrence changes; the other retains its original graph and expansion state.

Repeat with a cycle and a missing target to verify termination and visible placeholder identity. Start at 199 visible occurrences and request two more: the transition must be rejected atomically with the node-limit explanation. A transition to exactly 200 succeeds. Attempt a mode switch producing 201: retain mode, graph and exploration state and explain the limit.

Execution/evidence: No executable implementation exists in v0.2.0. Retain per-case results, candidate identity and file/HTTP screenshots when the future release implements this scope; no execution record is invented.

STV_TC_SY_044: Merge shared expansion sets

Test case: Merge shared expansion sets STV_TC_SY_044
status: accepted
tags: release_later, test_system
last_result: not_run
basis: documented
evidence: docs/requirements-stakeholder.rst; docs/requirements-software.rst
priority: unassigned
verification_state: not_assessed

Level/environment: Planned browser acceptance, Windows/Firefox, file and nested static HTTP output, network blocked.

Preconditions/inputs: Future occurrence-mode implementation; two parents sharing one child with two disjoint nonempty relationship groups.

Procedure: In separate mode expand disjoint groups on two copies. Switch to shared mode.

Expected outcomes: One shared object remains with the union of both expanded groups and no duplicate canonical edges.

Repeat with a cycle and a missing target to verify termination and visible placeholder identity. Start at 199 visible occurrences and request two more: the transition must be rejected atomically with the node-limit explanation. A transition to exactly 200 succeeds. Attempt a mode switch producing 201: retain mode, graph and exploration state and explain the limit.

Execution/evidence: No executable implementation exists in v0.2.0. Retain per-case results, candidate identity and file/HTTP screenshots when the future release implements this scope; no execution record is invented.

STV_TC_SY_045: Inspect details from a nested Windows checkout

Test case: Inspect details from a nested Windows checkout STV_TC_SY_045

Level/environment: Windows browser system acceptance; stable Firefox with recorded version, direct file URLs and nested static HTTP hosting.

Executable selector: docs/test-scripts/test_windows_paths.py::test_nested_windows_detail_loading_and_retry.

Preconditions/inputs: The fixture computes a nested output root where old two-hash asset paths exceed 260 characters and compact paths fit. Retain the actual measured lengths and the failed pre-fix attempt. Root and nested view pages display ROOT_A’s formatted body, table and source links.

Procedure: Build the host using the actual implementation. Open both pages over file and HTTP, activate Details with keyboard, compare rich content and links, then reload to clear fragment memory. Temporarily rename the detail asset, activate Details by pointer and require the unavailable error. Restore the asset, dismiss/reopen and require successful recovery.

Expected outcomes: All four page/transport combinations display the correct body and retry successfully. The old path exceeds 260 characters, compact assets exist and fit below that threshold. The companion compact asset software case verifies full digest identity and deduplication.

Evidence: Per-case JUnit/log, before/after path observations and rendered screenshots in the maintenance execution record. No arbitrary-depth path, other browser or other-machine support is inferred.

STV_TC_SY_046: Reject unaudited distribution inputs

Test case: Reject unaudited distribution inputs STV_TC_SY_046
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_legal_guard.py
priority: unassigned
verification_state: not_assessed

Level: System build/distribution interface.

Executable selector: docs/test-scripts/test_legal_guard.py::test_build_rejects_unaudited_elk_and_missing_notices.

Preconditions: Pinned Node/esbuild installation and maintained legal inventory; use an isolated copy for dependency/legal inputs.

Procedure and expected outcomes: Invoke the real frontend build against a changed ELK version, changed binary, modified legal text and missing EPL notice. Each must fail with its specific audit/input diagnostic before distributing browser output. Preserve installed dependencies unchanged.

Evidence: Per-case JUnit and command log. The clean installed-wheel case separately verifies the successful shipping path and notice inventory.

STV_TC_SY_047: Authored transport markers remain inert over file

Test case: Authored transport markers remain inert over file STV_TC_SY_047
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_detail_transport.py
priority: unassigned
verification_state: not_assessed

Level: Integrated system/browser regression.

Preconditions and inputs: Existing implementation environment; Node for frontend tests and provisioned Firefox/geckodriver for browser cases. Use a fresh isolated build; the test controls only harmless marker values and loopback resources. No external requests are needed.

Executable selector: docs/test-scripts/test_detail_transport.py::test_authored_transport_markers_stay_inert[file].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_detail_transport.py::test_authored_transport_markers_stay_inert[file]" -q.

Procedure and expected outcomes: Build and open the real fixture in Firefox over file. Open details and click the inert link; require no marker execution or loopback beacon requests, no forged src/srcset, and preserved local images, srcset, navigation, CSS and table.

Evidence: Retain actual JUnit results, commands and source identities in PRSA-002 development fix verification. Design acceptance is recorded in Round 14: Owner acceptance for v1.0.0.

STV_TC_SY_048: Authored transport markers remain inert over HTTP

Test case: Authored transport markers remain inert over HTTP STV_TC_SY_048
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_detail_transport.py
priority: unassigned
verification_state: not_assessed

Level: Integrated system/browser regression.

Preconditions and inputs: Existing implementation environment; Node for frontend tests and provisioned Firefox/geckodriver for browser cases. Use a fresh isolated build; the test controls only harmless marker values and loopback resources. No external requests are needed.

Executable selector: docs/test-scripts/test_detail_transport.py::test_authored_transport_markers_stay_inert[http].

Invocation: .venv-implementation/Scripts/python.exe -m pytest "docs/test-scripts/test_detail_transport.py::test_authored_transport_markers_stay_inert[http]" -q.

Procedure and expected outcomes: Repeat the file regression over a loopback HTTP server, with the same expected outcomes and explicit external navigation link retained without activation.

Evidence: Retain actual JUnit results, commands and source identities in PRSA-002 development fix verification. Design acceptance is recorded in Round 14: Owner acceptance for v1.0.0.

STV_TC_SY_049: Retained historical archives carry a complete licensing supplement

Test case: Retained historical archives carry a complete licensing supplement STV_TC_SY_049
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: scripts/historical-licenses.py
priority: unassigned
verification_state: not_assessed

Level: Repository/distribution integration.

Preconditions: Retained project Git objects and supplement for the historical case; patched offline runtime wheelhouse, development artifact and existing Python 3.10 executable for runtime compatibility.

Executable selector: scripts/historical-licenses.py.

Invocation: Run the indicated script with the implementation Python; the runtime script additionally takes --python310 <executable>.

Procedure and expected outcomes: Check every available historical Git archive and retained canonical archive. Require the audited upstream ELK fingerprint and byte-identical complete supplement materials; retain immutable artifact hashes.

Evidence: Actual result in historical-licenses.log and source/environment identity in Historical licensing and toolchain remediation. Design acceptance is recorded in Round 14: Owner acceptance for v1.0.0.

STV_TC_SY_050: Patched offline distribution remains usable on Python 3.10

Test case: Patched offline distribution remains usable on Python 3.10 STV_TC_SY_050
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-execution/prsa-001-003-fix/check-runtime310.py
priority: unassigned
verification_state: not_assessed

Level: Repository/distribution integration.

Preconditions: Retained project Git objects and supplement for the historical case; patched offline runtime wheelhouse, development artifact and existing Python 3.10 executable for runtime compatibility.

Executable selector: docs/test-execution/prsa-001-003-fix/check-runtime310.py.

Invocation: Run the indicated script with the implementation Python; the runtime script additionally takes --python310 <executable>.

Procedure and expected outcomes: Create a Python 3.10 environment, install patched bootstrap tools and the development wheel from the offline wheelhouse, run pip check, build the minimal Sphinx host, and verify installed module identity and copied inventory.

Evidence: Actual result in runtime310.json and source/environment identity in Historical licensing and toolchain remediation. Design acceptance is recorded in Round 14: Owner acceptance for v1.0.0.

STV_TC_SY_051: Actual source archive respects the distribution boundary

Test case: Actual source archive respects the distribution boundary STV_TC_SY_051
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_sdist.py
priority: unassigned
verification_state: not_assessed

Level: Packaging integration.

Preconditions and inputs: Existing implementation environment and frontend/legal assets. The test copies build inputs to an isolated source tree and seeds local-only evidence/cache/tool files, including execution logs subject to root and nested ignore negations.

Executable selector: docs/test-scripts/test_sdist.py::test_sdist_excludes_local_evidence_and_rebuilds_wheel.

Invocation: .venv-implementation/Scripts/python.exe -m pytest docs/test-scripts/test_sdist.py -q.

Procedure and expected outcomes: Build the actual source archive and its wheel using the normal build frontend. Inspect tar members and content; require no seeded evidence or local-only sentinel bytes, and require source, legal and build inputs. Compare rebuilt wheel browser assets and notices byte-for-byte with their source archive members. The separate existing installed-wheel case verifies an isolated offline consumer.

Evidence: Retain JUnit/log results, source identity, artifact hashes and member inventory in PRSA-004 source archive boundary verification. The initial old-configuration failure is historical; the latest outcome is independent of owner acceptance and release readiness.

STV_TC_SY_052: Clean rebuild retires obsolete publication files

Test case: Clean rebuild retires obsolete publication files STV_TC_SY_052
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_publication.py
priority: unassigned
verification_state: not_assessed

Level: Maintainer/Sphinx publication integration.

Preconditions and inputs: Existing implementation environment and local extension source. Use isolated temporary Sphinx source/build directories; no installed public output or external service is modified by the case.

Executable selector: docs/test-scripts/test_publication.py::test_clean_publication_removes_obsolete_assets.

Invocation: .venv-implementation/Scripts/python.exe -m pytest docs/test-scripts/test_publication.py -q.

Procedure and expected outcomes: Build the real Sphinx fixture with two Needs, a retired page and a download. Remove one Need/page/download reference and seed an obsolete output file. Rebuild; require one current graph, no old graph/page/download, no public doctree cache, and a complete byte-verified manifest. Previous output must remain outside html.

Evidence: Retain actual JUnit/log outcomes, source hashes and relative file inventory in PRSA-005 clean documentation publication verification. Design acceptance is recorded in Round 14: Owner acceptance for v1.0.0; complete release qualification remains separate from this individual case.

STV_TC_SY_053: Failed documentation build preserves published bytes

Test case: Failed documentation build preserves published bytes STV_TC_SY_053
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_publication.py
priority: unassigned
verification_state: not_assessed

Level: Maintainer/Sphinx publication integration.

Preconditions and inputs: Existing implementation environment and local extension source. Use isolated temporary Sphinx source/build directories; no installed public output or external service is modified by the case.

Executable selector: docs/test-scripts/test_publication.py::test_failed_build_preserves_published_tree.

Invocation: .venv-implementation/Scripts/python.exe -m pytest docs/test-scripts/test_publication.py -q.

Procedure and expected outcomes: Build successfully and snapshot every publication file. Introduce an unknown Sphinx directive. Require a nonzero build result and an identical published file/hash snapshot.

Evidence: Retain actual JUnit/log outcomes, source hashes and relative file inventory in PRSA-005 clean documentation publication verification. Design acceptance is recorded in Round 14: Owner acceptance for v1.0.0; complete release qualification remains separate from this individual case.

STV_TC_SY_054: Failed directory promotion restores previous publication

Test case: Failed directory promotion restores previous publication STV_TC_SY_054
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_publication.py
priority: unassigned
verification_state: not_assessed

Level: Maintainer/Sphinx publication integration.

Preconditions and inputs: Existing implementation environment and local extension source. Use isolated temporary Sphinx source/build directories; no installed public output or external service is modified by the case.

Executable selector: docs/test-scripts/test_publication.py::test_failed_promotion_restores_previous_tree.

Invocation: .venv-implementation/Scripts/python.exe -m pytest docs/test-scripts/test_publication.py -q.

Procedure and expected outcomes: Build successfully and snapshot all published files. Inject an OSError only for the fresh-stage-to-html rename after the prior output is moved. Require the failure to propagate and every previous publication file/hash to be restored.

Evidence: Retain actual JUnit/log outcomes, source hashes and relative file inventory in PRSA-005 clean documentation publication verification. Design acceptance is recorded in Round 14: Owner acceptance for v1.0.0; complete release qualification remains separate from this individual case.

STV_TC_SY_055: CI policy rejects privilege and provenance drift

Test case: CI policy rejects privilege and provenance drift STV_TC_SY_055
status: draft
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_ci_security.py
priority: unassigned
verification_state: not_assessed

Level: CI/distribution integration.

Preconditions and inputs: Maintained implementation environment for workflow/checksum tests, real GitHub workflow files, Git and GNU sha256sum. The runtime case requires the development wheel installed on Python 3.10. No hosted workflow or attestation service is used in these local checks.

Executable selector: docs/test-scripts/test_ci_security.py::test_workflow_policy_accepts_reviewed_files_and_rejects_privilege_drift.

Invocation: Run pytest for docs/test-scripts/test_ci_security.py; for the runtime case, use the installed Python 3.10 host to run scripts/ci.py runtime.

Procedure and expected outcomes: Load both real workflow files, require the reviewed least-privilege policy, and mutate copies to request write tokens, unsafe triggers, mutable action tags, privileged repository code, missing attestation jobs, altered subjects or an unrestricted attestation condition. Every modified variant must be rejected.

Evidence: Retain actual reports, commands and source/artifact identities in PRSA-006 CI and provenance preparation. Case design review is pending; local verification does not prove a hosted run or attestation occurred.

STV_TC_SY_056: Candidate checksums detect changed artifact bytes

Test case: Candidate checksums detect changed artifact bytes STV_TC_SY_056
status: draft
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_ci_security.py
priority: unassigned
verification_state: not_assessed

Level: CI/distribution integration.

Preconditions and inputs: Maintained implementation environment for workflow/checksum tests, real GitHub workflow files, Git and GNU sha256sum. The runtime case requires the development wheel installed on Python 3.10. No hosted workflow or attestation service is used in these local checks.

Executable selector: docs/test-scripts/test_ci_security.py::test_candidate_checksums_detect_changed_artifact_bytes.

Invocation: Run pytest for docs/test-scripts/test_ci_security.py; for the runtime case, use the installed Python 3.10 host to run scripts/ci.py runtime.

Procedure and expected outcomes: Generate checksums and source metadata for a wheel/source pair. Verify both with GNU sha256sum, alter wheel bytes and require verification failure. An extra wheel must make checksum generation fail rather than omit an ambiguous subject.

Evidence: Retain actual reports, commands and source/artifact identities in PRSA-006 CI and provenance preparation. Case design review is pending; local verification does not prove a hosted run or attestation occurred.

STV_TC_SY_057: CI runtime command imports the installed Python 3.10 package

Test case: CI runtime command imports the installed Python 3.10 package STV_TC_SY_057
status: draft
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: scripts/ci.py
priority: unassigned
verification_state: not_assessed

Level: CI/distribution integration.

Preconditions and inputs: Maintained implementation environment for workflow/checksum tests, real GitHub workflow files, Git and GNU sha256sum. The runtime case requires the development wheel installed on Python 3.10. No hosted workflow or attestation service is used in these local checks.

Executable selector: scripts/ci.py runtime.

Invocation: Run pytest for docs/test-scripts/test_ci_security.py; for the runtime case, use the installed Python 3.10 host to run scripts/ci.py runtime.

Procedure and expected outcomes: Install the newly built development wheel into a Python 3.10 host, execute the CI runtime subcommand, require an installed-package import outside the checkout, matching installed version, a successful pip check and warnings-as-errors Sphinx fixture build.

Evidence: Retain actual reports, commands and source/artifact identities in PRSA-006 CI and provenance preparation. Case design review is pending; local verification does not prove a hosted run or attestation occurred.

STV_TC_SY_058: Stable keyboard navigation and project root toggles

Test case: Stable keyboard navigation and project root toggles STV_TC_SY_058
status: accepted
tags: release_initial, test_system, navigation_stability
last_result: passed
basis: documented
evidence: docs/test-scripts/test_position_stability.py
priority: unassigned
verification_state: not_assessed

Level/environment: System browser integration: Windows, Firefox/geckodriver, both file and loopback HTTP, external network blocked.

Preconditions: Rebuilt local browser asset and isolated fixtures. Current development identity is retained separately from historical PoC evidence.

Selector/invocation: test_group_navigation_keeps_existing_nodes_still and test_project_root_preserves_anchor in test_position_stability.py; also test_async_layout_failure_and_stale_completion in test_browser.py; run with pytest using STV_GECKODRIVER.

Inputs/procedure: Build isolated P/Q seeds, A-F children; focus and activate P,Q,P,P controls with Enter, recording all before/after world and screen boxes. Repeat for a seedless project root with collapsed/reopened stakeholder entries.

Expected: All surviving nodes in the simple unchanged-height fixture move less than 0.5 px, clicked focus is restored without native scrolling, revision advances once per successful toggle and root coordinates remain stationary. The async harness additionally asserts last-successful snapshot identity after failure/stale work; independent-view cases remain complementary gates.

STV_TC_SY_059: Negative route rendering and viewport reset

Test case: Negative route rendering and viewport reset STV_TC_SY_059
status: accepted
tags: release_initial, test_system, navigation_stability
last_result: passed
basis: documented
evidence: docs/test-scripts/test_position_stability.py
priority: unassigned
verification_state: not_assessed

Level/environment: System browser integration: Windows, Firefox/geckodriver, both file and loopback HTTP, external network blocked.

Preconditions: Rebuilt local browser asset and isolated fixtures. Current development identity is retained separately from historical PoC evidence.

Selector/invocation: test_arrow_viewport_covers_negative_routes in test_position_stability.py with pytest and STV_GECKODRIVER.

Inputs/procedure: Expand downward P to five children (negative x), and upward A to P then R with a wrapping relation label (negative y). Read final SVG route points, viewBox and screen CTM. Record retained node positions. Activate Reset viewport and inspect fitted node boxes; repeat on file and HTTP.

Expected: At least one negative point in each configured direction fixture, every route point inside the padded viewBox, and first/last route endpoints on node boundaries within 2 screen px. Surviving nodes do not move on toggles. Reset fits all node boxes inside the viewport without changing world positions; markers and paths remain visible. Pan/zoom and focus have existing adjacent cases.

STV_TC_SY_060: Natural seeded order survives expansion

Test case: Natural seeded order survives expansion STV_TC_SY_060
status: accepted
tags: release_initial, test_system, navigation_stability
last_result: passed
basis: documented
evidence: docs/test-scripts/test_position_stability.py
priority: unassigned
verification_state: not_assessed

Level/environment: System browser integration: Windows, Firefox/geckodriver, both file and loopback HTTP, external network blocked.

Preconditions: Rebuilt local browser asset and isolated fixtures. Current development identity is retained separately from historical PoC evidence.

Selector/invocation: test_initial_numeric_seed_order in test_position_stability.py with pytest and STV_GECKODRIVER.

Inputs/procedure: Build shuffled REQ_20, REQ_10, REQ_3, REQ_2, REQ_1 seeds, read actual DOM/world x ordering and expand REQ_2 to CHILD_A.

Expected: Initial left-to-right IDs are REQ_1, REQ_2, REQ_3, REQ_10, REQ_20; all existing world/screen coordinates remain within 0.5 px after expansion. Project-mode ordering is independently covered by STV_TC_SW_045.

STV_TC_SY_061: Published nine-row evidence navigation

Test case: Published nine-row evidence navigation STV_TC_SY_061
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_classified_rows.py
priority: unassigned
verification_state: not_assessed

Level/environment: Windows Firefox/geckodriver; file and local HTTP with external requests blocked; built package assets and isolated Sphinx host. Procedure: Build all nine categories with same-row peers, multiple actual execution identities, a cross-level shared case and fallback case/execution. Start in turn at software, case and execution; expand all relevant groups, record DOM/world coordinates, Reset to inspect complete scene and collapse. Expected: Nine ordered rows and same-row top alignment; fallback below software architecture, visible unclassified labels and valid endpoints. Shared case appears once and does not switch row with visible requirements. Anchor and surviving peers stay stationary. Original links/details, independent views, natural seed order, project root and absent categories retain their contracts. Run pytest docs/test-scripts/test_classified_rows.py with STV_GECKODRIVER.

STV_TC_SY_062: Visible viewport boundary during graph navigation

Test case: Visible viewport boundary during graph navigation STV_TC_SY_062
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_viewport_boundary.py
priority: unassigned
verification_state: not_assessed

Level/environment: Windows Firefox/geckodriver, file and local HTTP with external network blocked; real packaged browser assets and a Sphinx fixture. Procedure: Load two views, move ROOT_A up across the viewport edge using Pan down and record actual clipping/hit tests. Inspect the visible marker, zoom, resize between narrow/wide windows and apply a border-box host rule. Check the 975 px client area and full-width separator after control wrapping. Activate Reset and relationship expansion with the keyboard; check revision, visible controls and unchanged second-view transform/state. Retain screenshots. Expected: One solid 1 px grey line at the true clip boundary, node absent above/on it and visible just below, line fixed under pan/zoom, no overlay interception or content-area reduction, working controls and independent views. Selector: test_viewport_boundary_tracks_clipping_and_controls in docs/test-scripts/test_viewport_boundary.py; pytest with STV_GECKODRIVER.

STV_TC_SY_063: Persistent details across navigation and capacity

Test case: Persistent details across navigation and capacity STV_TC_SY_063
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_persistent_details.py
priority: unassigned
verification_state: not_assessed

Environment: Windows Firefox/geckodriver, local file/HTTP, real Sphinx hosts. Procedure: Open A/B/C by Details, reuse A without age change, manually close B, open replacements and an eleventh distinct artifact at default 10; verify FIFO. Repeat with configured limit 3 and independent views. Pan/zoom, expand/collapse, change seed, overview and project page while boxes remain. Exercise Close all, Escape, keyboard focus/scrolling, missing-trigger close, narrow/wide container layout and current-width Reset. Hover another node while boxes stay open. Expected: Correct identities/count/order and right/below dock, actual 10/3 limits, no cross-view mutation, long content scrolls, controls/focus visible, hover timing/content/dismissal unchanged and no unwanted collection dismissal.

STV_TC_SY_064: Persistent loading cancellation and shared content safety

Test case: Persistent loading cancellation and shared content safety STV_TC_SY_064
status: accepted
tags: release_initial, test_system
last_result: passed
basis: documented
evidence: docs/test-scripts/test_persistent_details.py
priority: unassigned
verification_state: not_assessed

Environment: Firefox file/HTTP real host plus a controlled deferred-loader harness using the actual manager and safe content-restoration code. Procedure: Close/evict a loading box, reopen its artifact, resolve old/new loads out of order, clear all while pending, reject and retry a failed load. Show hover and persistent content for one artifact at once, including IDREFs, local media, offline placeholders and original links. Expected: No resurrected entry, stale insertion, focus theft or duplicate DOM IDs; error remains closable and close/reopen retries. Both presentations share safe cached transport but own DOM/lifecycle state; remote/active paths remain rejected by existing detail-transport regression tests.

STV_TC_SY_065: Readable details, metadata disclosure and artifact-ID navigation

Test case: Readable details, metadata disclosure and artifact-ID navigation STV_TC_SY_065
status: accepted
tags: release_initial, test_system
last_result: passed
basis: owner
evidence: docs/test-scripts/test_persistent_details.py
priority: unassigned
verification_state: not_assessed

Environment: Windows Firefox/geckodriver, file and loopback HTTP, external network blocked; real Sphinx-Needs host and packaged STV browser assets. Procedure: Open a 720 px dock in a wide container. Inspect metadata/status/ tags before any activation. Toggle the existing arrow by pointer, Space and Enter; check row visibility, icons, ARIA relationships and unique IDs. Reuse the box, open a second artifact and a hover copy, then compare local state. Follow the header’s artifact-ID link and require the actual source page, matching anchor and Need element in a new tab. Verify an ordinary copied-body fragment still targets its namespaced input. Resize to 1050 px and check the dock follows the graph without overflowing or exceeding 720 px. Check all four 1 px grey frame edges, side-by-side top/full-height alignment, first-card inset and absence of card shadows. Expected: Metadata initially folded, functional accessible per-copy disclosure, preserved reuse state and working original-ID navigation. No unintended changes to other links, hover isolation or safe local transport. Selector: test_detail_metadata_controls_width_and_artifact_navigation in docs/test-scripts/test_persistent_details.py (both protocol variants).

Test case: Reset exploration without losing current roots or cards STV_TC_SY_066
status: accepted
tags: change_increment, test_system
last_result: passed
basis: documented
evidence: docs/internal-interfaces.rst; docs/architecture/decisions/STV_ADR_011_view-and-page-controls.rst
priority: unassigned
verification_state: passed

Level/environment: System integration. Windows Firefox/geckodriver with file and loopback HTTP, pinned Sphinx host; fixtures contain two views, multi-seeds, shared/cyclic paths and 12 project entry Needs (also empty and three-entry variants).

Procedure: Expand several branches/pages, retain cards for now-hidden artifacts, change the interactive seed, then activate Collapse all nodes by pointer and keyboard. Return through old project pages, expand again and reset twice. Delay an old layout completion until after reset and trigger a layout failure/retry.

Expected: Current seeds only, or project root plus first five eligible entries; zero ordinary expanded groups and no restored old expansions. Node cap/hidden policy holds, cards/order and second view are unchanged. Fresh fit uses actual dock width; focus remains on the command; stale layout does not overwrite reset; failed layout retains committed state until retry.

Test case: Export and save the visible graph and details offline STV_TC_SY_067
status: accepted
tags: change_increment, test_system
last_result: passed
basis: documented
evidence: docs/internal-interfaces.rst; docs/architecture/decisions/STV_ADR_011_view-and-page-controls.rst
priority: unassigned
verification_state: passed

Level/environment: System integration. Windows Firefox on file/HTTP, network blocked, browser ask-location enabled; two views, 200 visible graph nodes, clipped edges, long scrolled details, folded metadata, local PNG/SVG/font resources and remote-media placeholders. Record browser version, viewport/zoom, file hash and screenshot references.

Procedure: Pan/zoom and scroll graph/card/stack; export at wide and narrow widths with part of workspace below the screen. Include visible hover on pointer activation, then repeat by keyboard. Choose a folder/name, cancel another download, repeat after a failed resource load and with delayed layout/fonts. Place the entire workspace outside the screen and require a readable empty-crop refusal, then scroll back and retry. Remove/rename the source output before reopening the saved SVG with networking blocked. Inspect XML, DOM resources, focus, live state and second view. Repeat at maximum default card count and with independent configured font scales.

Expected: Snapshot crop matches the activation-time screen-visible graph/detail area, including current scale, clipping/folding/scroll and applicable visible hover; no toolbar or off-screen region is rendered. Reopened SVG parses and displays without the source site/resources; no script/beacon or required external load. Filename/location are reader-controlled by browser prompt, cancellation and failures preserve state/cards/focus, and retry works. Check automatic-download mode against guidance, not an invented mandatory app dialog. Browser render comparison allows 1 CSS px geometry rounding; no missing visible text/media. Save completion is never falsely claimed. Vector-editor compatibility is explicitly not a pass criterion.

Test case: Configure and read both detail text presentations STV_TC_SY_068
status: accepted
tags: change_increment, test_system
last_result: passed
basis: documented
evidence: docs/internal-interfaces.rst; docs/architecture/decisions/STV_ADR_011_view-and-page-controls.rst
priority: unassigned
verification_state: passed

Level/environment: System integration. Pinned Sphinx/Firefox file and HTTP host; headings, metadata, tables/code, local media, long content, two graphs and a page with original rendered Needs.

Procedure: Build scale 1.0 baseline, defaults and independent tooltip 0.8/card 0.6; measure computed text sizes before/after. Hover, open/reuse/close/reopen cards, load delayed content/fonts, resize and use browser zoom and keyboard scrolling. Exercise metadata controls and inspect original page and node text.

Expected: Defaults are 0.7 of baseline within 0.5 CSS px rounding; independent overrides affect only their surface, with no accumulated scaling. All full content, hierarchy, controls/focus and scrolling remain usable; host Need/node fonts are unchanged. Invalid author values fail the build naming the setting.

Test case: Bulk-fold host attributes without changing embedded views STV_TC_SY_069
status: accepted
tags: change_increment, test_system
last_result: passed
basis: documented
evidence: docs/internal-interfaces.rst; docs/architecture/decisions/STV_ADR_011_view-and-page-controls.rst
priority: unassigned
verification_state: passed

Level/environment: System integration. Pinned Sphinx-Needs 8.2.0 host under Firefox file/HTTP; pages with mixed fold states/types, off-screen Needs, no view, two views with open detail copies, no Needs and Needs without collapsible metadata.

Procedure: Activate page Collapse all / Expand all repeatedly with pointer, Enter and Space. Use individual toggles afterward. Repeat initialization. Observe body, titles, hidden Needs, graphs, tooltip/card copies and ARIA/icons; include an unsupported custom host control fixture and mixed rows inside one disclosure. Verify individual native icon clicks synchronize ARIA after a bulk operation.

Expected: One group on pages with host Needs; all applicable host attribute sections fold/unfold uniformly, including off-screen ones. Individual toggles still work; body/title/ID remain and graphs/copied details do not change. No group without host Needs; disabled explanatory controls without metadata. No duplicate handlers, focus traps or invented handling for unsupported markup; failure is readable. No network service or hidden-data exposure.

Test case: Remember and restore a real browser view STV_TC_SY_070
status: accepted
tags: feature_view_persistence, test_system
last_result: passed
basis: documented
evidence: docs/change-requests/STV_CR_019_remember-current-view.rst; docs/internal-interfaces.rst
priority: unassigned
verification_state: passed

Environment: Real browser and built Sphinx fixture, file and static HTTP. Procedure: Enable by keyboard, expand/reseed/page, open ordered cards, pan/zoom and reload. Compare node IDs/world positions, card order and D3 transform. Exercise FIFO/close after restoration, opt-out, independent roots and pages, another tab, malformed/stale/over-capacity state, reduced card limit, blocked/quota storage and layout failure/race. Close and reopen the page using the retained browser profile. Check narrow viewport behavior and no focus theft. Expected: All agreed view state restores without HTML from storage; independent scope, last-save-wins, safe fallback and accessible failure status. Disabled reload uses normal startup; existing offline/keyboard controls work.