diff --git a/app/src/main/java/com/foxx/androidcast/sfu/SfuRelayGate.java b/app/src/main/java/com/foxx/androidcast/sfu/SfuRelayGate.java new file mode 100644 index 0000000..08923f7 --- /dev/null +++ b/app/src/main/java/com/foxx/androidcast/sfu/SfuRelayGate.java @@ -0,0 +1,18 @@ +package com.foxx.androidcast.sfu; + +import com.foxx.androidcast.CastConfig; + +/** + * Hidden gate for SFU / WebRTC relay experiments (post-alpha). + * Not exposed in release settings while {@link CastConfig#ALPHA_FEATURE_FREEZE} is on. + */ +public final class SfuRelayGate { + /** Compile-time preview; must stay false until owner spec + BE SFU is ready. */ + public static final boolean PREVIEW_ENABLED = false; + + private SfuRelayGate() {} + + public static boolean isAvailable() { + return PREVIEW_ENABLED && !CastConfig.ALPHA_FEATURE_FREEZE; + } +} diff --git a/app/src/test/java/com/foxx/androidcast/sfu/SfuRelayGateTest.java b/app/src/test/java/com/foxx/androidcast/sfu/SfuRelayGateTest.java new file mode 100644 index 0000000..13b1916 --- /dev/null +++ b/app/src/test/java/com/foxx/androidcast/sfu/SfuRelayGateTest.java @@ -0,0 +1,13 @@ +package com.foxx.androidcast.sfu; + +import static org.junit.Assert.assertFalse; + +import org.junit.Test; + +public class SfuRelayGateTest { + @Test + public void previewDisabledByDefault() { + assertFalse(SfuRelayGate.PREVIEW_ENABLED); + assertFalse(SfuRelayGate.isAvailable()); + } +} diff --git a/docs/20260602_REVERSE_SSH_proposals_summary.pdf b/docs/20260602_REVERSE_SSH_proposals_summary.pdf index f0bf320..b51930c 100644 --- a/docs/20260602_REVERSE_SSH_proposals_summary.pdf +++ b/docs/20260602_REVERSE_SSH_proposals_summary.pdf @@ -453,7 +453,7 @@ endobj endobj 78 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122520+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122520+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212303+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212303+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Android Cast \204 On-Demand Remote Access \(Reverse Tunnel\) Proposals) /Trapped /False >> endobj @@ -995,7 +995,7 @@ xref trailer << /ID -[<0bc2f0c306f87efd0a3d63157383ae9d><0bc2f0c306f87efd0a3d63157383ae9d>] +[<451f0f66dc9c89646f9eafccc7317ec7><451f0f66dc9c89646f9eafccc7317ec7>] % ReportLab generated PDF document -- digest (opensource) /Info 78 0 R diff --git a/docs/20260607-2FA-email-mobile-auth-flow.pdf b/docs/20260607-2FA-email-mobile-auth-flow.pdf index b724220..3101e9a 100644 --- a/docs/20260607-2FA-email-mobile-auth-flow.pdf +++ b/docs/20260607-2FA-email-mobile-auth-flow.pdf @@ -215,7 +215,7 @@ endobj endobj 37 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212303+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212303+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Android Cast \204 Email agent config & 2FA / mobile auth flow) /Trapped /False >> endobj @@ -450,7 +450,7 @@ xref trailer << /ID -[] +[<826cf08fa662639dd4eda2d9d3d0062d><826cf08fa662639dd4eda2d9d3d0062d>] % ReportLab generated PDF document -- digest (opensource) /Info 37 0 R diff --git a/docs/20260608_ALPHA_PRIORITIES.pdf b/docs/20260608_ALPHA_PRIORITIES.pdf index aa71284..94cc846 100644 --- a/docs/20260608_ALPHA_PRIORITIES.pdf +++ b/docs/20260608_ALPHA_PRIORITIES.pdf @@ -168,7 +168,7 @@ endobj endobj 29 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212303+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212303+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Android Cast \204 alpha priorities \(2026-06-08 renumber\)) /Trapped /False >> endobj @@ -267,31 +267,31 @@ Gatm:gMWKG&:Ml+bZ!V&$JA]e/q%dnDB_*CC\)3g>/S?V"%sGdS%nCl[M-8jMBddc,Oa`aR5o>^5k(Jl endobj 48 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 3569 +/Filter [ /ASCII85Decode /FlateDecode ] /Length 3679 >> stream -Gatm>>Ar7U(4P_U+M&E*R3o:/h4'0gg8%FJ8aArQlkV9_ck:22W`sU;lV;dZ%F'<'";lqP,lZd59ti^p/A@dHQn\iB2#30KfO=;1E`g6]LBY-0P&j"n#J#ci\G>%]SL;#c4^&SYZWV6hA(>r-*V05N/O1S/O:2e_oV,)*kE?892`N#tp/Q[LZ3ZEkmaI]O[FgM\%M9km&E(f7GK'CshIU%:(`)U_i0d]c./V>tYQD-[S?/03hc`;4=&aO^#hsK-eb$!K=3^k:23X5@*kg[=fYnCfD=6V544*ikB)@erC6#>H1?Fh3(3T/]+E66H8R1eCpkc+gn].0DN(.D&!SlOW4$V8Yn7N"S3qUGSCA1=pS"W97H*eeaIT`lY[^>]:fW)6Fk:q0nX*(L-_m7/qnjODBUDpim/i:;oF6B93A(F:1l,3k^*?,2TFM`,l8T:XjHV4?"f<)Q2]f9,L#tGI-$SloQ6N\"p:Ls8$I+oq22<2W`>@o"_Pa+ZlRC()!)W#"e$`@uI$XK^C$FZC,d@buQ5aG95)"2kQuY?]ck.5q\'<6ihWep,mo5l#$Qelk2"R%b^'@h=f.%=cfigNhfgQ`Ubqg4ZCJmMD:]Kqk^36kcZ*p3d@.jhQ^k0H0I?\gJ8@3bLtF`r7gf1e,,W\O#N,RbuA:=DcqUhj7(je\Z980L8!4J:^*ip=R"(5Oq&%o@Z2+/i2.&SJ3AKHNhQr&K,8E1q[t3XTCLP8(6Uk:nb4L,4?+mN\03g#Q8o6g:rR[N5gkuqGJ"2nGe/a2j0<7h(:/oo!#56I&FeuiJ+S1031#I\P:K,2!J%14]%nZ=\Ttl`h#Q4Pd'fLoBC4K-@IQr2_&;-Rt1=JIP:AiL,O+JWW#u^/u<#JdUd_^g,WDsQnQ6`CtX!Dp@8Pk">8aoiDN7sk__b*a24WV&E'N15cIj/^f*uN`6'Ze+0']:%eXHRbg6>4&`%+j:mtg$%3Vu4J;6dc1XbO;KskT&eYS+XI^OTCJu8>rMgaMgukoBkVbm<]Nlk\W!@=ED,SAXUoWi:rbB['P^FqX%B7c?`8Ueei$+(%"M#!=9Tdl3p6IM2h5NQm?G`o1lYi2hYkPWi,9e,`bo=p&15H:iAYog6$Yt`j7J/)gQ$_.UkR3-mS)kH`ZVEAfr.7hHp$.GQn0S&GVe(^G8r%s+l"B,64I[.bqiZ8]Qqr)!AYSGcd[CQ%,tG(Pr;#4-a8l5RY8E!YGPYKmLkNu!/G[.=K-oBUA\G]^N!ekI1k*Q98?^ec8&Y]2K)(\46YX)]B.'`s*7*Ir_*?If$s9InB&J!MH8MJsFi:!4j0&!h_'&X;V_[.R;Xf!F`;[kV^#R+7QF6_n-gI+QOH<^ltr/AbWGtnPn)<"`mjUI[l?JANp;sg[J!IgKHN:M2ge\*7Jos!$EosVTV'"/MV1q*EPE9<[fY`AFrdN!i(2huOIKdG.+hLpp-+:AalS&8D%6mGFlTeFjDXL-ZipLA_K:8X]179:DM8h]B\S6O2[QhCL;dNLpE?:B&,@6`@i@/g,:E(-OI=92Shs$N,3!#ARYmBm4nP4TdIMQkKt$J^Mca7W\?LQJS&tPumC>-$G!WM>g8j^F9G6X^P=0NS!`7c[nki4[XB>s:!@Dh!nF,*B$W:lZFo_IP@;^#.MK0!W8ISr^%O^H7_5)^k-gAffSmbaU".2k@>'75MG^7r,%;dicZ?Qi'$WRCaXAQQ+J[S[\p0_]Ydn^onoBmT"Y#;Z'V%^C@0uZR$eTGMs6IFG#^6]VA%rLjTcoqV=Aa7R&Z[rn]HLC:ctR<7GpVLu?'qITLTHS1/;$LV7fXJAjts#em6>lRGD0F%(jNZ"HF(YggX5[BUcXBP9tKpMoX_@!6+3[td-pGa5W1Gn+<>?/)K#;j0,oqhdh#t8/\PkKq'Pg$q+VuN3'q>m/aL>&7ecjfKoKC@#l4QEW&8+]WdU4OZDQ]?(!*(n-s':l4]dXD#/u5BF!\jGNgd,X:*7`,32,Ah8?kl!;+MtDY>#7VD![DfQ5D2SH/q0;/9RPBYVTbG/NbI141VCo[0;K9+CIDe<\KaP3bm*)Cgb0/3XeS80\I!#X'f;1_INTnPp6,f9C;*h.oO=rnh/cq1ZEl7Ce+LX5k[C'Fn^r'Ca`0?9Q>6`_1"e%`;8a@5an'V]P+;Jso(B`Gt2Q_^]]T6=8I#>sr9tFUsia24lO(H5+mDP-Q>P=6k?P#eETZ]3=L&@R3fRtoeMbT;2I\bC"O/DpH3WLZTO"Fk_QS;TCjbb%2EMHV8!t$U]Ac~>endstream +Gatm>D/\/g')p`p61hC3ZV>+iHEktI32B9sFHNre`5Q$`!sU@)[^LL_,U`+&mXG$B.8(Fnlcm$Ng6\!#VZg*./^nE)LQr>=`Qfp$"GU1B_hg"M9D''jKb/,/di\\V<g76[qC8OVBb`[LGK+"U(T)4LJ[-GT+7rXM._pM&QJU6#(5CF0U/N>/d/Jq=`^d-E(C<]T-:X=mT8l6:oIBR!1gGTj!mkS=Uk6s19/aS/#UV?=C4Xe94lZZLNE@;?dKUKk99.LSKKK;lqT%/,7'QC0F_],"#9I_;D%ep1UQKus(j)TXU(70ots6o-ZQ2;;)"(;_;KfXgRIOM<^5inKj!`'bEAL-U@0YJ?A%'QX\`1'^dFcbY4,NqRr=DeWfFB;1s6=](6n-#k!Z-SRGJXV0sr$%-/fPIr)/OR;Qa#6@.YWi7h$<:3Od%^p>R7r[-b:E^XmVIH.8pr_Q%\Au2W3d9qFXlSZZc\g>:PBPT9B%G*>k<4lRufX?/:S1Y&N;Wm2u8(kPi5E*e*ufLKuE6Dc_3pl]`P?U$2msU(`5pjKj9,TlH$^1u7blF0o,s;4;?LSo8P]$m35-:US&E)e"Cdp/2/ZJ9:*/6^2IdE30?3fY%g`^#uURAK?eoV=ms9[hpZE9HQW\n^-/G4`mE+%Z/`TX"Ori-@>%,qPs8!*aJ]S>e27n_1=7&_!(H#s&ta^1_&a,loVfIY7V+ZJnT\LBL7`He%@e!En7*/$+1>UItnfaE*:iRN4tH=V)+Y_k2^>lg*5]q=-"E5M+g97ugl#?jDek_!>+\6.i(QimBto5bNlpGu-$40ttWJA:NL/i35TS;MXVHMjdEi&9pN9A#RC''[R9lrZD1I>VBM\k&6\VfdZ3lQpZb@#RCM>Ln*.I\j-8-d"9XR!^Wen*Z5eh2uBX-6(!3`_[@^GCsBgHb8R=(38^*W3TMEjAbbPQt7@.V(FB:A@:tcN>)(*Um8,qT>6e8!6A@(PZHjYpJ+p+O!V4-@:]8t(/f-ohhlBNQRL\2Rf_Pp@o)p``aYrtXaf*hV?*0/&jHe=hUFA7oQ7;mrBGT5*!PR/mM-_(g@OD[AC'P9W=gnWL^Ok65$@dF^l&c_\m_`k8i)s)Lb,^;(F_eepG4g8FInB=DtZ6-a&W4N%Pl*JZU[a'_HNg2>m/mT5o/]J?ep+PpY^uRdZ7">OC5R*?4CGm_i,RM:k>JrRq1r[X[80XBi+0H/DtWamY@\4LqqEm1,03=&Ku(\5,KK`TrKEqZ[b^.J2DM]9/Wps"1df#I[ZT)5c[>Z#r(3#$Y.Gfb+q+.mR4RgnPnN#/F1]^o0ZB'&GK:8^J_VXmIf"Oha&X@!E[IY5s_].hR[H0eSMa#eeK3pk4)uShsD1\]):&[EiQZQ/===ZO83X?EQ(%'HXCA-/'gIWV#rTP$2&`/:X=2Y55Eo7lLW+C"N_Opj&-=DnNR+k]Q,cXIKDGVAl!]3T5/H7k&@h;4;Y":fM_@ij]_ak;6crHomICr[*&b=gDgRAFVCt^o^?U:ZipdIUMP;G^.!HUmeo$cNeg7Ca%%BJCj\X@lA)=G:aq@/GjK=+PFQW,E1ek!<0tGipY[Lrii;]7+?Ulf6"T4U8ZF@+k\L[AUAf]NrXa7o70=F"4dSUS/BCHr'o2T)75;R@"M`g/^)T,e?p:$Q"o!)&Xcd?,HH]CuOKfJ0Cmac7q/cW7?om=L&ME)H39RsH(YXZ\$h5*,Z2a[V(O\9;PKN#lqJ`4)4Y+'K;F7XnWiMm.pg,`uHm7NDP`qS37dm&hNaY:jW)Q\C`_pLR@;YE$$]P?)>q#%&`Lh6HF)^_P?4Zkhic1o9,/3emahd.jD4)pnP6t&QuOC&jnh5CH-U\N/WHYk(bLo)@Us1Pmp>icDhP!\9$(sCfNckl=qm5[Db21EF8itDse1iZR/P4@c`>%\)L>\f.;5n'tPAaU-DYjFqtaehlcMF)gAiO5t_FrS"6Km#O4QF&`1,/5QWmrWpAV\In/;pYuu;FlSdKZ5PAU!f+an190Y8^#T4_0o6p`I_SBYWG1N]e+$<-fr#$n>*q@PQ6;LSp]e")Hq#\JK0P5\WWhW\T%a+-jEmr/M8/,e.&9U>DWte_2?on:5_n4a^0sS-(Q<[$g&&N!$WD@mm0C,-nmttq4lYE+iQ+pKSf/@Z])G)^_(]e)22/sn(2WsXLulZ&:d`;2,f@+'65q2$Kj5,pVJU8K;q=)Z?Q"h\!0?]@^A1/hupoeq"##&Rpeo03%HtGf;Z8Mk6q9S[7%9$Zdt#$3\3bA36KeJiuYYqraSNMXV]=F&njE8@Q,4Go*Zb)l^cYnY?,KT.qJ\2NL3]-uO9SHi"k`k7TccHS`tOdb?nqHn.oc,+nBs]Td$M*_gnD/:d;M:BAY`G54V!$3<&9S]th+@r^S2AjHd-.+0*L6LtWE..FUT=*P^0JIk).L\08^eqOJ4%s'<69A(Pl(gsNUBHsfY=sT2ZB25fD1\%Vg0YtqT;sVO%Eo\"uYP9YRAucdpmKLB!QlQdm8R5o9@]t1UPUON`\gl)XjStfEmYBZs+#$`&:]~>endstream endobj 49 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 3765 +/Filter [ /ASCII85Decode /FlateDecode ] /Length 3615 >> stream -Gb!#_>BAQ-&q9SYf^[1RE>k;n6&LniQ_W2RlCL%V-)KjYAi(2.=fb2H+Xg]DVZ6TG8F[m]=/G;SAh\mXA8S'Thjo')ufo!$C?BH)#mV@(lh6P;J[,%$UM/[hE?);]A:(E$/q(BW<>Y,7V\ar9HPBCDM5.'N+ba%*]GGmN+Q^TL:))U5brLbWXH1!+#N4L7ut5#5IN6g6fTM?%2V[aS?dBrsnWBG"q;Lo]X_4>lgf"/DJb.\Gna0*P="m:ZofJ&XVg%qrup)I"'gEK6LCU`>,R(gIhi9\=sf;rS48Y$5O]unc%'`"&G'6gNC)+W!=ND:><=f-LXRAV&[`g2WW6t_JdfNCZVSe85_;"PQ#SeTr%=Ci8SG/([=:aRnYTaV\JgKW,L,rSfF4TLqiDap'S<-22BUiTu+"O.ai%()CqW5^V]G_7`-Uo9!HM$EX%l7Ha=Z;QLsk;qlL[A"5Q!_V*(OC3l6$+PVRaJ>KiuhpIaDfofYEmB#D!+BLcr.lnLS?"Fg@[C(quenc_0dTcdKL3-5!fl,n,(Q"`BRg#=g6R%r"6rXk'*P`%nTb*u:e3_p%=if"&XNLDI&)j=2CM`:#WP.p(KlK_s,1%="5_8L@duPjnQCcQ5iT36BT3Rc&%UTq\=EVMnqq_BY^OQ!M`5[!M@dE$lam)HqGoQ@O4_6-/YG*5t"LA3=^k6?$&TA[PEke#&TL5FSk"*IasVO[4He;i#kDci*P^-=Yo8r)c_$?KdP%1*OI48#NU[J8RZf%i3/\mef@(m;3\]PP=;6S;>$?p/E@0(>OsX-7Yb&5H]td-s-6!F1o/UUE'e/;bW(''W$g0>,F>F:k$jb(=2DFS.[/TpA%ul0,LFp/]DgoKcmKb0:mOOe6BZRpg&G+/C"H_!is\Q*l/=,f=eEAZ[[uj_KC>,`@&uROh("'TTLNX&=f73GJU'kb..$!.$N\Yf[1i!9Ih8U*R*>c4pU24>\`H+hBLIqNZDslO<6g0mK.2P(ch]PSX14@KZ]CgnZo6'2(pJ9_.ZYY^o*-qBmYM-b8Sa8(E2eBM3heBWd3:#\X&Qk<)":QMI%6Z#=Oc_?&.!A9URnH;di<=Qk(8c81"D)]qWnn[RNk7!M7TQFR`lB/!jD"2!i"l#"4RX\mA/X[G`P"d$$O&j:2h6#u=;/P:jt=,"EpU/MOf+htJ3]DT;V[9g=T?=uhS"GiU9[E#M/\-T)5cWn9fLX&7sO<7\9/Q.7(g0+I5.iIX^1XMtWZstA2?U@P&nRE:@8J@T8Ya;C'B$HJ3qU=dOh#.Fq@(4#e+H6,9>)r:2&:n=dbfoj;`_B^W*W7kFQg?,;k3N!\q:[+Pna.c'IMT_FVIoYKK16&PR8/4dHggEGZ@2s%Bb=_[\l^LmL0aI/?R_=ek`[9(FO<:6!kS\k6tOs#JQn52Tm"pUE^>CXkD=PL&YIWfYl="`7]CDW%-]?!0I>EK-lQK]&a7Nm,iqlR]!N%PFTOt!BtVUS1RAR7,LUaI'ACWD;G9's7>Ii1CmVuL3oOrhuB7j,7;!WN)/!$Z.En95MWIl`X-B^N>)0lskCfH7W,(FCeGb.E$IrR]M.+7s!0)]t:!5Yg2H@-'OKZRbsdN=lVZ)=on"*ZbdU]qE\\L_!crdI"\7=WY$?AH/KMgrXGXJ0d-Ddu:eVJOd9Z.dZ[L=mSScG]Og@0%MY%DItJK?$(K#hckR$Yqb#1hELkWnK#>pR#$QX2<0VQ^jJCBa!5ZUOFPS8o5E@+rek3YLU3'2>Qi&jAX12r\p1c_Fj)At*NKiH77#p(?>Lg2DFpA1MbS5@lSmV2oc'o66Z"$K2M9QWAl6qg.uQ2cksN016:QetM"^0YDc\eJg"8:'Ps2#2[5fj>;^F1;OkQ%^MM>g23jd_,.HPo^X,ZB=n&eB6O,YH??$4UU-oI\ZEniAAn-[U@:Q%021qf-Ao3:WDo5tHO-(EocgO8l.?_1qeUIeE't)(>jtI`tO&)+.S3C#o5ob:kV\Q-'us'+9cS]AuCaekq*UeJ9uC*l*7b6(reedYC7I8R"8"9n7eKq8b`Vb6\^-)"d_A[&@49l/*\MJ"'7[CJb%VNW%a6AVoXDKfb?!(RK='u\l9d3ngS7pGN5@4=1T%q.,:d^nYPe_]7!sr1Md&rl9@&hqnM0fHUQ;Kh`3LpTX=]-pG?83)(2tUCS:Waj=U.=$)le#qJ+iG&U"U=dY53Wn&IF_a2kIVb>Ib,u*n@)0-(jfoO8C[SKIL'M5:TfFI'YO)Cg`iN!X?O4uY_`HN+^2K_I-=2kc/nO6]-J,LeJj(e^uMmfiLRniB8cR6p+e^\1g>Me5ms,9]gnYRAZoI`NN`_.H1mQsHcH9^hma@BJe%#:rd$bCe?gjbu;6rA8/oIcsb7u6P54*$#4mjfFsohO^a?)f/>Epo4eLWKQ57JF?7r2%GMq@5j;2[@HhQ-!NbZK3pe8g=[GAdf,"FT.s,nr^X-;umugAmS0S?,Zac!3`BA2r2&?8G9'c0Y15'QhI:DD+0V"lb,5@;N-qt?qHnr))Uu5_GfL/BUUEn<`1,C\.`"?-biERZcNi,/q]5hN12G,nu_)CiG2r#+[s$W5)4q=77f-(S+="IacpQ()q*m1WiA7*/IB$Kpbo#!@hB_c(?PH(57hOd5jiPY$oFk7[Gl;J3V][,jk%:$eh&i4[<9=HD_BGcR^1u8'!34CYRG*/AU2[R/_:U.Z8cor'm^r'QW[&l]*Bk&GCTI2Rfr`dLMK"F^4dLO!*pcHJ#LE9Re#R:HE80D:'g]Tk7&Kp>WaM/]tD8E*Z:DDiJNR=M01Ia2oo`2eh15*D=q/DrP);P!ILX"aF4>NW9$-Gp801_endstream +Gb!#_>Ar99&q9SY(`55_e(QYI'U+lYfLhU,:0^A)q]J.+P:MPKa^quH0.m%XcR^MO7#h2ojC+mWMb[NoXsNpBI>FW8dEMZ]+fe@d._3K_eTnbiblQEE>7h1I2XVJODMA\+9U:LZot.4.j`h.3f&97.Z7-gP>so'rh7W+B\PrqYU)m##34F'ME-/n-%F/eEqp-%4YA!NN,=1BJd#>JL^UD'GAbH+_$).B'b)diX@+F/`+.rfis`P3C9cEcoc7`-#Z?rWLBN3UtMV]NBjcXe^bJ?Rh1pS@ahc].]NdkM?YeheTXP^r7Oim7u*s4.6/F65IZP-UU!Ej&(*gDD621s8d-^[NOnjABjf#ad`l?m'!P7;#L5KD3Z6e6q&H@9XhFL_3D+W,P-c>1t7SDi#_U[2RlSJu@CH'(gT2Oc0US1=jGk>7`+T9%?g^f2kBj>G_^kY&B/G)0S4n+F?I%IA[VrTIca(*THb0TYDF&L78?)&k]Lq\K25VppKFW(&qa!cI[`X.KfI1%4HssktuCL*XYX\7d!aJ@^p[8%f]d45S;I>*U+\aCCL':L*:t,Tl)qpXNs7]&bAWt\u(O-Nu75#@5an)CiFq$/4*:\nP*mk=q*DA<5[Ks>n#gf[VUZ.ZIjj>LOkqAe-]FXDH89tHU58HOc>tahRipqj!XU#TU5'n:9ho&oQjh1@?Z#;RX#;-a"K4a9>Q3eesK!fK2QK]rp%dlP)T"cZ(!g1dje&hAsH2[EuG'Q5rs7N-$\39P>(g\q6XjIuEO]>*MG/t&lC;+KR>huh44i9dK->O)$$TW"='fkD4'Wo6S"7oZ9-g!4d,;>amG@Ea`gGYlIo@ZLie#2LQ?uIaL3T1K3^trJ1?_5-J=O8/Vl/kfk9"/bc&`!aU>MF9,?f*SiDJ#TB(.9FF/]bO8g2MN$qc:S,BnOAKoaje,EXmKON=aQ/'S2<0rBu$Y,SWO%P3;-'*Ju2cX+t33*ROOOoVh0+?jBQE9B%?J]9i,NG_s`@@GG+;E'SE_EdI\,'K=V#^At'Qqb\g<&(,Y3s)aXqo,HS'#R@`)(sqn9CH:ElL5]t&k&'T`k&$r[#F7Y%HRb23,?]@26`,qRMKk.)pQG@N6\TM\)b%,O.k9$@_"".;"W"^U9GleY`s]1F90XP^8HT=Pq=3l&j!Bb&c"J<4@%*+(KhEL*&l!qZ5_DP.K!UnIMfPW06!hra',ZZi&=-?o1P\WA&<[!56$T6chWHC,I\$Rd0Lp8EI8#b+F+\?2*kZE+GD0B^8S5dfnm99d^_EQs$\g2In\0p^)F!fd:;b&t;#n[KSeLOAnMY_#<\/WL)r*K6hpl#@_nq[_01G2.?a&i:8!BNkTV>ou>ZMq:A<\S,"b2qi5p_"fW&J+.GZsn=$&8TNIQP;fFBKZ-CNB3tHYTkD?"2'!=?`\YKe;d^e]'/8f^2s5GoWupC?m#Ba$U)4Y'Sm%6P4V($,57<(:WQg7*PYS95GZK]LLG1Q]2(,q!p`k:.?U'#0BnEm^\UninSj&Z8k>cOeKMVH74@U7alUl_kOrkj'a'F![Dkhki#>9Wc`A\"K]Na+O]9lV$pomh&*:eojC3I@F-LDnB0d076uJ@[MVq&GDe:9;=Cum*t']C&:u"/q%!;af1]9$=DG*B3LnEfV_E]kI:E<`Bc4)/iaql6(9[RUJlm"&O_>JlVWaC8![\TH?06i22l"]^k*gQ"NKZn_;"?lgPW-;Wg):]7FKEj^sZ2s't43M63Ee[XQJG?NCg?NFULcCc/!R)mPMHuRmXedeE6-M'[))4FI7>W>X8eYTB93>N-jnVPrn'U]`U.0-T$c"$LE-/ff]NoB2*d$LY3ZWb"]tNX2UaJ3/sK'P)d(%3'JWT,,,7@3Q;e<:i-$ZEmWcHH7/&:XEG)M(&gCoWf0ENQ@].td#FIV_UXAgBX;c#LPe[_Q[Yo6\J]0^OiP8oM)j^mI'7>Fp4lihhgPVJYQkNjM7k=rmpHfT8Xd?`ZjN2Y?jLP"@-BAPX0#*Saq\NH4^=.ZiGTR4)I8N#CW1sX/kJR"1rU^qjqMF6+#<6WfFgY^jY4_mEDA62,7]E7]pO9(Uie?)]f:&3007,\Hru@]U6>B=7tD^g1=>r3$]D@UjQ=X5Z5d4W9kL`nVjlG5ctP)g1s<;j'9U`gW;ZQ\m*5tGdlcWAikNhfOsU*WGFurqWr;c^L=:QVT8:m`fH&tLpM#Fs_$<]Vo)$NM>XT+3oYP1T>l#4FcI[F9N]Y*V#dN>F0"N/TKjaQ0/GB(9mdbqCls9DT[:*B8lVk`O(4`'[S[[hPkp+<"\628heOD:+=[hO$6klkL=-L&aeV/b'8N9YuMlpii6RBcVl,5FG=-qCX09bX:ZG`0S-tX(O`90e-#m(aSZk`aMfslV^,.kJe><>sZ[`\:o3`r]_^\;G9Btt?BFr\[#%=TDI']lj*LK)QhqUA(E%d+D/3gF'HYhGfKs4>M)mj-e6]kt`+Dd0KYWXBZMWpRjhhqcOd[s,12Pme[.rWCQ]endstream endobj 50 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 2534 +/Filter [ /ASCII85Decode /FlateDecode ] /Length 2696 >> stream -Gau0F>BAQ-&q9SYf^VXIjMn#f!5)n*4NMO%[c8^;XYYB]c3$I#(1W5"8]d)^r8eO/-;"==Nk/,\Ub9TPCH?/6IYH5P?KlSSqA,4L6#nDq+;]'@];bHftKa'ikVbM8-CJm3AE;lW)ED01Df*k#8B^HZi5JTob/ELiU\=EhNs:aR.:)n#*Z5Eq*j$6$X\7-QAlo-9n/7-X)@Y"0G2nuT$1UT^5*KSEV'Us![9g\=gEJjEN<#QqM)s?=5W9;6,[!c.E"Qs`E_B\&,cJ#`:/T+C^Ua1n#fFp)kOBm0O^5B7g/S]75ZObql3MMc0"b4oegK_oIZQpJX)9rNCll=-P(bB=,fQEf0R':D)e,(10dl0E*ZG]Yc/@BC61d@T7_+B^bMLJ.Go'L^j7c?Aaj,M,rQs=bF*__QQKTf2UV@9VBai?R@Y:8)6JP3'XF+L-'g]R6<\b8fGb^1o3Ua[Be\6q%-j,KK2Ga:*!@G\&4kBTNrf+bj(Pd[0]N2:_)XXJ.%KmG\8GZ7jfW`n]6A%X*hbIqKDLVmH=46@nQE8Z4]f%N)`uke.MX0aa5HI#Gf[.)&)fJ_G,]tE?.A9-Y<"I>.Tp@-*LY#lFApZW=8dtIhs,lmO8ZUZhsT[j=8=(#*RB5GZ]'2LjDF9'l/@^a\O]DMK_A5*u(bkL&4e(kZt\sSM8b/_sf9Xcc^dkd@(ipLSh5%4&W?o$c=,D]H(["HHrK/gqg,D^`V?2dG3]GmAG8+/^qPFJ?Kt%jK48?p$GF`N6dsL$QUWQ>:_)R7CBH`2nV)__I]lHCJ?op2hVfO6Ntq$mSnKO%-sWG"Hee:iIp"Lc=MOM(4Bn\d3dP5b,E9Ae?oBPEsLpdgn?fA7V)e\28nLEP2@(j*T;VEZ^S\@nE!DLS9chRe'CL58(T$uNFW/4>Ym_ic6#>Ok:h?fDS&h^f:rQ=@i<%8MDmoODJO(+_oH9qhMRHQJk`i:-fch.g8Y%kp+*Y_'Bi:R/0;"qH9WKNp=<%8Ss)Z/i=kp-fWrs-5&%g7C$79@\'Sg!g;q?7:3J0%j'X$dTu.,[;PW`?,uAEO#B"MmAb)&)Ks[*-9mo`g=iBtK9bkES$l<#.ihCUaqOI,mem&=$o6OI(ra'kmUi]^acAXTp,e)p^;6kV+Y+cL("?$rU(doV"Fg$A]5iG;2(l-+nZ5:M88YZ!l!4M2NEjUZKeVp\@b1*Ge(2$RW,aWb@dZ=8286SV3Q'NjnU%Ar$IYc9Id>q.U!Ou#Dt],&i0YKEVThldl*3UOS7DkZ8i`/W\j,U\.P[oU:ou_);endstream +Gau0F>BAQ-&q9SYf^VXIjMn#eJ61(h6&mU8a%[7PBDN24!?r\F0hj-njNC2GqcT")7EQ05.'Ah;L3C+0Hja>s"_<.D0-gMa56@?N@!H756!uGQ_phAIgq`%4kf8gjdBm1RVhPA88am8:`5cntGbt.)0e-<9R$OW^K@oZD+cp`3s)Oo\[dLXPm(RBZU6b/>L0]G_<3T5ukdb3%ZLQbm>pjP1a+s'!g%l@O"TUaVL^$CY^_>$)&:bF]I##fs_U_e9D=&4,Xm(l6!Hm,?)Fe/eW7r?36(3JC)'nOu/6U!ogtho=IMD?t"k,aOcE_7P?s%S95kX5tZPOX$ZhH`jqJ@9&@>G9=0aRm@>D.G@"?Untl;30#oIdi?EL[kkPr5sI775B[*Y:gjVhMrE7G2.;-.Kc>#>-MnqNkC+EpCP\@LC+6%._=nciIVPBQjB-(FtMoG$j(@3NK7(\E^Qa$3>gXqe+/D&SEDTV\^>a!:u!3#X2JRn(V6+"SX@!=$A0)F%_(j"7Ahkf]YCIu-uEo+4Y89>`"?=k/Gi6DU2_B*)A4&P'PO-WoYfIa3#?e#H;;\W9[rXm2ioctdI_0sKKi6qf[;mc?.2E9@kR?=oZ00j,6Eq'.FhXRZ'ApnI]P7SCFu?>(dWI=#A94h.O7R,^:30ip^A?#LJE2Vqc[ja^Qhd5hOHLtI,QU!;0[3DZt[=>6i#(@6TjVtb\_QAaRp-&J#c;1Gd*WFMf@"tY#k-IMfl!G-%iG9@CJAS:=UaAsa&O2,3?]jgBa"7#mjBiRiU"'s&&qA3drOOl!%hMC>!RVpm:hU9Y*Fj8Vgm%"I%NC\25;-o4r[JJS=->WtR1hU`.\!q0]ubb/Q!2>0U89?qnht'[P,bm=O]S-Qp[?Dn*^_TUbmIr:0,Npl/6Vi+#Mrc[@Cf0Sap6edo3as[2mg>E8^)j'R/(Me.7&4UL_Aa"6D(>/W^^#O%%UhSohtf.@UgF)1Ns=&?@+,JX[WtSsS>^q-/`*J$*0pQa'q&*&n4>fTkq*fO7Ep<=mUbLC67!&5;rqT8&C$\^QOVa.ad1OR-BR\D0s!!L@SZH%P/bLeFD8m5C'ad`!%Hjo+`q^G7e9kghcK5@FP0QP8&tN0EpX`q,PG9cFfa52-8YkA"kM*9:XlLMV*)dDmOtrNh[pp(u9KA+tj7$*Mh)IS^2QLc"0QDjjl/g^;0]<-LQd8Pa&Rpp\92"AGaGW?Kq\tkORR5CQ6Es%cI6\XBYuP+_Zq\5rNFT95R$R',e+j?)U]1Ge-ulp~>endstream endobj 51 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 1967 +/Filter [ /ASCII85Decode /FlateDecode ] /Length 2026 >> stream -Gb!;dD3*C?&H9tY(e&2YV.Hp`DfAT)R/hG&8P1\gW!\f$n8^MY>ATM8qtD*M)iV&<^*K_)gmqTom**cCbVP=)",@s^q7gqM#'9!gH/L-qf>*;4K_Ya?o@B6DT5'5rOa@]gJkQ?b$%3EK[=4PKD!_Cd&Ojp6)M-;q'(t1sKbjKt'41)?$0D^YO[+rAY+ZZDBES6egZQIEpmB5Es;/20RpX^MLQtOcmOkX$$4@-]YC@>VRPj2(ZW-L6r1N=k3R4INe\,/r!o_X*?!'-`04=kMF*O:.8@"_dH"!(;JC=iP07[7^.Q*J,k4DiPp_JPEAeKZ3@.:S_Ed*2-1m.)NX3\3h7RrB^H^/rFm^rZ8m2qi2Y"&XX'I*0\:?_dV:b;0Wik%/X[pG[U2Vk>;X:/@l0-hFqUb6sa+ME!K?:J1E"L:L]ZEQKg]-WP%0'e#2)q)L(qI+*mR_/b!N$sqI=d9[9;I,:Q6/]2NpTaPJjq+G<&pf2Z]et2aAD[jm%_ahB?%g1;7(rZ1jVWDV[iCM`f_nj0QGfX#WaZiQ:AEspkL`0';9L]L,4O*;k?@iBW6eK[@G*DElWVhu]32n2o(GWk$)qV`em06/IiVIA+^8jQn'GD]ni9feghRO-;Q$^J6phijg??#U.g,%5\CV/uSPc8fCl#.h+!l[_.L.A#Fbl6+."$"NKnDVAMO1IFKn.k9dUaf\r'(;p3\PV],?U_7BX2PDFTo'_&%;?cIIU/(*hYG*MV-rJJG"L-5Yo-0HB.o\4q[6%Z:bd.J2ETN"B.!;hcsugDrV*Y.pbXgoMf)E_+-,QV+pJI1\jE."./f/;.&EE0VnZ5+bmGg`8>OlLX77klI&SfVgZ*j@;%/C09\kJCN3Vo/&t#sqWqnBH*l7%L(dqHWIP.UXcRD,Uj]C,7)FEU1Z)Nu75E:Om$S8r/%[ilX,k_;'r#`[eOHl\RF'/90FQCUUIq@@;S1IWGhIgh:nnm*"D=Rc98j",O%].3PpC`f;XB;\LY;=B@VA)*(HM(V0(p'mBF+#4-$eWCt=G'nG*;G9u@#:.OdF\Z5V%kr1D@HYCRgJ1OulEelFUR=$gOjND"`P*-,G,U1#HuKIbC;ncZ\Tn*E)F$7#DlW+D6Xqendstream +Gb!;dD0)19&H8h>Z/_6qjKq6m]Euok1NFbq8X38;jCUGMLI#mbLj9B$f`(X$6\#aM$(PNe[;;UJp\*_:p=TZRi:/$;s%OtBI"$Mee@E!.BB\3KlR*#>/TnZ!uRR9Tm8?;pI;FD.M6`0;MQrRcpChlG7hR>q]qf!9^CN4Y5corMu"hi"qD]?ggA0\&@X9f8I&=ghD'aaPS8TQ-#%C^qiAS)L9OX4t`a:VK'>a`ZaY!'RLZ4,\F2?pPnUbSh'-U234gH560$BC[4.G?6N0bV"[SP:r9.[&9P=P9:C+c(oGVKi4Xa.1^Aum3$Jn;H@cDGL%Qt'a?HS\W)]g9M)bmbf5qYjT!F8uO/XC$6pOJ.L`G=a:)8!jej.IiAl8_7!\tiVe-!Tt-+bG8>e?(c,b2_%06(tN=@PtWQAa30][l76"q;OZ7>Ho:MP:Q25$4L#XJc`jfD1WBp:VhuB@m\':Zn.V4nPW=cDSE-]Om!^HSb>MOE*F]nY54It,0!L06U6]S>A`.84c].e;?D.fkKOrniX_66EmWSOu0&#Lb84Y<;Z0oI7JdY$_7Wc&O]1%3#j^YOE]%84;1n;;U&ImiB3$81?\h\7''_hHtTi4:#e$6Gs;ee&no(4Y+64N_J!A(N$f_uL[+)^+5ZXblHc'-BbAD(rNC=MZl^$9cB0N6_$IrHK'6`BI+!oYD2:hlVF,[TMAm"DbRU8m>_/Y@beoIG(^J;1;%%O63Ka#EId"hk4;rq=EIJ+g%$*+/*(ls<9i4M1"_)!q,A]?$fFU\AhO9fN.[T7X,K4MSrJfO/p=2V;?1*_)DZY/,aM5S?uD%kXH8L)W*/\nDYY9^5[E+C:`UDuWGbh8rWXU<:W-XLT`0Si#\LliqmT'0I!,5\J9BL\/b*b;5p[Kli[;l0.El!24-Z"P1.pU=%O`Up+u!Ya)n(.]54JW"DnXqJkJ($MjCPY[T8f-l@0XMh-2o$?l]+d'pG1HYWakBkX\e1O4ZWli\TG0/(Y^"u2$NR%sERObbHL:P&.9o9A9]>rQ"^(2>S/pKFn;";g[-m:[d[AqOU'G'>S4&l=*3Mat=$7rE?pgOf(dM4`WFH;-)41f3d2@m4hAd>K3S-#.(AoqV;ke.qT4<%WG]-RXbjQ9kOncG)Qrqgho&t9jpTZM7u^VeY#ikW$YF-Vnpa)He(AF"/Kk6YMj2XokkkfGE=Fc~>endstream endobj xref 0 52 @@ -344,13 +344,13 @@ xref 0000006519 00000 n 0000006608 00000 n 0000007648 00000 n -0000011309 00000 n -0000015166 00000 n -0000017792 00000 n +0000011419 00000 n +0000015126 00000 n +0000017914 00000 n trailer << /ID -[<932c07bb3580b032147403333a208980><932c07bb3580b032147403333a208980>] +[<4e8503afa0e5976fd874bce2eee583d9><4e8503afa0e5976fd874bce2eee583d9>] % ReportLab generated PDF document -- digest (opensource) /Info 29 0 R @@ -358,5 +358,5 @@ trailer /Size 52 >> startxref -19851 +20032 %%EOF diff --git a/docs/20260608_BE_SERVICES_and_infra.md b/docs/20260608_BE_SERVICES_and_infra.md new file mode 100644 index 0000000..aa18128 --- /dev/null +++ b/docs/20260608_BE_SERVICES_and_infra.md @@ -0,0 +1,238 @@ +# BE services & infrastructure โ€” validation map + +_Last validated: 2026-06-08. Companion to [INFRA.md](INFRA.md), [REMOTE_ACCESS_IMPL.md](REMOTE_ACCESS_IMPL.md)._ + +**Documentation index:** [README.md](README.md) + +--- + +## Table of contents + + +- [Topology](#topology) +- [Service inventory (mobile + console)](#service-inventory-mobile--console) +- [Data paths](#data-paths) +- [Validation status](#validation-status) +- [DNAT chain (WireGuard lab)](#dnat-chain-wireguard-lab) +- [RSSH / RBAC](#rssh--rbac) +- [Planned: SFU relay (Janus-class)](#planned-sfu-relay-janus-class) +- [Agent scripts](#agent-scripts) +- [Open findings โ†’ tickets](#open-findings--tickets) + + +--- + +## Topology + +```mermaid +flowchart LR + subgraph Internet + MOB["๐Ÿ“ฑ Android app"] + OPS["๐Ÿ–ฅ Operator browser"] + end + + subgraph Router["f0xx.org router"] + RDNAT["UDP 45340 DNAT"] + end + + subgraph FE["FE f0xx-monstro ยท apps.f0xx.org"] + TLS["TLS :443"] + FEDNAT["UDP 45340 DNAT"] + NGXFE["nginx reverse proxy"] + end + + subgraph BE["BE Alpine artc0 ยท :80"] + NGXBE["nginx apps.conf"] + FPM["PHP-FPM"] + DB["MariaDB / SQLite"] + WG["wg0 :45340"] + SSH["sshd bastion :443"] + end + + MOB -->|"HTTPS crashes/graphs/heartbeat"| TLS + OPS --> TLS + TLS --> NGXFE --> NGXBE --> FPM --> DB + MOB -->|"UDP WG lab"| RDNAT --> FEDNAT --> WG + MOB -->|"RSSH outbound"| SSH + FPM --> WG +``` + +| Hop | Host | Role | +|-----|------|------| +| Public DNS | `apps.f0xx.org`, `ra.apps.f0xx.org` | CNAME โ†’ FE | +| Router | `f0xx.org` (`134.17.26.161` WAN) | UDP `45340` โ†’ FE `10.7.0.10` | +| FE | Gentoo HVM | TLS, HTTP proxy โ†’ BE `:80`, UDP DNAT โ†’ BE `10.7.16.128` | +| BE | Alpine `10.7.16.128` | PHP consoles, device APIs, `wg0`, RSSH bastion | + +--- + +## Service inventory (mobile + console) + +| Service | Public URL / port | Mobile uses | Console uses | Status | +|---------|-------------------|-------------|--------------|--------| +| **Hub** | `https://apps.f0xx.org/app/androidcast_project/` | Indirect (links) | Landing | โœ… OK | +| **Crashes console** | `โ€ฆ/crashes/` | โ€” | Reports, home | โœ… OK | +| **Crash upload** | `โ€ฆ/crashes/api/upload.php` | โœ… gzip JSON | โ€” | โœ… OK | +| **Heartbeat / RA** | `โ€ฆ/crashes/api/heartbeat.php` | โœ… RA poll | โ€” | โœ… OK | +| **Session stats / graphs ingest** | `โ€ฆ/graphs/api/graph_upload.php` | โœ… (when enabled) | โ€” | โœ… OK | +| **Graphs dashboard** | `โ€ฆ/graphs/` | โ€” | Analytics UI | โœ… OK | +| **Tickets** | `โ€ฆ/crashes/?view=tickets` | โ€” | Issue tracking | โœ… OK | +| **Remote access** | `โ€ฆ/crashes/?view=remote_access` | โ€” | WG/RSSH ops | โœ… OK | +| **RBAC admin** | `โ€ฆ/crashes/?view=rbac` | โ€” | Roles / lockouts | โœ… OK | +| **APK builder** | `โ€ฆ/build/` | โ€” | Internal builds | โœ… OK | +| **OTA channel** | `โ€ฆ/v0/ota/channel/stable.json` | โœ… `settings.json` | โ€” | **PENDING** HTTP 400 โ€” not on apps vhost | +| **OTA manifest/APK** | TBD host/path | โœ… | โ€” | **PENDING** align with device `ota.base_url` | +| **Diag API** | `โ€ฆ/crashes/api/diag.php` | Optional | โ€” | โš ๏ธ 403 at edge (use upload/heartbeat) | +| **WireGuard data** | `ra.apps.f0xx.org:45340/udp` | โœ… lab mode | โ€” | โœ… DNAT chain + BE listen | +| **RSSH bastion** | `ra.apps.f0xx.org:443/tcp` | โœ… alpha mode | Operator SSH | โœ… API connect payload | + +--- + +## Data paths + +### Cast session (LAN โ€” alpha scope) + +```text +Sender UDP/TCP :41235 โ†โ†’ Receiver :41235 +Discovery UDP :41234 (+ NSD) +``` + +No BE required for LAN alpha. + +### Telemetry path + +```text +Phone โ†’ HTTPS โ†’ FE โ†’ BE PHP + upload.php crash JSON + heartbeat.php session + RA + graph_upload.php session metrics +``` + +### Remote access control plane + +```text +Phone poll โ†’ heartbeat.php (type:ra) +Operator โ†’ remote_access.php (whitelist, open_session, dashboard) +BE โ†’ wg set / rssh session row โ†’ connect JSON on next poll +``` + +--- + +## Validation status + +Run: `examples/crash_reporter/backend/scripts/validate_be_services.sh` + +| Check | 2026-06-08 result | +|-------|-------------------| +| Hub / crashes / graphs / build HTTP | โœ… | +| JS syntax (app, graphs, tickets, i18n) | โœ… | +| RBAC API smoke (on BE localhost) | โœ… | +| RA API smoke | โœ… (BE) | +| RSSH API smoke | โœ… `test_rssh_api.sh` | +| OTA public URL | FAIL 400 | +| Browser SyntaxError (historical) | โœ… cleared โ€” deployed JS passes `node --check` | + +--- + +## DNAT chain (WireGuard lab) + +```mermaid +sequenceDiagram + participant M as Mobile / laptop + participant R as Router f0xx.org + participant F as FE monstro + participant B as BE wg0 + + M->>R: UDP 45340 (public) + R->>F: DNAT โ†’ 10.7.0.10:45340 + F->>B: DNAT โ†’ 10.7.16.128:45340 + B->>B: wg0 decrypt +``` + +| Script | Host | Persist hook | +|--------|------|--------------| +| `wireguard_router_dnat.sh` | `f0xx.org` `/home/scripts/` | `iodine_warmup_helper.sh apply_rules` | +| `wireguard_fe_dnat.sh` | `f0xx-monstro` | `xen_firewall.sh start/stop` | +| `install_be_remote_access.sh` | `alpine-be` | `wg0` + sudoers | + +--- + +## RSSH / RBAC + +| Component | Path | Tune on BE | +|-----------|------|------------| +| RSSH sessions | `sql/migrations/009_rssh_sessions.sql` | MariaDB migrate | +| Provisioner | `src/RsshSessionProvisioner.php` | `config.php` โ†’ `remote_access.rssh` | +| Bastion | `sshd` / stream on `:443` | host keys, port range `18000โ€“18999` | +| RBAC API | `api/rbac.php` | `privilege_sets`, lockout clear | +| Cron purge | `scripts/purge_remote_access.php` | hourly crontab | + +**Smoke:** `test_rssh_api.sh`, `test_rbac_api.sh`, `ra_e2e_cli.sh` + +--- + +## Planned: SFU relay (Janus-class) + +> **Not in alpha.** Gray = future design surface; implementation on branch `feature/sfu-relay`, hidden from users until spec lands. + +```mermaid +flowchart TB + classDef future fill:#e5e7eb,stroke:#9ca3af,color:#374151 + + subgraph Future["SFU path (planned)"] + SFU["Janus / mediasoup SFU
BE :8089 or dedicated"] + SIG["Signaling API
PHP or sidecar"] + TURN["TURN optional"] + end + + subgraph Today["Alpha today"] + LAN["LAN UDP/TCP cast"] + RA["RSSH debug"] + end + + MOB2["๐Ÿ“ฑ Android"] --> LAN + MOB2 -.->|"post-alpha"| SIG + SIG -.-> SFU + SFU -.-> TURN + OPS2["Operator"] -.-> SIG + + class SFU,SIG,TURN future +``` + +| Piece | Status | Branch / flag | +|-------|--------|---------------| +| `CastConfig.SFU_RELAY_PREVIEW` | Stub `false` | `feature/sfu-relay` | +| `config.php` โ†’ `sfu.enabled` | Stub `false` | BE | +| `api/sfu_health.php` | Returns `disabled` | BE | +| Android `SfuRelayGate` | Hidden dev compile gate | App | +| FE nginx `location /janus/` | Exists for other stack โ€” **do not mix** with androidcast vhost | INFRA ยง8089 | +| Nginx + UDP ports for WebRTC | Design TBD with owner spec | โ€” | +| Mobile `TRANSPORT_WEBRTC` UI | Frozen (`ALPHA_FEATURE_FREEZE`) | โ€” | + +When the owner spec arrives: wire signaling auth to existing session/RBAC, add SFU room lifecycle beside (not replacing) LAN cast, and extend this doc ยง with concrete ports and URLs. + +--- + +## Agent scripts + +| Script | Purpose | +|--------|---------| +| `validate_be_services.sh` | Public reachability + JS syntax | +| `verify_remote_access_prod.sh` | BE WG/RSSH preflight | +| `test_rssh_api.sh` | RSSH connect payload | +| `test_rbac_api.sh` | RBAC panel API | +| `ra_e2e_cli.sh` | Full RA operator+device flow | +| `test_graphs_api.sh` | Graph ingest + dashboard | + +--- + +## Open findings โ†’ tickets + +| ID | Severity | Topic | Track in | +|----|----------|-------|----------| +| **SVC-OTA** | High | OTA `v0/ota` returns 400 on `apps.f0xx.org` โ€” wire nginx + staging path | **Tickets** dashboard | +| **SVC-DIAG** | Low | `diag.php` 403 at public edge | **Issues** (documented workaround) | +| **SVC-URL** | Medium | Legacy `f0xx.org` crash URL 404 โ€” devices should use `apps.f0xx.org` | **Tickets** + device `settings.json` | +| **SFU-SPEC** | Planning | Owner SFU spec integration | **Issues** (gray / post-alpha) | + +File via crashes console โ†’ **Tickets** for service/URL/nginx work; **Issues** for infra validation notes and SFU planning. diff --git a/docs/20260608_BE_SERVICES_and_infra.pdf b/docs/20260608_BE_SERVICES_and_infra.pdf new file mode 100644 index 0000000..974d3c5 --- /dev/null +++ b/docs/20260608_BE_SERVICES_and_infra.pdf @@ -0,0 +1,307 @@ +%PDF-1.4 +%“Œ‹ž ReportLab Generated PDF document (opensource) +1 0 obj +<< +/F1 2 0 R /F2 3 0 R /F3 15 0 R /F4 17 0 R /F5 19 0 R /F6 20 0 R +>> +endobj +2 0 obj +<< +/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font +>> +endobj +3 0 obj +<< +/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font +>> +endobj +4 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 21 0 R /Fit ] /Rect [ 45.68504 716.2874 78.58904 727.2874 ] /Subtype /Link /Type /Annot +>> +endobj +5 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 21 0 R /Fit ] /Rect [ 45.68504 705.2874 174.837 716.2874 ] /Subtype /Link /Type /Annot +>> +endobj +6 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 22 0 R /Fit ] /Rect [ 45.68504 694.2874 84.37304 705.2874 ] /Subtype /Link /Type /Annot +>> +endobj +7 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 22 0 R /Fit ] /Rect [ 59.68504 683.8499 176.3925 693.8499 ] /Subtype /Link /Type /Annot +>> +endobj +8 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 22 0 R /Fit ] /Rect [ 59.68504 673.8499 109.7025 683.8499 ] /Subtype /Link /Type /Annot +>> +endobj +9 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 22 0 R /Fit ] /Rect [ 59.68504 663.8499 156.39 673.8499 ] /Subtype /Link /Type /Annot +>> +endobj +10 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 22 0 R /Fit ] /Rect [ 45.68504 653.2874 104.381 664.2874 ] /Subtype /Link /Type /Annot +>> +endobj +11 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 22 0 R /Fit ] /Rect [ 45.68504 642.2874 147.925 653.2874 ] /Subtype /Link /Type /Annot +>> +endobj +12 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 22 0 R /Fit ] /Rect [ 45.68504 631.2874 96.80504 642.2874 ] /Subtype /Link /Type /Annot +>> +endobj +13 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 22 0 R /Fit ] /Rect [ 45.68504 620.2874 164.829 631.2874 ] /Subtype /Link /Type /Annot +>> +endobj +14 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 23 0 R /Fit ] /Rect [ 45.68504 609.2874 91.92504 620.2874 ] /Subtype /Link /Type /Annot +>> +endobj +15 0 obj +<< +/BaseFont /Symbol /Name /F3 /Subtype /Type1 /Type /Font +>> +endobj +16 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 23 0 R /Fit ] /Rect [ 45.68504 598.2874 130.061 609.2874 ] /Subtype /Link /Type /Annot +>> +endobj +17 0 obj +<< +/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font +>> +endobj +18 0 obj +<< +/Annots [ 4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R + 14 0 R 16 0 R ] /Contents 40 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 39 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 + /Trans << + +>> /Type /Page +>> +endobj +19 0 obj +<< +/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font +>> +endobj +20 0 obj +<< +/BaseFont /ZapfDingbats /Name /F6 /Subtype /Type1 /Type /Font +>> +endobj +21 0 obj +<< +/Contents 41 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 39 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +22 0 obj +<< +/Contents 42 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 39 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +23 0 obj +<< +/Contents 43 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 39 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +24 0 obj +<< +/Outlines 26 0 R /PageMode /UseNone /Pages 39 0 R /Type /Catalog +>> +endobj +25 0 obj +<< +/Author (Android Cast project) /CreationDate (D:20260608212303+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212303+02'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title (BE services & infrastructure \204 validation map) /Trapped /False +>> +endobj +26 0 obj +<< +/Count 13 /First 27 0 R /Last 38 0 R /Type /Outlines +>> +endobj +27 0 obj +<< +/Dest [ 21 0 R /Fit ] /Next 28 0 R /Parent 26 0 R /Title (Topology) +>> +endobj +28 0 obj +<< +/Dest [ 21 0 R /Fit ] /Next 29 0 R /Parent 26 0 R /Prev 27 0 R /Title (Service inventory \(mobile + console\)) +>> +endobj +29 0 obj +<< +/Count 3 /Dest [ 22 0 R /Fit ] /First 30 0 R /Last 32 0 R /Next 33 0 R /Parent 26 0 R + /Prev 28 0 R /Title (Data paths) +>> +endobj +30 0 obj +<< +/Dest [ 22 0 R /Fit ] /Next 31 0 R /Parent 29 0 R /Title (Cast session \(LAN \204 alpha scope\)) +>> +endobj +31 0 obj +<< +/Dest [ 22 0 R /Fit ] /Next 32 0 R /Parent 29 0 R /Prev 30 0 R /Title (Telemetry path) +>> +endobj +32 0 obj +<< +/Dest [ 22 0 R /Fit ] /Parent 29 0 R /Prev 31 0 R /Title (Remote access control plane) +>> +endobj +33 0 obj +<< +/Dest [ 22 0 R /Fit ] /Next 34 0 R /Parent 26 0 R /Prev 29 0 R /Title (Validation status) +>> +endobj +34 0 obj +<< +/Dest [ 22 0 R /Fit ] /Next 35 0 R /Parent 26 0 R /Prev 33 0 R /Title (DNAT chain \(WireGuard lab\)) +>> +endobj +35 0 obj +<< +/Dest [ 22 0 R /Fit ] /Next 36 0 R /Parent 26 0 R /Prev 34 0 R /Title (RSSH / RBAC) +>> +endobj +36 0 obj +<< +/Dest [ 22 0 R /Fit ] /Next 37 0 R /Parent 26 0 R /Prev 35 0 R /Title (Planned: SFU relay \(Janus-class\)) +>> +endobj +37 0 obj +<< +/Dest [ 23 0 R /Fit ] /Next 38 0 R /Parent 26 0 R /Prev 36 0 R /Title (Agent scripts) +>> +endobj +38 0 obj +<< +/Dest [ 23 0 R /Fit ] /Parent 26 0 R /Prev 37 0 R /Title (\376\377\000O\000p\000e\000n\000 \000f\000i\000n\000d\000i\000n\000g\000s\000 !\222\000 \000t\000i\000c\000k\000e\000t\000s) +>> +endobj +39 0 obj +<< +/Count 4 /Kids [ 18 0 R 21 0 R 22 0 R 23 0 R ] /Type /Pages +>> +endobj +40 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 822 +>> +stream +Gatm9>u03/'Rf.Ggo%,f_R5qQhHJLu6\quo@kX)sPIPI!@V<,J`4qq.'Xf2&!C`+`[D)>p553iZ$"3Xlp77KLdfd[3!e`nG#3$gCP&m!:8&(,+519+c+*uRn+:&O%,1l7hbB>+U3%KNTK[<4$`mhK4P7/jV:)_G-&?e)5iK-*l"3?=H*/&hDO%(`&[=Q_I#+DSuSoP;/+;\h4Zr(s\C;jUQB`L4qj;Bba'Mu+#(m86f]SD\<85&ilI@d2$'BD;Q7ij">:Z1bED%:LG+Kr=WUJK7ZK:>*N@5M&k"DVq]O2KLi[Ye^UX"S+lGf<(ZCAFV[]4^p]>$c_m(ppZA%WKKVJE?a2KSR2HmV('t>.[am&p@Q"OD@C`0O,INK:mA*lg^Nme\Y?Ed\4iV(34KJ!u*gaJ]=7]XJL+6_G]4+E`C3Ih!4C&O[70B099J;j@=;?8fsI0:bfIsl(/4%#1>lOg3g5P?=gf_Y?M/$_?K;WNr2nr[f"&kBZ-gobO6=eSaHClKIc56!Qor(@rendstream +endobj +41 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 3191 +>> +stream +Gb!#^HZ.Xu')t1g@c53,hVCX:olb>e#G2U=&BbW!a!Gg\bqO_cdrd2tZEo&8U)CbcQ&eiT7XY&7jHLV_*SBKCRO\/J^`\*t'T5/Z`"]'>@O>IecScp^C$.mG^Q&e&%kLBjbe2W1e0"pq"#P9d`=hO,(e+(M=,b(/p(?i.#+oX/t4Wi0JqIN/UdUE?S]#aI2("7mr&=I(S]R=\Gckgr?kT5ZT9$I&/U0"f784?G#il-Io)n?*H!p+n6SuQ$MrG3@;5AsqYX]B&`/`3I=]1_Z%LDXFl7cFb-R-PZ5AU0i3"*H#"6^&9_S#5&?CKp1SO>>(V]WG[>j_,?"a(DI#MD^aJT0\V]R&]C2#rI'\\IYcS;b_@^f5><5P@I0?:YYb;,VRcTk4S)9N4h6P0kumLk[1U1'ho-'6OB[?'Y7Y*!SNqB#r''01\LZi0_TA:O)dT=jl3p&7)@U,/ig^f_sT#;Y/nWX5CPp04d2UP!r*YqHZBkUlR)I+R66>F\B.M8S%Eq[DIT;;?CPGF\oK^1jp:;XXEUqakU)'@(l:0)=^J*86;=^4Rsj,oqOcm#S@#0)p)jXp8%'<3TW'ge4YJ?=D9C^>\QJ5gagXOG(nkAZ)'OQ$kpDE8TJK1m&N(k^oT:6mK==D[4ng5;fLUEHu)=H.;NT/0k]`]*mORc7VmdIs"$kLfe.E=m!+q%1"_InT-k&]u]s,_k1#T$;]\J7;@3@its3%!=cY4[_erqiLXX9;;$;LWDV^&ahaH9b^Joah$?>F128@1#d98D%$i,)A/`u(#,HBG\-%_^E_VCqP^fF(CN2/_S<_C.qUHlUq66N:u!.[\a)VGa64>+XNU?&D\-%A%!aAb];OQFDF*Z.-Q@Y^nfTd3U_;t/9H@QZX,$hZ!c=7lA?J*sg)r0!eO`j)G`V^eRl)\PqLY"U?=)59f^=en_.;a`ugj=KP9S)dKo[Fo0oQ$s[t@WT7WqJ?jWU=X&%nJJZ.MGIc;2+tnGiu+8AZV`aIIt)^)#tr-;9#nE%e\UFGY6]k,WDX\lgYD\T"J9@0qn_7_">Mau*ngn18pnE$[)7O_-/B,38_;\c5=o*Q]`;1O"dr]0[BVu-7[m]7lpi8lgY><2c+M`dP$ul2("57^!omi+Xi'nH?LaDHL#aW8h(t71^'2O>LNQAa5MM*pf8L6;c'Ipq$dWhpA<,WcFhHnA-:[&Mi>6Ql)frZ\1L5_HDVk$*ZQRAj9P8;CW6$M8?0-fhEfZJT])"&-g6SShgpXr_5:_]$RJ>B[.(tU,;#,oVNa'(C",Zj4J<)>Up>*ub=XjY;k1E+kV^^@Puk1>/r(@7(X+c\>UQqnDs=ZotWVF7.`t95;>Y&6:c=T,lM"M=e?"fCRX`@%gqpqe!VTVq?YB`(_I5f_Dqs93O"jGc(?qEY]gG\nEu^^OS6s\\WVc-!=ZkHdiPS`7BjLPC0__[<6PPoGB;X\p^PFhaJAuWQ?%-R&YPcHGF0WMo_LMcs2NM<96@_ri,Xh>nKD5ic9`&UX#Ca\%kIos$rgMg>JtN&^J3i>30prFT-X^+.Vs8_\(CEP\TTO6G3/hYfsg[2Z8CH5QSFg:qeH^?Z$mJ$9]O-H4J:j]YRHg&5d"pFRN!j3dPa`V'&PS)5gP*p$Ur7leQ-!K'Du&LAG[56WaQ2L0!6eWrnSa3mFO`f?s!OHAdrh7f8$`$W7*BEV6e[kk`TV,k\Ja*3S)CMTA$"]>Ja_)CT4l=L_gTZdSsAMfMM9K3m.-sqE0%kC6ZfZ3KcDGW9cH<8er)F%:";BkeXg%YAM>@5XX>(U]:1Ll8N40pc\mSE$J*j%L.WT!FTVGf@g3]NAfg2OTYc\Qh,6aHG+J"q&UPIt)(OF<:e]it2Q#5;J14G4d:Tr=.IX7=FkWB`;):WkBSnT:?L1)'A;WfMfZZm4WAKMk1D4T"8A\tF,h4PL8bI.f=BYoGVBf?q;BXA!7aaq@=1"BXeC'(c1F(!f=gXTZUp;O#QXuC0L=3X[XA?9#2-jV@aA#)33I^ncP-OEKS1endstream +endobj +42 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 3190 +>> +stream +Gb!SnD0+Gi')q<+Z.#2fW/XL`i4JHH)*4;6)oXu'5M,D$O32KIP@?ehSYl*1l.o6@/;fUIoT2B`1JVkcdZ3`=qit:@?89Hr`5T)?lDZNW@de`7kGL#kGDsXEX'G2:E"p"f@FcilD>5oaW+XAobA0Um?.m.Kuo4g3aVf+f3_3_E/ZS^d%&JM5hVS-GUlE%4Jdcj-0Z;I9`&[/?+Fm84"(LVpMPVF]`N,GE!?s*0$4/%`A9Ph"A\S+FQlW\R=0?^WkTJH&LHEZbf$JrXZ%Pj^B:\;o%EMRVc;U$4@9-H-F4$-Mm9:@JOkt@?SJ=KZ)Ln,=]T^rE5D!5m8qbPDDH#\XD1Rca#^Y2@QcLn8)TUu:$!l9j=`b.="`qU>i/_]FKNo#Y'42'#`B%,=Rg@B5Ld,R)H-Z=OUR"B*N%(BBtQcRU]4@XGR:8)K)S]@Vi'#SO14=LIeeBT*bCE2\2U\2SQWm!koFejbpCoT.eX$n\oF-OlQZ^4]67,V"k)rf:*NL^GOO^#1[PGIL0Ma;u98/IkGIZZS:2Kd_1N[otL+EqeV9?:`fO>ihno(W=SSO#T%cPDHFBXfFDK>_7C"jVlt[o-6SqTPWe#gNqMc'7`/.q"5MiaIL(`K*C7l6QG$kE=A-j(X6'-Ii_<`:nCCl(M3.iAkDOb^%K/cKh:Y?:mo%9P4]rbZGJtbAd_oK'V/uR9i.Ac,7>Pcf:)R)OD'tCHVAnc?(0BVI7AAaFF*/O2G(is't"dS(^(Ao<4':f,)2O"B3p1dH9,UHFQ`$i:"D&?R!!In,S[M5^Fp`@b'5L$8H.O<<9ft9rgML&;L\8-NW(_-/7jS'OQI!uea9_7RRM%1BF!`OPu4$/-l^a+;bk<[0$l@^][j.qf^XGFo:L1LCMc1"3^CINXL(=mINZ-7*]]2Wm>Tc`^pP,=uNFS>S(pcS"bR93e[B\)1aX;.7_DN&\hkE+H5GKGY`P,%7[dEckO4,gA*n`;\a`i=ejpAjO&Ji0QfkDV'cP$P;=0L2T!;31(!DHUCF;m5=f/$/d0Ju'-Zfr6JKH0s=59k2kFmc`L8357sSfpin%4A&<,]R]I,$]3OJ'K8YRYcE]cP@*cO!1.";.7h0X8odfntOk(T9,tOVC"(6l,@UIS<8mf3mYcmr%(_Eg2.$p5\$B]Ck@eaJ7E$Fa7A'W9bg/4P#:nQ9eg_'mI?DlULuUh6bq,lkG_5V6M_j=?)d/QQY$JlPo>)L9&;i/!/F.`kD@Gi3JP'Rn0m5g)G>ajBFl[.u:d3Nu\)3N:tP[S=t87#,IfX_,2i"M.GBoRqU;h)Y\hF_L/m&jgAC>4T#c[,t5`hBT/Z[.sZ<<'#3k7V05-ieU)F;La2YULQ6AeLAn'Wo+oedb]l\+EW))ntehGm`h_%Kq^XpqC_,lFMF;WD-XDo=f"hZL"ao#e8$??mt0]mhX?RmEfJu9LSA-#l1%&[S5eS1JcO1_&'1uM@SS=lug#S(`u3t!;E"P%gklrHL(\LU$+ErWLN.*hNO.)4Fj0kpqslGhXk%Y4l#*@;OY0L4qUY6Bd$?rK2;Rg5T(`%7"jm47![d3pjh0:`m_NZ9i0DBLr:D[+mcoi)K$?::1I"!Jhbkoi3?"`kfk_8Tg(O%2p7m^<&RV'GjSCZAeW;r1mGJ))13r#;9ZetN>t`e>#4_)!BtQ'XZZ4OR-;G_?l>P,$*;*(b!e5i6Q=^E((L./g&QY6-aaF(`#h6I,CIH%Y>:0,`Nk*&7mG!-4RNEo.u0(K#N=3YS?UG15VhXA5O7u+;=/FRVX/A?h/i5rr>s.VQ0~>endstream +endobj +43 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 3117 +>> +stream +Gau0FHZ.Xu')t1gJk0lH\ntuk+5OU3:1C+Md`-&a>O3X@K9g1TXXn3U3KM..p_uhk/1GmWpKBC&9lchqiGXI:O9g?4pnteok\Q7`@gP^^R]hgK$7_KOUXB#'O!AAR;Ukp+e3k&9MBn"8V8BsAIn`88U>ZkX&TK-W`(+:L4Brs/74D^jl&q^5q%f?28E^"Y+d95l=aBYehV^(SorZ075673'KQbraM.cNP_b0Hu=TC7eq?Eh6oie%RZf0`pH5LAf:A2$6?+<.Yc@bl-NGO7s_%(CqgioH%W%a1b-*B=\^Bk1@bKO\NYG,_H=rIXuB'/4gc.6p7%>j%'_U=j[p/.$cJ(-5$_][T&*=Q-Zq]1/PC^=d!oL.Og1/a%nsas%V+$$7`@#rj'"`B4nh-7c>n@HacRUEi+rouP/SRY\"A+;GoEs#Z+nk:4A@e%]f-LoP.f>a6\!CTKi2bu8SjULXVuFhE$P6Btl0*HgqdM<$rH:'peo&Bihb,j^oh=";*cAjN&nMq/Sig.aO4?gEP@>)Ok6=VX"Q>HeG-qWsJ18bH$QZJ:JV#5,-S$V0Z$Z1/+qCY+%cS'7W-.foO@_06AW#OQ,%N!eE\*AfGl4h3+Q#_5%3d=qWLNNi?`h93*das3g>O\j("C:!=l\GA7X%RE_;i%Vg[*O=Cco[h_3ml2jf!=eeCq*p\!q0@aR]dbHh]AT$Cl3Rj&&(Z7(aM3f17?,#/7f*,SZ:I)m@;)C@_oXX\t@OLL8HNXa^_do$M3NOlYLStSM.^:c;Hmf%cH_S]4ZGJ1(NQ@OAbLB9#;"?-_H-OnRr1c^h>HoN^j$dPm"[JgVMJ@OJtI^^[F[E.3#96U%7[:jUi21O'1kS4Wn2to[#.\'(ZcGiF=UO0Xmj4&?e7f;_UnCTYSXn^aPb(Z6D4.UNF@$YV?W.6,AYPJ5J?.76tem7[[Kb*`C-JdZig7E),*ETTB5_=mR_(T+06E?VA,X8j<"tBVJt$9>54nC+@ng\ha=QmLOjd@r@E1b]"'+D;\A[Y""2.7lUq5#JrYi:4OODAK;#gM`)uXM"!7I5@B.!\5NU\Zf1_,KH2GCNC-=IaE(G$I^UErQ@u^oi8jKW+-OFW2XJ,,b7!pO9`R6cL&VI)MMU_O81m7>[H"V6-RZE]I6/\dfdB\MKPm^>9W3r2S:O'of.EiUJuY4jW(a\+SA_fTNscM1:&G8O4*6+R^7\*AF"#%LN*=AF956&%@8m1M>1_JdkfUn1>7k/o.4EQ./,KB"FT67?D2Q$Mj4Kp1hNSaXcpdmjPUF'sTJ(&EmWGdPoW9tl+F"nlYDX]00G6RZ2IQ[AZn'abPuL_#l+&_I#MU1+=0EQ+"8;OQ6gWKen5E8"cikp6eKU^!H:4lrap*:+*5oP6+=&J`?#LXs-rR\L9aV4rKLLf\Z-jpt;FPTaX>0mlj17`"LgqQ0?/]W!(m6+M:K4h?.[-?g:PO(W6jSK#hJ2Hei6$`1S7MGis>XM@I/c&\ir:'*8g:f8Fh5gX?[Qs.4B-6sjLXj7`Sab^gYM\V&RI8T@jTU:TAW\Ff@-:?mQ`ZZXfk1.MOdbWH:jZO+^#@#^7=B#')1i/aIg+@?iOlW>NbijY>MK\j`r:FSbCj//md\W8k\dRl(m(eKQN=1iWgd$,r#;j>*H_-[iY^IWbIl>bfFAok.+0M'<(.Nb:m7h:?.67E,dbJCd.t!]9q1Z#iYh%gD\3fhM*!d=2#*BU4P(La9;&IBALoU:VG6"rIoHu(u(/hcFH/ZW4gqPiCtD_o>TA_011c8Ykg"7rmSL8K`H7mTQ)Y$]CnFX'&7sD?d/:.eUqYSVqVq=57(c+1K^\8hN^V1NPlSF@36&G*ZcT/>M4^B"hQV=C^IeWlruVgL:#+gi9tIj^k<]/7Ohfk.g7?jHo'RL0_!r9Od,E/,Q#YQR'.lhq/oeq#iNTP`':g@Y(9.SfCi:?s+O!QqW3(=rWQBFBS&adO+@C:2E0s^+2=XW#>YYOgHu0H=M]dgeagF!XA=8%S?VpHFnlendstream +endobj +xref +0 44 +0000000000 65535 f +0000000061 00000 n +0000000146 00000 n +0000000253 00000 n +0000000365 00000 n +0000000513 00000 n +0000000660 00000 n +0000000808 00000 n +0000000956 00000 n +0000001104 00000 n +0000001250 00000 n +0000001398 00000 n +0000001546 00000 n +0000001695 00000 n +0000001843 00000 n +0000001992 00000 n +0000002070 00000 n +0000002218 00000 n +0000002334 00000 n +0000002633 00000 n +0000002739 00000 n +0000002823 00000 n +0000003029 00000 n +0000003235 00000 n +0000003441 00000 n +0000003528 00000 n +0000003851 00000 n +0000003926 00000 n +0000004016 00000 n +0000004149 00000 n +0000004293 00000 n +0000004412 00000 n +0000004521 00000 n +0000004630 00000 n +0000004742 00000 n +0000004865 00000 n +0000004971 00000 n +0000005100 00000 n +0000005208 00000 n +0000005413 00000 n +0000005495 00000 n +0000006408 00000 n +0000009691 00000 n +0000012973 00000 n +trailer +<< +/ID +[<0a21ec630059622c51746ded189e0805><0a21ec630059622c51746ded189e0805>] +% ReportLab generated PDF document -- digest (opensource) + +/Info 25 0 R +/Root 24 0 R +/Size 44 +>> +startxref +16182 +%%EOF diff --git a/docs/20260608_STREAM_DUMP_DEBUG.pdf b/docs/20260608_STREAM_DUMP_DEBUG.pdf index 04cb2fc..0719b25 100644 --- a/docs/20260608_STREAM_DUMP_DEBUG.pdf +++ b/docs/20260608_STREAM_DUMP_DEBUG.pdf @@ -107,7 +107,7 @@ endobj endobj 19 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212303+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212303+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Stream dump \204 developer debug recording \(FR 0.1\)) /Trapped /False >> endobj @@ -220,7 +220,7 @@ xref trailer << /ID -[<0d244f03f80a81b6b033b4d323b34444><0d244f03f80a81b6b033b4d323b34444>] +[<4e4af14b1218eb9decff8ad3a09189c5><4e4af14b1218eb9decff8ad3a09189c5>] % ReportLab generated PDF document -- digest (opensource) /Info 19 0 R diff --git a/docs/ALPHA.pdf b/docs/ALPHA.pdf index 45fd14d..709c8e6 100644 --- a/docs/ALPHA.pdf +++ b/docs/ALPHA.pdf @@ -153,7 +153,7 @@ endobj endobj 27 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212303+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212303+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Android Cast \204 alpha release & QA) /Trapped /False >> endobj @@ -320,7 +320,7 @@ xref trailer << /ID -[] +[<95139d8fc1ed2da3b56d4980d1b780a5><95139d8fc1ed2da3b56d4980d1b780a5>] % ReportLab generated PDF document -- digest (opensource) /Info 27 0 R diff --git a/docs/ALPHA_SOAK.pdf b/docs/ALPHA_SOAK.pdf index a731e99..5e4f4d9 100644 --- a/docs/ALPHA_SOAK.pdf +++ b/docs/ALPHA_SOAK.pdf @@ -92,7 +92,7 @@ endobj endobj 17 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212303+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212303+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Alpha soak checklist \(LAN demo\)) /Trapped /False >> endobj @@ -183,7 +183,7 @@ xref trailer << /ID -[] +[<3cd389deb41e9e9df8a6a0feadd5b9c6><3cd389deb41e9e9df8a6a0feadd5b9c6>] % ReportLab generated PDF document -- digest (opensource) /Info 17 0 R diff --git a/docs/AV_QUALITY_QA_SESSION.pdf b/docs/AV_QUALITY_QA_SESSION.pdf index cfc7eb9..7c7392d 100644 --- a/docs/AV_QUALITY_QA_SESSION.pdf +++ b/docs/AV_QUALITY_QA_SESSION.pdf @@ -214,7 +214,7 @@ endobj endobj 37 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (AV quality enhancement \204 Q&A session notes) /Trapped /False >> endobj @@ -455,7 +455,7 @@ xref trailer << /ID -[] +[] % ReportLab generated PDF document -- digest (opensource) /Info 37 0 R diff --git a/docs/BUILD_DEPLOY.pdf b/docs/BUILD_DEPLOY.pdf index 63806d5..8134d0b 100644 --- a/docs/BUILD_DEPLOY.pdf +++ b/docs/BUILD_DEPLOY.pdf @@ -92,7 +92,7 @@ endobj endobj 17 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Android Cast build ecosystem) /Trapped /False >> endobj @@ -190,7 +190,7 @@ xref trailer << /ID -[] +[] % ReportLab generated PDF document -- digest (opensource) /Info 17 0 R diff --git a/docs/COMMERCIAL.pdf b/docs/COMMERCIAL.pdf index a5f8d44..417c468 100644 --- a/docs/COMMERCIAL.pdf +++ b/docs/COMMERCIAL.pdf @@ -67,7 +67,7 @@ endobj endobj 12 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Commercial features \(developer-gated\)) /Trapped /False >> endobj @@ -135,7 +135,7 @@ xref trailer << /ID -[<0c23c7846cb813e7f6634f931914a505><0c23c7846cb813e7f6634f931914a505>] +[] % ReportLab generated PDF document -- digest (opensource) /Info 12 0 R diff --git a/docs/CRASH_REPORTER.pdf b/docs/CRASH_REPORTER.pdf index 143ac79..a816187 100644 --- a/docs/CRASH_REPORTER.pdf +++ b/docs/CRASH_REPORTER.pdf @@ -72,7 +72,7 @@ endobj endobj 13 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Anonymous crash reporter) /Trapped /False >> endobj @@ -141,7 +141,7 @@ xref trailer << /ID -[] +[<1a0c37f5f70803a73095c49ce8a7e42e><1a0c37f5f70803a73095c49ce8a7e42e>] % ReportLab generated PDF document -- digest (opensource) /Info 13 0 R diff --git a/docs/GIT_FLOW.pdf b/docs/GIT_FLOW.pdf index 2e1686e..77ec100 100644 --- a/docs/GIT_FLOW.pdf +++ b/docs/GIT_FLOW.pdf @@ -2,7 +2,7 @@ %“Œ‹ž ReportLab Generated PDF document (opensource) 1 0 obj << -/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 9 0 R /F5 12 0 R /F6 29 0 R +/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 10 0 R /F5 13 0 R /F6 30 0 R >> endobj 2 0 obj @@ -22,159 +22,139 @@ endobj endobj 5 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 31 0 R /Fit ] /Rect [ 45.68504 716.2874 75.47704 727.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 32 0 R /Fit ] /Rect [ 45.68504 716.2874 75.47704 727.2874 ] /Subtype /Link /Type /Annot >> endobj 6 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 31 0 R /Fit ] /Rect [ 45.68504 705.2874 88.37304 716.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 32 0 R /Fit ] /Rect [ 45.68504 705.2874 88.37304 716.2874 ] /Subtype /Link /Type /Annot >> endobj 7 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 31 0 R /Fit ] /Rect [ 45.68504 694.2874 161.733 705.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 32 0 R /Fit ] /Rect [ 45.68504 694.2874 161.733 705.2874 ] /Subtype /Link /Type /Annot >> endobj 8 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 31 0 R /Fit ] /Rect [ 45.68504 683.2874 120.381 694.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 32 0 R /Fit ] /Rect [ 45.68504 683.2874 120.381 694.2874 ] /Subtype /Link /Type /Annot >> endobj 9 0 obj << -/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font +/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 59.68504 672.8499 177.6525 682.8499 ] /Subtype /Link /Type /Annot >> endobj 10 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 45.68504 672.2874 140.285 683.2874 ] /Subtype /Link /Type /Annot +/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font >> endobj 11 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 45.68504 661.2874 152.397 672.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 45.68504 662.2874 140.285 673.2874 ] /Subtype /Link /Type /Annot >> endobj 12 0 obj << -/BaseFont /ZapfDingbats /Name /F5 /Subtype /Type1 /Type /Font +/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 45.68504 651.2874 152.397 662.2874 ] /Subtype /Link /Type /Annot >> endobj 13 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 59.68504 650.8499 189.1425 660.8499 ] /Subtype /Link /Type /Annot +/BaseFont /ZapfDingbats /Name /F5 /Subtype /Type1 /Type /Font >> endobj 14 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 59.68504 640.8499 180.5775 650.8499 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 59.68504 640.8499 189.1425 650.8499 ] /Subtype /Link /Type /Annot >> endobj 15 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 45.68504 630.2874 155.277 641.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 59.68504 630.8499 180.5775 640.8499 ] /Subtype /Link /Type /Annot >> endobj 16 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 59.68504 619.8499 231.015 629.8499 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 45.68504 620.2874 155.277 631.2874 ] /Subtype /Link /Type /Annot >> endobj 17 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 34 0 R /Fit ] /Rect [ 45.68504 609.2874 115.949 620.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 59.68504 609.8499 231.015 619.8499 ] /Subtype /Link /Type /Annot >> endobj 18 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 34 0 R /Fit ] /Rect [ 45.68504 598.2874 139.053 609.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 45.68504 599.2874 115.949 610.2874 ] /Subtype /Link /Type /Annot >> endobj 19 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 34 0 R /Fit ] /Rect [ 45.68504 587.2874 168.829 598.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 36 0 R /Fit ] /Rect [ 45.68504 588.2874 139.053 599.2874 ] /Subtype /Link /Type /Annot >> endobj 20 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 45.68504 576.2874 159.045 587.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 36 0 R /Fit ] /Rect [ 45.68504 577.2874 168.829 588.2874 ] /Subtype /Link /Type /Annot >> endobj 21 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 45.68504 565.2874 224.189 576.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 36 0 R /Fit ] /Rect [ 45.68504 566.2874 159.045 577.2874 ] /Subtype /Link /Type /Annot >> endobj 22 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 59.68504 554.8499 193.9125 564.8499 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 36 0 R /Fit ] /Rect [ 45.68504 555.2874 224.189 566.2874 ] /Subtype /Link /Type /Annot >> endobj 23 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 59.68504 544.8499 143.0625 554.8499 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 36 0 R /Fit ] /Rect [ 59.68504 544.8499 193.9125 554.8499 ] /Subtype /Link /Type /Annot >> endobj 24 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 59.68504 534.8499 111.375 544.8499 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 36 0 R /Fit ] /Rect [ 59.68504 534.8499 143.0625 544.8499 ] /Subtype /Link /Type /Annot >> endobj 25 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 59.68504 524.8499 175.5675 534.8499 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 36 0 R /Fit ] /Rect [ 59.68504 524.8499 111.375 534.8499 ] /Subtype /Link /Type /Annot >> endobj 26 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 59.68504 514.8499 200.565 524.8499 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 37 0 R /Fit ] /Rect [ 59.68504 514.8499 175.5675 524.8499 ] /Subtype /Link /Type /Annot >> endobj 27 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 59.68504 504.8499 228.9375 514.8499 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 37 0 R /Fit ] /Rect [ 59.68504 504.8499 200.565 514.8499 ] /Subtype /Link /Type /Annot >> endobj 28 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 45.68504 494.2874 73.25304 505.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 37 0 R /Fit ] /Rect [ 59.68504 494.8499 228.9375 504.8499 ] /Subtype /Link /Type /Annot >> endobj 29 0 obj << -/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F6 /Subtype /Type1 /Type /Font +/Border [ 0 0 0 ] /Contents () /Dest [ 37 0 R /Fit ] /Rect [ 45.68504 484.2874 73.25304 495.2874 ] /Subtype /Link /Type /Annot >> endobj 30 0 obj << -/Annots [ 5 0 R 6 0 R 7 0 R 8 0 R 10 0 R 11 0 R 13 0 R 14 0 R 15 0 R 16 0 R - 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R - 27 0 R 28 0 R ] /Contents 63 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 62 0 R /Resources << -/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] ->> /Rotate 0 - /Trans << - ->> /Type /Page +/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F6 /Subtype /Type1 /Type /Font >> endobj 31 0 obj << -/Contents 64 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 62 0 R /Resources << -/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] ->> /Rotate 0 /Trans << - ->> - /Type /Page ->> -endobj -32 0 obj -<< -/Border [ 0 0 0 ] /Contents () /Dest [ 33 0 R /Fit ] /Rect [ 62.14104 108.3646 173.725 117.9646 ] /Subtype /Link /Type /Annot ->> -endobj -33 0 obj -<< -/Annots [ 32 0 R ] /Contents 65 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 62 0 R /Resources << +/Annots [ 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 11 0 R 12 0 R 14 0 R 15 0 R 16 0 R + 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R + 27 0 R 28 0 R 29 0 R ] /Contents 65 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 64 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -182,9 +162,9 @@ endobj >> /Type /Page >> endobj -34 0 obj +32 0 obj << -/Contents 66 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 62 0 R /Resources << +/Contents 66 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 64 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -192,19 +172,34 @@ endobj /Type /Page >> endobj +33 0 obj +<< +/Contents 67 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 64 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +34 0 obj +<< +/Border [ 0 0 0 ] /Contents () /Dest [ 35 0 R /Fit ] /Rect [ 62.14104 586.0693 173.725 595.6693 ] /Subtype /Link /Type /Annot +>> +endobj 35 0 obj << -/Contents 67 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 62 0 R /Resources << +/Annots [ 34 0 R ] /Contents 68 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 64 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] ->> /Rotate 0 /Trans << +>> /Rotate 0 + /Trans << ->> - /Type /Page +>> /Type /Page >> endobj 36 0 obj << -/Contents 68 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 62 0 R /Resources << +/Contents 69 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 64 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -214,261 +209,279 @@ endobj endobj 37 0 obj << -/Outlines 39 0 R /PageMode /UseNone /Pages 62 0 R /Type /Catalog +/Contents 70 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 64 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page >> endobj 38 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) - /Subject (\(unspecified\)) /Title (Android Cast \204 Git flow \(green `master`\)) /Trapped /False +/Outlines 40 0 R /PageMode /UseNone /Pages 64 0 R /Type /Catalog >> endobj 39 0 obj << -/Count 25 /First 40 0 R /Last 61 0 R /Type /Outlines +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title (Android Cast \204 Git flow \(green `master`\)) /Trapped /False >> endobj 40 0 obj << -/Dest [ 31 0 R /Fit ] /Next 41 0 R /Parent 39 0 R /Title (1. Goals) +/Count 27 /First 41 0 R /Last 63 0 R /Type /Outlines >> endobj 41 0 obj << -/Dest [ 31 0 R /Fit ] /Next 42 0 R /Parent 39 0 R /Prev 40 0 R /Title (2. Branches) +/Dest [ 32 0 R /Fit ] /Next 42 0 R /Parent 40 0 R /Title (1. Goals) >> endobj 42 0 obj << -/Dest [ 31 0 R /Fit ] /Next 43 0 R /Parent 39 0 R /Prev 41 0 R /Title (3. Branch diagram \(steady state\)) +/Dest [ 32 0 R /Fit ] /Next 43 0 R /Parent 40 0 R /Prev 41 0 R /Title (2. Branches) >> endobj 43 0 obj << -/Dest [ 31 0 R /Fit ] /Next 44 0 R /Parent 39 0 R /Prev 42 0 R /Title (4. Daily development) +/Dest [ 32 0 R /Fit ] /Next 44 0 R /Parent 40 0 R /Prev 42 0 R /Title (3. Branch diagram \(steady state\)) >> endobj 44 0 obj << -/Dest [ 33 0 R /Fit ] /Next 45 0 R /Parent 39 0 R /Prev 43 0 R /Title (\376\377\0005\000.\000 \000R\000e\000l\000e\000a\000s\000e\000:\000 \000n\000e\000x\000t\000 !\222\000 \000m\000a\000s\000t\000e\000r) +/Count 1 /Dest [ 32 0 R /Fit ] /First 45 0 R /Last 45 0 R /Next 46 0 R /Parent 40 0 R + /Prev 43 0 R /Title (4. Daily development) >> endobj 45 0 obj << -/Count 2 /Dest [ 33 0 R /Fit ] /First 46 0 R /Last 47 0 R /Next 48 0 R /Parent 39 0 R - /Prev 44 0 R /Title (6. Hotfixes \204 chosen strategy) +/Dest [ 33 0 R /Fit ] /Parent 44 0 R /Title (4.1 Fast track on next \(alpha sprint\)) >> endobj 46 0 obj << -/Dest [ 33 0 R /Fit ] /Next 47 0 R /Parent 45 0 R /Title (\376\377\000D\000e\000f\000a\000u\000l\000t\000:\000 \000h\000o\000t\000f\000i\000x\000 \000f\000r\000o\000m\000 \000m\000a\000s\000t\000e\000r\000 \000\(\000o\000p\000t\000i\000o\000n\000 \0001\000\)\000 '\023) +/Dest [ 33 0 R /Fit ] /Next 47 0 R /Parent 40 0 R /Prev 44 0 R /Title (\376\377\0005\000.\000 \000R\000e\000l\000e\000a\000s\000e\000:\000 \000n\000e\000x\000t\000 !\222\000 \000m\000a\000s\000t\000e\000r) >> endobj 47 0 obj << -/Dest [ 33 0 R /Fit ] /Parent 45 0 R /Prev 46 0 R /Title (Exception: fix only on next \(option 2\)) +/Count 2 /Dest [ 33 0 R /Fit ] /First 48 0 R /Last 49 0 R /Next 50 0 R /Parent 40 0 R + /Prev 46 0 R /Title (6. Hotfixes \204 chosen strategy) >> endobj 48 0 obj << -/Count 1 /Dest [ 33 0 R /Fit ] /First 49 0 R /Last 49 0 R /Next 50 0 R /Parent 39 0 R - /Prev 45 0 R /Title (7. Protection rules \(CI + policy\)) +/Dest [ 33 0 R /Fit ] /Next 49 0 R /Parent 47 0 R /Title (\376\377\000D\000e\000f\000a\000u\000l\000t\000:\000 \000h\000o\000t\000f\000i\000x\000 \000f\000r\000o\000m\000 \000m\000a\000s\000t\000e\000r\000 \000\(\000o\000p\000t\000i\000o\000n\000 \0001\000\)\000 '\023) >> endobj 49 0 obj << -/Dest [ 33 0 R /Fit ] /Parent 48 0 R /Title (7.1 How to protect branches \(not local hooks alone\)) +/Dest [ 33 0 R /Fit ] /Parent 47 0 R /Prev 48 0 R /Title (Exception: fix only on next \(option 2\)) >> endobj 50 0 obj << -/Dest [ 34 0 R /Fit ] /Next 51 0 R /Parent 39 0 R /Prev 48 0 R /Title (8. Sync cheat sheet) +/Count 1 /Dest [ 35 0 R /Fit ] /First 51 0 R /Last 51 0 R /Next 52 0 R /Parent 40 0 R + /Prev 47 0 R /Title (7. Protection rules \(CI + policy\)) >> endobj 51 0 obj << -/Dest [ 34 0 R /Fit ] /Next 52 0 R /Parent 39 0 R /Prev 50 0 R /Title (9. Agent / Cursor checklist) +/Dest [ 35 0 R /Fit ] /Parent 50 0 R /Title (7.1 How to protect branches \(not local hooks alone\)) >> endobj 52 0 obj << -/Dest [ 34 0 R /Fit ] /Next 53 0 R /Parent 39 0 R /Prev 51 0 R /Title (10. Comparison to classic Git Flow) +/Dest [ 35 0 R /Fit ] /Next 53 0 R /Parent 40 0 R /Prev 50 0 R /Title (8. Sync cheat sheet) >> endobj 53 0 obj << -/Dest [ 35 0 R /Fit ] /Next 54 0 R /Parent 39 0 R /Prev 52 0 R /Title (11. First-time setup \(maintainer\)) +/Dest [ 36 0 R /Fit ] /Next 54 0 R /Parent 40 0 R /Prev 52 0 R /Title (9. Agent / Cursor checklist) >> endobj 54 0 obj << -/Count 6 /Dest [ 35 0 R /Fit ] /First 55 0 R /Last 60 0 R /Next 61 0 R /Parent 39 0 R - /Prev 53 0 R /Title (12. Private primary + GitHub publish \(dual remote\)) +/Dest [ 36 0 R /Fit ] /Next 55 0 R /Parent 40 0 R /Prev 53 0 R /Title (10. Comparison to classic Git Flow) >> endobj 55 0 obj << -/Dest [ 35 0 R /Fit ] /Next 56 0 R /Parent 54 0 R /Title (12.1 Add GitHub without replacing origin) +/Dest [ 36 0 R /Fit ] /Next 56 0 R /Parent 40 0 R /Prev 54 0 R /Title (11. First-time setup \(maintainer\)) >> endobj 56 0 obj << -/Dest [ 35 0 R /Fit ] /Next 57 0 R /Parent 54 0 R /Prev 55 0 R /Title (12.2 What to push where) +/Count 6 /Dest [ 36 0 R /Fit ] /First 57 0 R /Last 62 0 R /Next 63 0 R /Parent 40 0 R + /Prev 55 0 R /Title (12. Private primary + GitHub publish \(dual remote\)) >> endobj 57 0 obj << -/Dest [ 35 0 R /Fit ] /Next 58 0 R /Parent 54 0 R /Prev 56 0 R /Title (12.3 Daily habit) +/Dest [ 36 0 R /Fit ] /Next 58 0 R /Parent 56 0 R /Title (12.1 Add GitHub without replacing origin) >> endobj 58 0 obj << -/Dest [ 35 0 R /Fit ] /Next 59 0 R /Parent 54 0 R /Prev 57 0 R /Title (12.4 Where branch protection lives) +/Dest [ 36 0 R /Fit ] /Next 59 0 R /Parent 56 0 R /Prev 57 0 R /Title (12.2 What to push where) >> endobj 59 0 obj << -/Dest [ 35 0 R /Fit ] /Next 60 0 R /Parent 54 0 R /Prev 58 0 R /Title (12.5 One-way mirror \(optional automation\)) +/Dest [ 36 0 R /Fit ] /Next 60 0 R /Parent 56 0 R /Prev 58 0 R /Title (12.3 Daily habit) >> endobj 60 0 obj << -/Dest [ 35 0 R /Fit ] /Parent 54 0 R /Prev 59 0 R /Title (12.6 Suggested order of operations \(your situation\)) +/Dest [ 37 0 R /Fit ] /Next 61 0 R /Parent 56 0 R /Prev 59 0 R /Title (12.4 Where branch protection lives) >> endobj 61 0 obj << -/Dest [ 35 0 R /Fit ] /Parent 39 0 R /Prev 54 0 R /Title (Related) +/Dest [ 37 0 R /Fit ] /Next 62 0 R /Parent 56 0 R /Prev 60 0 R /Title (12.5 One-way mirror \(optional automation\)) >> endobj 62 0 obj << -/Count 6 /Kids [ 30 0 R 31 0 R 33 0 R 34 0 R 35 0 R 36 0 R ] /Type /Pages +/Dest [ 37 0 R /Fit ] /Parent 56 0 R /Prev 61 0 R /Title (12.6 Suggested order of operations \(your situation\)) >> endobj 63 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 1217 +/Dest [ 37 0 R /Fit ] /Parent 40 0 R /Prev 56 0 R /Title (Related) >> -stream -Gatn&;/`3h&BE]*.HW@ugU\4UOM5kl9mG8!T!lji$RK&3N$6FZ[n38o7rr/$oisS4!-+mM>GlehF.EV9o*tUP[[pI(5@=!>id1kg3]3H-N=E&pA4$+//:^_TQk'*;bY@pE''k)gJ=5?atmE8'RO)']oKSin8b\/LnSrfK$@jWeQu.a'U;qnX,[A;D3GXA]1EMH;E"]jN=b5(PFq^UG0,rMf,fUKtqe0/Tk0jX=c5Do#On`=EiY^e*CHqc@c(!k2E8>KFdIW)Qu2p)O-BD^k`Vi9ssB>Rb7#(41;5C?`',k$;Q%TH(J]B%'6SjeZ-2<g4pI@eGWn+*p?;?e++e3Tq"1)5!V?_F(K?$]7-[&O#9S>ko'hjB;B6GGVNhnL?sRtVTCU[[(\eYI;_S.Vp/#AUdJ5]"h&FQZ1DfUNB:p4]^"@E$T8*PKb=kU[".\Bi%$]YcQj(aD@5`(-(>6i5F(b[!:"OUc.q`b$'<-[VJ_p24'G:7&TC?9V"1A5n,;rrau'X%%T"PZIOWm2ec>ObBF"Xkr1kqLVlE,m]U^6_r2I4OM8=IW3%i;aKa%MJ-kLm"s;99K%6'8.20oR>[*a4Ao;m7KRQ9R2RlcG\XV,;(m%$anJfrA]d6dCcfck5>f<endstream endobj 64 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 3156 +/Count 6 /Kids [ 31 0 R 32 0 R 33 0 R 35 0 R 36 0 R 37 0 R ] /Type /Pages >> -stream -Gau`Vqet4K')k%D`F+7$\Ck&OW0`bL4g`J2boofnX`k;2jq,lPD6)(%'r@]1p5e+)?Im#W-/T^Q7dSJA%YljXq*%\W5fT.R^=tieRg%$='i5/er(QRXFWC(9=ekP3"EQ?TMk&!Oq%jA'Noh?VAeVaTq&ik2,"c)Q\,t*M9gbj*4Bki`aKNE__]3m'D'*.95oNNXWnajQOkm4;3(\'^d5MUjo1A""Y@B]G*6R3]M0Rk7R5S(P@oK(:BM*-d.:(V]OAUTcQGhB`hdeLi`n&'2gk"ZBZqc*I,7M($;mWM6-+YW>:Fig%^2bsN[QW_\90B0ODdNp8Kd'D-&2UO#r="MKIf#%=:#2pF#XAt!,'Q!PraXj#ZkZ8>HP,Z^n['&t@k0(YUYBG-S$L2(3)8AN\=tVC.2#^eZ+-L8*]u9/3T>mK%5L;c2DT6q0=A\j!J_0M-/]?#bG:)=B-iCUm`>s9rM=NmM[PbDLm;qhmYCU:/"A`T_\EZh&55JF,>)>^"AO,\KY,fktm%H=m$,&g$EJYlj@.1UN4C)D;b=H/LO^jgC1"`7;e>jdY^gF[-GK-YBTf3l9"0=?8qDUD9LtJe,]-VH=HVNI8A4F#;D9TV<%E#0@8t64p/*%_3]VbaW7FhZ,"Y8i7CbUq7u<9jV#&X:M/`:k,TEl[IJA1Fld61g&?1mZdO]sQ]k=q:^c1\)9:$\MBRNb'I*,q7*FG^&]"WY&]H-bu>3"9\hU!+JP]Q!&gRD?iGg%faVX$*gOe4fsCdU=K^kP;6#`L/c+7&DLFN)DOc6*?SLYcB0o&mJlVUf6>iJQ3E\n16=ViHVd2C<$YR0^5@n:lZ"*J"qafL-?%E9=_su?W!TMi)_:Q^p\!.D=%AYVua>(G$lW!&e)/aa`A+VJQt,KaY<@)*7b_ek,R3r_n'TI![D->8FYbDNYY0dBi\f6,=job8$8(tQl/1UT_,e2n]X9>5-9h?rig\[V`Oll8F46jGoqP&p[p->`[M"6F7A)O7eYX:&UWhD/KqcVe442`P[2u77Mc)UN"S3+n#YqQ>i%.&bmA(]ap5m.l4*@'^%0tTD_UhXUtOam6BZ'D8-EQjqK1nn7j;UsOr$n/,;!%qq3VPKNMb_gtHA*"Hs'Df9;'_sQX8ZN**jU353bH;!f$Vq^dFihq9-U]Bd\M#4@VM(%]#:d6WR6iM8_[KG>m;<_7H+Wm2%M/:(NlK?:9+,Djl[IQm3@>Y_9)`)`b1:8V0H=J5:=0")q-m[F>)W[7l#oWb0!6>7Q^W!:Y7-/\S(oSef9DFl5Z]lWc9a+jI6W3?EO%$To,0LpR!o>:/[n"#jO?hJu7;l3FQ^M>K\(gh)nWV"Q#K^PfI84AdBXl%Qps_a8YK@Yeq2p%34g/`1rs\93&=/k!ji_?-*)bNtB^XI+K5O<).Q]+F=Vf[-H6?T'9T6GZTh.Pk?:@R-%SZ6MNd%Ioc':tnEpH>\e51j=LQC+Xi@K:adEBD79qPk>?ieAlind;`:Le66,_F$Z)./\tXfF>Jqi>G.1pr?EklN>^QgI`-BM3+80i5?OPi(-egt36E!@jlhsp=:]TBc=^kt8Ttu*&U?S^[f,(i-/.JGP9Rcrol?[euOXdPV]Y-UOo*W)_@"4/=*HQFeDp`s#7B!W*Hgcf/PY"^;l*Ra^gW0)QL.;qNf(FtC_:`0=_\%%~>endstream endobj 65 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 3270 +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1256 >> stream -Gau`VlZ:f='*%C7@],d_aK@sqi)@@XFRlZrFCN:qeRgjC5JSHgZ).e\Uhjg!pV5U;02[*'P2"c&@[k:;fGA^\]:]?XrmR%&j#OoE+e5'fpG:Jla.Fa\%$Vn$f[_3c4G7t!i/r_Ua+IlX3.3d^r#4cUAB[2k[i[m5'ds\]l%:lUeV)AN6>6ds"VL;P.EQT20aF&>$oDps0Mb;,I32o6`=XY7'NM$RLdE(qqp\"W8sPr?(/DIE,8D^Il#XSZV?:]GFa.:c@AD[A@0,aZpL4Drpk&`&F&NSTl'TkFchHGLkYO`5R^9c.FTjr4SUBVsW-S3W$`FT`S3J\e6/Ro8':`\DPK'Bhp2lc"lAem7^Y&5jU%N'pi$T7+UuFI3'+&V3_N-o8$s!Po!q.\3'+p876R%qANGNAZ5,kVBXVTm^+NPBB(%k+QZQQ>a+B&N2te"DLuA\S<&JiEr)/Jl6AGoe:f)sMO[OodS1:;Hioo&8;`J$Q(('jT0T5OXdXkR!=0F5P1C"QZXOGFK:o.u,Fl41%Qg'sKkt)eZ.q?Iq4G!Tp0i,DJJBIB3l))AebYTM'W#&m$)'*U9GLL^Lbo5fJrbboJ@V#[(_m8/u#iu6=>1sU/=>ikrS\ILR.^Y8'YCHLmUKi8X_OoG`LMngqo.Y+#S)o"u$e42gRj1!3-%\XAB93?1XS#:$C#d:LTPCd26XK\0P9G+=^>:.MfD=@6V`ULXSD5H?EEf^/H.a?n-K/5hff:Dj]4L"@*O\]jFNc:*se9.(GFUT4Tnq+I`-MU[BVXMJaFmNk*?/4nf(XX[(^Zhka_Vi>?F_PH#H7([Z_E_ouA58Apk`mUR3\[GdI%*`gX4KachujW>,thT;.nUS`:l[Tng6-Z!7uQ3>ItUQd&[kSm;H?9JSP:kALr$V_>/)&%/p\g9:@S@kG2<19p<#,6T\ucLsU1S,k.SsSP9i'OTW_hn<`NIl3"GR924;S1>?rrA:d(hfkD.s@d$5k&\'!T:;pVH>QS-Y=t<3.FqJb=3DQ@cRC9o;!aZ3(]Kh["gOCX.8`X15ZJ$k7*AsBNO',rc;ip[=3bfioB2plt&;t=+W8bKC8'i^_SiqE+=_'84W/#8Pp],V0Vq;r=?4%2,`XBZV(-$u_6Ne&k;0JtD]D9ua&5,TT&+ECe.T(dB+s.)[qN=oBWNqjm1\lmf"JS!9=+)G(1fYUs5:=3E+iL_qKueF!bdRN$`90qV)%C'm^+0rhTE"NF\+fCN$?"-QT"Vj$HT)iH)>ZN/lMTbYARalt?[_g(7Gm%_0$eL9&#OFI/.l4p@^s)*;!b@@MXl@cab%Dl@H7KFe]EOPg$RV=HP:n[7).a%.!HG5jbp7k!b(P.%kMbW3OG)P$A6N/_VU?,D78M?7YqIQQJ^Xn3oL&Zu="XZq9%G*NdM5iY3Q4Be',7cq*,qdntS6k\mLu]6Eo&4o,6$M2NV$?m))\rY6?(%E#d:"'T[&1)oNZ0LVkpK=/c*7HfFXRWm$jXd7haSNm'o'p#gqK9:G2=o'jCim)[BS'HCN$J?AiAWF/e\[+n$Nk0Z6mt0P/H0kP+=PeU:/hsJ+pOYCJ=,do5MqM,*m(I]?K7R.61ds1)OK`Fk6j\nYBY#C"T"U$Z5@6*9q%!Q1btSd=p6==8`*MJ`76q0K#g.^3P3YjhOfTHfo13Leg4i-3J#Y]t3`;?.5&eR[6=e>T1DUHiS_;B`Odr!JJ@e!IW#pa9J\U]na&$LR.D&Bh%A;K"'a5i/NgaC2kt54;>]E@AJVj_o4u$r4/r2(@F2e3\EiY(%#r,fnd.LXO;*%YA2#?1i-CDi.=0Zg7T/Qe>CtWCkXPMAZUT3U+&IU=foHV\a213i([@U;DlLV@!_qNYeW5h7:Q`hT&U!1p\C,V]QI_A[J..6dZ>^];q-Cjt][]$]s9Kj@[Q6SS+BGk3lpiK,M.R`bA?1N@-_TYC$E0Uo0S3%BiE&pGif'Zmjq/0;G;f4&A?Wud`*;)PEPmfY)H/1-qKnT48EuD@B`9s8"DUEc-@\'l:BYU.l.8t*MnXf@5o?e@#VO!mHB;"6QEsAYkf+M5-DCB*SkD!HU3B(KdBl8HRrrEt41tM~>endstream +Gatn&;/`3h&BE]*.HW@ugU\4U,^o!eRs(W#]6?]tQUiJ/*:O+cB:Gdop,qQa028VMKoKR*)%IjZ-/I^defg]u!5]nn]@!u:kCAl6$n`6=j-'QahKlT3KeAoPYIKn]!9E$m6=9!s5h,hGB4E":")\6I=J>/@#OPsPutpEh5FoDVAQ#@&7cTL44fk<5^e9%]&#p^!EZ']+<)r6Sg+]CWOj>gGdNm_T'"5&4K&KeT-l(=2[fBMf+S`6P?I!]0'.r&i>!)YDIgCO"?S+_u>]lcs*:@ZcOW#(D(e0hKHfC/)r1Ogsf_;6eTP3898W,e+YcaI44\)LE-7rY=Iao/h2+bX.Y/5HYN(Sl=$h?:!b+Wj,`6'fu-J4/nE=a%CJJi4E#jUqLp,QBN-G0XV6b>3mY'%`E:.SG]$^hbmk5L6]X[G>$37Rb"EG$=rZCrWh%iaS&JlkD+``+>GkR?Jm0p_&.[NV9r"u[cNme=fOEePDH^nAmRYcK.?+^*bXO[74T[RBC:KQ6on*QD95]\^qr)=N_j:I#1u8@c,J[Q!@kXpb";kS%"r1'VD#mZl#l=+gc1gnOEfjL&n419Bf>bFEE*G6\4))]l;jI]=qRn-^X@eI:2F?%24A4[CFlY/Q>V`om.OOU3UNS`Od3EWX`[:_aX(Ik./8V+[ZQK3%NpfM/%_3Tt7R@X',s%g=@9c3nak#@j*abbe[m2&No[L043_U-mEb8n:;D&kfjM!,=WuuEV8a8o$@6mgCI1n]/e6NkcMjWGGFdKA.@F7kO9b97VDn4.ot+WNRAU2iI'3,!VNJ"+`CV>Zi:&i!mmb~>endstream endobj 66 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 4234 +/Filter [ /ASCII85Decode /FlateDecode ] /Length 3230 >> stream -Gb"/*D/\/u')q<+1!'#k]+0In=PMEX8H$8>Kq*^J&[+e^Uerlc2ibi-WsqTlh'@*mJ=B3a%O@9dX#d`Ia%@$=jRTp4/H8F+'1W$JJFip>n'KAgYB`\t/[mN'/VPasEURK(CorraqGB?:'&Y51A>r;Vcc"2:#;(8S]p(pDB^EL$'JW\^pu3T$S2S(?bHPCj3!qNjnmo93=n]7'k_OX\XS\'%&aArI3QZI<^"HKlrb8=I,8'-a9IHgl6Yg@_5.Jj9,!Fe:nOBam(!'E5d7Y\hEQYb4ss!#WU,7&GUlh$/E3[!(<kseC6)=?1^`UliUH8K_HDg%8E_gf"+7\5),$8@mAH2H,p(C1'OOcep"aM8SE!/Nhn3mM4jChl&6hlQf"\iKZ"Pku^.$qlLEqdfSZR;;i:#\K6sl6p)!uR;-0uM_[kJ>o#j4%S`h-Z`2f'd&fhOjuB=Nm#quubcn;Y'3Jc,uVIQB8Sp<`I`W;jO1l-/X)/]iML9>s[NGeb+A0bEfsL[qd^qq`l2@uL'S87F%jn>Z25e>;^:T8F0#81G_N8U[h)HV&U@'pK6j9X[)b()EOcL[qe3]#mS'F8:oIrj??8f/!UUcc!n@Nf;rDP4?)j_-fA\m(>W4YFpd#ig)$B.VCs!h(X>rs52;N.lCKFD(?+#faO_s#j@4X;;*L*C"?rBHGYhuEJf7n4i;S3A(\!on.gq:##J_In0:P7q/2dc*PG.lq<*^0,>IBd+RN[F674qF0ZV)9NDm#8]LN8S_5=];aW+U+RO(an$Nof03^]sl_AC&-Ma\$134LQRIn7@TY>dU:+9774/1TAuWQI,_C=_mSHdM-,P&I@Og1WNo3Fe6)#TtS>KAApneULLC1kVVO1nu,fHOr\$Fug\!"VNY0cJd8.stmqJ?Vl^`38rnm6?/\/!Zm-]Me3Mu3kJ,4/H5&&(gU[*3@iaDsB.R^']D&J<8g6-./_70s#B@EWs5V71cCS7eRqQ6ab;MZcWtoFWSoI6-6LhUHE+o+qT\F@3,#3G0kMk?s0?k%V]lq;gNB,:n]7PcHtE*"o+)<\8EnR,qM`]C5cIY9UUFSrP)"+o/f\$\60/Sl".F;e71PPdq4]@8+<(*%.7O2URn`VgqsD6ip?<_"J;L"ZTJbQ=DQP7nH+Tfk?(pT4.(([/)PRZ-G(a).L+F!R3/!bD^oShK85uBGSb*p;\@dAmYs]O![W42Z,+&=1&t:CN4ArjPh20j2Z@]TG,5Ha.\DhES(Y^:H*R]nIXG6&Bgp9`\2[0CN!!K]%E#fq@X@dB:8m"gO-\Mb\0T,'6,D;/:C9>f>:WI]ko;Upu4n;SA-F%HIr+'$\ggC%0_>j"DX0jl,o5p=I_k2U#,`t>)Cg28lS^?[IQS=G[n-cl\e2s)mn'+-<'Wffk.&kN=H8C\W9Iu"&$+;X\'1SS9<#61R\2V=iHDp2`pq%r"a;R%d]fVC=N]"B-@SmUD`31u%[L_@?/*Dd3'0<$E5CW@!8_&kr0)dTI\&"[g`boqGXdQ!oVsII.DMphSDPfQEH/!Vl9:W)qq^g$R.8Xouo/9KVf?ubM1i2_>`#ReH4sK^+J=ZmD(1Tj7TJ3%$a!(.;%R*FLZDEFMU3J9tALp)90Cr0aP3r`a@k\`]h)KKCZ9ddgW,3?+@,e_sWK@2lS(JP#`O0.*5eDsF`PiF9kZ"E8b`V:;%N(5=[K4CpZc?s/j^[4KDJpZX*#dEMS1lS(gGc:JD.;tED;sqG$>hkPIk)/[_af9u%t)iL?)?8's1KG[AI"0@Pn3Ysn'XP:K[*d.R,&U^Bam,fMiGZl6UK2V^_r@GNoW-/")d7qi7j#G=i)mZPV--='+P[/gU7QtI9qm_UR7@jdqj%#/F.[,=-r_tjAR$1+(*O,0lu^.atZsBb2Z"ggoT3(Cq17VgdG]nWb*#`FK6p\24qOE-L.80oKutd;?NoWO*BR%F\/!>R[*f-3V,JlGZ=o@/)mio2(=Sd#C0mSoCrP/!rKr(DoHN/T^cXXdL^UO9NG>>%sVmnAU=-Qb>CD)hP=cAV0I,:!WeVbjPZ387(,IZ%(H0>e;2b0*VN(`;~>endstream +Gb!#^D/\/g')nJ00j*?LDRPiWl9,/oBU__c6^i1&mi;n_+eU.8<\$hC-m]>,5Q6C`ZX,1cnpNO.[6o!p*6nuUGt;'=).-#0md'r1/7EP#J3mYS#"=_4=Pgp`bHi:'8g11uP%!U\#,Ys'\nZ"?%_H_R;X#Bg%a,k@ZM;)W1g35>SA!nkba)IoK,Zl9NWfa!D!_Cb__umo-\fl9k(h>Wn:H=1@[aNf&2TqUNdoEk7CcsrrKQ4D/AIm%P&$]'9k,6a5W>X*kCVrY"ru3fn"]/YbCJ%^K/iNAQa5#^F0WABn?lVt@7dc)kkJ:fTd3i1eQ%]1gQ5,;,Z?)!VVlL?!\mB7d5SL%'Onj_;:/iTT;,0O.V(+%OGK.ce"HYB$o55cH4As=]pa(CYH"4fQ]ToDCp`hH)+MEc&r^q\9*NMarEUaC/%%cS<=3OsIWk*5hsHCM;2Ji)`[QfF8c=m]'\>j5`9pugBoJETC!=V,mY/LIV+asm86W3#'i=![I@nrQn*qtKiV2TZM+il=N;os[Rrs"Vg=L&E%HI='^OL7Yl4_YP8Jo8/2%:tqcR^*@>rAN0s$5W5DYOnG&(B0F-fkC+7no].Vnd>s([l7-&(e94s!@(/,HCmn-KiS&ol6HkW?&3'En:C_/':hdY<7^3ZR^FK7kEQu(uhp$g!5/Q0RaOcf`E5An:t$/qZ`5^rA0.O,8=GB4;-/4SG!ii&q6iAc8Q1'dO!i@E7pbj7f8[bWKr;mn:":h:_+aFQ]XBeV27=o_,p%p[=af';[Xj(j=;&KVl7t[Juj91(/g.1gn,ak_MjbECK,sM0mlIXrA_W`;,CpMpliR>oM7lur#UfIOg]*,kATBJ'9^@e4VY'a9uqQcXY-r3rmI%B!PqYi5=T4,e"%A#_G/PR@^S21u8HrX0VX(Te_sm!RT68V;%0\!UY!a_gW`glH(K\1QTi;c(k2c4%nI\%Z*`:,Yb+K+Dq87=P9FVi-a21W72TcZr1cIB6C3\QjAFA_,.r:1_%21Ch"MjENiSNOc5,I8)l?gV-cO\/(jSm,3>C/GbP]SSn<([m>3Dg7#rH)m]8As7F[Y@W2FXkd=NBA1Sj[1g*7#BcSKt$q-@MC*b-CL3D_uF^d)Vi0-$L4(CMNJGr9@f'fQIA$m6+hr%DXm%%]mTkJtWYuH!s#mOR&bf)2@"/_`C,TV98`rXK+f:0G.oR"E0=^BSj*b-J,+TK!b5;(i:Ci=U34:<.>#_p%j(AUAk0#dTU.BU9Tc#^\<%[d1&Z*AbuVTT0n).94V7)1usYFoj2nuEtWH/h9J[ghbV75@gn_^c=BH7](2,(+$2&s0W\=T*S=/C7:Ihb5lG@hJO_FM[EV_rFSnN@<;hf=n@R/sfht_OJTaPclc.2HK1_m2c&SCMQZ(Z+AA^PPmOI,j=q8&i@J%2*njXflqLE?V]p1(m"](:Nu72=#D3F8Tp'c"p.^sl9'9L1'l`o@@fj+]kX(!epN[L3alESO+8dRthbp*jTh;<*gm\Y!P/q^SD5RkJS6`1LgR&!k=sLL@W'cM'"eTLftFQ=bYndWDrV#JWU0p,UIrJUq\*#1[9-B"m]2-R$J+XMl4PXeCTZp+'bA,():I&hhg[6JYPP[I#kRkm^HR'8C70\W?))i;p?"$A.8acc1S>=)1OJGi$P8*]+m]7^oA^16]FaNDLI7A?@/6S*U9PkQiNpdWk1&#\:Sc%hfnLSsK*Ug.[dJ9eQHO0E*4r'uY2#U8V%YhR![Y.Wi$4g>q5T$gZ-lUh`kK'W^gg!O\r=&cTR.nGJOSRQ]2ZE0lQ3*>$i2!V/+bUrsq89lSp7do+JM9T6QRCh##PpE?*$KDU?b>;tKpYHS>W03h$dq.ocp0V.~>endstream endobj 67 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 3294 +/Filter [ /ASCII85Decode /FlateDecode ] /Length 3540 >> stream -Gb!#^CQFrU(B*+)idTRCPDM".%mrk!g.XDmc-C(QPO9i&ajQ!"ZHWMN*[nU0Bn$!8H@R^\)`el(b3@PTQ[52!W-`DjJVbIArZCM-I^k$L>72t`GAFE&_h#FL_je9=hl\L^l1p'J>:qIT%t=]l4sjLQ-f80?6HBAO%1H\X&*A,!;cl9!11^\=U;pBY+\65G)i3dcq1)Jk'-GlcosE9aoA?lE7`^b)Yb$Xi0.\Bi&Dg0UE%1TC4B$4,,$n5,bsUbjX>qii"OL=uXG1`ZB$@('FM\+$[S!>cmd/0_9eBN^W%Dj.ilF.V_H'U4r2=Q/TY6i<_TlIh!X=nVFdEg+s06_HH;nP,C+"-..KPp-B>T(oi3&>Ai9&e<$:O[W3tSmqAXZY`3L-)kKCBQtIp8QI(E!Rsn%Zbs9[f8=Wk2^Jo+G/sCm#2fY1C'Ydl/g2Y_Ns%\qY&`hOoCSVHjL%<>@7H-;P[L:=9'(?'l_lHh]>Ss"*VY1&#C6lWMKl1/-*,G)Xm)](91anG=T_nMSbg[F\j,Z6YS8mb)a;CC[GidA1gT2-:Hr_uLU/LUO*/r7fQ_CI_Z3F-s(cl^`pa:$mC,a4H6ggALN\@/4CHAoWi^i0O^dW\rE7&+gik88ji'qF?o\b^!apk70m@)K_l0c*K"8kSM`ddHl%/c6J5G[3:JMS0f6P!!a>cQ9>6*895.6/H\@bU8W6@lQ9Q_8R-`t&!cV-L$oj,E=tca5P'Y'dF/QO9KXsF%$%Jd$r[O-hY2MoF?e(-s!km`%&5:1)=X70pHE"F15n]QP.Jqnd'S-eUWhJU3Z>Iqd:`mlLb,DHE<-6`=NKnP&lobmXO+pO4TNbU.jXUu)fh'Nb)Pj%m@OlK>35EP?oA3H9V9t?%>GmJk0aKEl&ri]1O[U:bOeTOJ4o`,%,%0Rm;Mrb*F.qI>Gh/LcV3VQ,r6]WR#1-fTI-I+9g6qs+QSiH'P_=dFgm"1KX>GbPna^3J)>db)&SZl=n_IgFY"L*O5kKFM&mS`q.\J%3^uJCk#>9m-Ct#*mcH:OeUV<*B/T=jGj@8qBqGm9DX&8@1?t&nY;\ZXEcr:E`E!j"MnglL#Hfih+0o1%.[(o]T.LmMp%tZ'3-k.abY"W^9-S[f"an-'2gHeX*MWC5lm6tA3.iU`aGC\ebPj5SkM^#tXYnPWGlJ_Ys.%IeihH3%2)W@_H8@Y]Z8j@QCTi@g;::4>V`Mq5oV?Dk_]W)lhgM\q,V"mfMjRsjB\l;og;[EhE4h=7Qbp2@d1'O7Y+UruX,Gr&\IV)4+qPoAXM_HLNJ4_R:pB(pKK:32O2h2#cNL/hnPVf^?@O;h`N38E=6Y=GP--M=a\[2SllGoHW9AN\!k%H?(?0^'>W.Y4L:/K7[2B,f\T_\lE:SF*o\E+?_)X>=Ol.?Cp>_SWBQ%;jZrcXV='P#a%+R^'"t:ENs4+gt%&+RlHuA_@PJ*%`kt6Z+?.EaNdE6p!5SoE5T8\u(P1a>'br_65et^6"U-[CQsq@G=O?j3\&%9?tr8dI&]L[UHV<(El7\-,^lXCYP^n$TuBM*;Cf%%2r;fHGZXB4\:hB3h0>QAI.:@NU\Zd+oYil"f%I-8\*b[QD[3B@nuIf7VUf&>l>lQQ9==%Puqq+\]K_ST;aW);tO+s-s'EM4Y-:iV\-m2:d3R+,bi19@o^r>"I_AMs&]Ohj;b7@cFSA%%gI$JSS@k@(Oq9^^I/j"9Tg0B:$'8,]SiN,b3s$]]h\egTqmOU)d$/I$6,?#o]7IHAN(M-40bD%AKZ6c:duebJ96\L#<;>ff9C*X%c0),btE>]Vgr7H%=Q-@[^1iMs>8cC9)'13aELV1!"rUH5M:-CCVLI.Md;K>Ac@+&>QNn7^L-hM`PIKcc&nt)f;Sp*L/21WuYTRI9QnFa#'/Wtl`YF&ePsLge?6'9R"!saV2TR9-RE](EWuERlSep+LAB]>k3P)'g#e$U@0!R]eW5V_-1]6XpuhMNV!T&6PjsZ"MM`YD%cQp18XnFY&C#ePQ'6YK.m,i\4udQ=7Br9SQ3&_,4V"$\KO7MLHAN-371t!3*Y-N;~>endstream +Gau`VgN)%.&q0LUFNr<1aW?B&SYEET/LQSAC/62(cFi?E-6\4#D]pO`qYOuW+@T/'"=pmfEQ+6b-ICu"l-fVAd.,-f^Ol[Ih$gH(%5:JC/\nSJ)eQk&LY:A41IFdgNoj(Vh$21a1u7_>I.$?.*t,[$MM.3?%6p#-SEWAQ=J"K-7Pfmp3A=*F$4C,Mp^^F?P.LM3_W7.?H;XU>QXfEQREe6[3pAH8&dEIlYH.XgP?,_1FmZhOR%Fd"V[f>>X*\*'mdt&I">RqehJ1eMeSTJX1P9gqtFjS)7KJpO0ISCGiidSq]eNs8Rq>VYfsCLPQZ5;d7VsCfh'+'k_c#b&(o1u?5l]/.n_.P0s[U:')X#tOdu1@ZH^KGIi2OA$*/8(3M]GLBNZ=HMhi1=q<7MckaEYXd.4:e:$C(98*iZt74HqXqW0U=7[PJ,9P6=TnmF-9AsASI.a.quaJi@Zc1U!AA8'21*k$/,mUZ]]j5U>%<$5m&Y(!-&YJU\aN>LUt91ono1d#/s@mI82!)=lg6ZO5Sr.0S)CF)[t7pNARaCPi0ZOO(d_5XKT&K4JOH37T0,r*A<6UlU7Wurr]:PQsEJg+^+Y4Fdap_EgY3R]=PB0-<>s*jh/$sChr?.G-U&]ATBHkn[5p2tfHZG)T>8bgs0?pb[K"BR&46dO3c='Oh1KO`!K`A\rNo8@$ff?fU,3\=-LXr34?+T(:[_S$44Z,coP]1B4\fc5heP&JDRR3/DG*6(8kW"m6lMBt3>Ls6U)/&urVj8:pG]l:pXL0`Q9IWAA.RE-;%4+,A=7&2Muq,a([F$b&rN^,BL:/\+`!3+J-:,?l0/lkPV/],7UJ]La&msbKI!U#]mD5UcW<]O5=5Br(Zj,JO"T0F^T?d&g%#b-^#WL15nW3`&F7A6$[UIa]+m3j(N:t%i((o\Hdcj8?FqY*]u8]9dn2'g.$>I%G#]5VDNZm;*BAIW)Z21jD(qn@0h(+^HPSA:[gE:^5Rb^9<\k2&k^omGDEj**P]`JO1<]1og".m7/5]7OK:p2ld(%`"+?t\7j$p7VKm`t,+b&F^`h9m0M;JU2P"sK-$NU4`[^LffT425ALhqk9^3XZrbLlAP2=P9s3c7GehWYN=M!^AcCUQArZhg#1]W?+Nmqm]Umo=>%KaGlJ0@:T8pjD:]j"e)$hmo"rc36cqAm<*RI*k@kT=UF.st3jFVp)`T<'a9c@Ia&SGbfZO3H>DfD&e[_Hoo$G7tNYh'm?LJ$Tm]?R'fJ;*,PR&!Li"VE*TP93%=%#;>!_OLXA4i?e\VbfOlZ?34)Z6j1^NT7PmBIJh=;L\/8!6#5\AHlt;:VsIGGW"9ar+?*Q.kDa]h[3I+C<5`Jjkd:'=PNA$0)0&PB\B,IFk$kjG;\L:qgNlK\gC!SS0lD(0;LSPi+LFe",gk=mY`,%9-g:3@\*FdEF@jaAA6;#6o!5&2cG'(".1Zb/L6#\q(\')(/:m0"3#qVC>Fd4dJAD"IlM9apBt1pINrJrbgW.j7dcN6UtV*,rf-8@!JZIUuZrY_(G@jm\`e(^'$"Jfjeg5qsiFMG>fAH>b,`Nfi_:Ti,iIR:W^4`9UtaT6KZS,fbCbHbt>5g>EWR\pAK(lk$P6P=N5a,&8!tM[_8ia_I_uLa-*<\j['Ij6r&\ZhH\.T#8tcn+]@%57RB]PJ>&05l--S#AV4cPHBCh=^F"nO6!i<^6lX;g&;#,DE%pJfV\*Tg1NuoXjSnJH]TgUQdFJqds1`9$0Nua5UH2W\#hlc)]=l%,ul\?9elC-VFT];^B?S$(hVtdK&!a.'f;!rIQcb(>h*_g*mo!t_-A%9i)`?qNujB_jOHXVNY-o"]$c@B4C6NZ#:`$G'Y-]X?CSSKFWU/g0o&`A%=slAcQ*o-U@S!nhYFq@+.dp,U[4D%oP&PMm&?j#CY`2OsiS3g>bXVhJ=o:\,enH+Dgkljs3s&j_`2=)FhWZb2mr\SU)LUTs>K(ZM$CY`bO3[?hDnr8gTs>*V+r(SZKgd`Pd,P4M[@&V0o,E5gI*kSg$kRfb&_i.Ag?a[q7\/-YTV+8^U\cXTKY7H&XsS>\.6HWH)5BQ/>lQS]^F/]_Y/J4G7&KE2n1)SpE\>^i?b.BoidSp]^2sO;sF6B!QD`eT"p%@d2Q[g3dKN0Q\^pL*+qIP0G#shOeMKK)7P\?*HJhZ[sTtP6K5ht7+8ME[Fe!0e\8jaB$Ck9%R@N9endstream endobj 68 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 369 +/Filter [ /ASCII85Decode /FlateDecode ] /Length 4171 >> stream -GatVX5u3+e(^An[^Z%C3'+8BUic/Ss1ugDUOq;F;6%R;_;?+=`Z,N(NQ7PaVkh!OsqN\q,K2/adJ4C)f90i[L!]2/Gp^RUS4rl]Q$mW'8,)Ic`G-TR5bg2d=oN.$ODZr1h1*"]H_@Qi~>endstream +GauHOHZRq"'*$j]@OKcCjj`9oUh%eWa%>[N2brXAmUS@U0*@&m`0__`P)??OgipL:_"U2?Q!TYG,SK$E?eF2lJl4nN^FK85[K:^H#kGA1WWnN*:^tNsa#geW4SaB!`\WU*A.Aj%!L>p2'RaNMF!lIP&*VdZ<["^aGik(Bj;TuphL8SS?pT>SaO`nDWJNMej,jtd2$DfWJr_"8.p/!K[KPKgRJ+_"NT5.k=ZS5)dHB_SMWjO,1HpC@]=Y7cr?8(ine9WFO*AXe?Qb.'nS>gnBTcr+(A!Xa$/.ogl-88Na@aH:(EH(IR2]iYj$pc6q"5U>Vh:Qe_0t63F;?lML1'&i&15*B\*tWDIFjnS-Dq%8o?3UjoP8RLKDb"t1=YrI%['"2'l+)<2:+gIaunIsVa`"R4d%X%1SM#;&5\b/7#L>L4CtJSVBG&2MT!US;#ZCq1=_#!NStIk[DVpBqVEY`;J9J.5bV2pKFYnNcs1uEcpS_,$&lAq4eS2]XeMh]1dns_UT58-&@#sQElPo76A?P2\5tcuadZK=A4!/:Godk^f-:C'#Ih(pcmggAEo2=I\d(a>3e=bW_3RK[!O*.g<@hst?Ni?SMlkdn*=]sK#lK)T.H01UI,VG2-cN"*Wp0YVi#@jZO#-;4^#:q#P;u,[rJ8A]A2mr2:\s$cab\3'!8H>hsD-/Y#A1Y.PD<[.?3W\7CRr">Ee@P-A@dh)-]]GXBWpp0P,%40X-@FpZiC8-=t8csKYW$r@bj_qPkVGWXa`VSn4cK6)[9(a/V?&qsPP),?jLrfs.#6T9(`4948=jY4t$*eUdnZgOM2IQ*;'n(M*Z#Jp579mp6e;g2d(VOZmGpcY(2!]jSjn`l97.D^17@#Q-CEfUhekGQ5N[JM.dI,>,2CI_lWX%bHU=Rl[j3SQ(!h1?V:^EaZUL-09%F4e#bn-7,_iYKNR]XZWgcN$2uM"me,/D]q39c<;S\J\NdY9OH@i66b"+c]3mH[8UO)!2udVj4O)=Qm".C98b[QU:I.TRB5oeG2FhF1JmDEl?k:D+k3]Wd>/;U&3,hr%"'l-l#-75QDgId0m2Z-Q8Pp0/h%C7F"YXIe&X3ahn[g"QMr5us7HY6knJ@%5"K1*G*BP>NiB:0`CV?9=QZr$jtA/#lK/0EhSrup$iJ;MK)=.^q&d&Y?f(c(ud^&!CN`ieH,"hD+^.YkG;geWY8PWMo37EAk'C)&CMA@0g_mEqqV4U54+IE4eA6)m,eU'Mb\7QYJ?1=saaSo/TJV:=;/U\5BAMWEBghiff'CqK>FjL'>4Y4TSi.gs6!ZKMN4:tq/@M_W_QrF"D"7J+_pO$H=HX>_&8"ngIP/*)*aEeu$g;20*d%9No;A7!<,B2dY8jTltjAABAGDL3.WV"Ajk6m5G`raieVm6A\7--Fo\*eg^crkS56dGZ(nPcl;&UeKV`_Co2&Qg:C`6n)SZu,^BSGl0_Pg\#D"6,u<;D\o'Jmka`e272oD&*j060A=9B^"dcYW;.NV5G0.LN"(sJZ1\h:b5%@i?cPLF=TDMMm=$If`tiS62LGA^([X8lY)5-Q"06VFOZ$IK\Q9Z2EFppu_.AX>Tj5DPu&&8*gc;plZC*9O3/APcqK0h[DjD&^!`L-D=ZdhDQEE_iQag")u+:K3uRHR4I?kq&_VWl->l`4[(=sF:eYPU(.6UYOAk9([-T2Me"Tn5mGZF;LC1b#B0V`\H%.hK7W#Ge3ms&7cG,'T^2_VCrV1X99H;U3fd:[4?&OfGlBjL]mTF:VoO!"?aaiC[.ktdLf)gl4W4urT0LU=1q>rjU]3Q)\OJ:(mS>C6gFKXL?42SU,Z`OcpoVie:j/0N:WJtaZVKOVE\nmcnVW#tC7cjS3r[)'Dg_mUALEHlJ4Xe"O"!O,.7N**#RkVn5@37Gnm5KCSpF7=-qbB9f%`hMCtoL(j40UDOAl@DNU9a]_lt"Skl/lTPHu$qUhX0ZPg]#IINPTuB3m/$R"CJ[5L?99g7=:_Gj]'-MqtCB=Ar-9NnLOjDNdO_Co0?CIG)1K-'$R4_o@Uq0i2agkO#e!/pMID,H"_CU!NOCV&j&lRCOA_Wf;cEM?\b;'c`"Cf5NE12Nb`e3JfW>=ej3MZ(`&<)mqB9BI$`UOet&:g;h>_FSr\q:kJ5_Rk])K2ae+^\LF0M]LU'sGN]4(Du;=`kLW&((qr(Zo%'5sA^egG*=fRDhj7$_Yk7la=Si#lY_GLk4a1K@-iX91J'Uj~>endstream +endobj +69 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 3416 +>> +stream +Gb!;fCQI4.(B$G3JmYtUUgoCUQ9"Fk9R?LcO!G3L[^q8&"fh%q88M"3HPU5j9JW,Fkd9A4!%i6/RD^cdto)75&1,K+*l>LNt00`QLi.NIQ\e+8fHof"V-g1DF[n*fI8,"N_U$!FBkT?ls5*GNJL&B(4n5^N?1;NX'<#m(s*'G7).:0N6lC:hg"ul:7andPCE5KB/T'ijp%$eIcYq+)K1TqXJS/?f1=i]lrq)OHmM41#=!R??-fo*p;B4BY:]].'e!CNp_,4^P1$#,e23r(ODJ)6[NqeVeR?Xui2aZtH,ttOA04iO/CN]>*eKu7gM,0_?g@f#PIpNl9<=.*bV`?3pR$if.b>1nfX_]mBeh9>=upn(YUH<$QBYHn+at"I`W,qK;6k5/J6td&;Smapp0G/OfMCE+.R_opi>p,XlJs.57/'LQ4lSe_CIm77BOW4.JKA+)ts)_fUBWM'9NRhZsaNt%%W-u""?U*&bp>LA1ILSI:qa2?;1r*&?!)JRYpes%8:hV]$;q^*?dh7#/]&esalFFIe;[^9AP$FYaoR4P8AYgKo;EepRosBos@/7Lb]!-<2Y@Gc5V636=7k866BM7$V'JqkqO]\G",41-Q/Mnrj=2FXrgc!W8J5WaR^`Oj&Ad,q'V1<0T9+B*@>]IdXY`BNF`)gk[1uXD?m'-(s_.V=tmNG&PXm+;*'/dE1W_mk2QoG8J-lFjq%rmTqR\=kYH)'[DogmcO&KQ3mFg%:mlPE/!&:Jja@0`%=XPNje%M4!%t(jN+(S-m2lI!1M3":ubb'N3CNSk)L'K323oHLNd(2"3-SI_RCHWI+QGUZi=";*oNOdQ(/K85TdPUlNX`\Q[3c-@=BUApRA.+>$O8^aeMG[M@8=Og6i7n(sF^kIVOG8^IM,B9d%[^4YE\,>MW4$0e*C+1AI]BlCB,b]3R&e2c>UG]'>/aZKLS+N;h\:%K0"<6/f,Z'UMj5[V#kS4aDPP7e`al0&PKBE27ehh;8b4a,IqFLGjGuX=5,em"aft@%&Es@0Z>n&c5toY2m@as/3rrC3!UCe[7tO&T^DU^k&^E9bN;/,.2RD]g3Egd/=O8oRS"??1K^4@H)l\E;g=4;3]OQ2l?tM0TWDgFV?cuo)Kln7rqR2UJi#F&%DF"*^32n:ZVICj0F[:q1-&mNY*)+B;RHm44i>C650T@X(G5]7q2OI2'%VKC^TFpC7]&$h\EnCrm6ZIi@#;CW/*:>Vo*F)r?=8@qEmUs#qaRoTF=e6gqO;.ufe?=]UG]Sb#RKOFG;>nGc_79G#fSOVFM6V\Qqe<:GMk\&C,;e$u1amDU9'_[F;\uq+O8W22(TkNuBt_;@R+#ir\]/?4>*bgW^Q0">rCk[VZt+jN.WdkP4Ju7\rkqgB8E`>'0;t8%>jo_(RY9f'`2qqS5j[0N/9p@8OHi<-c?L6.61P+%6bRCK=j6-aK#cUiJ3HTkmh@(h]IZsB(OGq,S-ZuAh;E729qm]2Mb#tV9G2.`P+H%u/oP4lH'a^dQt)ieP]8Dnl'`_i7'V:s-,ZI-^P!Va;>\IP]sPPeAWdU-@j+D6(,J)20:]9%64&o^2_6CU:?19&WB*hT:6Moa:5]YZNT]DcPl'i"Cu&q<*RUL/U<]1W_:P]3)Ae48FID9iA)Y+1:+U?fhXDlE*orpOYYogGWHEu;2p/PT>F%HE.LPI'22:D_CRHXO>g,L$H'WJRlQuc<$V&]H&A:iZ)^/2#0;S*NIi/p:q1JmFu?BI_[CW)p+k!+OY_3V[TZQ9cLcaq`AQ!BF_WWe*W_6og?ESeo-.k(L4*mV4Mkkk9QpMJecZUIAK?8)6b4>M.**n:\FmEV+]%Q<[0<5,oYVp`2_:mi!hobt&0jW]8qq'`^s8LcjO7+UR),&_hTZ;U*e`2U\:3fWZC0M?q3ZW=&DIct3mVm?fs!Js/1O]9m\khEW9Aa9R?_CY#MPJs?>`$rf2Lq\!J=tFkHfNDVL1GZWpB,Y\H)Rr7FT.NQJfAAH35-PTN3pr#+63_BUp_cBD*e2W&#_")`JL>/UaPAkIdZ:sm0\t9G@JKJ*:Op9a^Pg%#PQaZmHJ>b_/37@*@)&lU#Y\jM`%#b'_](gFo#SZ\YYJ@d,:\KU+doLM8olLF)0pB@fOiH`e+USTD[Yk`egkL,qE"rGX\`)I2ZN4M+qn95d0^PGceeU%'*]Z93=D%>/QqFb`V)/J",2cO.usK1hZkP$k^P49mFp3J,h6Lj7Go(A_qendstream +endobj +70 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1927 +>> +stream +Gatm>3p&*h,$_rikCsDKdh#c4"1u%XSgkX(_dHGZac%^KJL9<^Y.ug,uW)kVa_rRC(:p+@Q(sRTo;"/T?^f&NA=>>Z!E!c+X\=o/Y8K,3dD`P:48(3,JaU0uq#(%e4XDVl2(G%Gi,Jtp%LlI!'p_2#n=PUi,e:tl0dUI?Wa/DEjN(!U6sB@2f(Y,;l`E0WT(!k-VcoH9:FkcP/ZCD5S\'P'4A1OV+8f8)^4Ql7=0F/([m;ST"+#.WlO!5FY@qG=le=Ylri3@ECgHRR"O>r8IF63kC:P^P_DA'9>g,7>I6uF*-S&Rd]MIoMk;I=35mG(Q?I$[AaE,D'$4a=V0iDcPjiBMb-i0AhC;q;9chsipsb:B8nVB7V#I6%A98A=M-eLEqWc1A7.]Z$aPWpX>p5/Z.OS])4'%7?dP^Y82;YQ^iD!gJ7U8b::PftHRXE9PN%XDH&,d$3j1g;S-@rg6\B%nN^5@UOJeCY&hGYN1m**B,`cNKg"K0I"gOVH%J>/Ed&2s+:]JB5*uCA9>g#$us7uWb"]EiKb8&^=WpqQmqeAFS]s$n\f!fZ]'#SJRC1dSIg'-PuSHZ[+(C9QskU;/@7AKA,d=-ZV:=iA.(k4V2Z>q2ZiYL3XSg[NRLceHl5beUiYM'JMrYi";8O[_Ug7RBaV3u3&Yij3)P?59,uAKm_sbQMW;j:p!Hu;!eH=GX]fdK9Ebe@p=P80(7/qoG$)[J6'afe-q@iPNt9u:k9RV`VAfbqL"<1%Dn;@>7@CJo`e*)FXdlL1%HX\RV5o51NDMoN3I>hToDRH(jOf4LRLV>a:6qT97c@^,1P!:dU58WQm7TBguJJ]&s\e?7G5RB;'Xa:\0/B=M_.>KBCPGLarQa"@k*?!a,iP]3t9.*8"L]BNkUq1Bambne:o1dDF1f]?n/&cQ>::kWZ695B;VP&qPmSQ<-["h#p18I&HHMS6/8%6<0%DiapS&!=GGV]XgK9G'OTBG+f%4s5o>0Gm5r?"*5t>Vgm<$)Uj=L,+f7C`cIY`h*/(j[W@/O'WZ98U[R[n1G]A0O)Rf;=_!&VVVWtDSg;lT>`kp2^j]/*3-=WiaLp8puELF>*V&R_-=i9gt:8$KQ%0[%]D0o+2]81iI.FqdLh?_#5RJ`N2*ac&`^<.Oic>TJhYH#h/4f"s^4Tr8Emm)KVWJ.][mKMrBi*LNOFs/B]:JB@Zk])Z-1d<=@N,F&:r?r4>``J0(Y/KD0kpJrBX/^>X-,~>endstream endobj xref -0 69 +0 71 0000000000 65535 f 0000000061 00000 n -0000000144 00000 n -0000000251 00000 n -0000000363 00000 n -0000000468 00000 n -0000000616 00000 n -0000000764 00000 n -0000000911 00000 n -0000001058 00000 n -0000001135 00000 n -0000001283 00000 n -0000001431 00000 n -0000001515 00000 n -0000001664 00000 n -0000001813 00000 n -0000001961 00000 n -0000002109 00000 n -0000002257 00000 n -0000002405 00000 n -0000002553 00000 n -0000002701 00000 n -0000002849 00000 n -0000002998 00000 n -0000003147 00000 n -0000003295 00000 n -0000003444 00000 n -0000003592 00000 n -0000003741 00000 n -0000003890 00000 n -0000004006 00000 n -0000004380 00000 n -0000004586 00000 n -0000004734 00000 n -0000004959 00000 n -0000005165 00000 n -0000005371 00000 n -0000005577 00000 n -0000005664 00000 n -0000005984 00000 n -0000006059 00000 n -0000006149 00000 n -0000006255 00000 n -0000006384 00000 n -0000006499 00000 n -0000006727 00000 n -0000006893 00000 n -0000007185 00000 n -0000007307 00000 n -0000007476 00000 n -0000007598 00000 n -0000007712 00000 n -0000007834 00000 n -0000007963 00000 n -0000008093 00000 n -0000008279 00000 n -0000008401 00000 n -0000008519 00000 n -0000008630 00000 n -0000008759 00000 n -0000008897 00000 n -0000009032 00000 n -0000009121 00000 n -0000009217 00000 n -0000010526 00000 n -0000013774 00000 n -0000017136 00000 n -0000021462 00000 n -0000024848 00000 n +0000000145 00000 n +0000000252 00000 n +0000000364 00000 n +0000000469 00000 n +0000000617 00000 n +0000000765 00000 n +0000000912 00000 n +0000001059 00000 n +0000001207 00000 n +0000001285 00000 n +0000001433 00000 n +0000001581 00000 n +0000001665 00000 n +0000001814 00000 n +0000001963 00000 n +0000002111 00000 n +0000002259 00000 n +0000002407 00000 n +0000002555 00000 n +0000002703 00000 n +0000002851 00000 n +0000002999 00000 n +0000003148 00000 n +0000003297 00000 n +0000003445 00000 n +0000003594 00000 n +0000003742 00000 n +0000003891 00000 n +0000004040 00000 n +0000004156 00000 n +0000004536 00000 n +0000004742 00000 n +0000004948 00000 n +0000005096 00000 n +0000005321 00000 n +0000005527 00000 n +0000005733 00000 n +0000005820 00000 n +0000006140 00000 n +0000006215 00000 n +0000006305 00000 n +0000006411 00000 n +0000006540 00000 n +0000006694 00000 n +0000006802 00000 n +0000007030 00000 n +0000007196 00000 n +0000007488 00000 n +0000007610 00000 n +0000007779 00000 n +0000007901 00000 n +0000008015 00000 n +0000008137 00000 n +0000008266 00000 n +0000008396 00000 n +0000008582 00000 n +0000008704 00000 n +0000008822 00000 n +0000008933 00000 n +0000009062 00000 n +0000009200 00000 n +0000009335 00000 n +0000009424 00000 n +0000009520 00000 n +0000010868 00000 n +0000014190 00000 n +0000017822 00000 n +0000022085 00000 n +0000025593 00000 n trailer << /ID -[] +[<36847aa6eb42a713708da2ef65affec9><36847aa6eb42a713708da2ef65affec9>] % ReportLab generated PDF document -- digest (opensource) -/Info 38 0 R -/Root 37 0 R -/Size 69 +/Info 39 0 R +/Root 38 0 R +/Size 71 >> startxref -25308 +27612 %%EOF diff --git a/docs/GRAFANA_vs_others_graphvis_pivot.pdf b/docs/GRAFANA_vs_others_graphvis_pivot.pdf index 09ec7df..416baaf 100644 --- a/docs/GRAFANA_vs_others_graphvis_pivot.pdf +++ b/docs/GRAFANA_vs_others_graphvis_pivot.pdf @@ -123,7 +123,7 @@ endobj endobj 22 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Android Cast \204 Graph Visualization Pivot) /Trapped /False >> endobj @@ -258,7 +258,7 @@ xref trailer << /ID -[] +[<02ecb336d8253da2310f8b926dc86743><02ecb336d8253da2310f8b926dc86743>] % ReportLab generated PDF document -- digest (opensource) /Info 22 0 R diff --git a/docs/INFRA.pdf b/docs/INFRA.pdf index d009875..e871b77 100644 --- a/docs/INFRA.pdf +++ b/docs/INFRA.pdf @@ -153,7 +153,7 @@ endobj endobj 27 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Android Cast \204 production infrastructure) /Trapped /False >> endobj @@ -319,7 +319,7 @@ xref trailer << /ID -[<87a8fa5b1e63c3bbf3a0dcf885fa3e7d><87a8fa5b1e63c3bbf3a0dcf885fa3e7d>] +[<0498f6a9043ddb9a43e67d247203d44f><0498f6a9043ddb9a43e67d247203d44f>] % ReportLab generated PDF document -- digest (opensource) /Info 27 0 R diff --git a/docs/OPEN_API.pdf b/docs/OPEN_API.pdf index d38151a..b2c5214 100644 --- a/docs/OPEN_API.pdf +++ b/docs/OPEN_API.pdf @@ -112,7 +112,7 @@ endobj endobj 20 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Crash console \204 open ingest API \(design\)) /Trapped /False >> endobj @@ -232,7 +232,7 @@ xref trailer << /ID -[] +[<1172dfbddb551aec654c3f5c4c4daf51><1172dfbddb551aec654c3f5c4c4daf51>] % ReportLab generated PDF document -- digest (opensource) /Info 20 0 R diff --git a/docs/OPEN_TASKS_GRAPH.md b/docs/OPEN_TASKS_GRAPH.md index d15e9e3..a9c9405 100644 --- a/docs/OPEN_TASKS_GRAPH.md +++ b/docs/OPEN_TASKS_GRAPH.md @@ -1,8 +1,8 @@ # Open tasks โ€” dependency graph -_Last synced: 2026-06-04. **2.1โ€“2.3 postponed** (developer DNS path deferred). Renumbered per [20260608_ALPHA_PRIORITIES.md](20260608_ALPHA_PRIORITIES.md)._ +_Last synced: 2026-06-08 (post infra/browser/graphs/RSSH fixes). **DNS 2.x off graph** (postponed)._ -**Documentation index:** [README.md](README.md) +**Documentation index:** [README.md](README.md) ยท **Service map:** [20260608_BE_SERVICES_and_infra.md](20260608_BE_SERVICES_and_infra.md) --- @@ -10,7 +10,7 @@ _Last synced: 2026-06-04. **2.1โ€“2.3 postponed** (developer DNS path deferred). - [Removed from graph (done)](#removed-from-graph-done) -- [Postponed (off graph)](#postponed-off-graph) +- [Postponed / off graph (DNS + mail)](#postponed--off-graph-dns--mail) - [Priority tiers (open only)](#priority-tiers-open-only) - [Dependency graph](#dependency-graph) - [Task index (open)](#task-index-open) @@ -23,26 +23,25 @@ _Last synced: 2026-06-04. **2.1โ€“2.3 postponed** (developer DNS path deferred). | ID | Note | |----|------| -| **0.1** | Stream dump โ€” `StreamDumpWriter` + dev setting | -| **3.x** | Register + verify + TOTP + migration `008` (BE + views) | -| **4.x** | RSSH alpha โ€” BE bastion, Android mode, JSch tunnel | -| **4.wg** | WG lab โ€” BE `wg0`, FE DNAT via `xen_firewall.sh`, prod API smoke OK | -| **RBAC** (core) | Admin panel + lockout clear; **5.5 validate** still open | +| **0.1** | Stream dump | +| **3.x** | Auth register + verify + TOTP + migration `008` | +| **4.x** | RSSH alpha โ€” BE + Android + JSch | +| **4.wg** | WG lab โ€” BE `wg0`, FE + **router** DNAT persist | +| **RBAC** (core) | Admin panel + lockout clear | +| **Browser** | JS syntax validated; `validate_be_services.sh` | +| **1.1 / 1.2** | Graphs drill-down, columns, full-width (`shell--graphs-full`) | +| **5.3** | RSSH API validate โ€” `test_rssh_api.sh` OK on BE | +| **Infra doc** | `20260608_BE_SERVICES_and_infra.md` + PDF | --- -## Postponed (off graph) +## Postponed / off graph (DNS + mail) | ID | Owner | Note | |----|-------|------| -| **2.1** | Developer | DNS MX/SPF โ€” deferred | -| **2.2** | Developer | Forward addresses โ€” deferred | -| **2.3** | Developer | Inbound verify โ€” deferred | -| **2.4** | Developer | Gmail filters โ€” optional; with 2.x | -| **2.5** | Agent | SMTP outbound โ€” frozen until 2.1 resumes | -| **5.4** (mail) | Agent | G2โ€“G6 **email** legs โ€” frozen until 2.5; UI/TOTP can be tested without mail | - -Checklist when resumed: [tmp/20260608_help_request.md](../tmp/20260608_help_request.md) +| **2.1โ€“2.4** | Developer | DNS / forwards โ€” **postponed** | +| **2.5** | Agent | SMTP โ€” frozen | +| **5.4** (mail) | Agent | Auth mail E2E โ€” frozen | --- @@ -50,12 +49,10 @@ Checklist when resumed: [tmp/20260608_help_request.md](../tmp/20260608_help_requ | Tier | IDs | Alpha blocker | |------|-----|---------------| -| **WIP / QA** | Browser JS, reachability | **Yes** (blocks BE sign-off) | -| **P1** | **1.1 / 1.2** graphs | No | -| **P4** | **5.1โ€“5.3, 5.5** validation + OTA/URLs | **Yes** (auth mail path **deferred**) | +| **P4** | **5.1 OTA**, **5.2 URLs**, **5.5** RBAC UI soak | **Yes** | | **P5** | **6.1โ€“6.6** app LAN | LAN alpha | -| **P9** | **9.x** landing | No | -| **Infra** | Router WG DNAT persist | No (lab only) | +| **P9** | **9.x** landing (excl. globe FR) | No | +| **Post-alpha** | **SFU** relay (`feature/sfu-relay`) | No | --- @@ -63,58 +60,45 @@ Checklist when resumed: [tmp/20260608_help_request.md](../tmp/20260608_help_requ ```mermaid flowchart TB - subgraph WIP["WIP โ€” QA / deploy"] - BR["Browser checks
JS SyntaxError ยท views"] - REACH["Services reachability
OTA/crash URLs"] + subgraph P4["P4 โ€” backend alpha"] + OTA["5.1 OTA channel
SVC-OTA ยท HTTP 400"] + URL["5.2 device URLs
SVC-URL ยท legacy host"] + RBACV["5.5 RBAC UI soak
API โœ“"] end - subgraph P1["P1 graphs"] - G11["1.1 pending fixes"] - G12["1.2 pending FRs"] - end - - subgraph P4["P4 backend alpha"] - B51["5.1 OTA channel
50/50"] - B52["5.2 device URLs
50/50"] - B53["5.3 RSSH validate"] - B55["5.5 RBAC validate"] - end - - subgraph P5["P5 app LAN โ€” dev"] + subgraph P5["P5 โ€” app LAN ยท dev"] A61["6.1 Opus/Speex"] A62["6.2 LAN soak"] A63["6.3 lifecycle"] A64["6.4 rotation"] A65["6.5 audio lag"] - A66["6.6 stream analysis
uses 0.1 dumps"] + A66["6.6 stream analysis"] end - subgraph P9["P9 landing"] - L9["9.x hub / globe"] + subgraph P9["P9 โ€” landing"] + L9["9.x hub cards
no globe FR"] end - subgraph INFRA["Infra โ€” non-alpha"] - RDNAT["Router WG DNAT
f0xx.org persist"] + subgraph POST["Post-alpha ยท hidden"] + SFU["SFU / Janus relay
feature/sfu-relay"] end - FULL["FULL_ALPHA
mail path deferred"] + FULL["FULL_ALPHA
no DNS/mail"] - BR --> G11 & G12 - BR --> B55 - REACH --> B51 & B52 - - B53 --> FULL - B55 --> FULL - B51 --> FULL - B52 --> FULL + OTA --> FULL + URL --> FULL + RBACV --> FULL A62 --> FULL A63 <--> A64 A65 --> A66 - G11 -.-> L9 + + SFU -.-> FULL style FULL fill:#1e3a5f,color:#fff - style BR fill:#991b1b,color:#fff + style OTA fill:#991b1b,color:#fff + style URL fill:#b45309,color:#fff + style SFU fill:#e5e7eb,color:#374151 ``` --- @@ -123,30 +107,23 @@ flowchart TB | ID | Owner | Depends on | Status | |----|-------|------------|--------| -| **Browser** | Agent | BE deploy | WIP โ€” `SyntaxError` on crashes/graphs/tickets | -| **Reachability** | 50/50 | deploy | WIP โ€” OTA path, crash URL host | -| **1.1** | Agent | browser OK | Open | -| **1.2** | Agent | 1.1 soft | Open | -| **5.1** | 50/50 | reachability | Open | -| **5.2** | 50/50 | reachability | Open | -| **5.3** | Agent | 4.x โœ“ | Validate E2E RSSH | -| **5.5** | Agent | RBAC โœ“, browser | Validate admin flows | -| **6.1โ€“6.6** | Developer (~99%) | 0.1 โœ“ for 6.6 | Open | -| **9.x** | Agent (low) | bandwidth | Open | -| **Router DNAT** | Agent | โ€” | Open โ€” `router_wireguard_dnat.sh` | +| **5.1** | 50/50 | nginx OTA path | **Open** โ€” `SVC-OTA` ticket | +| **5.2** | 50/50 | โ€” | **Open** โ€” `SVC-URL` / `settings.json` base | +| **5.5** | Agent | RBAC API โœ“ | Light UI soak (optional) | +| **6.1โ€“6.6** | Developer (~99%) | 0.1 โœ“ | Open | +| **9.x** | Agent (low) | โ€” | Open (globe out of scope) | +| **SFU** | Agent | owner spec | Hidden preview on `feature/sfu-relay` | --- ## Critical path ```text -BLOCKER: Browser JS fix + deploy โ”€โ”€โ–บ 1.x, 5.5 UI validation +BLOCKER: 5.1 OTA nginx (/v0/ota/ on apps.f0xx.org) โ”€โ”€โ” +SHARED: 5.2 production URLs (apps not f0xx.org) โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ–บ FULL_ALPHA +OPTIONAL: 5.5 RBAC UI click-through โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +DEV: 6.2 LAN soak โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -AGENT: 5.3 RSSH validate (4.x done) โ”€โ”€โ” -SHARED: 5.1 OTA, 5.2 URLs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ–บ FULL_ALPHA (LAN + RSSH + RBAC) -DEV: 6.2 LAN soak โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - -Deferred (not on graph): 2.1 โ†’ 2.2 โ†’ 2.3 โ†’ 2.5 โ†’ 5.4 mail E2E - -Parallel: 6.1/6.3โ€“6.6, 9.x, router WG DNAT, Android APK rebuild (WG route fix) +Off graph: 2.x DNS/mail (postponed) +Parallel: 6.1/6.3โ€“6.6, 9.x (no globe), SFU post-alpha ``` diff --git a/docs/OPEN_TASKS_GRAPH.pdf b/docs/OPEN_TASKS_GRAPH.pdf index 188c692..5a5bc42 100644 --- a/docs/OPEN_TASKS_GRAPH.pdf +++ b/docs/OPEN_TASKS_GRAPH.pdf @@ -2,7 +2,8 @@ %“Œ‹ž ReportLab Generated PDF document (opensource) 1 0 obj << -/F1 2 0 R /F2 3 0 R /F3 8 0 R /F4 10 0 R /F5 12 0 R /F6 13 0 R +/F1 2 0 R /F2 3 0 R /F3 10 0 R /F4 12 0 R /F5 13 0 R /F6 15 0 R + /F7 16 0 R >> endobj 2 0 obj @@ -17,32 +18,42 @@ endobj endobj 4 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 11 0 R /Fit ] /Rect [ 45.68504 716.2874 87.90904 727.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 14 0 R /Fit ] /Rect [ 45.68504 716.2874 146.165 727.2874 ] /Subtype /Link /Type /Annot >> endobj 5 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 11 0 R /Fit ] /Rect [ 45.68504 705.2874 113.277 716.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 14 0 R /Fit ] /Rect [ 45.68504 705.2874 123.061 716.2874 ] /Subtype /Link /Type /Annot >> endobj 6 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 11 0 R /Fit ] /Rect [ 45.68504 694.2874 84.36504 705.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 14 0 R /Fit ] /Rect [ 45.68504 694.2874 130.149 705.2874 ] /Subtype /Link /Type /Annot >> endobj 7 0 obj << -/Border [ 0 0 0 ] /Contents () /Dest [ 14 0 R /Fit ] /Rect [ 45.68504 683.2874 87.91704 694.2874 ] /Subtype /Link /Type /Annot +/Border [ 0 0 0 ] /Contents () /Dest [ 14 0 R /Fit ] /Rect [ 45.68504 683.2874 113.277 694.2874 ] /Subtype /Link /Type /Annot >> endobj 8 0 obj << -/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font +/Border [ 0 0 0 ] /Contents () /Dest [ 17 0 R /Fit ] /Rect [ 45.68504 672.2874 109.709 683.2874 ] /Subtype /Link /Type /Annot >> endobj 9 0 obj << -/Annots [ 4 0 R 5 0 R 6 0 R 7 0 R ] /Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 22 0 R /Resources << +/Border [ 0 0 0 ] /Contents () /Dest [ 17 0 R /Fit ] /Rect [ 45.68504 661.2874 87.91704 672.2874 ] /Subtype /Link /Type /Annot +>> +endobj +10 0 obj +<< +/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font +>> +endobj +11 0 obj +<< +/Annots [ 4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R ] /Contents 28 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 27 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -50,34 +61,19 @@ endobj >> /Type /Page >> endobj -10 0 obj -<< -/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font ->> -endobj -11 0 obj -<< -/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 22 0 R /Resources << -/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] ->> /Rotate 0 /Trans << - ->> - /Type /Page ->> -endobj 12 0 obj << -/BaseFont /Symbol /Name /F5 /Subtype /Type1 /Type /Font +/BaseFont /Helvetica-BoldOblique /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font >> endobj 13 0 obj << -/BaseFont /ZapfDingbats /Name /F6 /Subtype /Type1 /Type /Font +/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font >> endobj 14 0 obj << -/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 22 0 R /Resources << +/Contents 29 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 27 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -87,104 +83,139 @@ endobj endobj 15 0 obj << -/Outlines 17 0 R /PageMode /UseNone /Pages 22 0 R /Type /Catalog +/BaseFont /ZapfDingbats /Name /F6 /Subtype /Type1 /Type /Font >> endobj 16 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) - /Subject (\(unspecified\)) /Title (Open tasks \204 dependency graph) /Trapped /False +/BaseFont /Symbol /Name /F7 /Subtype /Type1 /Type /Font >> endobj 17 0 obj << -/Count 4 /First 18 0 R /Last 21 0 R /Type /Outlines +/Contents 30 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 27 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page >> endobj 18 0 obj << -/Dest [ 11 0 R /Fit ] /Next 19 0 R /Parent 17 0 R /Title (Priority tiers) +/Outlines 20 0 R /PageMode /UseNone /Pages 27 0 R /Type /Catalog >> endobj 19 0 obj << -/Dest [ 11 0 R /Fit ] /Next 20 0 R /Parent 17 0 R /Prev 18 0 R /Title (Dependency graph) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title (Open tasks \204 dependency graph) /Trapped /False >> endobj 20 0 obj << -/Dest [ 11 0 R /Fit ] /Next 21 0 R /Parent 17 0 R /Prev 19 0 R /Title (Task index) +/Count 6 /First 21 0 R /Last 26 0 R /Type /Outlines >> endobj 21 0 obj << -/Dest [ 14 0 R /Fit ] /Parent 17 0 R /Prev 20 0 R /Title (Critical path) +/Dest [ 14 0 R /Fit ] /Next 22 0 R /Parent 20 0 R /Title (Removed from graph \(done\)) >> endobj 22 0 obj << -/Count 3 /Kids [ 9 0 R 11 0 R 14 0 R ] /Type /Pages +/Dest [ 14 0 R /Fit ] /Next 23 0 R /Parent 20 0 R /Prev 21 0 R /Title (Postponed \(off graph\)) >> endobj 23 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 520 +/Dest [ 14 0 R /Fit ] /Next 24 0 R /Parent 20 0 R /Prev 22 0 R /Title (Priority tiers \(open only\)) >> -stream -Gatn"?VfE1'ZJu,.F'/*RceJ,EO%OCT1p4BL&)AfAZ;BVg*Ca`(uLpSQ5(">W$#V"M*JXfi=pmWXFZV(AL8-`4U1mr9"uG4kt)(Yh2<52XDJk<(YrVBjA!Wf`ODK].96WeFTl;GYP\aF<.@);c!B"^K:+=b/>-YptYlg*3\f?[st6W6?k;2]$.2([Q$!agL0oamhMqr1&*jf-m+LqDrd]!-0,eYHRtQQn:IsV>oA[F=OBkdc6(;-?5oUqg'c#"m-B:OsBIpBO:anNp-f8G:O2mJaQqPj'tXI:(!WofnbCI2q``^_EO>PU?U&E9dIk\f.`$'Ei6%lI_'W68endstream endobj 24 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 2075 +/Dest [ 14 0 R /Fit ] /Next 25 0 R /Parent 20 0 R /Prev 23 0 R /Title (Dependency graph) >> -stream -Gb!SlCN%rc'`FV1EKO]tg*I.LU1>"X!,"mW$sqrImY2l&$JCRU\$kD@:=K..]Hf-@",\09r_=4/-R1T7B>?KcVSEUL^o.KNUV1Sm/4LP@QlSa-YW[.^j7Mf])Z>dp$(k$t_)qEu0paPU<,Si6gea!PB-QS,NC4N*a^pi[g(fOr)>RfolS;63?BVe6&*;"lO+3ZX(YaKdQ]!AYSLJYf4Qj-?o6th>`.=_]YUfI_V-+RlG$nkULR(bkYl4[ZDI1k:[i^N=rg(ag4U?fH@jo>I!+VfGj\AA(AaTqU@sIZRQ@fE].DcUT7ZBgmr+\p8phF\g<&WdZAXbV(:r<[Gl[/)i&M0amh`$:(A11=l,1c^eFVHQQp`!b`4UA$h%#g<2I3DPW5NIuU'`a5#0uM:7@`TQi6ngf6Q4[+n7FisYO2/DK\^TbEan*dEP:gr&AO1)+^4#:^Z7,$r5`B<>Aq&4KY^7S[q;B-a7-RIcF8%>i7r8=C*V/7g+sk?B>>oW3bs(\'_rXULEDtAC,LOccBf)B:'g<%'4Nd3P'Ch>Lb'/oG&XWk]("ODcWk*=o9[_oZl4r/4d`S>dNb7G8\DL0a"1A#Wtk9b(/BfJ-fr$^EPQi.ACNX_q>fK_\(CWAkLacKuEtql9]#"PaI[SQ1l:t=Mutsl5PpYjVFM7+Zf9s\7^*1a^^QG1uI1M`adHL:]8(uqSC&%Cco2q"AVC-$G>uL[n];%@]Bs00Lhs]s']s2"NM)Z*DA0FoPtdL3'I-pkOk'\"lXu!I;f7s≥d^hc%)n*qOQGjA'-[`bMa8f7O^lL4S;8"i;o<.LTb.krM\\_^E&AWRqV\DG7n4?U"Z]SM^X-PC]eaNN*^C0]1sRHOH8EWtIlC!^)9TS,XgYjpe!oEl^.JIG@8;)LloO:4Wb!noAA@dd%AqpkX+c`5*PNN:M6f"Ua`?l-tGX*uu"-BF@9^)()(:]S/sqO?uE0A*,,9,rgNo5TDt/a6]i^>?oZ+PH`]np4AePp"C;om56el8MUG8g(WGi.rBOWg\[7<Y3&MH:/;l=7uYL=`O)V:J!\JM[Ve(K-Jp(d1P,H$;1J*mP[?VRHIN3H[KRpjK=1a/GsjcaC:>ke"NS=OtQM];pn)k9qKX6fIak?M2cK)\ZfNq:]NE!n((/`XAc@)94\+>;^W<<^L5L!!^KZ8G(Y'_U;L0>>h0`puDigD`.820pS0X[*VPeb`J!Oh-,Z*3e@:dS,96Eb=H!k`+0oQ?%=`!Gj@E(Um8fb,Gg*%U+`%FN":?W]Oklee/'q$:R'=/!oo3"?f,kZI'o1P1ZP[hLC8^nM\DcP(anY]ZTVr[l.ubcIF"2i1NXIN_EhPVCWV=Fj6_$c9W9^5JrDT[g#hMF.<,0]641re.+&`E<65)lGdo&m69L4oOa%.YrrSFBBX[~>endstream endobj 25 0 obj << -/Filter [ /ASCII85Decode /FlateDecode ] /Length 896 +/Dest [ 17 0 R /Fit ] /Next 26 0 R /Parent 20 0 R /Prev 24 0 R /Title (Task index \(open\)) +>> +endobj +26 0 obj +<< +/Dest [ 17 0 R /Fit ] /Parent 20 0 R /Prev 25 0 R /Title (Critical path) +>> +endobj +27 0 obj +<< +/Count 3 /Kids [ 11 0 R 14 0 R 17 0 R ] /Type /Pages +>> +endobj +28 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 586 >> stream -Gat=)gN'#R&:N^lqB],gjc4BeHm=J>CD<`/hbDNU^F"iYjK`uT*PKZ3W=H]k6=l<%rs5f&XXbb[QL4e!:#t&cB6,)&,4SLIO"9\80@5'NH-5`38rP:Ha^%BU:_4MiT/;"3tXhV#c1-455RHCPH_B@7n>cH`\Lb"V4QgA.I\!U#eA*E>OcqPi-Pt2b$E:J3EfGa)9[bG"s^Z4e-+qD)Y@Sj`KY:ZL,1[/-YAna%1i>sB;/nX8;5n;B74O'eO@_4dHg]E#$21VG'JDW57mBZfN-j>tNkoQ3Na9VN5K'G1G#0mGkHrl06<(&g*8j$H+Z#)>9Yh'^Gieea9mTbKrP]r$?ZX#]Xp*S>6GREc-L"8]b)S]%e+Y:\(95S;%$Yc"^F>AZ(kouRUj#D9%N2(Ae^*#e>.>)a63!CZ]khaW[=F(u^7!]uT2H1X]f&X8reukr'1G*F[14r2inMJ?*2>=K-S8tHCcECU6@e(R&_;lo0]SE\k\=9*A$)[ssCt[d3CT=B*p_&8'a!g`X*NW^*H`@c/=T8Bo8m)8~>endstream +Gatn#;,>q#&BE]*.IOH7Rch$;38#5iYXq3WUOGTt=lReEBq.0feo/m2/O`&2"]SVs,l?s.n,Bm["AT?Vhg>b"`PAB-";G69^kbEecJd8Hr_7>N)(?=KMFX>IAmD2Fh4nK"'-WVD-I\@J"IN46N=c$4K\jY9SWiseMmF'Lgf4uM$^g4CguG>5;9kXGPM4hP'-5'iTt4iFc)V-UYo>R&c1kLA'6ZL=T(KutR8D]Wn#%\31S;MqRprZI1X<:KnG'lhJ/-#TZPTHa43>6dVDYL5f&IskP-`_*NR'7@&fj+p1R2W,T#7h/#6gthh^IYNd6l-F-d4T@.NrcWQLqp(MHB&n%l&!^q'Xr83OpWiMN_X-=lmOES@(KOXK!P7$oF["/TYeHfQZR0$=hm#Ji0R3XE+`8P~>endstream +endobj +29 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 2816 +>> +stream +GauHNqet4K')k%D`?;qsmV]%\Pc2XrE.HD"l]=68obkMqZq%;>l!rfHpD`>[ZD#3XS@#_gqELaoAX]7m<=amUT&[8`Qi),+'s2[kNlVMb>V)*=!$99C(8ej*d9H&IIckQ4Ri1,1ZWjth76_6"GA&AEGuDZ9c;VV6A7J#a3pK@t/KTdCU%8dJ[T4)dQ17[4TAUZ_%@.?gstV#q"oBWXC.g%&d_#19!3?Ec,j3,p@k48eWC_r4ItmjdW2Y[-3Us>CU#UAlM%Zi)H_Nd@@JLR'MP&Bd=0##j(f#e&ca8m*>&dR&#[E&u3[&tf\-UXWl?G&1,cCusZP"tI["Pu+2TdgG`Pgj1b6/##<N%4S'u:7i*,a-Xb5<]4imr8G6ZZ#R%oBlS3Q>dr.TLTQVP>?QKq0%l:ol)i7fq*O!%^)5Ooh&E<#ARY$.Qa^5:9riQ&DN\+#$I%$OWBp:<0c%dg[a@E-;)a.RVS`=IG;_8>;7n0-g>*TM[D^3I(ka0sFpY:r?Q-eANd!+*Ve5NABn:*bJW.RP(on2\$>6/Z%7p"'!cJPRmlis*'hs)RA=jh4s9U)F57At]6tZ3F!\Ka)qI)DE$E)Xo1k^k>d&^o+771L$ORT99CNc")jQf^af>CgZJGNlH/t9NGDXJL]oQ?E])?8ooWV@V;2[5)_aV\P2Wj#GK%k;0ZZ1clo^MW^s//:l?NsQ:E7VC,+4i>:kn.\0WlZ'c6&,8O9c,,K'EujUkpi,jVa]"R>s29@ZAjQ7/48;2K`)n6aULrFI$ecs8XpSR>+DpbJn8g*o&a*6YNms)U@E?RIigX25c1<.@2+-/)*f-eMpckmr71#BG9(`l`@9Q$Fsso3nE&"aQTp1h*4$1FF`]6Ng:TCJ=<>[H6l[^a4-!=7mrQugFh/-$7?K+Dh3@cmYZe%CJSJtOs+cD#rDdOHVkekt-&EWslMP'TC.6^:&.n7)6e5SEneoh#\[]Xm>`X_IsX?@+A+9>ZE/^6/R8=E;[M.?6O@KSTZ+_9(5"<[6rK-+g9j5RB1+M=b8&K3ItJ('?`b0Vl6TfB:bSL^K`[gUpAkRC##D(X5'BeIDL=@kCfYm:Vih$@&-0bF`O974"IWt(;4+2;_VA3,>,e7Cg?o?K99">GeWiVX>[(ki\fr#(EirMS5U8?M?E7sFbcJLU[_Ln%j_aE;?B]Ka?>6?!^5ABL3Uo>R!FP]>g5<+p*F"(p(Pr@pJ'N]8+$VoY:3l?q/9k8p@PO6@Q&EEb=!/./2\6]/U;G\Pp$C@'ii$=MiHS0f#^(Z>>2fTEVLZeO9Wm_I70bJ6jEnTbOFj6ZdOpA6O)No[a),1B*9'X/-ffXWQu=J)J\KE-J[Ho_t3,Io9W'".]du-1cVf?endstream +endobj +30 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1850 +>> +stream +Gau0E?#Q3)&:O;V(ocece!k1+?'^Q8l:O$UPI=MUg2?dsW?M?U=op-":&8m[qjdn[&'#O<;A7$pEbe/N6ID#KTG/-^7IP@"+/3";p^e!%dAD#l$3E_U6cGE)%k[KqI]3k20VHV?)^1BH3V(S^WK3,,^Dg3N\`"G]*'Fo46;1'VZ&0D#i<#36"Ua#'0K/U5kpcbUOCd(e3Pq%)ENA?t-kn>@tVp5PG7G(e#gUW6\`]*8VrD3('?j=^'!PGNW7eT"tEQ&0pr$^Dco76@%B;3S@crd&B:=A%#\Qbi5^b.`bOi-E0V?>!o8aV)pp4V;1-5t6Sg;:VI6i-AQm)oQDpXm9c.FG*)R3F&&B3\PeUuQK@XjXXb@5+$$Fnu?I.VS2`!d)Cq?"]Y`i5=p0b>Q:?([2lJQL^E'(7@mD6t7-SNWM7D$tn06RcJ][j>(Q&_X7]L\jceVk6.CrKfFFmRpeCPl#)&dsnF+54o9fM>_>)/$n7N4g!Sk2V0W/KosTl+([E?,K:L#Q62pZcD/3Fa^j6h<[s'BW<+DC%AXd&ZeTZ?JMp5mG.PXejBXak0Y#.ruk!`pJ:l@=BdMfMd!]dY"Is1G?;"Vb_2KmhL0HtiTtcY\^0:m:!sc^RQ@Mr`:,*rQZrH"pbm7:mZtmrGk8i!2FVK(`[k-CVS7Cuk?`p@R'ju-d]Sph7YHJ=/@6JPWAF8a:7\uGm;hX1K:C[;67rIiSke2r=gf\&SdF6`'h+dKp5",MhS$'2Flr#LC59tC4lWY?Iu2-a=,8`2*b*\F`4^Ei$F)WJ-3Yra?q75^!ELT:#d@m@``Me(iEing<"F-2ZqoL.,HT2J&Ra'a%rdR4mR=``JCTM,!j'])&Rb9t8J'`!i*Nef'F8hjSNO+1$DW'?2`lopi6KuU]DgeZU$$#ON7f&FZe<;-+k/SF5t&0nJ#nK+-_??ge)!\*&)k*p;_Ec$?V2c+leR=N";,t6U!/n'e]EZ)1fl=?b+(#dEkeXpd#6afFU[1_8-GV_Id^+5PHDk/D4-QJ6M1O+6$l`+#Sr-u=?.cNckR;n7C&?gTPh@0EnVdcuA633:X=CF1W$ErWBSiNS!Fh10HH69),8pfBeH2]s*+OOdZk<\<)^lNiO%5ViPNKf@Uh>IJG"!?A3B0'WFsec93&!(R2XWEuC/>]i'*K#a6aA>mGi6%sAc0/?8]j^='tg;qHX5?eqo(l$:>2nX:,&W>sE])f<3"2uk^dko:c)`Pq6!a;e$dM(58l)F,5)FLmEU)?ZX:Hsf9-NL2!2L%H=+FJpY='JbVc)`WQNoP03WVOhpP352omQSC[9>!`ej:!,F#AO^T^/-DI(/dnX'1/!!sK5b@T]4kj,qTe-^(XnC,n]E!^NI5nZQ!ICD1$O0%V/bbgR-'1U/J0jN]ZPP@>*K_cr[YS=WV,bG5Y.3rstMYuZ@-dZ@Un5\Ln#e%slimn*:cgr+?+ZQ`n-D:[ieH\YDlc1]B+[e:KPR5+PHYgC`1a9.p'I<_`rr[$'CVK~>endstream endobj xref -0 26 +0 31 0000000000 65535 f 0000000061 00000 n -0000000145 00000 n -0000000252 00000 n -0000000364 00000 n -0000000512 00000 n -0000000659 00000 n -0000000807 00000 n -0000000955 00000 n -0000001070 00000 n -0000001311 00000 n -0000001417 00000 n -0000001623 00000 n -0000001701 00000 n -0000001785 00000 n -0000001991 00000 n -0000002078 00000 n -0000002385 00000 n -0000002459 00000 n -0000002555 00000 n -0000002666 00000 n -0000002771 00000 n -0000002866 00000 n -0000002940 00000 n -0000003551 00000 n -0000005718 00000 n +0000000160 00000 n +0000000267 00000 n +0000000379 00000 n +0000000526 00000 n +0000000673 00000 n +0000000820 00000 n +0000000967 00000 n +0000001114 00000 n +0000001262 00000 n +0000001378 00000 n +0000001632 00000 n +0000001752 00000 n +0000001858 00000 n +0000002064 00000 n +0000002148 00000 n +0000002226 00000 n +0000002432 00000 n +0000002519 00000 n +0000002826 00000 n +0000002900 00000 n +0000003009 00000 n +0000003127 00000 n +0000003250 00000 n +0000003361 00000 n +0000003475 00000 n +0000003570 00000 n +0000003645 00000 n +0000004322 00000 n +0000007230 00000 n trailer << /ID -[] +[<5097cc94053c3b6e8997e7857bc38449><5097cc94053c3b6e8997e7857bc38449>] % ReportLab generated PDF document -- digest (opensource) -/Info 16 0 R -/Root 15 0 R -/Size 26 +/Info 19 0 R +/Root 18 0 R +/Size 31 >> startxref -6705 +9172 %%EOF diff --git a/docs/OPUS_SPEEX_VALIDATION.pdf b/docs/OPUS_SPEEX_VALIDATION.pdf index d105486..fe8112e 100644 --- a/docs/OPUS_SPEEX_VALIDATION.pdf +++ b/docs/OPUS_SPEEX_VALIDATION.pdf @@ -133,7 +133,7 @@ endobj endobj 24 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Opus / Speex / stream protection \204 validation checklist \(task 3\)) /Trapped /False >> endobj @@ -276,7 +276,7 @@ xref trailer << /ID -[<800b999f5cc49285439507fa35707bf5><800b999f5cc49285439507fa35707bf5>] +[<2caacf63b125206582f1e01401b081db><2caacf63b125206582f1e01401b081db>] % ReportLab generated PDF document -- digest (opensource) /Info 24 0 R diff --git a/docs/OTA.pdf b/docs/OTA.pdf index 51ef9d7..4461c09 100644 --- a/docs/OTA.pdf +++ b/docs/OTA.pdf @@ -112,7 +112,7 @@ endobj endobj 20 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Over-the-air \(OTA\) updates \204 deployment schema **v0**) /Trapped /False >> endobj @@ -233,7 +233,7 @@ xref trailer << /ID -[<8ce728cd48920bf00138be4ae62e19b8><8ce728cd48920bf00138be4ae62e19b8>] +[] % ReportLab generated PDF document -- digest (opensource) /Info 20 0 R diff --git a/docs/PRO_AAR.pdf b/docs/PRO_AAR.pdf index 3374c75..c41500e 100644 --- a/docs/PRO_AAR.pdf +++ b/docs/PRO_AAR.pdf @@ -97,7 +97,7 @@ endobj endobj 17 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Pro / OSS split \(cast-core + cast-pro AAR\)) /Trapped /False >> endobj @@ -202,7 +202,7 @@ xref trailer << /ID -[] +[] % ReportLab generated PDF document -- digest (opensource) /Info 17 0 R diff --git a/docs/README.md b/docs/README.md index 2f3628f..98380b0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -46,6 +46,7 @@ Click a link to open a guide. Section links jump within the document (GitHub, Cu | [20260608_ALPHA_PRIORITIES.md](20260608_ALPHA_PRIORITIES.md) | **Master priority plan** (0.1โ€“9.x renumber, owners, alpha path). | | [20260608_STREAM_DUMP_DEBUG.md](20260608_STREAM_DUMP_DEBUG.md) | FR 0.1 stream dump spec. | | [OPEN_TASKS_GRAPH.md](OPEN_TASKS_GRAPH.md) | Open tasks dependency graph (Mermaid). | +| [20260608_BE_SERVICES_and_infra.md](20260608_BE_SERVICES_and_infra.md) | BE service map, validation status, SFU preview (gray). | | [USB_HDMI_CAST.md](USB_HDMI_CAST.md) | Roadmap D/E: HDMI awareness, USB-tether transport. | --- diff --git a/docs/README.pdf b/docs/README.pdf index 144e0aa..aa07291 100644 --- a/docs/README.pdf +++ b/docs/README.pdf @@ -112,7 +112,7 @@ endobj endobj 20 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Android Cast \204 documentation index) /Trapped /False >> endobj @@ -181,10 +181,10 @@ Gatn$;/_pX&BE]".IJp[1m^!8_qmqJ8<[5Zm> stream -GatU6=``<>&q9SYkbhY13@rmN]ZF9!3!"X4-hgTN8gV@TMR>k\[dUE74VA$W(`8*M-2+9-e([RBfA5G;_]M)>J*m?mbb0='"#%H+$,"cM?oA"+G4k`ihp.JINhXXc"KJ>AA5S]_4X>(d3Ef_I$@K+Wd#hc!AP6dkMB%$uJErfmb[80jfC<2k#p9M1O2Fu_/4^#CA=bc3T2B+nQ$OUd3Q^"F+^#I\"S:+fIKIjIpJ192I;(u#NT)'qJaG,+$fV;DG4`?OhL#SRZ>mrir;je&`Aii:-L//PS7?Z77b8=lIZ0N36p"Z7)8N=l>dNb\:]kk&n5Nb.MoSK=oXNK=lTgK=o^PK=lHcK08&0K04A7K6e19Wos>Y1i].8hKr_,j2^)i:L.$qaTB0VC)3@o5GGgsi\&4jM=>eSNr`Jt-W5nl?eV_hS)RX1PGI2o=oI\5ITa7U$$NI`B_Agq[9N"f$k-KYh[1,Z2uoU?Rb5o@PK)d@;7;9)n2=1A;*Ol'IVO5=[bnUcFE4eIot`nTtFI2=3o/fg:/1%%8UJO6LDqe$NFaN?WDf"^jB5LOaYRI6b4'FWC$NrRE^-YG-Y(MqrG+QjP3-l?+$Hjm\RY=\%m>\d>=Kq2p&g,c[f&5.T]ot+jSD+:0B4S$`*\T32DOXV3H6tPGNa\_&M?*2<'dUdpWZWdE,49uj2'qd2Ke?W^_$O'.eNQhL_G,(cfJhP[,<6Q>cQsLnDaMddXm-in8V>lSu^&I2]<1N8[!%@f[QtJiKe;9M`FAY?J,WfJA$c4$[lND\]S[KSou!TX0jgR(jMlNbjf@%1FGk"2;hs=JcF[4BajUSNn9AeDsRXeSmdF`ou0CmqMWh-PLiPWI%RXVn'A)I_<<89>.aI\O5Qs4IG8ppZ,`1o9U46<0u5l7cJQP/=gtn_Pup?0B&*A;HZ7ZeO1)2c?M%E9l(!#i^U2\MX5;qEFLG?2F52l])$f$G[UdtAB\L$SF.VKC&9f[gUS!H'\l&u:F[mH"uQ:6]*[4tg0jGj'J.\FHB96bEeDo_=1H;4*!C4nmQ<.h?[3DtV<\'X3T.T0i>HOW(5-pj`@^R6dc!ZOj7Vtb#`rf]SC,u:YRndY)5dE0^$NgMTI+pZ+s1n]Kbl=3,0+"%^aP3MY"9PjmHi%mX!cK<32?#me=)Clo=rie]T[8n)=(khKNX\^h.]F$4,1/@gG.P^&[=J+O-=EpaV;r^(ceQG?Q8Up9us27USUh(g\6O4Y5Js.$#I*e@!^`^dBVoOiT"a/q_`df`R^+oo2F@_[:.U119q=@nWKoer#B3iHQF:@mR$V+3Xq/m`1cKB=bUdQR_t-F,'[:^;GOD)CF81_1c$_Yf0coYonR$8KMeAh:F@@\.:tE@iPG%N(H6)hPtpP![2d"aT'0N7ohngkA>4*$K_W[Y?lb[b8>%ZN3,-M:I/UJ!?fT-Yfq+\qUpYQ]AgE6F,JF?/l`&\gf*5!VIdam/Rp'r6D8=+VfU'N*+k9DDZV;Z>7s9Sp(%2`o/5.YT*7O.47A""r7$':;%%t7+-G5o%to,35#Z',>%l?cl"jfI6gOG[36"ASk38JB\5\gRh#pR)h=\:NNKuOLo@&5n&[IfBe*g3CEUNT@,P8$dknD!_G5N9-84q?JJ,YQt>P.-@7%We98T&8FNMl$#p$HqT[sH&9`oa&ME@qbbE8*7b!p'UZRuNo#`4-PEIlef1@mClDq_d4JR(*okg%6?%2@`97-=HN<82<_7eE><99iJs^8N1o]WTiOj\mOb,3%&*%T+BQc0n#[^5N$+F07!1k]/5S4>:4GRVo92Y':^hO%n*sNG=3;#O+O]c=B2MUO14K)qh/c#2MK7oCoZ:lJL%go5FTVY9DY.0mXbjlUAsK;*_8+96V*]\(i6F7/(/rV4#.H6+)%jQU;'333JJEb)_-\!41jQUT)MJ8i>-48'7S0%9'g()T6&'e_JrZ,Y/a[\4WVO3aBMlTQ0!n$$ni])^/P,3OB$TP,i'J&$*%<3E!S,.GhWi9L@>Q%:(~>endstream +GatTKBlg#kp3V8-q=H.XY7!EOhhWG4G;L3q1[eA@MB^\&'=M=(antc"1^J[h,%.6ZP3+T6m63$O0_iO4s-jM6bnBks/?g*Ff>%_V!L@6BQ<1i(f_nQ2lq*)U#TtWi:ZM`^^5$)C!=,)E`5(M+\Xj("-UF^W(`E0X%+dl$1>fkIgN)0oo"ajRMp"h2X[is<`/H7n9qW[-N#a"sX_;L\&8_`T4>V/:)o9_j]bN]KY8nJ"60JIm0\dC&?5UMs#i8V=]*j'QFr#?6?bZ0H_"&j(s.\L8iQiT7&plAYaAerK)n;I`1[O?8,*Qs?s;H7ZUQ+qgh-0mF!H@p"`[WBj5PIsL[O5X4R"HG&Fl7iXdM`gY,J],V:oOO('#V%sZ\.ibASl5AApGBA;0UjAGJ,!AD-PiA=5=k*1Ss\gr=fkH1Ql0XN/r&I][EfD7UudE$-MlSbk!.nE^\j11c"8?It,@`L3TcQh5apM#SdO=0Y,PpG$,8WH+2,VbfQf=l%lKr-L=&%Wj-^)%]2W.ufl4_Ib^i9&OeDKeMh)@lr0GS'to1eANnbkuJ<7o&nrb9in-7PA*kBBjSpjO&l9/N"Yp\N@3WbZK&?nQq>qf8-2=GAV]q[DZuL>,0STm02rJYd3$nr/H$T=CDm\1pcBj8#Qd4p9t5cE>Wi-`f=$[#fq]N2W[7GcQ:S^,.9b.0Y\r('[teS&Fr'6JL;1!CZBTOost5UZ8Q/RWj\tH[1Z,>9\"(SA8=qKZ1W\S`p+e%T(*$IQC)SK>)ui$V/e]N)7HqFCfr3W0PE#mGQ$c/*KQNdl;&h([TJKcO7hSXM#C(YO=#C&6A:ru3tQUO\0ac[g8BVFombCsl;n7J]-7:B69Mq.Z$,oODtsP-@T%&B?>:tac1>UrX5@Zunat^bi\m]c0)c;K(lgWg7`L2>bNVpl^h[c><)1n`6P&#$MYOXS=XbK62^LYX:+"\B3)[fi`+r-,QL'EePt]Q\(_Ko%YmR08,B\_Uc=URY0cA.kQ>!F18==8"l$TJTlUfWsMX#NUVrP`>R"5ie+\(3'/*]9G+5Q4_JMqXPe\74faA'e5O-]XuGl"2$=?6BW=77KOCUYTH+t!*^G=&n&g+gI#"T*uOpTDo*8)%;>&KP_7q9m*;C(hg[:V?@p[Io)G3&^,O&?\up;CAFmX(\ZmWK4'n$Zusfiuli1J`1NkMi+!H/45cj2_h/MTgNB>#@)^-2c?,pHlBoQ@;bV91_rSt8UF$h*OUdhIVAC8/!mB4-5VJ-!DFkgUFLKD.nV"nBc?/cmckeK4qlfu>A+Hb5X;d,Q&G+qd^[MR*5e$H742VmM&At4+EO9XTBq0?;7Oi!2)s9=#$0t16$8o,+\1Y&&2Enf6JfW;@/.\g>)AXnaH!2ij]Z.-'fG9Xo]Lk5nEEY5h:N][>(Sk6-2pl8^9b.or4sYWQd/`DskhB.&oEAkU3S[^p-;U+'iL%W1c!6`3Q^Y&eLR9^ZUWKTDMU@%(%kAds1"J1cA&325)ina&/QG=uBUm2/"_r;TRZe[pDYsOQnHd"a_HQVN8F&\5NPLFO6rP#%1\7Sl4&KXu,\`9eKI092q4oiu!&GqAn2l_4RTPVRY!jL*D+9*WZc%&@GcNld;WH8@3?!@qQ4(B_W%FrMR.s*YQF(ko*_g:?W)7)mgSBaeM[ce(I`3S89Raq"3QSqDT]g)E3h)2-o?hTS/S[kHd6!aKEl[G(,Y8=t(0DV@P2P)LH^l:o>VeP:L#\spmfP@02g/M!ciNUk`S<"+"25@aX-7+gD6$7U(X'@d:A!<(aUChQS*0ZPg1X7ND@S(0(*H\#5SO"4XR71N:8EpSs1#GY5+J4[qO.q#opiD=5GdZ20+W2B_k&bIikAZeM0\\QFdWcRb:s+&mp9Q"?XdPO>s((%u$>0;2f.0EVGu_bYWO`_WR>a=Ap94(H;3.m:<"'e]"hc72pUKeEOhe?i(1p()ZKE?:PX&J4REo&R$bp$>[-p:!rtdi'7#*k>b=:A3jbbq"O^cW[GZ15$W.=h/^*6@?H)-,(M+*AdTIb>>?<8_mprsQPkTSi!LUaa=DJb8_dmfV$D-,fh8C/oqRWPX)b&5oa)1iA(Wm8dU0o$q)IL"V=u%+JkkC]$*H<8K2c>K>`p2kVGB1RB0tG(l4^!qD&)):ta>YrGUYgII)W!6qO8F3Z3CQ>-5?qT]N66Z7.$>HF7u[O'2O",%XYA$GiWm&HguEFdIr]@M^JB;>n\X:T=Z6I;h2pSjl_ACE3Z!(Z+_a06)h5\^MFuTT?bY%JOI$_/T'#AN'Q:'L]#[F-M[H&A,dr;#Ot,gQV=2/j\+W1_LF:%_?=#$'rq6'Wu5VE3c\l`o$g+X\e,)YHqqU]NPY6ACWcP3`g[7o`YC^-n[.D,Z&92a"&s8.!M:[k=.0V@#kLJdMBl-s4ncBR2kAV$*C#e2X:u@EMn?hb/6@0RWnA?Q[g+M36NHjX)!O!)fnnRY(sF?dIau8Aqc0A6G8FJ;W\WH*f0IS%EeMIOtSt5n]G1r0_PUC`0HeJMO8PA#'7?0.*enm*TTTLo*c%*G>V4&T4Qs-[SNmKMJ`%X*%7e1\:fLpL-`sP;V(RMeU3@;HeG,O>2?SbhhIphendstream endobj 34 0 obj << @@ -229,11 +229,11 @@ xref 0000004122 00000 n 0000004197 00000 n 0000004919 00000 n -0000008167 00000 n +0000008247 00000 n trailer << /ID -[] +[<22cd500a0b10b610bf3c3a20eda45db4><22cd500a0b10b610bf3c3a20eda45db4>] % ReportLab generated PDF document -- digest (opensource) /Info 20 0 R @@ -241,5 +241,5 @@ trailer /Size 35 >> startxref -8980 +9060 %%EOF diff --git a/docs/REMOTE_ACCESS_IMPL.pdf b/docs/REMOTE_ACCESS_IMPL.pdf index fae330a..f849672 100644 --- a/docs/REMOTE_ACCESS_IMPL.pdf +++ b/docs/REMOTE_ACCESS_IMPL.pdf @@ -128,7 +128,7 @@ endobj endobj 23 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Remote access \204 implementation notes \(v1 WireGuard\)) /Trapped /False >> endobj @@ -213,10 +213,10 @@ Gatn$Df=>`&B> stream -Gb"/*lZ:gj&c\H;@_];5gt_^k_[r77p<>[H#1H'#4R\=R?$1Yr"_d+%-##('(Q,T_HG+_h>Wl0`"rpm]PO6m_uXO7bY1eCX0`HqqqqgRV`N23"DF#e]_YZOFiT.2)Q?@(5h0<;:O]cCH/l$']M-,a//5l`5C#%Z+d[&7Eim#6VL!]EN(5k[Z1YP!9&n]BkNAUVK+DFM5pnY8*qR.(uQiP@?V'ST>r=KV_VEuG$_6p=o'+K!U_dP2!=2l4-.7[uZZ=1ZMMK2gBIEPKM`0#F!9M<@_Z`f"e.lV(<5iFY`GPg]U;Q_$_R)>KU$kUE)aq]?fBVeT?\WL7u'V1sCOXZobM12h"cRoI3*A&n;PUQM_(he#%@0iaiZt+8jJ1^;&pJP3Y5SDa$WFE^]iD7kRZ(7796FTARMCOdb"J)5!Kh\.P4e)YoiDUN&bT.1b)A,@;=:T(#h9]2oQ8;"]3$1luX`_D&@*!2B68#pd@\-bQB9)ViT*!%+]I5kbClKp(-JJ>CuIiGA0TqJ2TmS2Y>U1XL6eYebLa_S0a\^pInc1i)==mJo)q2MZ]JK$s^T3Atb7686mEPdk-`RdTIY,H,JjaMZ-B3!G!l)^hr`Tk-!ha?=dunAL"+1UBqcZVo5,3;rYX"gQn9_B%6C6f9Q:s/XBi\uch)G"I0tVe0C-LL_mM=U^Yi&*?-\4$pEH\@"elp,T0&/(KZjq/0h8upi%S:d_"dkuPefuW[=)G[(YB,JYY7u9RZ'1G*Cea+\N(.b(paC[2@@#.m?e;`iUdj9i_JK?EE<5*,U$F$?mmg_O`bBTaJ#6f^SGo/A.2d<\*0i:Ej7,;41+:_tE@>sfK(L0o&3V,kf*:Bl*\7m=6QoY%/T$O"$U9*k][CDplmYo;kX6lAI[ik$Oulq1`3ZdCo:N)rfAeLd[`f"Z8mD*Rm/br9&%b$U",Zd6>3+dX^-b3Zs)LC42g8\_Q4j_Z&GE=b@jCLs#HQX*2Lk&>(6j\JhT1E+l][>S"9]g2@?'dbXCHP90/Y?d#pUKUd@IiL4MaTeh%b=&%kckkS(sD"oGYs'0-+s/i$)tn5?D[-4)2d-SBg>I100P/g*_tS0A3%NQ`r&TjA-E_BJ$Z3MpDP"UkD4g9+A9fNCcG"l[_RRcVApA8.$b73rFg/EJ8rPb+4?'u2%%V3hALLm%5T5\<)rkXn3poI3'KInouJi$M.Vk2XGBqhpTFOF)a22@6K.a\d3%FJ@%$FKDK0XX\EGkY<:6gQpn$Yg7&*eq4bb:fP/ZXs'1;i2LJ;AAF_)QGUED2LH5p<e-+#c"`"[aNhS35O]e;8R@+n##\)6*"FGtrB=.tcfSS:#dD+V/m_G!7\8NOZ3"`J'J74AHsV/0c4=R#J-q0-s]UL.'mE-L[[:4k%q*60;i2KD#K)i&ZXNj"bVP(SeaR$RDM(>p.O8i\PLKQFTQuV)3Kgk&H([14M#a@-#dnpJ/Y"3aL[WHoUk9[&kFm`I3O'B2lK]h(L9Jf0>U&?Ji/@X:PQ\QP8l^k@cHgSGrUJkOlftm@7b%@)iFi'5Q]&7*0(qZdUB6.Z[+#-`mm$f%Ms>9X?7Ln!-D)&ctK;\gTj&_8/_t+^T$S-$5[QiIq!A6XQ^n:1S_rmifA`&]s6)]g"q"cW88f1Fd6GZe[bggAdF^ENj<=IGKj/S40^H78#h>j5#L"F:9jZi'-^)On/_cV@@b2h4ntb*#0EHY]t(K^?rEl+>4?_aoSqJN3FfUFrk-@n@7,HDjPtk\Boh'=T]l*63BD_%>\n[f`EC:5YPBq^o(\+![bqM8dXRYo7p!JNFBT`\shXfXi@m.Ea6j[41&&7R$DG)F_pk/3A`S..*BF52=X(]ChOk_l"4Als'M*To=AJ^ScIZZd=\FUHKZs[]@RcDeC!4/p2YZ\[qkP\5O]>Lglr-?Rsl5+WQJSfMt%;[D9#mpZ[:KRQSJJnjIl%+L+chI>pp+LfCX0]"Z/3p*AQ+@*@FqempOOF/H)Lf09D9K8T_kB!<%B%V4RdMXA+p=.@q[qjAU7Q+jE>"oW5/j#lnPm@qhYC,!-PWUkH+;/%cq.Et8^l*ARI6%bP,(Pjr/eBLP3'l8>MmH`IZt1%=3a=;qQ!:G./j<%1UamL:jAp46uPP!=EuN-3#Rk$16mg,j0j9,!5Or!ZJ"3D1)QN#n4FdD"MTi\gYO<7FG9Ch$-EeGV&LqL"X6hI=AST%sj`-g19-2ReY6h722lXs3m)l/*&%'Wp7D357?B!q]1R2DD*iDg4`=_[ISE"b0dbk3K-GX3=R&k=/2d$S68^?'N*gM8%2<"H91n)kso'"8s^-_5H/%J/t\O4@d^K2_W$EYgAUF^IGBhOdZ78p[>Dp&1=&>0K)KX-'<.9q9h-Tb*TaHXuKSV6f@1;6cp/1M-q1WA0)=+k<0*NL_Ve!B$-Jt0?,WJJ$3*@f".9qDg/l\sW[,V5/1(MW0/IId!Da.MP2NZ;E'tboaOiu?!k2Fa\Wfh(q*;L$j4N[`>0L1R_[WkdV?X9ZZlpd\UMr3%L&7(U<("0bjW&3\^l*ht&T;$_0RgpdNhqp'T:\$TCO=s.`J8%D2BfKisG1?BH,]bIG:4=T/R31AM^VCqf'u5b-!)=rG_>~>endstream +Gb"/*lZ:gj&c\H;@_];5gtgISCg11=C;r'h;9iN)Q]:E1]5pd)4`NS=L-h+13n7M*c[*B;=7*tInAQqf5:$._8KQi1Z0Ys/h#Y.;fFnp4SmDs0)D5e45.kh`9A8Ud9S4@dap[F#9W(jGn]I?K1-:1u\BU0^jj_78L$l'fdK\%Rl^AhX0.u,S!]F[j_!C;A,9e8H>+Ep5_'MQG+eXJrO?+\slP)bFq4]:VgJEKgT`FO0hlnPH+Tg2Cm^C^2DFk%RO4+7CPu'm7]7@(9#]KlYi-T-P$D]N.>g%j:F,QjRB4QadTWA9K*`iTi\16Sq(2u?`^N6H?_eT=::J>&S81s(?+!#\u#)lG)tqW+CYM(o;D9>5q\BpUsm_:j%2"-,;dNjEN;P&3@+Da+!uE^ZG=40DGGKhnQ[^:]./,:0a#1-RekE?fY?/b6<28)oQ<1[_LTo3N8^*q<=c]*n,T5P$Ho6[lfZI.lBt--4;Ps6p'O.'a/IIVU)a;m2LU$A2GoK>\W"IH7;\f\aU-:nN<8iI-@grI!73k0fq;k**0?C(3h3mT8:QUTM=]G\ZNc;%BI9+4OkDZ^*U&5lJ78p=eK06MS,0@m8Qb9;0[%BD8+(7a?lEl=S7,>%\EG;8cj/kS[;&&l-dVDp^,pmPFe^EF0!gnX"7[38R[S_dDr5h^msYdsVKf]l^S2(4+m78O+A>V1'54e[#S@'$CBH*h].JXSXhPB%nVQB]A%'I^?,e:\2Ca+<7ar*Qbu\88o?47mNk#Xa[Tq3_sgo.dGA7Ol?0hS4H`,>XZt\M*fQ&q$meLfhmFHPs0E;(,BQ2Lf[,2i):qYH@^7+!%Qlc!?'NfUN`8)CD+C:+P:%IDLHW5=1\YMV%l_S_po"o:BkN%+D,?j?#?9d?28ejIm:N&U7Yfd6+XFf\;gk-61t'P*WLV;TaZ%TDe`,HHi*L?!ekLN<`aWlP'k>^6+RUl#k86";^uLU'e0/MIk7"=$&Y3>Q^9=n:"-it,e2@)U0j)FZ*RM_MAJC^#a-Ug81-Ja,4EB[Bl-g'\Q7QkbZ@n&:*_8<6"i]Zd1^r<)Kj;iQF@=Du.3S5P[reC<62D9=O?Z6b/o_P:E;T1rlM]g8=in?E'H;a,&ETioj>bP!,W\uUTgfcC&@>?VagOW`!:7$pHKF'2'IYH'9=Nh3R/9jiB/3ji9hT*V"<5&]RAp:e&+rUC&Ds^IHQF+;^=E@CCWBlR"u%+l;:Qm>&*ud&G5hiZQI\U95KIroolbGX`KqCZ1BSGq(!Oh>(aDK\A0Z4a="Ml_N\Up,7gBK,GC9"R/NB_Lb!g2O;=A.sMsjDZQ-:@sWbU]1isKrh"Ba4"pu@\:SmZ5Bl]Yt.L0B_c1W63)Cdr/(?(-tYAn<[_b/p!Z)"O=YC$$Y6?&K*f79h7o8E8bCc8+D9L<8)*nm$4cY"@\k(\/=K[L4rt,fgsB@F1^@)f2RU33FHLH9(h;ZTo/gm02LQ-OuUea>2?R,*tc;aZQ`1,P.8.'h1BhG]-#5VpcO?o7uqA7[n-o/fn1I5G?e[l[IYD\p]iJH$S"HZ9]27>YeaR3(IaLiqtmjSCa+B205)YJr6Vd3nEkgLm$'cB;\0oot)Z!MuW3f71OIippPf[Fh^#J@3UL`0qp%ibBqX3)sRW917?5<$e4F^'/4aZlF.)^%e,kY`ncco_*%0VT=PT?G6(X_':D6]AGs3D>P&/W4J(m(&+Fr`9!ig;-'#_k=[8P%maeV%m_+ABkUn"]!'eo^^Q"mU"Eo)6TuQ[eIu4+sa4]eF75t\%)+17G6(Nl7NWN,ThbD!iHebJ\]072a6WLI-*Nj8jdLKPu4%;41=q3I^B1nQU'_7e(n\G,\Aud=j[^e(C4r<5o>tl^`9BIIl9\kaHIhh'El[fcdQ1-6\"NWDnprGOh!p,5IE@gjmW>.H#&\G,/M+YZr^)N=TDQb^shI")30!Aa_P5NNo_lN412eDO^7>jC8)A>V?9><<<77F=gR2-dfRfI4j#@M!garul&lu/Q$7kS./!j-sco1D0j^MeH0p5ke'SbRnS3HW_8''#\Nn4_-JId!m!11B,\Dbh0hE4'a\`DZt(Za,]bpTZ^%]q^+N`V[1S[A*Ns4+4@W2MEHI[FI/aH$TH1+C5)+NB:Jud(Y1YkcQ8XGS\nY8a98B\Ud"Y=Y=[-1A=UkL?SG.?>>sas[:JZkg(\4OAQ]k1$#fcDbC+m:Cm+%s0%e?;&qpd(aL_Ah_+(9Sl,6(IY"A&G;u'U>oBL(L;qnj]Ud9cB('a$XXs5m=LS'p75O<(-_P\a0B[oaG\6,6jaHaah5L)FSO=mskKYA$44e,Lc/UK%-9n>;>&2uKk/RKX/]GX"X+ARA@@[KhiZG73)!L8=Y,pgS;ZYb_HLA^`s%QIi15S0-rbB)qfIJC5XL56GY^:D=0Fn@]sTX(9;\P+Uc4YpQN_c.M\q*5nZ!#3g/Lk8[6eRC^TNeE\h&KWUj:EdER('&mqX777JTDs/PK]i^L,iijEF-9?]bendstream endobj 40 0 obj << @@ -267,11 +267,11 @@ xref 0000005069 00000 n 0000005144 00000 n 0000006050 00000 n -0000010186 00000 n +0000010169 00000 n trailer << /ID -[<0ea4a9599ca2b4815b3cdd11dc5a5773><0ea4a9599ca2b4815b3cdd11dc5a5773>] +[<115c8383c89ec480b2b9deeb38eac471><115c8383c89ec480b2b9deeb38eac471>] % ReportLab generated PDF document -- digest (opensource) /Info 23 0 R @@ -279,5 +279,5 @@ trailer /Size 41 >> startxref -12418 +12401 %%EOF diff --git a/docs/REMOTE_ACCESS_VALIDATION.pdf b/docs/REMOTE_ACCESS_VALIDATION.pdf index 2de663f..cc2666c 100644 --- a/docs/REMOTE_ACCESS_VALIDATION.pdf +++ b/docs/REMOTE_ACCESS_VALIDATION.pdf @@ -107,7 +107,7 @@ endobj endobj 19 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122521+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122521+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Remote access \204 validation \(Linux CLI + mobile parity\)) /Trapped /False >> endobj @@ -220,7 +220,7 @@ xref trailer << /ID -[<4aefba77718541cc2646cdb6a66281c0><4aefba77718541cc2646cdb6a66281c0>] +[<673f7a357c9c05e8a1d6a5eab503b7d5><673f7a357c9c05e8a1d6a5eab503b7d5>] % ReportLab generated PDF document -- digest (opensource) /Info 19 0 R diff --git a/docs/ROADMAP.pdf b/docs/ROADMAP.pdf index ee469be..866c269 100644 --- a/docs/ROADMAP.pdf +++ b/docs/ROADMAP.pdf @@ -168,7 +168,7 @@ endobj endobj 29 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122522+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122522+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Android Cast \204 implementation roadmap) /Trapped /False >> endobj @@ -350,7 +350,7 @@ xref trailer << /ID -[] +[<5bee862ffc07cb85575bd1d024be9265><5bee862ffc07cb85575bd1d024be9265>] % ReportLab generated PDF document -- digest (opensource) /Info 29 0 R diff --git a/docs/TICKETS_ROADMAP.pdf b/docs/TICKETS_ROADMAP.pdf index 025c0be..46e7e04 100644 --- a/docs/TICKETS_ROADMAP.pdf +++ b/docs/TICKETS_ROADMAP.pdf @@ -102,7 +102,7 @@ endobj endobj 18 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122522+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122522+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (Tickets, Gitea, and alpha smoke delegation) /Trapped /False >> endobj @@ -209,7 +209,7 @@ xref trailer << /ID -[<8fe3abb3b6ae298d8e49cb9ed97a806a><8fe3abb3b6ae298d8e49cb9ed97a806a>] +[] % ReportLab generated PDF document -- digest (opensource) /Info 18 0 R diff --git a/docs/USB_HDMI_CAST.pdf b/docs/USB_HDMI_CAST.pdf index 6ef350a..7f41f0a 100644 --- a/docs/USB_HDMI_CAST.pdf +++ b/docs/USB_HDMI_CAST.pdf @@ -82,7 +82,7 @@ endobj endobj 15 0 obj << -/Author (Android Cast project) /CreationDate (D:20260608122522+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608122522+02'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author (Android Cast project) /CreationDate (D:20260608212304+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260608212304+02'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title (USB-C / HDMI and USB-tether cast \(roadmap D & E\)) /Trapped /False >> endobj @@ -159,7 +159,7 @@ xref trailer << /ID -[<2f3e1c2548fcb7ec850b1fea338ffefa><2f3e1c2548fcb7ec850b1fea338ffefa>] +[] % ReportLab generated PDF document -- digest (opensource) /Info 15 0 R diff --git a/examples/crash_reporter/backend/config/config.example.php b/examples/crash_reporter/backend/config/config.example.php index 309fc02..6385ae2 100644 --- a/examples/crash_reporter/backend/config/config.example.php +++ b/examples/crash_reporter/backend/config/config.example.php @@ -80,6 +80,12 @@ return [ 'max_attempts' => 8, 'lockout_window_minutes' => 15, ], + // SFU / WebRTC relay (post-alpha) โ€” hidden until owner spec; see examples/sfu/README.md + 'sfu' => [ + 'enabled' => false, + 'signaling_url' => '', // e.g. wss://apps.f0xx.org/sfu/signal + 'janus_url' => '', // lab only โ€” port 8089 is a separate stack (INFRA.md) + ], 'mail' => [ 'transport' => 'smtp', // smtp | sendmail // Alpha: use apex if apps.f0xx.org has CNAME (no MX on subdomain) โ€” see tmp/20260608_help_request.md diff --git a/examples/crash_reporter/backend/public/api/sfu_health.php b/examples/crash_reporter/backend/public/api/sfu_health.php new file mode 100644 index 0000000..39ac4eb --- /dev/null +++ b/examples/crash_reporter/backend/public/api/sfu_health.php @@ -0,0 +1,18 @@ + true, + 'sfu' => [ + 'enabled' => $enabled, + 'status' => $enabled ? 'preview' : 'disabled', + 'signaling_url' => $enabled ? (string) ($sfu['signaling_url'] ?? '') : '', + 'janus_url' => $enabled ? (string) ($sfu['janus_url'] ?? '') : '', + ], +], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); diff --git a/examples/crash_reporter/backend/public/assets/css/app.css b/examples/crash_reporter/backend/public/assets/css/app.css index 29e0ff5..22ae61f 100644 --- a/examples/crash_reporter/backend/public/assets/css/app.css +++ b/examples/crash_reporter/backend/public/assets/css/app.css @@ -40,6 +40,17 @@ a { color: var(--accent); text-decoration: none; } a:hover { text-decoration: underline; } .shell { display: flex; min-height: calc(100vh - 40px); flex: 1 0 auto; } .shell.single .main-pane { max-width: 1100px; margin: 0 auto; padding: 24px; } +.shell.shell--graphs-full .main-pane { + max-width: none; + width: 100%; + padding: 20px 24px 32px; +} +.shell.shell--graphs-full .graph-detail-body { + max-width: none; +} +.shell.shell--graphs-full .graph-detail-table { + max-width: none; +} .nav-pane { width: 56px; background: var(--surface); diff --git a/examples/crash_reporter/backend/scripts/ingest_validation_findings_20260608.php b/examples/crash_reporter/backend/scripts/ingest_validation_findings_20260608.php new file mode 100644 index 0000000..f8e4fe6 --- /dev/null +++ b/examples/crash_reporter/backend/scripts/ingest_validation_findings_20260608.php @@ -0,0 +1,117 @@ +#!/usr/bin/env php + 'ticket', 'label' => 'ticket', 'bg' => '#6366f1'], + ['id' => '20260608-validation', 'label' => '20260608-validation', 'bg' => '#f59e0b'], + ['id' => 'infra', 'label' => 'infra', 'bg' => '#0ea5e9'], + ]; + if ($kind === 'issue') { + $base[] = ['id' => 'issue', 'label' => 'issue', 'bg' => '#94a3b8']; + } + return $base; +} + +$tasks = [ + [ + 'key' => 'SVC-OTA', + 'kind' => 'ticket', + 'text' => 'ISSUE SVC-OTA: OTA channel HTTP 400 on apps.f0xx.org โ€” wire /v0/ota/ on apps vhost or align device ota.base_url. See docs/20260608_BE_SERVICES_and_infra.md', + ], + [ + 'key' => 'SVC-URL', + 'kind' => 'ticket', + 'text' => 'ISSUE SVC-URL: Legacy f0xx.org crash upload URL 404 โ€” production base should be apps.f0xx.org. Update settings.json / dev defaults.', + ], + [ + 'key' => 'SVC-DIAG', + 'kind' => 'issue', + 'text' => 'ISSUE SVC-DIAG: diag.php returns 403 at public edge โ€” acceptable; devices use upload.php + heartbeat.php. Documented in BE services map.', + ], + [ + 'key' => 'SFU-SPEC', + 'kind' => 'issue', + 'text' => 'PLANNING SFU-SPEC: Janus/mediasoup relay post-alpha โ€” branch feature/sfu-relay (hidden). Await owner spec. Gray section in docs/20260608_BE_SERVICES_and_infra.md', + ], + [ + 'key' => 'graphs-5.1', + 'kind' => 'ticket', + 'status' => 'closed', + 'text' => 'CLOSED 5.1: Graph brick drill-down โ€” full overlay, axes, legend, hover implemented in graphs.js (2026-06-08).', + ], + [ + 'key' => 'graphs-5.2', + 'kind' => 'ticket', + 'status' => 'closed', + 'text' => 'CLOSED 5.2: Graph columns 1/2/4, clickable bricks, full-width shell--graphs-full CSS (2026-06-08).', + ], + [ + 'key' => 'browser-js', + 'kind' => 'ticket', + 'status' => 'closed', + 'text' => 'CLOSED: Browser SyntaxError on console JS โ€” deployed assets pass node --check; validate_be_services.sh added.', + ], +]; + +$device = ['manufacturer' => 'validation', 'model' => 'infra', 'sdk_int' => 34, 'release' => '14']; +$app = ['package' => 'com.foxx.androidcast', 'version_name' => 'validation', 'version_code' => 1]; +$now = (int) round(microtime(true) * 1000); + +foreach ($tasks as $task) { + $text = trim($task['text']); + $key = $task['key']; + $status = $task['status'] ?? 'open'; + $tags = val_tags($task['kind']); + if ($status === 'closed') { + $tags[] = ['id' => 'closed', 'label' => 'closed', 'bg' => '#6b7280']; + } else { + $tags[] = ['id' => 'open', 'label' => 'open', 'bg' => '#22c55e']; + } + $payload = [ + 'schema_version' => 1, + 'ingest_kind' => 'ticket', + 'ticket_id' => 'validation-20260608-' . preg_replace('/[^a-z0-9.-]+/i', '-', $key), + 'title' => mb_substr($text, 0, 256), + 'brief' => mb_substr($text, 0, 512), + 'body' => $text, + 'opened_at_epoch_ms' => $now, + 'rating' => $status === 'closed' ? 1 : 3, + 'owner' => 'admin', + 'tags' => $tags, + 'device' => $device, + 'app' => $app, + ]; + if ($dryRun) { + echo "DRY {$key}\n"; + continue; + } + $ch = curl_init($uploadUrl); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => ['Content-Type: application/json'], + CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + CURLOPT_TIMEOUT => 30, + ]); + $resp = curl_exec($ch); + $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($code >= 200 && $code < 300) { + echo "OK {$key} HTTP {$code}\n"; + } else { + echo "FAIL {$key} HTTP {$code} {$resp}\n"; + } +} diff --git a/examples/crash_reporter/backend/scripts/ra_lib.sh b/examples/crash_reporter/backend/scripts/ra_lib.sh index 4d7dafc..648cb16 100755 --- a/examples/crash_reporter/backend/scripts/ra_lib.sh +++ b/examples/crash_reporter/backend/scripts/ra_lib.sh @@ -34,10 +34,16 @@ ra_ra_post() { local device_id="$2" local random="${3:-}" local app_version="${4:-cli-sim}" - local caps='["wireguard","files_app_home"]' + local mode="${RA_TUNNEL_MODE:-wireguard}" + local caps + if [[ "$mode" == "rssh" ]]; then + caps='["rssh","shell"]' + else + caps='["wireguard","files_app_home"]' + fi local body - body=$(printf '{"heartbeat":{"type":"ra","status":"%s","device_id":"%s","random":"%s","app_version":"%s","tunnel_mode":"wireguard","capabilities":%s}}' \ - "$status" "$device_id" "$random" "$app_version" "$caps") + body=$(printf '{"heartbeat":{"type":"ra","status":"%s","device_id":"%s","random":"%s","app_version":"%s","tunnel_mode":"%s","capabilities":%s}}' \ + "$status" "$device_id" "$random" "$app_version" "$mode" "$caps") local url body_tmp code url="$(ra_heartbeat_url)" body_tmp="$(mktemp)" diff --git a/examples/crash_reporter/backend/scripts/test_rssh_api.sh b/examples/crash_reporter/backend/scripts/test_rssh_api.sh new file mode 100755 index 0000000..41c3320 --- /dev/null +++ b/examples/crash_reporter/backend/scripts/test_rssh_api.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# RSSH control-plane smoke: whitelist โ†’ open session โ†’ connect payload with bastion fields. +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +# shellcheck source=ra_lib.sh +source "$ROOT/scripts/ra_lib.sh" + +BASE="$(ra_base)" +DEVICE_ID="${RA_DEVICE_ID:-rssh-smoke-$(date +%s)}" +COOKIE_JAR="$(mktemp)" +trap 'rm -f "$COOKIE_JAR"' EXIT + +ra_admin_login "$COOKIE_JAR" + +body=$(printf '{"heartbeat":{"type":"ra","status":"enable","device_id":"%s","random":"r0","tunnel_mode":"rssh","capabilities":["rssh","shell"]}}' "$DEVICE_ID") +code=$(curl -sS -o /tmp/rssh-hb.json -w '%{http_code}' -X POST -H 'Content-Type: application/json' -d "$body" "$(ra_heartbeat_url)") +[[ "$code" == "200" ]] || { echo "FAIL heartbeat enable HTTP $code"; cat /tmp/rssh-hb.json; exit 1; } +grep -q '"action":"wait"' /tmp/rssh-hb.json && echo OK wait + +ra_admin_post "$COOKIE_JAR" whitelist "$(printf '{"device_id":"%s","whitelisted":true}' "$DEVICE_ID")" >/dev/null +ra_admin_post "$COOKIE_JAR" open_session "$(printf '{"device_id":"%s"}' "$DEVICE_ID")" >/dev/null + +body=$(printf '{"heartbeat":{"type":"ra","status":"enable","device_id":"%s","random":"r1","tunnel_mode":"rssh","capabilities":["rssh","shell"]}}' "$DEVICE_ID") +curl -sf -X POST -H 'Content-Type: application/json' -d "$body" "$(ra_heartbeat_url)" > /tmp/rssh-connect.json +grep -q '"action":"connect"' /tmp/rssh-connect.json && echo OK connect +grep -q 'bastion_host' /tmp/rssh-connect.json && echo OK bastion fields +grep -q 'remote_port' /tmp/rssh-connect.json && echo OK remote_port + +echo "All RSSH API checks passed." diff --git a/examples/crash_reporter/backend/scripts/validate_be_services.sh b/examples/crash_reporter/backend/scripts/validate_be_services.sh new file mode 100755 index 0000000..429ccf3 --- /dev/null +++ b/examples/crash_reporter/backend/scripts/validate_be_services.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +# Reachability smoke for mobile-app + console services (public or CRASHES_BASE). +# Exit 0 when all required checks pass; prints FAIL lines for ticket triage. +set -uo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +PUBLIC="${PUBLIC_BASE:-https://apps.f0xx.org}" +CRASHES="${CRASHES_BASE:-${PUBLIC}/app/androidcast_project/crashes}" +GRAPH="${GRAPH_BASE:-${PUBLIC}/app/androidcast_project/graphs}" +HUB="${HUB_BASE:-${PUBLIC}/app/androidcast_project/}" +BUILD="${BUILD_BASE:-${PUBLIC}/app/androidcast_project/build/}" +OTA="${OTA_CHANNEL:-${PUBLIC}/v0/ota/channel/stable.json}" + +fail=0 +ok() { echo "OK $*"; } +bad() { echo "FAIL $*"; fail=1; } +note() { echo "WARN $*"; } + +http_code() { + curl -sS -o /dev/null -w '%{http_code}' --max-time "${CURL_TIMEOUT:-15}" "$1" 2>/dev/null || echo "000" +} + +js_syntax() { + local url="$1" + local tmp + tmp="$(mktemp --suffix=.js)" + if ! curl -sSLf --max-time "${CURL_TIMEOUT:-15}" "$url" -o "$tmp" 2>/dev/null; then + rm -f "$tmp" + echo "fetch" + return 1 + fi + if node --check "$tmp" 2>/dev/null; then + rm -f "$tmp" + echo "ok" + return 0 + fi + rm -f "$tmp" + echo "syntax" + return 1 +} + +echo "== Android Cast service reachability ==" +echo "PUBLIC=$PUBLIC" +echo + +# Hub +code="$(http_code "$HUB")" +[[ "$code" =~ ^(200|301|302)$ ]] && ok "hub $HUB HTTP $code" || bad "hub $HUB HTTP $code" + +# Crashes console (login redirect OK) +code="$(http_code "$CRASHES/")" +[[ "$code" =~ ^(200|302)$ ]] && ok "crashes $CRASHES/ HTTP $code" || bad "crashes $CRASHES/ HTTP $code" + +# Graphs +code="$(http_code "$GRAPH/")" +[[ "$code" =~ ^(200|302)$ ]] && ok "graphs $GRAPH/ HTTP $code" || bad "graphs $GRAPH/ HTTP $code" + +# Builder +code="$(http_code "$BUILD")" +[[ "$code" =~ ^(200|302)$ ]] && ok "build $BUILD HTTP $code" || bad "build $BUILD HTTP $code" + +# OTA channel (may 404 until wired โ€” warn only) +code="$(http_code "$OTA")" +if [[ "$code" == "200" ]]; then + ok "ota $OTA HTTP $code" +elif [[ "$code" == "404" ]]; then + note "ota $OTA HTTP 404 โ€” not wired on apps vhost yet" +else + bad "ota $OTA HTTP $code" +fi + +# Device APIs (no session) โ€” 403 on public edge is OK if upload/heartbeat work +code="$(http_code "$CRASHES/api/diag.php")" +if [[ "$code" == "200" ]]; then + ok "diag API HTTP $code" +elif [[ "$code" == "403" ]]; then + note "diag API HTTP 403 (edge block; use upload/heartbeat for device path)" +else + bad "diag API HTTP $code" +fi +code="$(http_code "$CRASHES/api/heartbeat.php")" +[[ "$code" =~ ^(200|400|405)$ ]] && ok "heartbeat API reachable HTTP $code" || bad "heartbeat API HTTP $code" + +# JS assets +for pair in \ + "crashes-app:${CRASHES}/assets/js/app.js" \ + "graphs-js:${GRAPH}/assets/js/graphs.js" \ + "tickets-js:${CRASHES}/assets/js/tickets.js" \ + "i18n-js:${CRASHES}/assets/js/i18n.js"; do + name="${pair%%:*}" + url="${pair#*:}" + st="$(js_syntax "$url" || true)" + [[ "$st" == "ok" ]] && ok "js $name syntax" || bad "js $name ($st) $url" +done + +# Authenticated API smoke (optional) +if [[ "${RUN_API_SMOKE:-1}" == "1" ]] && command -v bash >/dev/null 2>&1; then + if CRASHES_BASE="$CRASHES" bash "$ROOT/scripts/test_remote_access_api.sh" >/dev/null 2>&1; then + ok "remote_access API smoke" + else + bad "remote_access API smoke" + fi + if CRASHES_BASE="$CRASHES" bash "$ROOT/scripts/test_rbac_api.sh" >/dev/null 2>&1; then + ok "rbac API smoke" + else + bad "rbac API smoke" + fi +fi + +echo +if [[ "$fail" -eq 0 ]]; then + echo "All required service checks passed." +else + echo "Some checks failed โ€” file tickets via ingest or Issues dashboard." +fi +exit "$fail" diff --git a/examples/crash_reporter/backend/src/AuthEmailSchema.php b/examples/crash_reporter/backend/src/AuthEmailSchema.php index b6e3b1d..cf8bc4e 100644 --- a/examples/crash_reporter/backend/src/AuthEmailSchema.php +++ b/examples/crash_reporter/backend/src/AuthEmailSchema.php @@ -3,20 +3,28 @@ declare(strict_types=1); /** Migration 008 โ€” email registration + 2FA tables (SQLite dev + MariaDB ALTER). */ final class AuthEmailSchema { + private static bool $ensured = false; + private function __construct() { } public static function ensure(PDO $pdo): void { + if (self::$ensured) { + return; + } if (!Database::tableExists($pdo, 'users')) { + self::$ensured = true; return; } self::ensureUserColumns($pdo); self::ensureAuthTokens($pdo); self::ensureAuthFactors($pdo); self::ensureAuthAttempts($pdo); + self::$ensured = true; } private static function ensureUserColumns(PDO $pdo): void { + $existing = Database::columnNames($pdo, 'users'); $cols = [ 'email_normalized' => Database::isMysql() ? 'VARCHAR(254) NULL' : 'TEXT NULL', 'email_verified_at' => Database::isMysql() ? 'TIMESTAMP NULL' : 'TEXT NULL', @@ -26,14 +34,11 @@ final class AuthEmailSchema { 'recovery_email_normalized' => Database::isMysql() ? 'VARCHAR(254) NULL' : 'TEXT NULL', ]; foreach ($cols as $name => $ddl) { - try { - $pdo->exec('ALTER TABLE users ADD COLUMN ' . $name . ' ' . $ddl); - } catch (PDOException $e) { - $msg = strtolower($e->getMessage()); - if (!str_contains($msg, 'duplicate') && !str_contains($msg, 'already exists')) { - throw $e; - } + if (in_array($name, $existing, true)) { + continue; } + $pdo->exec('ALTER TABLE users ADD COLUMN ' . $name . ' ' . $ddl); + $existing[] = $name; } } diff --git a/examples/crash_reporter/backend/views/layout.php b/examples/crash_reporter/backend/views/layout.php index 3d55de8..23ef01b 100644 --- a/examples/crash_reporter/backend/views/layout.php +++ b/examples/crash_reporter/backend/views/layout.php @@ -51,7 +51,7 @@ > -
+