Expand OpenWiki SSH and platform UI guides
This commit is contained in:
1 parent
66876eaab0
commit
4cb105931f
27 files changed
+2487
-52
No files matched your search
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:d3b79d8cc51a720b38f06a1c8dc127782900a85f704bee57b59abaf8bf3f8d30",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_5a53c5a47b7445f7a7b6f8865297a805",
|
||||
"statement": "TFM shares AppModel across main windows but creates per-window WindowModel state; RootView supplies that model through the environment and focused scene values, while external authentication uses a separate scene removed from ordinary scene-opening commands.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/App/RootView.swift#L189-L212",
|
||||
"version": "repo-lines-v1:sha256:d71f166db375946ef90321a74b2b3943f9137b43d68003f6991b1c9c56dbc5e9:eyJzZWxlY3RlZExpbmVDb3VudCI6MjQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjBmNTg3OGE2YmZmYTQ4OTg5M2U1ZDljYjAzNjU1Y2QyMzBkNTNjODI1MzNlNmM1MzllNjcyMzVjN2ZhOTQ3NDAiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImM3NzRiNTdmMDI4YzVkNTlhYTZiNWJjMzJhN2Y3ODhiY2NlZTk3Y2QzYzRmNGJmZjJlNjRmNjI0MjVlMGYwYWYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImQwODBmODZmZDI2OGM5MDgyMDQzM2EwYTU1Zjk5MWFhM2M3NWMyZmRmNjc0NTRkYzA0MDgwNzUwNjk0ZjM2MzkiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjVmZjY1OGMwNzA0YjlkODZkZWVjOTc1M2EyODI3YWM3YzJlYTE5ZmRjMGQwYWU5ZDBiM2YyMzdmMzZhN2M5ZWIifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/App/TermindApp.swift#L150-L194",
|
||||
"version": "repo-lines-v1:sha256:00c8269a3e30e0a6c21609b9611182d7db6ea597b5034e06084b9777a951d26b:eyJzZWxlY3RlZExpbmVDb3VudCI6NDUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjU1MjJjNDJjZDE5YzZkMDNkODA4YzQ1MjcyMDU1MjgyNWI3ZWExYzViNDkxYjIxODUxMWNhYzc0MTVjZjlkOWIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjcwMWZjNjEwMWEwZjJiMGNiNmFkNTEyYzg2MzExYzEyNzllM2VlZjMwNWExMDQwMTc5MzUzMTQ4N2MxYTllNDMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImY2YzczNjhlYWI2MWJhOGIxYWJlYTEwZmIxMTE3OTIzZjk5ODA2NjU4ZDFiNjcyODkyMjU5ODAxOTIxYWI0N2YiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImIwZTJhYTI2ZTg3N2YxZWE5MzA4NjE5NmU0Nzg2N2U5MGYzNTk4ODI2MDA0MmY2YTM1YzEzZTlkNDRlOTVhM2MifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_a3a9d8910c524019afd270300d91ffd1",
|
||||
"statement": "RootView owns one NavigationSplitView and window toolbar, overlays status on the active workspace without docking it, and places Vault, Assistant, Metrics and Settings in front of a persistent workspace deck.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/App/RootView.swift#L33-L113",
|
||||
"version": "repo-lines-v1:sha256:8913b022efb5a07ab706ebe6a1a7b1525c4450e3b9d74bd547e9963252c1afb9:eyJzZWxlY3RlZExpbmVDb3VudCI6ODEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjFmMDhhOGI4NmMyMTkzOTMzMWNlMmRlNzQ4Y2MwMjQyODI5NmExNWUyOWUwMTJmOWI1YjI5YmE3NTQ5MDViOGUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk1YjBiYjljODYyYTczYjRiNDU5MzM0ZDE4Y2UxZjFjNzk0YTQ1ZmZiMTY1YzY2MGEwOWQ1NDgwZjg1OWJiZDYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjU5OGYxYTA0YmVlNzFjM2NmYzJiNDcxOWU2ZmQ5MGM5NmY0N2E5MWU0ZDJmZGU3ODgzNTNjMDM3MDQ2NmY5ZGEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjRmZGVlN2NkMWQ1ZDFjYzE2Njc3Njg5ZTc2MzcwODEyYjUxMzEyZThhMTc0YWQ0YTE1OTM0NzRjODk1ZWFmNTgifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/App/RootView.swift#L338-L386",
|
||||
"version": "repo-lines-v1:sha256:f0b2ae44180a4334c03b0e087292f318df3a66f475b3fbbdfc60784351930cb0:eyJzZWxlY3RlZExpbmVDb3VudCI6NDksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImYwMjA0MzJkYzQ3NGFmN2VmY2NlYmMwZTQ1ZDAzYzIxYmM3OTY0ZWMzZWY5NDE2Zjg5NmRlMDVlNmM0ODAzMzQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjExZGM3ZDc4ZWRlZDE0NzliZDk3YTZjN2UzYWQ0OGQxNzFhNjRhZTNlMTQ1MGNhNjBlZGRlYzY0YTViOTFlZTAiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjY2MTcxMDUwNWVkNzc3MzZhNzZlZmNmOGM1YWMxNzUxNzczYjg1Mzc0NzhjN2U2YmJlM2Y4YTNiNDA4ZmNjMjkifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_0acb6b4def5948e6a4460d6fa6b7e9fa",
|
||||
"statement": "WindowModel separates destination, sidebar mode, page selections/searches, presentation routes and focused workspace state; user sidebar activation can restore Assistant's prior destination, while History is disallowed for focused Telnet/serial sessions.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/Features/Sidebar/WindowSidebarView.swift#L10-L134",
|
||||
"version": "repo-lines-v1:sha256:22601aaff9d328068b1fdf3e19c6d087be1345821e56a2dcfd89439f6a14e53b:eyJzZWxlY3RlZExpbmVDb3VudCI6MTI1LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJkNjU2ODhjMWU1N2RkOGFlY2U1MDk2ZWUzNGVjNTQ1YTc2MTFkYjFkYmNmYWVmMDAwNzI2ZGFjOWU1M2YwNjdiIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiIwMWJhNDcxOWM4MGI2ZmU5MTFiMDkxYTdjMDUxMjRiNjRlZWVjZTk2NGUwOWMwNThlZjhmOTgwNWRhY2E1NDZiIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJjZGEzMTJmZTE1NTcwNDM5MzM0YmM5MDBkYjQ0Mjk1MzYyZjM4OWY1YzZlZDhlNDE1YjgyMmMwZjdmMDQyYzQ4IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIyNzY2YWJkZGRkYWYzY2JmODc1MTU4MGY1Mjk2NDNhNDE3M2M5YWE0NzQ2MDYyNjhkOThjZDNhYWQ1YjQ2Zjc1In0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Workspaces/WindowModel.swift#L15-L112",
|
||||
"version": "repo-lines-v1:sha256:5f84807a4eb3379b2ae4b1841e09ecb705650709c818098c52f8d4ee3e1a622e:eyJzZWxlY3RlZExpbmVDb3VudCI6OTgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjgwOTJkZGExNzNhMjQyOTg1N2E4ZTE0NjQzODVlOTU3MDFjZTM5MDU5ZDFhYzhjNGIwYjMzY2RhMmE1ZWEyMDQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjE2ODZlODYxYmYwOTRlZTkxYTNlOGZjMTUxZWQ2YjUwNzc4MjRhM2FiMzg0NGVlNDk5NjI2ZWVhNmRlYWYzOGMifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Workspaces/WindowModel.swift#L191-L268",
|
||||
"version": "repo-lines-v1:sha256:f5718d1b71ad7c7def6b624cde665c906c9802551770e7f53d160988ddcb29cf:eyJzZWxlY3RlZExpbmVDb3VudCI6NzgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4ZjlmNWVkNjdiMGJlMDE1ZjczN2JmOTQ3NmFhMzMwOTJiM2I1NmM4NDRiMWUyMDYxZWY1ODY1NTNmMDk3ZmYiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU2YjA0NDkxNDY5NzIyZTgzNjNhOTRlNDA0NDUzOGUwMTNhMmEyMTdlMzZiMWU1NjhiYTYwYWNiN2I0YzhmMmUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjVmNDY1NmRkY2JkMzQ5ZjUxNWNlMGVhMTk3ZmI3YmRmYjUxYzNiOGM4OTk1MmUyZTQzZWRjNTA0ZThlMjU0NWEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjY4OWI1ODU5NmY1OWExZjU2ZDIyOGEyMzlhZTI2MzMyMDU3MDg3YTc3MjFiMmZlYWRjYTMxYzI5MWViMWRjZjQifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_06d39725ef0143c0a6dce17ce0125e86",
|
||||
"statement": "The persistent workspace deck retains all open workspace views, gates hidden interaction/accessibility, parks hidden layouts at identity-keyed cached usable sizes, and prunes closed IDs rather than relaying every container resize to hidden split trees.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/App/RootView.swift#L338-L356",
|
||||
"version": "repo-lines-v1:sha256:b633b5e83bd4ab48cc86823138859bc2895d3eab20f6d75a4a3812c3a5c2333f:eyJzZWxlY3RlZExpbmVDb3VudCI6MTksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImYwMjA0MzJkYzQ3NGFmN2VmY2NlYmMwZTQ1ZDAzYzIxYmM3OTY0ZWMzZWY5NDE2Zjg5NmRlMDVlNmM0ODAzMzQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjM1Y2E5MDNhMWE1YmZlMTQ0OTM3NWE4OWFmMWZlZTZkODgyN2JjMDRmYWVkYjczMWNlYmUyMzA0MmU5NWJhMGYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjExZGM3ZDc4ZWRlZDE0NzliZDk3YTZjN2UzYWQ0OGQxNzFhNjRhZTNlMTQ1MGNhNjBlZGRlYzY0YTViOTFlZTAiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6Ijk3YjZlZTM3OGExYTEyM2Q2ZGEzMDJkYTM5MTk5MjEwYmE0MWMyNmJlZjNmYWFiOGRlZjY2YWVmM2I2MzVkOTgifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Workspaces/PersistentWorkspaceDeckLayout.swift#L20-L108",
|
||||
"version": "repo-lines-v1:sha256:36c22131a55ec5b65823348af839c0293b5a92ddefbe81767e35d7639cd91675:eyJzZWxlY3RlZExpbmVDb3VudCI6ODksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImUwYTE2OTVjOWVlODY1YjZlODA3Nzc2NWVmZDRhYjFkOGZmN2YzM2ZmY2EzNDExNGIxYTg5Zjk2ZTczOGFkYjEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/PersistentWorkspaceDeckLayoutTests.swift#L74-L134",
|
||||
"version": "repo-lines-v1:sha256:9d7c190805419307ba5211d61e72ec659015727987fd841592067a8d6eb192e6:eyJzZWxlY3RlZExpbmVDb3VudCI6NjEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjAzYWE5YjQ2YTMyZGVmZTczNGM5YzZlY2Q3Mjg0ZjM0NzJkZTM3MmY3MTgzYjVmODI2YjQxMTVjNzhiOWQyZjkiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjoxLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_b365ec9386aa45e4bce94b9bf4c68e9a",
|
||||
"statement": "WorkspaceContentView renders stable-ID split leaves and fraction-based branches, previews divider movement locally, keeps a dragged source mounted while omitting it from preview geometry, and disables hidden-workspace shortcut owners.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/Features/Workspaces/WorkspaceContentView.swift#L176-L285",
|
||||
"version": "repo-lines-v1:sha256:5134b0bd318bd899fa1579a853f15b51469662b047f32ff3a55dbccd6ff29e7c:eyJzZWxlY3RlZExpbmVDb3VudCI6MTEwLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJhYTJkODRhMzFkYTc0M2EzMzg3ZTNiNmJkYTE5OTc1Njg1ZWVkN2U0YzQ1MGM0MWJiOWMyYThkYzIwOGQ5NzU3IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiJlNmIwNDQ5MTQ2OTcyMmU4MzYzYTk0ZTQwNDQ1MzhlMDEzYTJhMjE3ZTM2YjFlNTY4YmE2MGFjYjdiNGM4ZjJlIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJkMDg3ODhjMDM5NzhjMGMzY2I1Nzc5ZWI1ZTZlYjE3ZGU3OTE3OWYyOTYxZmY0ZTFhNWYyYzk1OThmZDkwNTRkIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI1ZGEyNzI3NjZmMDhhODkwYjdlM2Y3NTk3OWFiOGIyNjNiNDNmYWUxN2VkZTcwMTcwNGVlYjAxYjhiMGQ0ODAwIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Workspaces/WorkspaceContentView.swift#L48-L112",
|
||||
"version": "repo-lines-v1:sha256:de3f598a948f020128b7e0148afc9a3163fc403e3912d2c1f9da49b9e8adebf2:eyJzZWxlY3RlZExpbmVDb3VudCI6NjUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImY0NDkzM2JlYmY3OGIxOGFkNjc4Mjk0MzM1NjdjYzk4MWNlYjdiM2FlOGIyZTRlNjA5NjRlOWYwNDQ4MjJmNTUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjMxZjM2M2EwMzVkZGQ0Yjc3NDMwODE4YzExOGI3ZWUxMTJmYjk2MDQ5YWRmNThkOTIxMDgzMWM1YWNlZGY5NGEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImI2Y2E1NzUwYmI4OWNmMDJkYjkzZGFmNjY1NDk4MDI0M2NmY2U1Y2EzNDY5Nzk5ZmE0YTk0ZmE1NmQ5NWQ0MTEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImMwMTM0MTQ3MjQ1YTAyNDFkZGVmNjlhNTFiZmIwNzYzMDI4MzNkZWZiZTcxNWI0ZDNjMmRjM2E3ZGQ2NzBkOTEifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_64dc4408c2b440c6af34f6b948dac351",
|
||||
"statement": "Vault list/editor children retain identity across the split breakpoint; a covered list keeps its cached size and editor transitions animate position and reserved space rather than resizing the form.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/Features/Vault/VaultWorkspaceView.swift#L15-L99",
|
||||
"version": "repo-lines-v1:sha256:e7b1d3162b4921f3534c97d5e853e4156f5572dca3293ade07c64f0c79e23dac:eyJzZWxlY3RlZExpbmVDb3VudCI6ODUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjNiYTQxMjgyYjkyN2Y1MzU3ODhjMzBmOWVhNzYyYWNkZjQ0YzQwYmY5OGM5YzU5OWViOWI2NzJmODgzNjY1MWEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjZjZTQ1ODEzN2ZkNzk3MGI1MzZkYmI3NDc1MDY3NjUyNTc3ODA3ZmFhNzIwMjY3NDU2N2M3NWU5ZWY5M2IyN2YiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_cc630e7ab5c3431095f27b3a7bf6e683",
|
||||
"statement": "ManagedCardPage supplies typed sections, stable item IDs, externally owned selection, capabilities and business views to a reusable renderer; drop geometry yields stable-ID mutation intent while resource-specific actions and presentation remain with the page.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/UI/Managed/ManagedCardPage.swift#L166-L270",
|
||||
"version": "repo-lines-v1:sha256:163099e2bf8642a65bf5f109ed97a94391eccff6d279c4a2878cf40e88d94917:eyJzZWxlY3RlZExpbmVDb3VudCI6MTA1LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIwMWJhNDcxOWM4MGI2ZmU5MTFiMDkxYTdjMDUxMjRiNjRlZWVjZTk2NGUwOWMwNThlZjhmOTgwNWRhY2E1NDZiIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiJiMjA4N2Y3ODgwZGRiMjI0NzdkZWIyNTA3NjgyNTUyMDgyNWU3ZmZkZWQyZmY4MGYxNWYwNjU3Y2VmZWE4OWZjIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI2NWE2ZjEwNTViZWI5YmVkMDAwZjFiYzc3N2ZhOWYzOGEwNTZlNmQxYjFkZTg5YWFlYTdjOTgxZDUyZWRkZjdhIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiJkYTQ5YmM5ZDM0MDM0M2IxNTBhNGVjZmEwZTEyYjg0NDE1ODZkMjhiMmQ1OTczZDRhNmU5OTdmZTg1ZDI5YTZmIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/UI/Managed/ManagedCardPage.swift#L6-L163",
|
||||
"version": "repo-lines-v1:sha256:d1192ab4a16076d4b949c9aaa5fe7803f9f1f59f5ecc227acc66788726330b69:eyJzZWxlY3RlZExpbmVDb3VudCI6MTU4LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI2M2Q5YjEwYjUzMDUwMjgxM2M1MGRhMmUwMDNjNWFjM2FmMjdkZjk0MDRkZmE0N2ZlOGM1MDFlMzJjYjRhMmUxIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiIxOTUwMmY5ZWEzMWZhNmI4OGNlZTI3OWJkNmVhMDc5YWNhOWZiMzZkYWViZGY2ZmI5NTUxYTdjYzdjNTNiNDZiIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI0ODgxZmMxMzdiMjIxOWE3Yjc2ZTc3YmNlODRjMzYyMzAwNDkzY2IzOTIwZmZmMzFjYzBjY2Q0NDQ2NjI2ZTFjIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIxOWU3NjM1NWNmMTE5OTQ4MGMzZjk5ODM2YjE0ODZjODQxZDg5MWZhYWQ5MDRjNjA4ZTA5MzAyMmQzNzU3YWVlIn0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_1361b995f8e646c6a534186edcd83dc7",
|
||||
"statement": "The workspace compact Assistant has routing separate from the full Assistant destination and composes transcript/interaction regions with explicit terminal context; Escape cannot fall through from a blocking interaction into closing the conversation.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/Features/Assistant/AssistantView.swift#L7-L14",
|
||||
"version": "repo-lines-v1:sha256:a3755412e818d877b2c9c59bc75105e21157bb4519e47f13f4ee6fd2764de97b:eyJzZWxlY3RlZExpbmVDb3VudCI6OCwiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiZmFlZDhjNWNjMzg0MGRjMjMwYTRiNGY3MTExN2UxZGE4MjRmZmJmYjA5ZTZjMWVmYWY4M2U1Mzc5MTNkNjkzZCIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiNDEyY2EzNDVjY2Y3NWJmOWMwODA2YmNlNjk1YmU4ZGU4MDhiNzk5ODQyNTFhN2E1NGQyMDJjZjYxMDFkZDQ1MSIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiNTcxZGE3NDM0NTdjMDNhMjQwNDRhMTk3NTQ2MGE2YzQ4OTllODBiNzUyOGUzMDRkMzE0ZDY3ZmU1NWE0MTYwNiIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiMWMwMDRmMzdkODZkOTFjYzUyZGY1ZDhiYjAyYjU0YmI1ODk5YjA1MWYzY2M0YTU5ODk2ZDFiNTZjYjQ1NGNiMiJ9"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Assistant/AssistantView.swift#L89-L225",
|
||||
"version": "repo-lines-v1:sha256:a235a02d0e28feb4b79c8d8a6f5e3844a9598fd35568c864ee8ed9cabfbc4c8d:eyJzZWxlY3RlZExpbmVDb3VudCI6MTM3LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI5MTFlOGI2MmUzM2JjNDg0MWM4NmE1MmJiZmQ0MjRhZTQxZTBiYmVhODI0MjJkMTBlMGQyMGI5ZjMwNWZiNDBjIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI1NTAzMmU5NjRkMDkzMjM1MWU1ZDE4NTI2OTI4MWIxNzFhM2EwOWIwOGIyODZlNjYxZWE0NzAzMjNjODJlYjRkIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiIyYTFiOTczN2RlNTU1MTEwZjU1YmYyZmI2N2UxNzk1ZTU1ODA4NDdjYTQzOWI0YjBkZmJjN2U1YmZjNGU1YjcxIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI5OTliZGVmZWVhY2E2MzQwZTAyOTBkYzg2ZTg4OWM4OWQ1ZTE4OWFhNWJhNDRiNTg1YjNiNzA3MzRmNGE2MmQ4In0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_0d6597fc4a834df3a50ee13a514a20e4",
|
||||
"statement": "TFM transcript owners are cached per window by conversation and surface, preserving native list and presentation state across mounts; the default eight-owner LRU trims unmounted candidates without forcibly evicting mounted surfaces.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/Features/AI/TranscriptListView.swift#L113-L155",
|
||||
"version": "repo-lines-v1:sha256:b0a2bbea3a31751d53d263fce80b4747b349be8806a0ef7029d69b94ef991c5b:eyJzZWxlY3RlZExpbmVDb3VudCI6NDMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjUyOTIzMzk5NzVlNWVkZTE3NjkzMjlmOGFhY2I0YTJkODRjOWQzODkzNzFiYzljM2U4OTE5NTQ3NGJmODE0Y2UiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImIwOGY1NDk4YTdjNzIyZmEzNzgxMmIyNGU3ODNiNTQ2MzlhYjIwYzcyZGU3MzliM2U3N2VmMmI0N2JjOTI4NGYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjU4MzUxNzM0YWU0ZjMxODBiNGM5ZTNmOWYxZjJhYWUyNmRlMDZlZDBmZGMxOWU2ZDhiMDNlYTkwNjJkYWViZWMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjUzNjM2YTE3MTJlNGZmZjcxMjVhZTBmMmQ2YTRjNDI4ZDRmNTlkMjNmMjFkNzk4MWJjNWVlNzY4N2U3ZDFiZWQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/AI/TranscriptListView.swift#L229-L316",
|
||||
"version": "repo-lines-v1:sha256:6ef569238eb6062020862d6ffa07f08588826db3232bdeaeb678f9a62f913a43:eyJzZWxlY3RlZExpbmVDb3VudCI6ODgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjJkMzQ4OThiZDNmY2JmNTVlNDViMGYzNjQ0NmZkZmJkY2UzZmY1YzM5YzBiYjBhZTY5OGUzMWY4OThmODA4YWYiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjlkZDBiMmU3NDkyMmQ3NGY1MWRhMDlmMWRhMjU4NmNlOWM2NmE1NjVjNDczZDk3ZTA0Nzc1ZmQ2MDU0ODNmNjMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImRhMTc1YTAxMTVjOTI2MzIwOTlmZDNhZTYwNWUwYTdkZDlkOWI5MWI1ZWJmOTY2OWFhOTg4Y2JiNGZkZmY4M2UiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjkyOThmZDE1YmNiNzRjOTY4MWIzYjhmMTFmMmViODk3MzdiNDEyYWM1NDFjY2IwZjYyMzkzZWU3MDM2NmNiNWQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Workspaces/WindowModel.swift#L79-L85",
|
||||
"version": "repo-lines-v1:sha256:b69a1a372b311f2063b3336a7711b85a4fe987e441fed3547c6eee91b09aca0a:eyJzZWxlY3RlZExpbmVDb3VudCI6NywiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiMzVlYmVlMmE0NGY1NjRhNDMwNDQwMjM1ZGYzMTY5Y2Y3MDZjNmI4ZmFmZDJhY2ZlYTNkNzNhZWI4YzRiYWRmMyIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiYTZmYTQwYzVjYjhhOTFjNWU0YThmYjg1NGNlZTAxMzE5YzJiN2E0ZTliM2U0ZGJjZDg0MWQzODdlZTk0MDMwMCIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiMjQyODk0NTYwODIzMzA5MTM4MzBhYTg2Nzg0ZjcyYmMwYjcxZTU3YWFmM2ViNmMwNzM3ODFhMDY2MTg5ZjhkMyIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiODJlYjAyNzczNGZjNjk5NDAyZjQ1YmI0NjMxNjRlM2FhODI4NmVkMDBjZWJjMjk2ZjAxOWFjYjUxNDMxZDUyNyJ9"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_7a2deac25d6743f7a2d4968eb179b904",
|
||||
"statement": "ResponsivePageLayoutTests includes visible-window-gated narrow editor cases in English and both Chinese variants, while its offscreen Metrics case verifies native table identity, sorting and scroll retention across width changes.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFMTests/ResponsivePageLayoutTests.swift#L11-L145",
|
||||
"version": "repo-lines-v1:sha256:5b068452fbef1aa51055084952ffe5a65659654f7005cb478088ce4aec0273cb:eyJzZWxlY3RlZExpbmVDb3VudCI6MTM1LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIwNTliNmRmNjgzMTA0ODE5MDZmMjgxZDIyMWIyMGQ3MDNmYjRkMWM2YzIwZjU0YjI4ODI4N2FhZWJhYWU5YzQ2IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI2NmI1ZjE4ODA5MTA2ZDU5MmUxMDc5OTcxODA5ZGZlMWFjMjQ5OGNhYzcwZjBiOWQ5ZTllZDUzOTQ0ZjQ3YzAzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJmNWJlYWMxN2RmMTlmMTQzYmQ5MzE5MWU0MWRiZmNhZjgzY2Q3ZmUyMjQ4YWIwMTQ0ZDg2MmRlMDkxNmRlMjBlIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiJjNTAwNGFkN2FkNDNkZjUwNTZkNzI5ZTVlYTQyMzVmMmUyMTk1MjA5ZjM2OTQzZWY1YWMxMmIxNzE2NTI1OWMxIn0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T02:51:54.212Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:a662291087c13d029a1df20ca0146d683e78704cee78016e30152e3701dcfe4c",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_fbb919f62a2d4ab88aafcc4c1186731b",
|
||||
"statement": "TFI registers Vault, Metrics, Workspaces, Assistant and Settings once through MobileFeatureRegistry, rejects duplicate IDs, and renders one NavigationStack per registration inside a sidebar-adaptable TabView.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileFeatureRegistry.swift#L33-L117",
|
||||
"version": "repo-lines-v1:sha256:d364588db1f38ceccea3efc2c9e341dc2217c7aa5a52f4271de1af1e566e39d0:eyJzZWxlY3RlZExpbmVDb3VudCI6ODUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjcyYzBhYjFhNzUwMDZhMDA3NTE5YjhmZTgyNGQzOTVlNGVjM2JkNWJhMjY1MDNjZjA5ZTJkZGY5ZWMxYTI0MTQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjhiZTBhODk2YTNjYjAzNmM0NDZiNDgyMTA3MDA4ZDZkOTZmNTdkNzA2MGRiNDk4ZjQ5YTVhNjhkNDI1ZWI4NGIiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjoyLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjM3OTRkMDJhODEyMTk0NGQxNzZkMjY1ZTliYjljYzU5ZjZhYjg5MGJjYWRmOGFlZmRlYmRiYmI0ZjJlYTg0NDQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileRootView.swift#L6-L45",
|
||||
"version": "repo-lines-v1:sha256:b834a79fc6ea73d5f538e434a971465a547981778a11473875c7fc2dea3a98e0:eyJzZWxlY3RlZExpbmVDb3VudCI6NDAsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImZlMzA0ODhhNDJjZmI4Y2M1YTgzMjM2YjRjNmM0YmE4NTg3YTY1ZDlmNWZhNDUyZGE4ZjY2MzhkMjhjNDZlYmQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjRiNTgwYjRjZTYxYzIyNTk3MGFmOGYxOGIzZTJmMmNjNmQ2NjRhMzIwOTY4MTI4ZmVhMWU2NjhkOGQwNGExZjEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjkxMzlmYjYwZDNhYzI2ODlkY2VkNjQ1NTJiNDJlOTZmNjZjMjE5YmYxYTA1YmY1YjhiN2I2MGEzNTgyY2Q5NDciLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjM2MTlhZGM1NjcxMTNjZmI2YWE4YTM2ZmI4N2U5ZWI3N2FhZGFlNjU4MDc3ZDRlODQ0NGNkNGM0NWM1YTFiNWUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_1d7bbd68fa0c4fc59513ce9d4306d506",
|
||||
"statement": "MobileSceneModel owns scene-local routes, workspace selection and an Assistant library over shared application services; host activation reuses the scene's recent matching terminal workspace while explicit connection actions can create independent workspaces.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileSceneModel.swift#L83-L128",
|
||||
"version": "repo-lines-v1:sha256:ab6c66761d5743f76343b319a30dbdb113dffcf9b01a21a180e87ef109d63c60:eyJzZWxlY3RlZExpbmVDb3VudCI6NDYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjEwOTA1MzRlNGFlMDdmZThiMGM5MTk4MWE3MGY1ZDFjMmM4ZWE1YzMzZmY5OWEzZGQ2YTBjMWQwNWM3NzBmNjAiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjI0OTBmZjExZjVjZTJiYzA2ZTFkODlhZTNjZmEyN2Y4NzhiMzZhNzE4Yjg0NjU4ZDFlNjI3OGExNjdmNjFiMmUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjhjYzk0ZjdiZjEyMjBmOTFjNDQxODMzYjYxMGRjZGQ1MGM1N2ViNjc1YzNiYzY0YmY3Y2EyZThlYzkxNzBhYmEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjNmMDZjZDBkMzM2MDE5NDAwZDMzYmMwYTA3ZDBhMTE5ZTViZTAxZTFlYjhiY2M1MWM1Nzg4NTM1ZTQ5NjJmNjEifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileSceneModel.swift#L9-L42",
|
||||
"version": "repo-lines-v1:sha256:e5998ce27bda04ed0b490b5d1148e9b4b664b062f03fb15af16bde8edc4e8dea:eyJzZWxlY3RlZExpbmVDb3VudCI6MzQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjdlMzBiMWNmYzNlMDdhNWQzNDFjZTY5NjdjZDYzMTI4MWQzYzQwYmYzMWQzNTI1MTM2M2MyNzYxN2NiZmIwMzYiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImY0Zjc3ZWUyMTVmMDIxOWU5NjFjNzM3NGFhNTQ2MzA4ZjNjMGVlZDI3MzQzZmEyYjY0Y2EwYjZhZmVkMmQwYzYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImNkYTMxMmZlMTU1NzA0MzkzMzRiYzkwMGRiNDQyOTUzNjJmMzg5ZjVjNmVkOGU0MTViODIyYzBmN2YwNDJjNDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImQwMmY3OGRkOTFmY2NiMDNkNTg4MDU0YTRkNjhkMmRlYTU2NTgzODI3ODU5ODNlMTEwOGZiN2IzOTY5MTdkMWUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Application/Agent/MobileAssistantModel.swift#L243-L306",
|
||||
"version": "repo-lines-v1:sha256:49f1bce4a65005b1a5ad1f81083f3d10026f66f89e587a688a8625139aadec14:eyJzZWxlY3RlZExpbmVDb3VudCI6NjQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjgxMzhmZDI5OTQ0ZGQyMDFhMDBlYWM2MjRhZGRiMzM1Yjg0ZTcwOWQ3YmViZmUyMTZjNTE2MTE2ZGQ3NmJiMmEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_0dea8b77853f44fa8371c862252d7682",
|
||||
"statement": "Cross-tab workspace selection stores a pending workspace ID and switches to Workspaces before the destination task yields and activates the push; replacing pushed details uses workspace identity, and restored workspaces are published before connecting.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileAppModel.swift#L584-L600",
|
||||
"version": "repo-lines-v1:sha256:4695fd57bfd1677ccfbaa7ef3e23c87ff6c636ab1d93fe889299f5b87723ace0:eyJzZWxlY3RlZExpbmVDb3VudCI6MTcsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjA4YjM0MjE2MjYzZjM3NTkzNDUyZGMyNDNlYTQyNTQ3MDJkZTEzYjI0OTliYTQ4ODYxODk2NTI4NGNmNDQzNmUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImQ1NWE2YmQ5MDhjMTBjOGM0MzYyZDBkNDAyZDI0Y2JkMDY2MDgyYjNjMjQ0N2YwZTA0MjZhYjEzY2M4NDc2M2MiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImY4ZDgxNTIzY2NhNWZlYmRiNWVhZDU5MDU2NmU5NjhlMTVkOTViZjRlODNlZjNkYjExNmJhOGM1NThhNDY0ZDQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileSceneModel.swift#L142-L178",
|
||||
"version": "repo-lines-v1:sha256:4124b1e32581d0253871aa6cb5e808434339a36b8b5d5d26641924d744c374a4:eyJzZWxlY3RlZExpbmVDb3VudCI6MzcsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk2MzdmYjc1Yjc0N2Q4NDhkYmI3NjVlNGQwYTdmZTg1NmI4NDNhZTA4ZWE4MDU5N2I3NDY1NWUyMWFiZjIyYzkiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjU4NmIyYjk3ZWIxODI1ZmE4YWE5ZmEyYzlkMzBkNWMzNzEzYzQ2NTgyOWQ2MDA0YTNmNmMxYzgyZDY3NWY2NWYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImVhOGQ3MWI2M2IzZWRjOTkwNGU2YTUyMzcwN2QwMDhhNzU5ZmZiMTg2NmE3NmQ3OGM1ZWU1M2Y4NTc5NTdlYjkifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Features/Workspaces/MobileWorkspaceListView.swift#L97-L134",
|
||||
"version": "repo-lines-v1:sha256:8ed777a702c5cf095c6e8561b8a55394782bc121e7c768eb32cd6fb2ebda7900:eyJzZWxlY3RlZExpbmVDb3VudCI6MzgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImExMTcwZDgwNGM3OGE1OWFlZGM1NDE3Njk4MmYyMGQ0NjI3NDAwNDVkMjQ1MDBhMzAzMDNmZmUwZTFkZGZlMjAiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjIwMTk0OGE1ODI0YmJmZmFkZTU5ZTM4ZjQzNTA4MTFjYzI1ZDdkMTdlMmY0MzQ2NjZkOTgzMGYzMTUxNTdlYzYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjVhYTlhY2ZlMTgzNjhiYzc0YWRkODViZDRhYTJkMTMyYjdhNDBhYWQxNjY0ZDAyNDJkYTgwZDY0OGQ3Y2U5ZjcifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_f7833291ad804b5e8df8ad299da5103b",
|
||||
"statement": "MobileContentRegions computes a largest continuous obstacle-free rectangle and an optional usable pair around an active division, retaining overlapping candidates; occlusions alone do not create a split.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/DesignSystem/MobileContentRegions.swift#L3-L105",
|
||||
"version": "repo-lines-v1:sha256:71b6f3d89fbf3450b46fcb1debc5f82841ec9fa75cab124145eea8367ee3f950:eyJzZWxlY3RlZExpbmVDb3VudCI6MTAzLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJhZWJmMTg3MGFiMmNhZWI2MjVlYTc4Yzc2MjMxMWEwNjMyYmZkYjMzZmQwZTcyMzljMWE0ZTA3MDMzNTQ1MjYwIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MiwicHJlY2VkaW5nQ29udGV4dEhhc2giOiIzNTk2NWZlOGY4OWQ1NDllNmE5MWNmOWIyMTBkYzU3MDhhMGQ4NTkxOTFiOTk0MjZmOWEwYzMwZGM1ZDZlOWZjIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiJmMjI1MmVlMTBjYjkyOTZmMzZkOWFiZGQ4NGMwYzRjNmU0OWUxNTczNzMzNTdhMWEwNWE2ZmJkNGNjMzZlMWMxIn0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_3756aa96e03d48109d75e3ee48be75d8",
|
||||
"statement": "Reserved-region and vertical-toolbar system queries are gated by both TERMIND_HAS_IOS_27_1_SDK and iOS runtime availability, with injectable test regions and fallback behavior; compact/regular layout is only a separate size-class hint.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/DesignSystem/MobileContentRegions.swift#L107-L137",
|
||||
"version": "repo-lines-v1:sha256:7a691c61df5fdcd3624bd197ed8e56c0d9cd1f8632794c4a9d2a2637306605d3:eyJzZWxlY3RlZExpbmVDb3VudCI6MzEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjQxZDljYWJlZDk0OGRkZWZhMjk4MmY3ZTY0MDE0YmIwMTUxMWYxMzgyY2ZkYTg0OTU5MzgzYWU1NWQzMzJiODEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImJiNTM1Y2UyOTdjYTM5YzdmZmVmNDQxZjhjZmE4ZWQ0NWRmMGRlMzg3Yzg2Y2FkZjYwMzQ0ZTY5Zjg3M2ViZmUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/DesignSystem/MobileLayoutEnvironment.swift#L3-L14",
|
||||
"version": "repo-lines-v1:sha256:5f15aae79627c3d5fc16686563b9c84439fbd1ad55eef1c7485aacc147f845b6:eyJzZWxlY3RlZExpbmVDb3VudCI6MTIsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk5MjBmY2M4MjM4OTczZjc3ZGU4MGM0MDczYjM4YzViNzEwNjBkOGM2ZjM4MTQ5N2UxZTU0Nzk2MzFkYWMxMjIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjoyLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjM1OTY1ZmU4Zjg5ZDU0OWU2YTkxY2Y5YjIxMGRjNTcwOGEwZDg1OTE5MWI5OTQyNmY5YTBjMzBkYzVkNmU5ZmMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/DesignSystem/MobileToolbarEnvironment.swift#L3-L54",
|
||||
"version": "repo-lines-v1:sha256:b56c53266e16c75ff79a519dd609349c8be9eaa4d3baf6603da6236c7037bc30:eyJzZWxlY3RlZExpbmVDb3VudCI6NTIsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijc4NWRiZDhlMjkyYWJhMTBjZGFjZjJiZjU5M2I4OTM0YWQ5ZWUyNjEwMWMxN2M1ZTBkYmMzNGY3MDgwNjBjNzMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjoyLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjM1OTY1ZmU4Zjg5ZDU0OWU2YTkxY2Y5YjIxMGRjNTcwOGEwZDg1OTE5MWI5OTQyNmY5YTBjMzBkYzVkNmU5ZmMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjoxLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_f700a112a37b4bf6abd0e0238cfe07b3",
|
||||
"statement": "MobilePaneLayout retains valid child sizes without replacing native surfaces; workspace content uses a continuous region while Assistant uses transcript/interaction regions, and both separately gate hidden hit testing and accessibility.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/DesignSystem/MobileContentRegions.swift#L138-L163",
|
||||
"version": "repo-lines-v1:sha256:c6c6e516865f5bdc89834ad893a875e31ed619ccb60fceaa4e62e36ea547e77e:eyJzZWxlY3RlZExpbmVDb3VudCI6MjYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjZkNDg2NDhjOTA2YTJlMjI2Y2RhZjdiYTljN2IzZDA1ODA3NjRiZDIwMmUzZTVmZTZiZjY4YTU1NWEwYzM0ZmMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Features/AI/MobileAssistantConversation.swift#L470-L510",
|
||||
"version": "repo-lines-v1:sha256:e9b974874173a4ff5d1e7e2d6317dbd3b20b189c7b9f5bbc73c075866c59cdb0:eyJzZWxlY3RlZExpbmVDb3VudCI6NDEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijc1OTA0ODUyMzg4MjVlMWRlYTYyMjQxNmU1M2Y4ZGFiOWVkODQ0NTAxMDc4Yzg2MmRiMjU2OTAzNTY5YmNhNjEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImVkZWFkMDAzZDlhN2U2MzkzYzkxZmI0MDM5NjNhOGNmMzIxYWZkMThkNGQ3ODYxYmEyNTIzNGEyMmViNjJmYWEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk0ZTFlNWJhMDRiZDMwZjMwMDA3ZjY1MTJkNWM2MzRhOGNiMDRjMzJiYzFkM2EyYTY3ODM0YjY5ZTJiY2Q5NGEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjNhNjM3ZmU5YWQyZjE1YWNlNjQzOWE0OWUwMWRmYjI2M2M2ZDkwM2VjMjVjZjlmYmM3ZGJlYzExOWZjZjNjNDIifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Features/Workspaces/MobileWorkspaceView.swift#L108-L135",
|
||||
"version": "repo-lines-v1:sha256:a03eb7daabb1c8a1986e421d7763dfdc849ee50e34d46e2ec9276435b7c710ad:eyJzZWxlY3RlZExpbmVDb3VudCI6MjgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk5YjkzOTM5MjI3Y2RlYjcwZTQzMDExZTkwYWQwZGFmZjdhNzNjZTg4Njg2YWQxOTQzM2VkMTQ3OWEwMWI0MTIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjJlZmMzZjA3MTQ3ZWY0OWE1NDEyMjEzZjExOWViNTE4YWFjZjBiNTYwY2QzNWZkMWZiNWI2MjhlZWExYTVkMjQiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjZjNjI3MGZmY2YwOGZiNjMxNTgwZDdkOGUzMjk5Zjg3YjEwNmQ0NWExODljOWI1ZmU1MTMwMTk1YjdkMTU0MWMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjA2MGFmNmJjY2NhMDlmZmZhZTc0MmUxZGU0ODgyYjI3NDQ4N2U3MDZjN2QzYmRmZTY3NjJkMTFiM2JjMWI3ZWMifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_748f112d3d0b4cf4ab8dc8a29b1dbc6a",
|
||||
"statement": "Mobile workspace switcher style and tab visibility follow toolbar placement, while SSH, Telnet and SFTP have distinct toolbar actions and per-action connection/capability gates.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/DesignSystem/MobileToolbarEnvironment.swift#L3-L10",
|
||||
"version": "repo-lines-v1:sha256:c2c2c6cc83fb13a43da977780d588d98f9a511a89ae9829800d1bddd3072d00b:eyJzZWxlY3RlZExpbmVDb3VudCI6OCwiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiNzg1ZGJkOGUyOTJhYmExMGNkYWNmMmJmNTkzYjg5MzRhZDllZTI2MTAxYzE3YzVlMGRiYzM0ZjcwODA2MGM3MyIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiNDEyY2EzNDVjY2Y3NWJmOWMwODA2YmNlNjk1YmU4ZGU4MDhiNzk5ODQyNTFhN2E1NGQyMDJjZjYxMDFkZDQ1MSIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjIsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiMzU5NjVmZThmODlkNTQ5ZTZhOTFjZjliMjEwZGM1NzA4YTBkODU5MTkxYjk5NDI2ZjlhMGMzMGRjNWQ2ZTlmYyIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiM2RmNDc2ZTkyYjVhYWU0NDY4OTFhNzZiNGJmMzE4NDRjZTgwY2MxNTg0NmFlM2ZmOWI4N2U5YTE5NzZiOGYyMiJ9"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Features/Workspaces/MobileWorkspaceView.swift#L136-L251",
|
||||
"version": "repo-lines-v1:sha256:976c28bf78aa6392599820075c94032e15056dca9dd496cb1d760930b9e40847:eyJzZWxlY3RlZExpbmVDb3VudCI6MTE2LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJhNjJmNmU2M2U0MjE3OTlkODZiZTU1OWVmNzFhNDAzMzJjYzM2M2JhNmM2NzlhYTk1Mjg5Njc5YjZjMTVmOGFlIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI1YjNmYzQwMDRkNTU5YWM3ZWE5MjVlZTljOGYzMTA4MmUwZTFkODI2Nzc4OGM0MTBjMjQ1MzEyY2MxMjZjZGZhIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI4NjE1ZjdkYWRmOGM3ODMxMmJkMTE4MmIxODgyNzQ5NmQ4ZmM2YTY3MWFiM2Y4MWM1YzcwOWY4NTBkNTE3YWRkIn0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_fb3544d0980c48599887d6612b11baab",
|
||||
"statement": "MobileTerminalSurface owns its native terminal beyond SwiftUI navigation; added Find commands preserve ordinary terminal key handling and intercept Escape only while Find is presented.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/Platform/MobileTerminalSurface.swift#L6-L69",
|
||||
"version": "repo-lines-v1:sha256:3624f801251beed293020479cdb34a78602161708c16e117e725216ec47b3618:eyJzZWxlY3RlZExpbmVDb3VudCI6NjQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjZlMDFlMWE0NWVhYmVhMzQ0NDkxYWU2MzhhZmFhZTdkOTIxMDFiNWViNWY3ZjVkY2QxOTg5NmE3ZDc4NWI4Y2EiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjQ5ZGYyMTVkM2NjNmU2YWIwOGZmMGZhZWNmZDc1MmIzNWQ4N2M1YjdiMDMzODU5M2U5YmFjYjk4MjFkZmIwYzAiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_a88cbc6d056546b8aabc5e7739084fe9",
|
||||
"statement": "Workspace-view disappearance disables external presentation/drop handling and cancels drop loading rather than directly disconnecting the workspace, with drop activity also gated by scene activity.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/Features/Workspaces/MobileWorkspaceView.swift#L65-L105",
|
||||
"version": "repo-lines-v1:sha256:b287ecf4f8ee1bfad66491a3c69f6237734a8e15f4e849b61fbd9742e2899c66:eyJzZWxlY3RlZExpbmVDb3VudCI6NDEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjNiYTQxMjgyYjkyN2Y1MzU3ODhjMzBmOWVhNzYyYWNkZjQ0YzQwYmY5OGM5YzU5OWViOWI2NzJmODgzNjY1MWEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjJiMWUwMzMyZjgzNmM4ZWJlYzI0YjBlNGNjY2RkZTljMmEzZjRlNDczODRiZDdmN2VmM2JlZWY2YmJkMGUzNWYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImQ1Nzc4NmY4YjgyMjM2NjdlYmYzMTExNDg0ODk3YzIwZDE4NDVkYWIyOTNlYzY0NWZlNjVhOWExMjE4YTgyM2EiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjYyY2M0NmY3M2JkNWNlOTUwY2ExYWY5YmQzYWY3MjUyNzQxYzAzMDczMTU5MTNiYWQ2MDAwOTcxYWJjNTkzZGYifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_e3dd2b1edf154b89a1354de59e82fd70",
|
||||
"statement": "Mobile Assistant shares application-owned execution/store services while scene libraries select conversations; focus restoration after replacement revalidates conversation identity, and the view composes an incremental native transcript with a measured scrolling interaction region.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/Application/Agent/MobileAssistantModel.swift#L243-L306",
|
||||
"version": "repo-lines-v1:sha256:49f1bce4a65005b1a5ad1f81083f3d10026f66f89e587a688a8625139aadec14:eyJzZWxlY3RlZExpbmVDb3VudCI6NjQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjgxMzhmZDI5OTQ0ZGQyMDFhMDBlYWM2MjRhZGRiMzM1Yjg0ZTcwOWQ3YmViZmUyMTZjNTE2MTE2ZGQ3NmJiMmEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Application/Agent/MobileAssistantModel.swift#L9-L39",
|
||||
"version": "repo-lines-v1:sha256:82b51c51f7632b9209f536cc1ff9f4eff1e9b61477387dbf7369a46f05bd8809:eyJzZWxlY3RlZExpbmVDb3VudCI6MzEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjI4ZDUwMzc5NDJmNThhMWQwZWRlN2QxNDYwNmMwZTJlOTE2OGUwMzRkNDFiYTU2ZThkMTA5YTRlNzY5NTgxZGUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjIwYWZkMDliMDljYTY2Y2Y0YmIyN2QwZWMxOWQ2ODUyMzA1OTYxNWE4OGQ2MzRjYTIzYjMxYjdmYmM1OGY5MDAiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImQ4NjlhNmI3MWE1OTA2NzY4MWZkOTE5ZWJlNThkZmMzODZkMzI3YTRhNmJlMDFiMGI0YWYwYmFkMmViYWY3MzcifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Features/AI/MobileAssistantConversation.swift#L447-L544",
|
||||
"version": "repo-lines-v1:sha256:faa0f3af974bcc94ad86beb910bbf1472ed30b41c38daeff0ce7879220b8ba03:eyJzZWxlY3RlZExpbmVDb3VudCI6OTgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImJlNjUyYzFiYmFkYjBkNmExNmM5MzI1MmQyM2FjMzljNjlhOTE2ZGFlN2UxZWNhZTM4M2I1ODIxMGY5OGFhZDQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImJiYjRiNzI3ZmE2ZGQ3OWEzNzlhMzIxMjU1Zjg3Y2MwODFmODg5Nzk2MDc1ZDQ4YzM0NDhhMjcxNzQzMmFjYTAifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Features/Assistant/MobileAssistantView.swift#L201-L235",
|
||||
"version": "repo-lines-v1:sha256:4623f534ceb1da048c60fd5fe8898f82c06f8c1758d82d4ef01c9463a3476903:eyJzZWxlY3RlZExpbmVDb3VudCI6MzUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImJmMDAyYmMwYjBiODRlYjRjOTAyOTY3MjI5OWUyY2I0ZGFkZDI0YzM2OWEwOGNjNzQxODliZmYxNDIwY2JmMGMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjAyMjc5NjRkNmQ4OGIwNWViMGZiZDZjMzY3MTYzYTdmNzY5MjljNmVlN2E5Y2UxZDRkZjRmN2Y0MWIzNGUxNGUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjBmMDRmY2IyNWUxOTUxOGU4ZDU4MjY1MmUxNWQyMjBkZjUwNWVkZmI0OTllMjUxNTY1YjZmYjAyY2MwYzZiYjAifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_e7423fe4f094438aaacb38fb8f626adf",
|
||||
"statement": "TFI aggregates scene phases before entering background handling; background expiry suspends workspaces, stops forwarding, pauses transfers and expires Assistant work, while an active scene resumes retained workspaces and appropriate services.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileAppModel.swift#L491-L523",
|
||||
"version": "repo-lines-v1:sha256:3e5f5ee2eaa48a81fe415e9bb3d77294bdb003e45542404a755bb1e569796e90:eyJzZWxlY3RlZExpbmVDb3VudCI6MzMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjExYjYwOWM3ODJiMmM2NDVhM2M2ZDFmOWMyMDA3YzdjMGVlMWI5MTI1YjJjOGIxOTU0YTFlMTVjY2UxM2VkYjMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjExMGVhYzUyYWE2NjM0MDczNjQ0MjU1MTg2YTc5NGIxMjdmYzQ5MTA2NTRmYTNhMjBiOTgzMjMxOTIxZWU2ZWEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjYwZTJhMWYwNzIwY2I4YWNhODQ4ZjIzNzM0N2E4YjUzNGY2YTEzZDVhZTBmMTQ3MDE4ODQ5ZmZjYjkxOTRlZWMifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileRootView.swift#L49-L74",
|
||||
"version": "repo-lines-v1:sha256:427a1b65cef9a08c166a810c9819f16094bdadda3efd6d064bf1010c9467c8c8:eyJzZWxlY3RlZExpbmVDb3VudCI6MjYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjMwNmIyOTNhY2FiZjI2YWJjZmZmNDhiYzNlZmVkZTIzZmEyMDFiYjA3MDMzMDMxYzcwOWVkZDc2NmQ1YjQ2NWMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjRkNGM4YzM4M2UxNWUxNjA3Njg3NDNkZjUwZTY1MWE0N2YzOWY5YTcxZWJjYzMwOGMwMTFlOWQyZTRiMjE4Y2UiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjM2MTlhZGM1NjcxMTNjZmI2YWE4YTM2ZmI4N2U5ZWI3N2FhZGFlNjU4MDc3ZDRlODQ0NGNkNGM0NWM1YTFiNWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImQ1OGE3YWU2OTU4YjYxMGZmMmRhM2Q1ZDM0MjdjMWYyZDZlMDQ2NzRmYzdkZjEyNzgwYThhMWU0NzFkODVhNjAifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_b97c7e449e5b4b0e95aa983dbef8cad9",
|
||||
"statement": "MobileAdaptiveLayoutTests validates five native destinations across widths/languages/Dynamic Type and retained native list, focus and marked-text identity through injected region changes, rather than proving behavior on every physical device.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFITests/MobileAdaptiveLayoutTests.swift#L9-L180",
|
||||
"version": "repo-lines-v1:sha256:fd1dfb3439ec991b16afb53f24aebc218d39fe34cb89144a79d75a4fa14cad8c:eyJzZWxlY3RlZExpbmVDb3VudCI6MTcyLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI2MTcxN2I0ZjY1MWU3NTQ5ZTUzN2QxZDg3ZGNmODNhNWRiYjkxODAzNmJjZDExMDRkYWM4M2QxMmNkNzZlNTYzIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiJhMGE4ODZkMjJlMjhmYThjZmFkMzg2ZTUzMzlmN2JhNGFmNDEzM2U4NGRmMjU5YTYwNTNjNjJiMzI4ZjQ2Y2U3IiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJiY2JlNmZkZjFkNDEyOTVmNjUwMmJhODFjNWQyYjdmZTdkOWZhMDFmZTU0NWQ3ZTZhMmFiY2M5YmUzMjRiOGI0IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiJjMTNhOTQ2OThjNjNhZjM5MmJkMWI0YTZkZWIwZWI5ZjdmYzFlNWVjZTQ0MGM1OTU3MTdkYmEyYjM2ZGJjYTU4In0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_19b54bd8848c4be3964fb5d9df46007c",
|
||||
"statement": "Mobile card columns derive from measured width, with accessibility Dynamic Type forcing one column instead of a fixed phone/tablet count.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/Design/MobileDesignTokens.swift#L3-L16",
|
||||
"version": "repo-lines-v1:sha256:9942ca35a253f97eef9813e34a3351e94136b20663ae8bff5329a07bef6515d8:eyJzZWxlY3RlZExpbmVDb3VudCI6MTQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijc2M2E0MDYxMjcxNjkxZGY5ZTZlNzNhNDc2ZjY2MGZiNDAzZmE3OGYwNDBjNDVjZTBhMmUzM2ViZmFlYmNlMjciLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjoyLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjBmODVkNWEwZjU0NTg4ZWEyNzdkOTIyZjAwMzZjOGFiYjMxNDg0YzQ4Y2UwNzY0MjZjMjdjMTA5NWVmZDE4OTYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/UI/Managed/MobileCards.swift#L16-L36",
|
||||
"version": "repo-lines-v1:sha256:6da6b4de4629b151fe2d915afe6eafcc3013b98cccccdccc1cfda9a9aa2a47ea:eyJzZWxlY3RlZExpbmVDb3VudCI6MjEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImNiMTc4YjMyZGYyYWZhNjMxODU1ZThhZWViMDNhNTg1YzM0MWE1OGRjYWZkZWJkNWJmMDYxZmViNjhlMjgzYTkiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjE0M2NlZmIwZjcyMmRiNzRjN2E2YzI2OTgwMzU1ZjQyMjA0Yzc3NjJlNzY0ZjI4YTFhMzk4OGU5MmMzMjgxZWMifQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T02:51:54.212Z"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:023da98f47ee307e4847967ad5bf01156edea72720624942c87f64e1a41cf401",
|
||||
"pageVersion": "sha256:714b4eca157c6f95f4ef0792e6f173f13d9134413253216b19e74bc1fad3e833",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_bd9f5ddda6b6466eb79c622b02fd73f2",
|
||||
@@ -233,6 +233,6 @@
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T01:13:21.371Z"
|
||||
"at": "2026-09-22T02:51:54.212Z"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:a5119333dde48ffa8eb6bc9978c53286e04e316ad5ab041d1b989f56e5315d0c",
|
||||
"pageVersion": "sha256:10ea95f6fb5ea0feb5b5f8460c1c8c84091a3d340782befcf5566bda2d187362",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_7c677489fd8b4a4fadd006a4da4e9937",
|
||||
@@ -173,10 +173,28 @@
|
||||
"version": "repo-lines-v1:sha256:126ca2648f3109930cbb465d7a74bfc5658d320d430810327b912dc24d3cfa67:eyJzZWxlY3RlZExpbmVDb3VudCI6MjksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImJjZGFlMzAyOTk2ZDRmOTVmMmEyNjM1MjE1NDI0Njc5YjIyMDgwNGJlOWFlNDI0N2YxOTJhOWY2OTQ2MjY0YjQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjU0NGJkNjE1ZDNhNTc5OTNkMTE2NWY1MWRhMmQxMjA4YzY2YzI2YTVjZDU1NzI5MjJjOWFkMTE5YTdlYTIxZmYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjFkZDcyYTdjYjEzOTAyMmM5MWUxNjFkZjlmMmFjMjMwNTRmZWQ5OWU4MTRmMGZkOTcxYWQ2NjkwYzdhYjhkNzUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_230f868f2d7243f3af8c52f923ccc951",
|
||||
"statement": "SFTP file admission precedes context channel acquisition, so an operation may hold a global/per-host file permit while waiting for a session-channel budget lease; file permits and per-connection channel limits are distinct controls.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHMultiplexedSFTPChannelOwner.swift#L77-L87",
|
||||
"version": "repo-lines-v1:sha256:1a1557053779412a1d1fbfe9ee02060e7644425dc0727d31baf45291237fef1f:eyJzZWxlY3RlZExpbmVDb3VudCI6MTEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImY3Yjk2NGEzMjUyYTE1ZTlmYWQwMDRjMzMxNjllOGEwMzQxZTZkZGZlNjY4NDM3YzZmZDQzMmFlNDM4YTA4YzQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ3MGI3YTI5OTkwMzg0MzU0NmQzOWJhZGQ4OTc0OGJjYzE1M2U0NDZmZGVmOThkMGVkNWRmZmViNzFmZTI2MGUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjYyNGZjMjBiZGY3MTUyZGVhZGUzNTkzZTczZjIyYjg1MmIzNDA4MTVmZDZkOGIxOWYyMTY5ZTE1OTZkNTM4ZTkiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImJkZmMyYTI5ZjY1MzVkYTM5NWM1ZDRlZDJjZWUwN2VhZDUwNGIxNTM3YjBlYmYyZGU3ZjkyMDJkODM5NTM3NTQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferContext.swift#L99-L188",
|
||||
"version": "repo-lines-v1:sha256:66bc442c33d6cd347e25766a912d6e5aa904ff35fbd79cb65d9b0da8bdef9739:eyJzZWxlY3RlZExpbmVDb3VudCI6OTAsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjM1NDUwN2Y4NGExN2EwZDY2Zjc1NzU0ZGJmZmEyZjJhODNmZmYwODg4NWUyMmEyNDI5ZmRlNmQzNTljNzVmMjIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjgzYmRlNWRjNDUwMWI5ZTk1NWQxN2ZjZThlMmZkMGEyYTIwNzkwMTQwYjNhYWVjNTQwYTJhNmYyMGZhY2M1MTMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImNlMjMzODU2ZGRmZDZjYmUwMzUyNmJmZTEwMjcwYWYwMDc5MGZjZTQ4YTgwODQ0MzdmN2MwZGE4YzJhMTJmODcifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferCoordinator.swift#L488-L552",
|
||||
"version": "repo-lines-v1:sha256:517342c98e35cff6cb998aecd82535e3ee5f3866f6b9ff6ce05fb886ed0eac4c:eyJzZWxlY3RlZExpbmVDb3VudCI6NjUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijg1YjdjZWMyMGY5OWFlYzBhY2NkZTMwNTkwMjZmNjlkNDk3NDNhNWM0M2M2YThlMjMyNDdjZjBmZDRjNjgwY2IiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImRiNjcwZmIzOGY4NGVlMDAxM2IwMWVmM2JlMDc4N2ZmOGMxMzJmMzNjODVjMzY5MTM5YzIxNjFhNGU4Yjg3Y2MiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjAwNDU3Y2EwZThhZjE2NjNkMmM3NDg3NmQyNjJlOTUxOTNlOTEyNmFhZGY0ZmI4MmQ3NzVhN2VjOThmYmMxODQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjkyMWFjYmUwMzNiOWVmMGE2NWY3YjgxOTBjNzMxZWYyMTVkNzI5ZjkyZGUyZDk5NDMzMDEwMWY0NGE0YmY2ZDkifQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T01:13:21.371Z"
|
||||
"at": "2026-09-22T02:43:23.140Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:3080e12d34f1ea00779670c9322ef8a881013cc0b9818b54ea393ff11c802b17",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_bc1531cd55cc445cbd6964ff7331b6c1",
|
||||
"statement": "The PTY worker requests a PTY and environment before starting the shell, then conditionally queues shell integration bootstrap; environment-request denial is nonfatal while other errors fail setup.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L1083-L1180",
|
||||
"version": "repo-lines-v1:sha256:2164423f1b9aa82653b53f87f67999e98520b9ba40af2835513b1225728d6091:eyJzZWxlY3RlZExpbmVDb3VudCI6OTgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU2YjA0NDkxNDY5NzIyZTgzNjNhOTRlNDA0NDUzOGUwMTNhMmEyMTdlMzZiMWU1NjhiYTYwYWNiN2I0YzhmMmUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjcxY2FjMTgzYzIwODNjMmJlMDJlZDRkN2I0NTJlMDg5NDMyOGMxN2NjZjM3NTIwMGE5OThmNjNiZDVkN2VjOWYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImE4ZTAyYmQzMjRlZmJkNTI3ODdkMjU5YWU0MDJhYmJhZDUwOTA1MTI0NjdkMjc4OTVjNmFjMDkyYTdjYmVlZGYifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_96a24d38299a43fea84866ad9be62f44",
|
||||
"statement": "Host shell integration mode resolves a global preference or explicit override at connection-attempt start; a live desktop session retains that decision until a new attempt.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindDomain/Hosts/HostShellIntegrationMode.swift#L1-L14",
|
||||
"version": "repo-lines-v1:sha256:8b433137dfb79d25b281cccb1b9b74a08e101fade6a195941d7efef9ed518886:eyJzZWxlY3RlZExpbmVDb3VudCI6MTQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImVmNmIwMDE5YjA2YWFlZmNiZTIxMjg4ZTBlMTNjZGU5ZDcwYjAyMzk3MmVmNzg3MWVkNTc4NmQyZTA0MTgzYTIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjowLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Terminal/SSHSessionModel.swift#L382-L393",
|
||||
"version": "repo-lines-v1:sha256:2d7c1067ff14563a949bc78654462b0d48bfbecd9e225171047a45b65099a66d:eyJzZWxlY3RlZExpbmVDb3VudCI6MTIsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ1MTZiODA1NzQxMzg1ZDNmN2U1M2MzZDViNGQzNzgwMjQxN2IwMmIxMWU0MmIwYzJkMjIzNTI0YTgwM2ZhZjIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImM2OTYxMDRkNmVhZjFmMmNjNmE3ZmQ4NzhmN2M4YmYxOTUyMmQ4NmE3OWRmMGU5ZjU5YmNkZWQ1M2U1ZWE4MjAiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjExMDQ0Y2I3YTNhNDZmYTMxNTcxYjczMTkxOGU0ZjRlNDJiNGFlNWM4YTkyZDhmYjhkZmY2M2VjNjU4NWE3YjMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjcwNWRhNmVjM2Q5NDQwNjFjMGNiOTljZTcxZTE0YzhlMDQ4YjcxMTcxNjFlYzJhYjdmMDY0ZGM2NTFhYzU2NzkifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/HostShellIntegrationSessionTests.swift#L12-L60",
|
||||
"version": "repo-lines-v1:sha256:95e39f238f3a3230b2625e10c609012a2297c333e1880c456e9d19178944639d:eyJzZWxlY3RlZExpbmVDb3VudCI6NDksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjIxMWY2OGIzN2Q5ZWI3MDg2NmFmNjRmZDA1YmQyNmRmNGRhNDQ4NTQzOTkzYWIyOTA4MDM1OGZiOGM1NDdmM2UiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjBmZjZmOWQxY2Q2YjdmZTdiOWRiM2E5OWY1MTVjMDM1ZGNmMTQxZWQ3MDQwYWNlYTA5NDBiNTE1YzcwZGNlZDUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjlmN2RiZjFiYTRhOGU1NWIwMDA2NWRiYTBhMzBhZDk0NzBkYTQ0NGEyYzA2MmY1OWIxYmU0ODVmYjQ5ZTY4NDYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjM5N2VhNmQwNWIzZTVjNzU3NjUwN2ZkOTUzOGIzN2M1YzRjNjBjMTlmMGU1YjAyN2E1ZDQwZGZmMzNmNGVmZTcifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_bd6cf9271fed49b2a19e1baa1ebd67a9",
|
||||
"statement": "The bootstrap probes shell and optional system fields with per-instance token markers and reads os-release as text rather than sourcing it.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L181-L211",
|
||||
"version": "repo-lines-v1:sha256:db3daa22700e1ea926f41c9326f98af92fedf9a7559b745dd1d0245dcf17ae39:eyJzZWxlY3RlZExpbmVDb3VudCI6MzEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjFmNjhkOTMzMjViNThlMGNkMzNiYTRjOTlmMTA5MWE1NTEzZWJkNDZjOWQ0Nzc2ZGExNWUyOTc2YzIwNDVjYzkiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjFlZTQxMzIyNDczYmQyNTFmYTQ2Yzc3MTExM2ZlNDViYjk3M2E3YmMzNzk2NjZmNzBhODBiOGY5ZDNlNGRjOTQiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk5OWJkZWZlZWFjYTYzNDBlMDI5MGRjODZlODg5Yzg5ZDVlMTg5YWE1YmE0NGI1ODViM2I3MDczNGY0YTYyZDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImZlZWMzYzFjNTE1NTc0OWRjNTQxNjRkMmIwNWJiMzhhYTQ0NDhjNTE5YmYwYmJiZWJhOTRjZjJjYzY3ZTE0NjMifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L57-L106",
|
||||
"version": "repo-lines-v1:sha256:5190454f198ab6441bfb3696601f48299f45e83b534d9e4f11630293c7e9f52e:eyJzZWxlY3RlZExpbmVDb3VudCI6NTAsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4ZTY4Nzc0ZDlmNzI3MDlmNGNlMTY4YTE3MmIyZDFiMmY1OGFmZGU1NGFkNWZhMjM5NjI1NDI0YzI2ZGU2ZDQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijc0ZDYzMjEyODNiYTdhNzI1Y2M5MmVkMmI1NTEyNWFjOWU5NzM5M2RhM2U5MzQyMTkxZDZjN2UxYzJkNTU1MDEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImMyZGZhNTNkYmQyZTY1ZDZjNGE5YjVlNzIwNTYzZTUzNzNmMDI1N2Q1MGU4NDU5ODAyYzllNjcxOWQ3NjRiYjIifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_f81d12eff32548b1a806995b8e177a96",
|
||||
"statement": "The bootstrap uses 3-second response deadlines and a 500-millisecond quiet timeout; its initial timeout restores output but keeps scanning for a late probe, and a late supported probe skips installation after user input.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L1182-L1190",
|
||||
"version": "repo-lines-v1:sha256:0638886559d913277b65dbdefbb8a12265aaaf7934582349de48cf5efdca45bb:eyJzZWxlY3RlZExpbmVDb3VudCI6OSwiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiNjk5NTVlMzRjNzZmN2Q1YmZlYWMzYjFlNGY4ZjI0MzZlYjM2NmUwYjdjYjJlZDRiMDAxY2NkOGZmNGI1MjBlNSIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiMWQyYjFjNDQzYzYzOWMwMmI4ZjM1OTA2ODY4MTZkNzNkYzk5MGQ1YjhiYWVlZTBhZGU3Mjc0ZWIyM2I0NDRlYiIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiOTk5YmRlZmVlYWNhNjM0MGUwMjkwZGM4NmU4ODljODlkNWUxODlhYTViYTQ0YjU4NWIzYjcwNzM0ZjRhNjJkOCIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiYWE1Nzk3YWQzZGJlMjJjOGViZGNkZGIyYmVhNjk1NjQ4OWJkNDhiZmVmY2EwMGQzZTQ4ZGE3YThhYTA3MjU3YyJ9"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L133-L241",
|
||||
"version": "repo-lines-v1:sha256:4c6170cd54fd1e8242cc60cd8c4be3821dff1001c934a8c7b3608f9b2c4bf3f8:eyJzZWxlY3RlZExpbmVDb3VudCI6MTA5LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIxNGVhMGMxMGMzMGNmZTVjMWI3ZTU2MGE0MjFmNzdhMTAxZmEyMTYwMTYzMDU1YWEyZDUxODU5MTRjYWJkYzQwIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI2ZTc3ZWUwNWE3ZDlkMGVmZWEzOTkwZmFhMGYwZTc3YmMxYzQ0N2QxMjJkNmRmYjE1YTI3MmQ5MDBjOWNmNTcxIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIyODdjZWYyYzcyMDY4NDA2ODlhM2RlN2ViNzFhY2RmNzg0NGYyMmRkNTRkM2IyNTg1NDk0NmMwNGE5NzkzOGZiIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L315-L352",
|
||||
"version": "repo-lines-v1:sha256:a9295d4b02bbcd7b1e0c3dcc982416a7fe50f4c437780dc2cca312a463e534f6:eyJzZWxlY3RlZExpbmVDb3VudCI6MzgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImRmODBmMzAyOTcwNzBhNmVmN2EyYzIyZmI4OTgxMmM4OWU5N2NkNGY0Njc0NDhkOGJiMzk0ODUzMWY3OWZiYWEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjliYjI1MGMxMWI4ZWVlZDllMDA0ODIxOGFlMDBmMmEzM2E3ODAyZmEzMDY2ZTA0MWMzY2RiNzI0MGYzMzVjMjUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjRmNjZmMWUzMmRhMzUwMjcyNzFkODU4ZDhhZDBmMTc1MWNiMWJjZmM5MWUyZjUzODA3ZGQ1NzcwYWEzN2VjN2QifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L53-L54",
|
||||
"version": "repo-lines-v1:sha256:b0c18de8d6e708b4918644e935c094d117ff32b5f0212de196d23ac14dc285a1:eyJzZWxlY3RlZExpbmVDb3VudCI6MiwiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiOGU4OGVlNzRkN2VlYTViMDU4NWUwODg2MTY1ZGI2ZWY5MzU2YTQzODMyZTQ3ZGI2MzdhNjY5NzRhYTU0MzVmZSIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiNGI3ZjJlMmVhNjJkY2M1MGNhMzJlMmU4ZjMxMjdkNWViMTdmZTNmYjdlYjJjMjU0YWFkZmZkM2EyNmRkZDkxOCIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiMDEzODUzMzYyYTc4ZDMxZDRmYzM2YmE0ZjQ3YjZjN2JkODgxNTYxOGE3MWYyOTk3YWJlMDZjYzJkMzU0Yzc5YiIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiMGUyOGJlNDZlODFiZWUyMjllZDdkMWE5NGVkMGU1MzcwZDQ3YzdhYTQ2NDM3NmMyY2RjN2ZiZTg0YzcwM2MyMCJ9"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_c3541976db5f4e84a583c4486ddd24e2",
|
||||
"statement": "Bash, Zsh and Fish installers define session-local hooks and compose bindings, report cwd through OSC 7 and command lifecycle through token-scoped OSC 777, preserving the shell-specific hook mechanisms rather than editing startup files.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L443-L463",
|
||||
"version": "repo-lines-v1:sha256:fe419183706a45905e697a9a26e6b1fc4abd95021c8a4df32e1bd9d05dcdf4af:eyJzZWxlY3RlZExpbmVDb3VudCI6MjEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImRhNDI5MzllMTZkMTk0YTI5ZmFkOGE0NWMwZjBhNDQ1MGIyNDk5NDk3MzQwYzlhZWFjOWM3MmUzNDFhODI5MjUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjUzNGQwODExMTYyODk0ZDlkMDBkOGVjODBiZWUxMjA1ODFmMjVhNzUxN2E3MTIwMTk1MzViMjdhNjFmNDAyYzkiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjNkMTdhYjYyYWVkZjI3MjI0ZGJjYmY4NTBiZjkwZGY3ZDAwMjUxODM5MzA0YzUzMzVhNWNmNTVlMzNmMGYxYmUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_906cac619d6746ef87edab1d28337dfc",
|
||||
"statement": "The command event filter preserves partial prefixes across reads, accepts only matching-token BEL-terminated events, bounds payloads at 64 KiB, validates exit status and duration, and leaves wrong-token frames and ordinary OSC titles visible.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L469-L627",
|
||||
"version": "repo-lines-v1:sha256:6301872be5e3064ce2037fc3ab40b1be36bd04bb61d2d985cf3fb69b827ad129:eyJzZWxlY3RlZExpbmVDb3VudCI6MTU5LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI5M2EwZmZjMjhmZGEzYzE5MTE5ZDgwMjE3OGYxMmQ3ZWFkMDkwODI4ZmE4ZDhiZTM2ZGExMDRlYjIwYzkzMjQ4IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJiZjBiNDVjMzAzODA1ZDQwYTM3YmY4YmNlZmM0NGNkN2Y5N2ZmNDQzODlkZDU3ODdhMzg5YTg3ZmY2NGYxNGM4IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIzZDA2NTNiYzE0Y2ExZmY0YTQzOWVkZThjZGJiYWQ5MTJkMzE2ZjJhYjc3NDRkZDQ0ZGMyNGNhMTA4ZTZjY2QxIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/CommandHistoryTests.swift#L281-L406",
|
||||
"version": "repo-lines-v1:sha256:e8c2c07dbd22ef8efcf468c9b425adf26a32e3e1051c398a0357f7232ade3678:eyJzZWxlY3RlZExpbmVDb3VudCI6MTI2LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJlNjY2NzRiZDE4MjM2ODFjZjM4MWRjMDk2NDMwNGQxYTljYjg5OTgyZjhhNGVkMjY5YjE4MTQ1YTM2NzBjOWZkIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJmOGU4N2M0ZjVmMWU3NjkyMzI3NDY1YjNjYmRiOTdlYWY0NmE5YmU3YzFjNjhlNDE5NWMwNmU3MTRmYTdjZmVhIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MCwiZm9sbG93aW5nQ29udGV4dEhhc2giOiJlM2IwYzQ0Mjk4ZmMxYzE0OWFmYmY0Yzg5OTZmYjkyNDI3YWU0MWU0NjQ5YjkzNGNhNDk1OTkxYjc4NTJiODU1In0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_7f79a0b4a7fd4b9fb8e7cb637e7515d8",
|
||||
"statement": "PTY output passes through bootstrap suppression, OSC command-event filtering, OSC 7 path charset rewriting, and streaming conversion to UTF-8 before native terminal output; home is separately parsed from bootstrap metadata.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/RemoteCharsetConverter.swift#L203-L287",
|
||||
"version": "repo-lines-v1:sha256:b2c8d09744bd68a4d88b7ccefe46d09deaaeb0807b2225a12eff31fc91cce81f:eyJzZWxlY3RlZExpbmVDb3VudCI6ODUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjBhNTI5N2QzNGVkMTczNTExYzAxZGM5ZTMwMTQ5NzUwYzZkZTVkOTBjYzJiM2YzNzU1YTcwMTg2MzAyMjg4MTEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjdiMTI2YjY0ZmEyZGMzYmUzNjIzMDk3OGYzZDQ2YmI3YWY3NWE2OWM1ZDIyNmI1ZjFhODFmYTI4MTRhMDAxNTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImEzYTNmMTI0MzM4ZmRkOTE5NmVlMTVkNWI4NGE1M2M2MDQ2MDlmMjA3ZDhlZjZiOWE4NzcxODhmNjUzNWZiOTMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjQyNTc2NWFjNWIyNGY4OWE0MGU5ZmRiYzM0MGRkZDk0OWU4MjAzOWJhMDdmOTAxOGNhYzhiMGRkZDE2ODFjMzMifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L1535-L1640",
|
||||
"version": "repo-lines-v1:sha256:d8ea84a8472974d67322a27e956994e3a86df6bb563c15e12803d2e1d0d1d62a:eyJzZWxlY3RlZExpbmVDb3VudCI6MTA2LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJmMzZkODAwNjcxYmMwMmE0ZDc4Y2QxZTU5YmRiOWNkNWUzMWZiODQ1MjZiYjhhNTdiNTk4MDEzNDhmMjQ1ZDJiIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiIwMWJhNDcxOWM4MGI2ZmU5MTFiMDkxYTdjMDUxMjRiNjRlZWVjZTk2NGUwOWMwNThlZjhmOTgwNWRhY2E1NDZiIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiIwOGJjMzI0NTk4OGZhNzE1OTRkNzc3YTFjMGRkYzUxMjBmNDQ0N2MwNzg1MTczMTUyNGZiN2ZjNzc1NzQyYTM5IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI3NTBjODFjOWUzMzY3ZjQzODYzZTFjZmM4NzZhZDg1NzdjYjQyZWVlYzg2Zjg2ODA3NGI2NTI5YmFiZTQ5MWNlIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L243-L285",
|
||||
"version": "repo-lines-v1:sha256:a4e11f5711fe2d8d730fb946aefc5db709c608654197a19c9596ac8d564e753e:eyJzZWxlY3RlZExpbmVDb3VudCI6NDMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjcxNWY2ODQyZjBmYmRlMWI3ZjQxNzE3M2QzNTVmZGQyMDQ4ZGMwMWRmNzk5MzNjMjgzMDVlNzNkMDQzYzYxZjgiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjAzNjJkOTMzNTk5MTk4YzE3NWI5YjBjMDhkNWM0OGM4NzUyMDY4ZjhkNGY5YzdkN2Y1ZjhlNmU1Yzc3ZDRmY2IiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjA1MGRiN2U0NDFlODVmYTM2ZmNhYjgyYjNlMjdjMTcxYjg5NjQxMDgwYTAzNzg5ZDBhNzc0YTdhM2YxZjI3MjQifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_ee7e1649cd0847a583d24f85e9e2e504",
|
||||
"statement": "Desktop installation availability does not mark the shell prompt ready, whereas mobile additionally treats availability and command completion as prompt-readiness recovery boundaries; both use shell events to associate history with command completion.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/Features/Workspaces/MobileWorkspace.swift#L537-L598",
|
||||
"version": "repo-lines-v1:sha256:6d89df935a9c75efc237328c919e3bc6ca1c78f99c6c13f7046995690e4a744e:eyJzZWxlY3RlZExpbmVDb3VudCI6NjIsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjZiNmI1YzY4ZDUzMjk0NzYxNjkyN2YzMTc3MmEzNmY5ZmY5ZWZmZDA2NDQyOGE0YTJlNDQwYzMxYTZhODYyNjAiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjdmODIxZTIwZTQzYWNkNDk3OWZhMmVhMjViOWFhOGJjNjE3YTYxNGU2NmM5MjA4ZTg5MDZjNzBmNWI1NWY3NjEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImY4ZTcxY2JkOThlNWM1ZTg2ODZkODQ5NmI0Y2Q0M2UyNGZkN2QyNmFmNGJiMjA4YjZjNjc0NGZkOTRiMzQ5OTEifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Terminal/SSHSessionModel.swift#L1131-L1243",
|
||||
"version": "repo-lines-v1:sha256:ca18861ef703aa764dd5a336b22baadb3f133fbf2de8b2942aac358d6eb07c4a:eyJzZWxlY3RlZExpbmVDb3VudCI6MTEzLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI2ZDkzMjJlNjcwMzQyYzQyZDRmMWExNjYyNWU2YmZkZDE4MzVkNTI4N2Q1OTYxMGM1Y2Q1MzAzMjY0ZTM0NWUyIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI5OTliZGVmZWVhY2E2MzQwZTAyOTBkYzg2ZTg4OWM4OWQ1ZTE4OWFhNWJhNDRiNTg1YjNiNzA3MzRmNGE2MmQ4IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIxNGEyNDg3M2UzMjIwZDkxNzYyNDRlNjE3MTUzNzA0YWQzMWViNTY0Y2UzYWVjNGNlNWU2MDZkMGMwMDQwY2M5In0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_6f2bf54104ae447c94f2dcea2fabe112",
|
||||
"statement": "The command draft controller permits one in-flight draft read with a two-second timeout; replacement clears the remote line and bracket-pastes text without submitting it.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindApplication/Agent/TerminalCommandDraftController.swift#L24-L99",
|
||||
"version": "repo-lines-v1:sha256:729eb6fd54f742892512d8d27d3af194f0aa6f00170c283258620b3ecac94845:eyJzZWxlY3RlZExpbmVDb3VudCI6NzYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjVmZTY4YTliODc1YzE2OTUyMjM3OGE5NWJmMGM5YzE1OTQ5YTQyZTNhYzNiMmUwNDE3ZmYzOGJjOWFmOTEyN2MiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjZjNGY2MWQ0YWEzNzkxMTQ4YTUyNGZmNzA2YWE5YTg2MjQwMDZkNGNhMTIzZWM3NWU4YjQzOTRlYmZkYjdhOWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_d098c2f42a614425aa566d8997cd3fc8",
|
||||
"statement": "Desktop shell callbacks are attempt-guarded, mobile consumes exit and shell events in one generation-guarded AsyncStream, and PTY closure clears shell state while preserving the underlying transport if sibling SFTP channels remain.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L1673-L1699",
|
||||
"version": "repo-lines-v1:sha256:3d327810de155d8668a4285111fb9dd6fbe29b51346a25664492171bfce0b324:eyJzZWxlY3RlZExpbmVDb3VudCI6MjcsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjVkYzgzNGEzYWJjM2YyMTI2NWMwYzNjZTFlYWZlMzMwNjJlOThlMTM5ZDMwNTE1Yjc5Mjc2OWVlZjY2ZDc2YzkiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjRiNDU2YjFlZDgyZGNkMGQ4ZmQzYjUxYWQ3MzE0ZjZjMThiZmU3YjNiYjFhMDI1ZGU5NDU0NGRlYjVjODFkY2QiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk5OWJkZWZlZWFjYTYzNDBlMDI5MGRjODZlODg5Yzg5ZDVlMTg5YWE1YmE0NGI1ODViM2I3MDczNGY0YTYyZDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjU3NTk5Y2ZkODFkNGUxYWYyMTMzNjIwY2UyOWUzOGZlMjVmZjYwYTdlM2ZmMzdiYjQzZDdlZjMzZjQyOTVhMTYifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Features/Workspaces/MobileWorkspace.swift#L1231-L1262",
|
||||
"version": "repo-lines-v1:sha256:2c2040591a2e139ddff1472edfdd06e425158a841d6259fea8c29c9d4da40c48:eyJzZWxlY3RlZExpbmVDb3VudCI6MzIsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImJlOWU5OGIzNTQ0ZjI3YzY3ZDhlNmU2YTc4NTM1NWNmMWI4ZmY2ZmVjOTFmYmNmZjAyN2E3ZWUyMDFhZDk4NGEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImM0MmE3Njc1NWI1NDcxYjk2MzRmMjE0ZWRlYzRhNTZkNTU4Y2IyZmQzZjNjNDI5OWNhODRkMWVjZTc3ZGJkYzMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjVhOWYwYzJmMzE3Mjg5ZWZmYjJmZTRhNTIwYWJlNGY1Njk5ZDIyMDY2MTk0NWNlNmY2ZWUxYmVkNjNiMWIzMGUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Terminal/SSHSessionModel.swift#L826-L831",
|
||||
"version": "repo-lines-v1:sha256:52d47a062877d79081bd70483a65e58330e9eb7d6c24da4edd0c1d1c3bc7f9b6:eyJzZWxlY3RlZExpbmVDb3VudCI6NiwiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiMWQwOTQ0ZmE4OTNhMGM5N2ZhODNhZmRiNjYxMDEwNmMzZDcwOWNhMzc2ZmE5NDFlNWRhOTlmODU0NzFhNDY5NSIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiNTUyMmM0MmNkMTljNmQwM2Q4MDhjNDUyNzIwNTUyODI1YjdlYTFjNWI0OTFiMjE4NTExY2FjNzQxNWNmOWQ5YiIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiMDhkY2E2MGVmOWY4NTBmNGQyOThkNGNmZTQzOTZkYzBjNmNkM2M4NzQ4NGY4ZjczYzE1YmNhMWVjYzkxNmEwOCIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiODkxMzBhZmY4ZGI2NTMyODFiMmFkZDA1YmQ3ZDg2MmI2NTM1Nzk4YmE4Y2FmNzc5MGExYjk4YmM0OTU3MzQ5NyJ9"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T02:43:23.140Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:47c2d7e416b47c5104e7fa88cf33c353214d35e4e26759a0bff70dcbd3adda04",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_c56b98e3167443d9a8aa8d3405b35eca",
|
||||
"statement": "SSHConnectionWorker serializes libssh2 calls on one queue while independent exec state machines and multiplexed SFTP operations share its authenticated session; the PTY worker instantiates the same SFTP owner on its own queue.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHConnectionWorker.swift#L8-L131",
|
||||
"version": "repo-lines-v1:sha256:193cd4b48d8149ba2c9919ad80dfd65aeece1adf8642a39b87f39cfe134f61e2:eyJzZWxlY3RlZExpbmVDb3VudCI6MTI0LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIwMjM5MGNhZmNjYTg0OTFjNWY4NzFmNjQ5ZWRlMWIwZGNhYzJlNmMyYWQ3OTdkNTQxYzUxMmM0ZjA3MzVmMzlmIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI1YjEzYWJjN2JiZjlhMTcwMmM3OTMzYmZhNzRmNzdhNDhjMzMxMjQ5YjM2Y2JmODBiZTZjMjE0N2Q5ZGU3NDlhIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJlZGRiODU3ODAwYTVkNzI0N2ZmMjNjNWNkNWU1MmM1NDdiYmY0YmMzNjViOWE3NDI2OTllZTMzZGJiMjg5MmMwIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI3NTJiMzc4ZTE0ZjJiMTgzOWMwNjU5YTlmZjUyNTVkZGEwOTM0YTZmODE5OTI4YmE5NWJlYTVhOTk2YWY4N2M2In0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift#L813-L831",
|
||||
"version": "repo-lines-v1:sha256:2de1659a1cd439fdddc0fde0627bff47f0da238fee062b5b5083c23ea6955a0c:eyJzZWxlY3RlZExpbmVDb3VudCI6MTksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjJhNTU0NTJjMmJmOGMwMGM2ODZkYjliOGI3MWFmNjQyY2FmZDU1YjU2MDU1YmEzNzAzOWM3YmU0OTI1ODIxN2QiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImVmNjA3ODI4ZDQxZDU5YjhjM2Y0YmZmOWQ0ZWQyZDRkODYyMzRlOGZmOGE4M2U5OTQ4OGYyMjhjNWQzMzMzZWEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjhhN2EzNmI0MzA3YmM4MWYzZDA1ZmJiNDRjMTYzYzMxM2FjYjU0MTZjOWM0NDBjOGY4NTZlN2VjOThkZWJlZmMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjYzOTc2OWNhYTNkYWY3NDRhZmVkY2M1NzVkYTMwOWVjNDE2NDFkYTBlODhkYjA3NWU5YWJkMjM3NmY4ZmZiYWIifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_a3c1fca8143241f2ab151c4b45559643",
|
||||
"statement": "The client-side SSH session ceiling defaults to ten and normalizes to 1–100; each physical connection has independent FIFO admission, live decreases do not revoke active channels, and cancellation/close release queued waiters.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindDomain/Connections/SSHPreferences.swift#L3-L20",
|
||||
"version": "repo-lines-v1:sha256:ec7b5d0da945502b33cba69ca2f618ff127db15be6f264b2ede8cb9cd8d31b1a:eyJzZWxlY3RlZExpbmVDb3VudCI6MTgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImJhZDcwNjcwYjgxOTEwMGIzNjY2ZWFlMWY0ZmM2Y2ZiYThjZmUxN2U5NTkyZjU4ZjgzMjg1OTcwYjc2NDM5ZmEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjoyLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjExOGJmY2MwNWRhNWVkOWI1NWRjNTcyNWE0ZmNkYWVjNWMyNTc1ZmRmNGNlMjJhMTk5MDliMWIzZjRkZTgxZmQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHMaxSessionsPolicy.swift#L4-L200",
|
||||
"version": "repo-lines-v1:sha256:9bde4307dfcab74ede6fef3ec2144323e41540749c800efdcca35e183861894f:eyJzZWxlY3RlZExpbmVDb3VudCI6MTk3LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJjMmIxZDdhYzdhMGNlMjI0Y2UxZTE0YmE3NzBjODBmNTY1YTQ3OTY0Njk4NmI4MDRlZDljODZjMzIxYmVhOTdmIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJhNThkNGE5MTA3NDA1OWYwYzhkMjEzNmY5YmY4MDgzNDYxNDhmYzhjZmIzNTQzZGRjYmM3NTBlNzU3NmU3MjYzIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MCwiZm9sbG93aW5nQ29udGV4dEhhc2giOiJlM2IwYzQ0Mjk4ZmMxYzE0OWFmYmY0Yzg5OTZmYjkyNDI3YWU0MWU0NjQ5YjkzNGNhNDk1OTkxYjc4NTJiODU1In0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/SSHMaxSessionsPolicyTests.swift#L9-L113",
|
||||
"version": "repo-lines-v1:sha256:e71c6dd327ab111e02dfc19e5cd6314560c448912c0547a2824604478a3cbdec:eyJzZWxlY3RlZExpbmVDb3VudCI6MTA1LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI0Y2YwOWViMGM1NzQ0ZmI5NzMzMWI5OGZmM2ZiZjA1YTYwMmJhM2Y3ZjY3ZTVkYTViZTkwOTUwMzNmNjI1ODI1IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI2M2NlNzkwNmRkZGFkMDhhOGIxOTUwZjE3NzhiYmQzYTI2ZjRmMDYxN2NjMDgyMzU1MGVkMjJkNjY2NTIxNTUyIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiJjMjgxMTBmYjg2OTA3ZTQxYTM2OGI0YjE0OWY3Zjg1NjBjZmNkODc0MzZlODFiNzAyY2YxZmM3MDJlMzU0OGM4In0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_41393c68e500479bb8a34abce9cb38a1",
|
||||
"statement": "Exec acquires and revalidates its connection budget before creating command state; each command has isolated cwd/stdin/output state and a 1–900 second deadline created after channel admission.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHConnectionWorker.swift#L191-L245",
|
||||
"version": "repo-lines-v1:sha256:17e50375fb51e5ac8af62e6e6ac4bfdbbdc831225461b9215b0d08f015a08671:eyJzZWxlY3RlZExpbmVDb3VudCI6NTUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjY4NGY3ODAyMWM4ZmI1YmVjMjE3MDk5YWU1Yzk5MTRiYWEzYTE4YTc3N2VlN2I1YWFiZjQ4NTI0MzM2YmIyOTIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU2YjA0NDkxNDY5NzIyZTgzNjNhOTRlNDA0NDUzOGUwMTNhMmEyMTdlMzZiMWU1NjhiYTYwYWNiN2I0YzhmMmUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk5OWJkZWZlZWFjYTYzNDBlMDI5MGRjODZlODg5Yzg5ZDVlMTg5YWE1YmE0NGI1ODViM2I3MDczNGY0YTYyZDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImYzNjc3ZmM1NmU0NTcwMGFkM2YxZjRiMTUwZTJiNzhlYjdhZTFmYmVlMjk0ZDYxYWI1MjRjYzJjZDY0NjQ0ZTEifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHConnectionWorker.swift#L30-L86",
|
||||
"version": "repo-lines-v1:sha256:6c1ba9870985e8c9bba299071e2606e945e71a3282c6cbea88289129ae7887b7:eyJzZWxlY3RlZExpbmVDb3VudCI6NTcsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxODIzOGUwNmJkY2FhYzc5ZDM1ZTlmOTg1OWRkYTgzMDU0NGI3NzQ0OWExOWI1YTQ5MTk4NzE1MGVjY2I3NjciLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU2YjA0NDkxNDY5NzIyZTgzNjNhOTRlNDA0NDUzOGUwMTNhMmEyMTdlMzZiMWU1NjhiYTYwYWNiN2I0YzhmMmUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjY5MzJmNWU5NjVkMGFhZTNlNTlkYTJmOTg1YjY0MTRlZTQ4NTAzNjA3YWUxNTFlOWE2NmJhY2I2NjIwOGE1N2EiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImFiMmJlMzMzODVhNDk1NmZmMzM2Yzk2M2RmYWJhZjJmZjc5ZGMyNWI3OTlmMDM3YjliZDk5ZTViNjYzNzRkZmEifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_d04e37fdde2f4f209036467448f0a0e0",
|
||||
"statement": "Exec serializes pending channel opens and advances opening, startup, running, close and free phases in bounded ready-queue turns; socket events and a 100 ms timer wake work, and output limits count remote bytes independently per stream.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHConnectionWorker.swift#L268-L359",
|
||||
"version": "repo-lines-v1:sha256:bedfb2d2b36f4ef11bc9c348fc5d016b2ac53b17399f49d1f664f4bc850fbf54:eyJzZWxlY3RlZExpbmVDb3VudCI6OTIsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjkwZjIyZmNiMjA4MjEzNDM3ODYyZTNmNDlhMzM4YTgzY2I2NzY1NTkyNWY4NjRlYWY3ZTAzZGJmODBmODcxMDAiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk5OWJkZWZlZWFjYTYzNDBlMDI5MGRjODZlODg5Yzg5ZDVlMTg5YWE1YmE0NGI1ODViM2I3MDczNGY0YTYyZDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6Ijg0NzQxZjg5MDE5YWZmYmY2YTdhZDgyNjI4ZGQyYjI0MDQ3Mjg1NmU5ZmJkNGU1MmE1MzQzNTMxZWFiYWQ1YmQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHConnectionWorker.swift#L361-L594",
|
||||
"version": "repo-lines-v1:sha256:9195795410c2ff9123bb2d37564bc9070ffe88afda5010930d2e76b5f930f5c4:eyJzZWxlY3RlZExpbmVDb3VudCI6MjM0LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIyODJkMGI1OTQxMmI2MWM2ODQ2NTMwOGI0NmYzZGNiNGQwNDYwZmZjYjQyZDZiMTQ3MThmMzI3NmE3N2EzMjkxIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0NzIyMjJlNDY5MTI1ZDE4NmE3MDU0YWZkNWU2M2M3MmQ5YmUwNjE5ZWYxODBkZTI2ZjIzZmJkYTY0ZGYzY2M0IiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI0ZWM1MDQ0OGMyOTBlMTI4M2Q3NzM1MmU3ODg4NzkxZmE2MWYwMDcyZmQ4ZjQzZmMzYmUwM2VhMGZkYjg3ZDc5IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiJkZWNiMjcwNDZkMTczNDY5YjJiYzRjOTAxMzk1YmE5ZmFlYzRhNTI2NDZhYzQ1M2FjMmI2MzNiNjQzZTY4ODhlIn0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_f8c0a46577a6425297fa6d5f39de45c1",
|
||||
"statement": "Multiplexed SFTP serializes initialization, retains a session-channel lease per subsystem, performs bounded operations on the enclosing SSH queue, and asynchronously sleeps two milliseconds on EAGAIN rather than using the exec ready dictionary.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHMultiplexedSFTPChannelOwner.swift#L77-L213",
|
||||
"version": "repo-lines-v1:sha256:c49e91690e4a2f60a01b7fddcfc037638243470bc3b5830bc6615ebe87acbaf8:eyJzZWxlY3RlZExpbmVDb3VudCI6MTM3LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJmN2I5NjRhMzI1MmExNWU5ZmFkMDA0YzMzMTY5ZThhMDM0MWU2ZGRmZTY2ODQzN2M2ZmQ0MzJhZTQzOGEwOGM0IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI2MjRmYzIwYmRmNzE1MmRlYWRlMzU5M2U3M2YyMmI4NTJiMzQwODE1ZmQ2ZDhiMTlmMjE2OWUxNTk2ZDUzOGU5IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MCwiZm9sbG93aW5nQ29udGV4dEhhc2giOiJlM2IwYzQ0Mjk4ZmMxYzE0OWFmYmY0Yzg5OTZmYjkyNDI3YWU0MWU0NjQ5YjkzNGNhNDk1OTkxYjc4NTJiODU1In0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_4e9e5f3d7a614c90baf8b9bc6990e2de",
|
||||
"statement": "SFTPClient owns its primary channel and connection with a generation check, while SFTPChannel siblings reuse the same driver and channel disconnect does not itself close the underlying connection.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SFTPChannel.swift#L120-L160",
|
||||
"version": "repo-lines-v1:sha256:90b011ae02e3bee10bcf09a48d4f9819fcca02e9e11cbcf34e581456a40567ff:eyJzZWxlY3RlZExpbmVDb3VudCI6NDEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImFjMWVlZmFhYWRhNDYyNWFiN2IyZTQwNzk5YWQ2ZDRiY2YyZGE2OThhZjJkNjgwMTg2MjBhNTlmZmU1MDFmMGYiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjBjNzhlZGQ4OTljZjYzZTBiZTcyNjJmMzk3MjYxZTlkNjkyYjFiYWJmNzVmNjcwN2ZmZTE4YTMzOGE2MDhiZWYifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SFTPClient.swift#L339-L389",
|
||||
"version": "repo-lines-v1:sha256:92ce054ba0cac6bd0131387d6bdc854f0f3b544f12dfab215488a400e10280e8:eyJzZWxlY3RlZExpbmVDb3VudCI6NTEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU5NWUzNGNlMjIwYmQ4ZWVlOWIxZjg3NTNiZmIyMzkwYjRmODk2MjA0MjNiOTAwMWUyNjM3MTNhZmZiYWE5YWEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImMzOWU0MDJkMjEzYjIyYTdlMDhhN2M4YTEwODIxZDljMmUzZTA2ZTNjNzBkOGQ4YWE0MWM3NDNjNTI5ZWMyNzkiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjkzMWE0ZmExMDhlMmM3NGVmZjgzN2RhODlmMDcwZWI3YWY2MTcwMWI5MjU1NjQ4N2MzMjkxMThjZmNhMDZjNjcifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_9f238818cba048f9957d2c072a35e8f8",
|
||||
"statement": "Current I/O tuning uses a 256 KiB quantum/read allowance, two-millisecond slice and 2 MiB/1 MiB flow watermarks; immutable chunk storage preserves libssh2 retry pointers and vectored flush avoids coalescing.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHStreamPump.swift#L300-L417",
|
||||
"version": "repo-lines-v1:sha256:704ee736507518a694cd306166f32c5c6f35d75ea96ccf62eafe3efe0045b80f:eyJzZWxlY3RlZExpbmVDb3VudCI6MTE4LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI1Yjk4ODEzNTM2ZGVhY2Y4NDYxMDM0Yzg0NmMwMmM1ZjI0NTRhMjQ2NzQzNWJlZTZmYjQyNTI0MTNjNTc4MzU1IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiJhMmNlYjliODNiNjE4ZGEzNmIwZWUxYzNlMDAxMDM3NTBiMjBkYWYxODY0ZGFjYWQ3ZWJlYjEzNjRiMWIxYzU4IiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiIyNTdiZDUwYTljZDkxMDQ2NDA0NDc0YmZkNDRmNmY4ZTdiZDVmMzA2ZDg3NGMyODc2OGVhZGNlZGNkNGQzNTYyIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiJmNzk5MWYxYzhkNmFkODAzMzg5ZGQ2YTdlZTQzMGYxMThlYTcyM2I5YWVjMGNmOTMzODAyYTlhNTFmNGFjMTEwIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHStreamPump.swift#L6-L165",
|
||||
"version": "repo-lines-v1:sha256:9fa0f5c2789a7f740933d13ad1ad45bb27316ecf3c4558a77696962016aee953:eyJzZWxlY3RlZExpbmVDb3VudCI6MTYwLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJmNWU3MGRhMDMxNjdkYjk1NmU2ZGEwMDg3NmY4ZDFhOWRmNmM2MmJmODcwYTNjNzU2ZTdhNTc4MWFiYWQyMmY4IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiJhYWM2NWE5N2I4ZTY3YzdmYTViZWI2MTE3MDg1MmU2ZTdmY2MwNjM2ZGNkZTE2Nzc2ZGVmZGQ1NTcwZDk0ZjdlIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJjNDZmOGNkZDAwNDQ5ODFmZDcyNDdhMGM4OTMxNjgzNGQzZWRhYzllNTEwMDU4ZDRjMDRjYTNkZDg3M2MxYWE2IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIzODNiMzdkYjM1YWI4NzUyZDZmYWQ5ODU0ZGQxMjdmM2Q4Zjg1OWUyMjRlNmE5ZTJkMmIyMTdkZjdjNzYwNDhjIn0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_6a0ff558093440ecb7f6ba6a9d671aca",
|
||||
"statement": "SSHConnectionBuffer accepts full encrypted writes and queues unsent remainders to avoid the documented pinned-library forwarding confirmation retry problem, applies receive/pass backpressure, and makes disposal independent of peer I/O.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHConnectionBuffer.swift#L5-L117",
|
||||
"version": "repo-lines-v1:sha256:92f99457d411031a60a4f16c3c03b5a97af19b25644dd6f9bc937340cd4c1137:eyJzZWxlY3RlZExpbmVDb3VudCI6MTEzLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJmY2M5OWUyOTBkMTYxYjM4NDUzYWRjZDQwNDBjZmRkODI2ZmU5MTdkMzg5ZjljZGIzOTZiNjg4NjFlMDIxN2VkIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiIxNDg3MWFmOTQ4NWM4N2U4YzBjNGRjYTdiMmEyNzE4YjlmOWEyZjdkMTNkZWFjNWNjMmE2OWM4MjVlYWNlYmZkIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MCwiZm9sbG93aW5nQ29udGV4dEhhc2giOiJlM2IwYzQ0Mjk4ZmMxYzE0OWFmYmY0Yzg5OTZmYjkyNDI3YWU0MWU0NjQ5YjkzNGNhNDk1OTkxYjc4NTJiODU1In0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/SSHForwardingPumpTests.swift#L275-L315",
|
||||
"version": "repo-lines-v1:sha256:41bb566425d10190c8b15e32246dc1f40e0c12d9b3396e5f63f3b3281bcef92f:eyJzZWxlY3RlZExpbmVDb3VudCI6NDEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjBiZGMyN2M1OWUzNGVjNzY3MTNiYWM3YjNjNTNiODNjNjRiNDYyYTAzNjE0ZTI4MmQ0MGMxOWE4MzVjYzM3ODQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjZlOGI1YTBjMTc0ZGNhZjdhY2VkNGQwYTM1MGJhOTZlN2U4YTkwOTQ2MzJjNTBiZWUwYjM4ZjkzOTQ4M2RhNjUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_91f6aa7362ae47b3947fa5edd6e40b8e",
|
||||
"statement": "Socket event cancellation waits for both source cancel handlers before descriptor closure, and exec cleanup changes its generation, fails outstanding commands, closes SFTP and budget, and prevents stale scheduled work from reviving the transport.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHConnectionWorker.swift#L638-L681",
|
||||
"version": "repo-lines-v1:sha256:0830bd7a8c51bc71fc205a6939538d1ccf925d7ccd1f7a9235ae4073c87929d9:eyJzZWxlY3RlZExpbmVDb3VudCI6NDQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjE5ZWE4OGJkNDhjNTM5NjJjMWQ2NGFiMjg4NGE4MmMwY2U0Y2FiOTUzMDQ5MWJiZmQ3ZWZkYTkxMDFiNDA4MDEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjliNjczMDVhYWExZjMxZGMyNGE2YWZiNWI1MzM5Mzc4ZmM0ZDE3OTE4YmY3ODNjNTIyNTllNzU3NDkyMTI0OGQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHStreamPump.swift#L167-L213",
|
||||
"version": "repo-lines-v1:sha256:4040a667df1fe0285dd692a90a1ee046fdb545e2ebe3faf171cdd4609e696ef3:eyJzZWxlY3RlZExpbmVDb3VudCI6NDcsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQyYjNmMjk0NGJiOTU4OTUxNGY2MzA5YjRiYzlmOTEzMDMwYWIzMzZiN2Y5MjlhM2I3NzZmZmUwNjZiMjJkYWQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjYxMjUwYjdhMzFjNDRkM2Q4OTg4YWYxNGNlZDAxMDg1ZmU5YmM5NmM3MmY5YjJhZDFhNTBmYWE0MDQ0OTIzY2UiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjJjY2ZkOWRlMWU0YTgyZDJlNDNkNDNhMTQ3YmQxMjI3ZjJlODU4ZjIxZDkwOTAyMDM5MmFiNDM1YTNkMzA0MmMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjI5MDRiNWFhNDdiZTI5NTYyYTM3NmVhNGQ2Yjg5MDBjMjkyNThjNDFlMzFlYjYxYzE5M2M3MWMyYTNlNjJjZjkifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_1fd2c2f8970047b8bf324a93ca5f2650",
|
||||
"statement": "AgentConnectionPool reuses Host/fingerprint keyed connections and primary SFTP across runs, joins in-flight opens and protects active exec/SFTP leases from its default 180-second idle retirement; replacement exec retry is limited to connectionUnavailable.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift#L1051-L1093",
|
||||
"version": "repo-lines-v1:sha256:2f42e9d3dec1ae9ef7bebbca339793f38e26964a5da29fdac17952be06061ded:eyJzZWxlY3RlZExpbmVDb3VudCI6NDMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk0ZTQ2MDk3Yzg0MjkwZmY4YjdmOWNmOWUwMmYxMTRlZWU5N2VhYmM2MDZiZTdjZmJhMjI3ZjEzNjFhYzNiZjciLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImE0MGVhYTUxNDQzMTlkMjQ4ZmM1MGEyMGY3M2VmYmM4ZGIxZmQwYjIzZmRhNjVkYTM1MDU2YjhmM2I3YTNkNWYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImUxMDE0Mzc2ZTEyOWYzZjE2ZjM3ZWQ3ZDUxMTQ0YzY1YjAyYzlkMGViN2Y1MzNkNjg0NDZkOGI4N2Q4OTJhODIiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImE2OWMzZTIxNmM4N2M1YmU4MjdlNzM0M2IxZGEwNDM0MGY3NjMzMzJmYTc0ZTNjNzZkNWY4MDgwN2ZkNDRiODEifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift#L1318-L1432",
|
||||
"version": "repo-lines-v1:sha256:707e4db604c194ca27b91f7ad568cca6fc34450bb25dcc1a35ea700157cc5e6f:eyJzZWxlY3RlZExpbmVDb3VudCI6MTE1LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJiMjdlNTE3ZjU0YWJjYmJhZjMxMzRlZWE1YmZlYjQzNjBkYTQ3ZWIyN2Q2NWZjMWEzMGM5N2RlMWY1YmI1MjQ1IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJlMzIwZmNkZDBjNmFkNDQ0ZDIzM2Y3M2Q3ODIyMTY2MDcyZTEwYWJlOGZkZmRmNzgyYWNjMWVlODNmZjU2Y2Y1IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI2YTBmYmI0NWVjZWU3ZmMwMWY3NDZiZGU2ODJlMTE0YjkyYzU1OTlkZDllMDUxNmQyMmQzYzMyNWVkMDM3NDZmIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift#L1469-L1584",
|
||||
"version": "repo-lines-v1:sha256:aba7ec5c1e1cccd658c5215426672c337e11ebdcdc7d2878000d06641ed5a32f:eyJzZWxlY3RlZExpbmVDb3VudCI6MTE2LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIzOTA2Y2EyOWJlYzI3YTBkMzUxYjRlY2RlYzE4NGFkMjZmNzgzOTgzNDFiMmIzODljYTM1MTM3MGEwM2QyNzRkIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiIxNTA1OTA1MDFhOGI1YWM0OWJiZDk3OTc2Y2UyZGE5NTA0YTQ0MzcxNmZjYzY4M2E5ZTRkN2M0MmRmOWRhODE5IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIwOTIwZjM4ZTMwOGI1NDBkZDU2YzQxZDUyN2NkNjQyYTZkNmQyOTNhZTNmMzkyNGY4NGVlNjNkZTUxZWQyYzBkIn0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_7123bf788f2743a8a7913ca5b49918fe",
|
||||
"statement": "SSHExclusiveConnectionAdapter serializes complete operations on one owned connection and has no topology or fallback selection policy.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHExclusiveConnectionAdapter.swift#L3-L36",
|
||||
"version": "repo-lines-v1:sha256:ef2acbffed6b7a7fd6955d7fa3a6f0c7c93e6cca2ed82d431dbc1a64ff794d6d:eyJzZWxlY3RlZExpbmVDb3VudCI6MzQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk0OWUxM2UyOGRlY2Q3Y2U5NDdmMjMzNzM5NGQ2MWQ5Y2I1MGIzZGI1OGJlYjUzM2M1Zjg1NjVmNGUwNzdiYzIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjoyLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjExOGJmY2MwNWRhNWVkOWI1NWRjNTcyNWE0ZmNkYWVjNWMyNTc1ZmRmNGNlMjJhMTk5MDliMWIzZjRkZTgxZmQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T02:43:23.140Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:d4f1f7d73a06d827f38ce7288a9b41c230491a7091ac8cc51be5f45c67272655",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_3a403468456840acbfe0a524b90d5717",
|
||||
"statement": "TermindPresentation contains reusable SwiftUI form and presentation types, while ArchitectureBoundaryTests forbids app, AppKit/UIKit, storage and RemoteInfrastructure imports there and separately restricts ListViewKit to approved native-list workloads.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindPresentation/HostConnectionFields.swift#L1-L111",
|
||||
"version": "repo-lines-v1:sha256:cfc4b5c8a77e75a4ebb7d6dff1d9dbc696b1f54b5191c44f27ec387a151614b6:eyJzZWxlY3RlZExpbmVDb3VudCI6MTExLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI5ZThiYWYzZWNjYWU4YmFhMzJlODZlNDBmOTIxZDI2YTEzMGJhNzRjMjNmMDIxOWE3ZDI2ZWRmNzdjMmQ1YWEwIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MCwicHJlY2VkaW5nQ29udGV4dEhhc2giOiJlM2IwYzQ0Mjk4ZmMxYzE0OWFmYmY0Yzg5OTZmYjkyNDI3YWU0MWU0NjQ5YjkzNGNhNDk1OTkxYjc4NTJiODU1IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MCwiZm9sbG93aW5nQ29udGV4dEhhc2giOiJlM2IwYzQ0Mjk4ZmMxYzE0OWFmYmY0Yzg5OTZmYjkyNDI3YWU0MWU0NjQ5YjkzNGNhNDk1OTkxYjc4NTJiODU1In0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/ArchitectureBoundaryTests.swift#L109-L136",
|
||||
"version": "repo-lines-v1:sha256:b450e65c0342f68e65c8a351124b15b9007545d00dc02109ed5fe96e7c557c7b:eyJzZWxlY3RlZExpbmVDb3VudCI6MjgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjhjOGQ4ODMzMDg3NGVkMGZhMzg1NTE5YTJkMjRiNjUyNTUyMjM3ZjBmNmIyYzhkMzAzNzY5ZTQ5Mjk0OWVmZmEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImU4ZWFmM2UxZGIyODRmNmE2ZmQ0ZTA2NmFlMmZiNjU0YWU2OGZkZmNmM2U3ZTRkY2E0YzJkZDIxNGE0OWI5ZDAiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjE5NjRiODI3ZGRhNjlhZDUzYmU4NzU4ZTNmYTBkOTc0NzU5YzFlM2Q2OTgyNGY3NzI1NmZmOGVlNDA0YTA1Y2UifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/ArchitectureBoundaryTests.swift#L164-L189",
|
||||
"version": "repo-lines-v1:sha256:6c4d5d5c4c175c000011e3bd3f9bdf066ac2595cafd11058e3f0ea3bb1fda5ec:eyJzZWxlY3RlZExpbmVDb3VudCI6MjYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk3OTk5ZWY4ZDk0Y2NkYzU3ZmJhZDE1NzllYmJkZTM4YjIwYTUyNDk0ZGMyYWYxNGFiZGU2MjY5NmJiMTMwOGUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImU4ZWFmM2UxZGIyODRmNmE2ZmQ0ZTA2NmFlMmZiNjU0YWU2OGZkZmNmM2U3ZTRkY2E0YzJkZDIxNGE0OWI5ZDAiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjQ3NDI5ODQ5YmU0MTZhMzMzMmY5NTcyYmY1NTM5ZDkzOTZjNDEzMjY1MWE4MzhiZGRhZGIzN2IwNzg1OWViMmUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_949c855ac8d84a1c81dd9481a84d5007",
|
||||
"statement": "TFM centralizes desktop geometry in Metrics, including shared sidebar sizing and row rhythm, separate split-divider visual/hit dimensions, card ranges and a common 840-point full-Assistant reading width.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/Design/DesignTokens.swift#L168-L179",
|
||||
"version": "repo-lines-v1:sha256:00748df99bec6a04a12573576bcdbb1c2a9f1cb812c81e6a9b461e3dfa77c12d:eyJzZWxlY3RlZExpbmVDb3VudCI6MTIsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImY0NDkzM2JlYmY3OGIxOGFkNjc4Mjk0MzM1NjdjYzk4MWNlYjdiM2FlOGIyZTRlNjA5NjRlOWYwNDQ4MjJmNTUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjFjOGI4MWY5MzU3ZjU0NmYxZjVlZmEzZmViNTQxYWQ4ZTA4OWE5MGVmYTMwMzdhNmQ5MWNkZDRhOTAwMzU2YzQiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImEyODM3NzA4NjE2ZWJjZmY0MjYwYzJlNmZmOWZlZjUyNzEyMDVkOTNiNDBiN2NlYzFlZGUzYTQwOTY1Y2IzMjQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjFiMjNlYzc0NGZhMDQ5MWVkYmI3ZWUyMjQ4MjI4NzFjZWY1MmYzZTI4ZTBlY2YxODY2MjEzZWE3N2M1ZjEyZGQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Design/DesignTokens.swift#L302-L312",
|
||||
"version": "repo-lines-v1:sha256:24e6281c6bff443f5a1a314ebe09628eceb68032e8dae543429faf6b76506c55:eyJzZWxlY3RlZExpbmVDb3VudCI6MTEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjY1ZDA2ZmRhNDMyNjhhNzc4NDIwNGY4NDE0ZjUyMjM1NTM4YmU2MDIyZGQyOThkMmNlZTlkNDIxNTNkM2Y4ZDEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjlkZTUwZjVjMjkxZTYxMjMwMzU3ZDAwN2E1YWY3MjRmMTI3MTgzMjllN2RmNjliNjYyNzMxNmU5NmE0NDU3OGIiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk1MTg1YmJlODI3OTY5MGQ5NGYxYjExY2NiYTg3YmYwNWFhNmI3MGFiYzVhOWY3MmRkZWM5MTgyZTM2ZTAzMWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjljNzlhZjE0MTMyZWU1ZjIzMjgyNGVhOWIwZmQxOWJmMTdiMTllY2U4NTI1OTc2NzAwY2YyZTcxMjA2ZjMwNzUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Design/DesignTokens.swift#L5-L114",
|
||||
"version": "repo-lines-v1:sha256:a2b8ffb151b0ae2c147e0ba830f51fdf75d976483f2e0356f47763943546ad5a:eyJzZWxlY3RlZExpbmVDb3VudCI6MTEwLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJmZTFlYzhjMjc2ZGIxNjMwNjM2ODQ5NWU1MTFlODkyZmIwMmNjOWJmYWYwZDRiY2ViMjBlNGEyOTczMzc4MTk5IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI4NjUyNGEwOTk4YjE1Y2U1MGNhZTMzODgwYmI3NmRkOTIxMjU3ZjQ2NGRmYmYwYTMzMWRjMTczMWE5YTJjNTYyIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJhN2ZmMmI3MTBlMTM0NjVhM2ZlNTIxNjMwNWI5MzgyMWQ2ZDMzZjUyZmUyOTUwYzM3YWM4MGIyZThkMmQwMGMwIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIxYjY3NTZkZjg0ZjNhNzRhNWVlMDFiYzZkMTQwZmU1ZjkyZTUxNTU3NTdlNGE2ZTliZmUyNWQ3MzcwMGQ0NTIxIn0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_3f5b9e81f75049609142a3429f5255cb",
|
||||
"statement": "TFM uses semantic AppKit-backed color roles and appearance-resolved native colors; actual sidebar selection distinguishes key and inactive windows while generic Highlight uses a quiet accent wash.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFM/Design/DesignTokens.swift#L320-L395",
|
||||
"version": "repo-lines-v1:sha256:97cf99d4e0f76ce0d1ca96dd7e8ad269e9879b9b2f7bb1374c797bae6cddd789:eyJzZWxlY3RlZExpbmVDb3VudCI6NzYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjIzN2U0NzhkZjRjYTk2YmU0NWVlNTIzZDBkODg2MjhjOGU5MzE4ZmJmMWMyMzNhNzQyNjhhY2E4MGJhZTJhMDkiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImIzYjg0MTY2NGUxYTA4MTE5MTQyZTcxNTVjMGFjOGIyZmQ1MDA0NTdjYzcyMjExYjM4YTM5ODE5MDRkMzBjOGMifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Design/DesignTokens.swift#L482-L574",
|
||||
"version": "repo-lines-v1:sha256:4432b9753f4552d16c407fcecdefa6ef80687c033011ae52cb7707be6f67e2ce:eyJzZWxlY3RlZExpbmVDb3VudCI6OTMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjI3N2FiMjhiODUxODE0MmY1ZTI1YWU3ZWFlOWJlZDVmZDg3ZGU3MmM3OTZmNGI2ZjYxYzA5YTI2NDNhYWUxNGMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjBjMTMzMmE0YmFmNjc1NzQ3YTM1NjcxOGZiZmQ2ZTRlNGQyY2Y0ZDQ0ZmQ4NDliMDEwODBlZTcxYjg1ZDMzZjMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjE4OTI1ZThiNTI3MmJiMGZmNTQ2YzhmNGMyZjgzNjM5MTRjNjZiOGU3ZTM1NTJhMzRjMzk1YjVkMWJmNDgzZjEifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_9b8f98f539cc4266bb6731b13b191bab",
|
||||
"statement": "TFM uses system glass on macOS 26 with native material fallbacks, while mobile cards use glass conditionally with dense-text backing and opaque/stronger-border fallbacks for transparency or contrast accessibility settings.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/UI/Managed/MobileCards.swift#L59-L109",
|
||||
"version": "repo-lines-v1:sha256:2e0914d2ce2a68e255ad11b2db9afb74cedb5cfad807d3a4122d138bad3b62e9:eyJzZWxlY3RlZExpbmVDb3VudCI6NTEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImI0NTkwNDRkNjNmYzg4MGVlMDRhM2RhNTJlMjRkM2UyODM2Mjg3NzkwMzI4MzUzYjQ4NDJmNTcxODI4MGNjOTIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjhlNjAyMGUyNjc2OWE3MjVhMjg4YmY2MmI1YzY5Nzc3ZTUzM2M3N2Q4NDg4ZTE1ODZlNzY1NzY1YTNjMTBmZGYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjUyY2IyY2M5MzZlNjA0ZGM4NDFhN2I5M2MwMWE5YTRiYWY3ZjMwNzg0M2FmYzIzMDMxMDEzOTkyNDc5ODk2MTQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjhmNjNhOWYxYzdmMmY1MWRhZjQ2Y2RhYWIxOWVlZGEyODI0ZGQxMzlkZjc2ZDZkZWY3MWQ3ZTlkNjg0OTc2NWUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Design/DesignTokens.swift#L397-L480",
|
||||
"version": "repo-lines-v1:sha256:111f22df63028d345b5a301a2b9f8f0a97b4dd313819bd76a9f079c25758133f:eyJzZWxlY3RlZExpbmVDb3VudCI6ODQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjMwNjk0ZTI5NzY5ZTg0YTk4ZjI3OWNjMmMzNmRlYjBkZDA5YzQyNDQxMzJlNzMyYzNkYTE1MWU0YzhlMDJlZWEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjU5NThhZWMxMGMyMDdjMmZmOTQ5ZDI0MmE5OTllMTQ0YzIyYTQzNGFkYjAzM2U1NTdiNGFkOTAyZTllMTBlNGYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImIxZjFhYmY3MWE5NDBkOTM4YjJlOGUxZTRkMzJkMmI4MTU1M2I1OWFiOTk5YjBmZmM0Nzc0MWNmNjNmZTgyNDYifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_494e99b603c543258ff256960ea0f999",
|
||||
"statement": "Mobile cards use width-derived columns with accessibility sizes forcing one column, a 106-point minimum height and at most two visible tags; primary card taps and secondary context-menu actions differ from desktop managed selection/reordering machinery.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/Design/MobileDesignTokens.swift#L3-L16",
|
||||
"version": "repo-lines-v1:sha256:9942ca35a253f97eef9813e34a3351e94136b20663ae8bff5329a07bef6515d8:eyJzZWxlY3RlZExpbmVDb3VudCI6MTQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijc2M2E0MDYxMjcxNjkxZGY5ZTZlNzNhNDc2ZjY2MGZiNDAzZmE3OGYwNDBjNDVjZTBhMmUzM2ViZmFlYmNlMjciLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjoyLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjBmODVkNWEwZjU0NTg4ZWEyNzdkOTIyZjAwMzZjOGFiYjMxNDg0YzQ4Y2UwNzY0MjZjMjdjMTA5NWVmZDE4OTYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/UI/Managed/MobileCards.swift#L111-L158",
|
||||
"version": "repo-lines-v1:sha256:eb7fba14c77fb4a3c68f08d65675e9b0e3292b74398c9f092e4dda1ba6eab046:eyJzZWxlY3RlZExpbmVDb3VudCI6NDgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjA2N2VhNDZhMDhiYmUzNWRhYmZlZDVlMDA1YjhlNTE4MzZmMjg2NThhYThhOWMzYzkwY2Y0ZmY3ODVlNjljNjUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjNlZjNjYmZhZWE4ZTAzYzgzYjJmYzIyNzJmOWMwMWE1Y2Q1YzdlZTkwZmFjMzk0YzM4MjRiZDZiODQ4YmRkN2EifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/UI/Managed/ManagedCardPage.swift#L17-L62",
|
||||
"version": "repo-lines-v1:sha256:4ea92db8be32326fcb3251c661ed832a845356120d5a5c42605eb2fb77a45ee3:eyJzZWxlY3RlZExpbmVDb3VudCI6NDYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjE1NzhhOWMzMTI0YTkwNTcwOTkzOWJkZTkzNDU0OTNlZmYyMjgwNTNiNmM2ZDEyZGZmMWI1YmIyYzc3MTQyYmIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjdjOGJiOGYwZWZiMjkyYWU0MzEyZTlmY2E4MGRhMzkyYTk2Y2E3ZGM5MjdjYjc2NjNkYzA0OWM2ZmYyZWQ1ZTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImI5ZDliZWQ0MzJjOGY0ZmMxN2Y0YzRmYjI3OWI2OWU2NGM4MTBiZjRkNWIzZWMyNTc5YWJiNDFhZjE5NzNjNzUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImYwOWNlZmI0ZjNmOGU4ODIwNmEyNjhhNTEwZTQ4OGVlZTE2YjRlOTcxMjVkMzNjNmE2ZTNhMDZiZGY5NjM5ZmQifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_46e2a269c939465d9438906f630d5ee3",
|
||||
"statement": "Shared Host organization/profile/connection fields bind to each platform's local draft; desktop nested edits stay in the Vault work column while mobile uses an editor sheet with its own dirty-state, validity and save policy.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindPresentation/HostConnectionFields.swift#L6-L111",
|
||||
"version": "repo-lines-v1:sha256:21e2c33e64294fedef351ebc371d67340cab0362a768accf66778255d01645fb:eyJzZWxlY3RlZExpbmVDb3VudCI6MTA2LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJkZGRiMTRiMzgzMzAzNjRhZDk3YmViODY5NWVmYzMyYTFjMjkwZmUyYzk3Y2EwNjAxZmYzY2QzNzhjYTVmMTI5IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJjZGEzMTJmZTE1NTcwNDM5MzM0YmM5MDBkYjQ0Mjk1MzYyZjM4OWY1YzZlZDhlNDE1YjgyMmMwZjdmMDQyYzQ4IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MCwiZm9sbG93aW5nQ29udGV4dEhhc2giOiJlM2IwYzQ0Mjk4ZmMxYzE0OWFmYmY0Yzg5OTZmYjkyNDI3YWU0MWU0NjQ5YjkzNGNhNDk1OTkxYjc4NTJiODU1In0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/Features/HostEditor/MobileHostEditor.swift#L27-L79",
|
||||
"version": "repo-lines-v1:sha256:989c495bfd26d21f97f26434e923b8a5d77420e8b42a8e631b0c6d640d69fea6:eyJzZWxlY3RlZExpbmVDb3VudCI6NTMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImZlMzA0ODhhNDJjZmI4Y2M1YTgzMjM2YjRjNmM0YmE4NTg3YTY1ZDlmNWZhNDUyZGE4ZjY2MzhkMjhjNDZlYmQiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjBkNmFlZmJiYzE2NGE0NjBmMTYyMDM3M2FmODUzYWI0Y2I3ODUwNTk3YjY5Y2UxNWQ0NGI1NjI4NjdjNDhmMGEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjAxZGQ3YmJmYzM4MTU4YTI1YWNiMmUzMWU5NWZjYjdkYjFlMDRiYTA4ODg3ZDBhZWM2ODVkMzNhNDQ2Y2E0OWQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImM2YWU5ZDE5OTIwZjMyYWQ5Yjk0ZWI3ZmYzNDk4ZWM5ZWY4ODBlMDEwYjZkNWUyZDgxNGQ5ZWQ0NmNiZTdmN2MifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/HostEditor/HostEditorView.swift#L8-L100",
|
||||
"version": "repo-lines-v1:sha256:61f6f4836f9c752b4a98127700de4b5e4e05c6af251cf6e19c01b00df95fdef4:eyJzZWxlY3RlZExpbmVDb3VudCI6OTMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk3Y2Q5ODQ4ZjJkY2Y0M2VjZmQ0MGVlODYxZDNjZTI1OWU5NjQxMDAxZDdlNjIwNDk2N2YwMzE0MDY2NTY2NDciLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjA4ODc1MTVlMzgwNGJlM2RiZGU3YjIzNmNiMWE2N2ZhODg3MTNkYWMyNTM3OGU4NjcwN2YyNGVmMDg1MDQ0NzQiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImNkYTMxMmZlMTU1NzA0MzkzMzRiYzkwMGRiNDQyOTUzNjJmMzg5ZjVjNmVkOGU0MTViODIyYzBmN2YwNDJjNDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjJjNTM0OGE3MjlmMjNmOGM1MTFlZjEzYWI4NTk4YjhjMWZmYmYzOTY4MDhlNjk4YWEzOTFkOThlYmUyMDQ3OGMifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_38752b62285c4c8186145966dbbbed45",
|
||||
"statement": "SingleLineTextInput normalizes newline runs only for user edits and preserves attributed paste content, leaving reads unchanged; native input/paste is delegated through app-supplied environment adapters rather than shared platform imports.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindPresentation/SingleLineTextInput.swift#L5-L104",
|
||||
"version": "repo-lines-v1:sha256:8517518712e3e7fe5c1b6326720f846ac4df92f98c70eb6224989c871c0e1418:eyJzZWxlY3RlZExpbmVDb3VudCI6MTAwLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIwZDJkYWYxZGFlYjZiOGI1M2YxY2UyYTkyNDRlM2MyNWFmNWJkYzg2YjI5MzAzZmEyNDlhMjQ2NzhjMGY0YTk4IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI4M2U3NzA5NTNlOGQ2MWYxOTRlYjMwZWM3ZWFhZDFlMTVmMzRkODdlODY1NzhlNWI0NzBkYWI1NTQyOGVlNGI3IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MCwiZm9sbG93aW5nQ29udGV4dEhhc2giOiJlM2IwYzQ0Mjk4ZmMxYzE0OWFmYmY0Yzg5OTZmYjkyNDI3YWU0MWU0NjQ5YjkzNGNhNDk1OTkxYjc4NTJiODU1In0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileRootView.swift#L38-L40",
|
||||
"version": "repo-lines-v1:sha256:fe4f7b76d0e828b3efcc1149610d9473ee75c37dea844773edbdf38fb6d2563e:eyJzZWxlY3RlZExpbmVDb3VudCI6MywiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiZTZiMDQ0OTE0Njk3MjJlODM2M2E5NGU0MDQ0NTM4ZTAxM2EyYTIxN2UzNmIxZTU2OGJhNjBhY2I3YjRjOGYyZSIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiNzgwYzY5NjJiZjlkODdlYWUzZDM0NmJhYTU0Y2ViYmQ5NzlmMGE3ZGM2YjFhZTAyOTlkNmQ1OWQ3M2NjNmFiMSIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiNTRkODU5NmJlODAxOGIyOWMxZTBkMDQxMTlkYThkMTczMmFiNjIwOTc1NzE2YTUxYTNhZTMyYjVlYmE0NjFmNCIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiMGZhYmFlYmY0MDQxZDI1MDBjZTYwNmQ2YWVmMjQ0N2JlMWIyODcxYjIyZDk2MTE4YWFjYTFhYjAyOTMwZTQzYSJ9"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/App/RootView.swift#L66-L68",
|
||||
"version": "repo-lines-v1:sha256:4c425dd1303db02793b86c9cf49c3ff74ea15c6f905acb57242c21e45ed558cf:eyJzZWxlY3RlZExpbmVDb3VudCI6MywiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiNjkwMWRkMzc2NTZjOTYxNjhjOTZlNTFjMzI1NmIwN2FlYjFkZTQ3NjRjOTg3ZWM2ZDdlOGZlNWMyZDQ1Y2NmNiIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiMzY0YTcyMWU0YzgxOWYwODVmZjBjYjBhZWQ2ODZiODI0ZjUyZmE4YzkzMDg5ZjZhYzE5NTlmMDExYmU1NmIxZiIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiY2U3MTQzMWY0Yzk3OGI5ZTZmNDg5MmIzYmM3ZGJkZjg1N2NmMzBhN2IzMGQ2ZDBjNjVmM2JkMTkyNDhiOGQ2NyIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiNDg1NDM5ZDQyZGZkODdiOThjOTVlMTdlMDhjMTJiMTU1MDgwMjQ5Nzg1MjdjNGZjZDQ4OWM2OWYyYjBmNjQ1ZSJ9"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_51d61d1df79b4e9786c0e1d36ae234a5",
|
||||
"statement": "AssistantTranscriptEntry shares stable timeline-derived typed rows and caller-supplied edit/fork eligibility, while desktop cached native ownership and mobile native-list environment/update handling remain distinct platform concerns.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindPresentation/AssistantTranscriptEntry.swift#L5-L87",
|
||||
"version": "repo-lines-v1:sha256:9b4a8fdb54d6eafc5aedfdaccbb5be8f4ae8d0761ec05b8381b1b04ca7f7fb9f:eyJzZWxlY3RlZExpbmVDb3VudCI6ODMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjM1ZDlkYTI3OWI1Zjc5NWFjZmIxNTBkNmM0MDc4MzQ2ZTcyZThmMTZhMjc3MTZhYTJhMjg5YmEyYWUyNzY3OGMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjAxYmE0NzE5YzgwYjZmZTkxMWIwOTFhN2MwNTEyNGI2NGVlZWNlOTY0ZTA5YzA1OGVmOGY5ODA1ZGFjYTU0NmIiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImM0NmY4Y2RkMDA0NDk4MWZkNzI0N2EwYzg5MzE2ODM0ZDNlZGFjOWU1MTAwNThkNGMwNGNhM2RkODczYzFhYTYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImNlZDIyNWJjNzhkY2E1ZjNiYTNjOTMyZGEzMWE2NWUwYmE3YzYyMmYzNWQwNDE3MTgxMWI5YmNmY2NlOTAzNWEifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/UI/Components/MobileNativeList.swift#L52-L145",
|
||||
"version": "repo-lines-v1:sha256:63db98221e62b57b881f9c96d8653b3d12820558c7f274af15646856a21cab77:eyJzZWxlY3RlZExpbmVDb3VudCI6OTQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImFlYjVhMWRiNDZmZGU1ZmU4ZmZlOTA3Zjk0ZmUyOWQwZTFkNjVhY2QxNzFmYjFhY2UyNzY5OGIxMDI1MmUzYTgiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjIwOGMyNDViOTNmMGI2YWU5YTg3ODZlNGQ1YjdlNmQ4YzBjYTYyYWMyMGQ1NmE3NDkyN2FhMzNmMzNkNzQ5MzQiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6Ijc2ZTQ1NDkxY2E2ZTZlYmUwOGI3YWFiYjI0ZjkwNGM1ZDVmNWRmYThmZGFkYjMyMzllNzAxM2ZkNWY0YjkyYmQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/AI/TranscriptListView.swift#L113-L155",
|
||||
"version": "repo-lines-v1:sha256:b0a2bbea3a31751d53d263fce80b4747b349be8806a0ef7029d69b94ef991c5b:eyJzZWxlY3RlZExpbmVDb3VudCI6NDMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjUyOTIzMzk5NzVlNWVkZTE3NjkzMjlmOGFhY2I0YTJkODRjOWQzODkzNzFiYzljM2U4OTE5NTQ3NGJmODE0Y2UiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImIwOGY1NDk4YTdjNzIyZmEzNzgxMmIyNGU3ODNiNTQ2MzlhYjIwYzcyZGU3MzliM2U3N2VmMmI0N2JjOTI4NGYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjU4MzUxNzM0YWU0ZjMxODBiNGM5ZTNmOWYxZjJhYWUyNmRlMDZlZDBmZGMxOWU2ZDhiMDNlYTkwNjJkYWViZWMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjUzNjM2YTE3MTJlNGZmZjcxMjVhZTBmMmQ2YTRjNDI4ZDRmNTlkMjNmMjFkNzk4MWJjNWVlNzY4N2U3ZDFiZWQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/AI/TranscriptListView.swift#L229-L301",
|
||||
"version": "repo-lines-v1:sha256:0305ac87dfcc366416168b342052bc94ebb9fccda4f3361f7b6fb712be588452:eyJzZWxlY3RlZExpbmVDb3VudCI6NzMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjJkMzQ4OThiZDNmY2JmNTVlNDViMGYzNjQ0NmZkZmJkY2UzZmY1YzM5YzBiYjBhZTY5OGUzMWY4OThmODA4YWYiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjgyMjU3YjhmODJhNGMzZmVjOTM1NTUxZGI3YzBjYmEzZTZkNTFlYzhhYzQ4ZjgwYWRhOGYxYjM0ZDU3YWRiZTUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImRhMTc1YTAxMTVjOTI2MzIwOTlmZDNhZTYwNWUwYTdkZDlkOWI5MWI1ZWJmOTY2OWFhOTg4Y2JiNGZkZmY4M2UiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjA2NzUyNTAxOWE1ODYyMzQ3YmY5OWNmNWIyNTM1NTNiODJlMGExNTU3ODkwMDNkODAzZTlkZmY2OGEzZDhhMTYifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_fb4ec4cb422d4bf794c41c6a8a163ef0",
|
||||
"statement": "UI visibility gates also control interaction/accessibility, motion helpers expose Reduce Motion policy, and adaptive tests cover language variants, native identity, focus and marked-text preservation rather than only final strings.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/Features/AI/MobileAssistantConversation.swift#L470-L510",
|
||||
"version": "repo-lines-v1:sha256:e9b974874173a4ff5d1e7e2d6317dbd3b20b189c7b9f5bbc73c075866c59cdb0:eyJzZWxlY3RlZExpbmVDb3VudCI6NDEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijc1OTA0ODUyMzg4MjVlMWRlYTYyMjQxNmU1M2Y4ZGFiOWVkODQ0NTAxMDc4Yzg2MmRiMjU2OTAzNTY5YmNhNjEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImVkZWFkMDAzZDlhN2U2MzkzYzkxZmI0MDM5NjNhOGNmMzIxYWZkMThkNGQ3ODYxYmEyNTIzNGEyMmViNjJmYWEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk0ZTFlNWJhMDRiZDMwZjMwMDA3ZjY1MTJkNWM2MzRhOGNiMDRjMzJiYzFkM2EyYTY3ODM0YjY5ZTJiY2Q5NGEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjNhNjM3ZmU5YWQyZjE1YWNlNjQzOWE0OWUwMWRmYjI2M2M2ZDkwM2VjMjVjZjlmYmM3ZGJlYzExOWZjZjNjNDIifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFITests/MobileAdaptiveLayoutTests.swift#L75-L180",
|
||||
"version": "repo-lines-v1:sha256:7029c2d16c93e885407ee0ac5dcf872a2cf816cf64cf5a6e1c2f1468bc6a7609:eyJzZWxlY3RlZExpbmVDb3VudCI6MTA2LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIwMWJhNDcxOWM4MGI2ZmU5MTFiMDkxYTdjMDUxMjRiNjRlZWVjZTk2NGUwOWMwNThlZjhmOTgwNWRhY2E1NDZiIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiJhMGE4ODZkMjJlMjhmYThjZmFkMzg2ZTUzMzlmN2JhNGFmNDEzM2U4NGRmMjU5YTYwNTNjNjJiMzI4ZjQ2Y2U3IiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI5M2IxZTE2YzVlMWYyNGI4Njc3YzQzYjI2ZmYyMGI3ZDM3MGE2OGIyMWIwY2ZlZTA3NmQ4OWNlNmNjYmEwMmFmIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiJjMTNhOTQ2OThjNjNhZjM5MmJkMWI0YTZkZWIwZWI5ZjdmYzFlNWVjZTQ0MGM1OTU3MTdkYmEyYjM2ZGJjYTU4In0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/App/RootView.swift#L342-L351",
|
||||
"version": "repo-lines-v1:sha256:f3e76fe3409f2b446bae7dbcf097ec6627a488879b512df98b753d5f8a05e16f:eyJzZWxlY3RlZExpbmVDb3VudCI6MTAsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImZiZmVmODg3ZmEzNjEwYjA4MDVkN2ZiNTA5Yjk0MjU5OGQ1ZDgyOGU5YmNhMTlhNjM0OWJiMDU4NzcwMzhhOTEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjI2ZmI3ZDYyZTU5NjIxZGEwOGZkN2U4NzViYWRjNjg3MTNiMzk4NWE2OTcwYjgyMTRmNzg5NGY2NmU1MzY0Y2UiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjIxMTI0NDU4ZWE1NjRkODI3NTg3MGQyYzFhMDcwZDU4Yjc1ZGJiZTZhZjNlNWE1MWU4ZDgxNWZjYTgwZDhjZjUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6Ijc2ZGJlYTRiYmU0MzNiZGU5ZjY1YzBjMjQ2Njg0NmRkZWNlMjMxMzJlN2YzZmExN2FlNzU4NjExZmVkMWZiN2UifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Design/DesignTokens.swift#L641-L653",
|
||||
"version": "repo-lines-v1:sha256:3c988e344958aba4985f21b1d058cef3c1c62f7b0d8e078f055b7b91a6c20a3a:eyJzZWxlY3RlZExpbmVDb3VudCI6MTMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjJhYWZlZTk3ZDM5ODNhYzRhOWFiYjVhNzBkZmI3YzllODY3YjE1ZjU1ZDY0ZTI3Y2FhYTljMTA2Zjc5NDhlMDAiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImIzOTI4OTA5ZjJkODYyNTA4NDg0NWZhNmU2MGMwMmM4OGEyMDY5NTQ2NTJhYTExYThiNTczMWZmMGQ4YmI3YTAiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/ResponsivePageLayoutTests.swift#L11-L69",
|
||||
"version": "repo-lines-v1:sha256:21aa196f63070d976f1462a407de54fc4c7cb135aa5aabebe918aa91c2962e26:eyJzZWxlY3RlZExpbmVDb3VudCI6NTksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjA1OWI2ZGY2ODMxMDQ4MTkwNmYyODFkMjIxYjIwZDcwM2ZiNGQxYzZjMjBmNTRiMjg4Mjg3YWFlYmFhZTljNDYiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImY1YmVhYzE3ZGYxOWYxNDNiZDkzMTkxZTQxZGJmY2FmODNjZDdmZTIyNDhhYjAxNDRkODYyZGUwOTE2ZGUyMGUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImQzMDdkZjlkOWY5NjA4ZDE4NjQ2NTc4N2JlYWUwNDc1YTQzMWFkNjcyNTU0NDgwMjc0OTI4ZjRiMWY1MzJjYjIifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_1b33e13826ae471f9fd6980368bae792",
|
||||
"statement": "Continuity uses different retention budgets: desktop parked workspace geometry, an unmounted-owner transcript LRU, mobile app-owned workspaces with background-expiration policy, and stable children in adaptive mobile region layouts.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileAppModel.swift#L491-L523",
|
||||
"version": "repo-lines-v1:sha256:3e5f5ee2eaa48a81fe415e9bb3d77294bdb003e45542404a755bb1e569796e90:eyJzZWxlY3RlZExpbmVDb3VudCI6MzMsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjExYjYwOWM3ODJiMmM2NDVhM2M2ZDFmOWMyMDA3YzdjMGVlMWI5MTI1YjJjOGIxOTU0YTFlMTVjY2UxM2VkYjMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjExMGVhYzUyYWE2NjM0MDczNjQ0MjU1MTg2YTc5NGIxMjdmYzQ5MTA2NTRmYTNhMjBiOTgzMjMxOTIxZWU2ZWEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjYwZTJhMWYwNzIwY2I4YWNhODQ4ZjIzNzM0N2E4YjUzNGY2YTEzZDVhZTBmMTQ3MDE4ODQ5ZmZjYjkxOTRlZWMifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/DesignSystem/MobileContentRegions.swift#L138-L163",
|
||||
"version": "repo-lines-v1:sha256:c6c6e516865f5bdc89834ad893a875e31ed619ccb60fceaa4e62e36ea547e77e:eyJzZWxlY3RlZExpbmVDb3VudCI6MjYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjZkNDg2NDhjOTA2YTJlMjI2Y2RhZjdiYTljN2IzZDA1ODA3NjRiZDIwMmUzZTVmZTZiZjY4YTU1NWEwYzM0ZmMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/AI/TranscriptListView.swift#L235-L300",
|
||||
"version": "repo-lines-v1:sha256:d47b768fd10b200cad1d9efae62a3d964153c40657e48afe627f2f4b06626738:eyJzZWxlY3RlZExpbmVDb3VudCI6NjYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU2YWMyMWZiZDAxNzVkMjIwOGU2Y2IyYmUxNzNiOWIzZjIxMGIyZTczMGVlMzRhNzY1NGFmNTViYzI2ZDI3MWIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjRhMzE3ZjA0YTZmM2YwMTlhNWI0ZmFkOTkxMjEwMWQyNDk2MzgyNWI0M2NiZmVlY2ZjN2U5ODA2NzE5NThkMGYiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImJiYzM5ZDU4YWE3OThkOWY1NGZmN2Q1NjU4MWU1ZTk4OWZjMWU5Y2FhNmU0NTc3NzMwMzc0NTc3MjkyZTdkNDIiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImE2OGVmNzgxYTUyZmVkYWI2Y2E4YTI1YmI5MDQ4ZTg4YWNlZTFjZDQ4NGFmMWRhZDA2NTY0MmFlODhhM2I0MzUifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/Features/Workspaces/PersistentWorkspaceDeckLayout.swift#L20-L108",
|
||||
"version": "repo-lines-v1:sha256:36c22131a55ec5b65823348af839c0293b5a92ddefbe81767e35d7639cd91675:eyJzZWxlY3RlZExpbmVDb3VudCI6ODksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImUwYTE2OTVjOWVlODY1YjZlODA3Nzc2NWVmZDRhYjFkOGZmN2YzM2ZmY2EzNDExNGIxYTg5Zjk2ZTczOGFkYjEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjE5ZTc2MzU1Y2YxMTk5NDgwYzNmOTk4MzZiMTQ4NmM4NDFkODkxZmFhZDkwNGM2MDhlMDkzMDIyZDM3NTdhZWUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T02:51:54.212Z"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:d24179ca1c2b20df58b7397bac9751d16803f018d8a202587f430adc1bfabae3",
|
||||
"pageVersion": "sha256:1a4657f6bcb6994d787c4a157adc6dea712f0eb0512567400e87efceb803eb7c",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_83870f4f1ad6403ea0d8bd8775729a76",
|
||||
@@ -125,6 +125,6 @@
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T01:31:00.738Z"
|
||||
"at": "2026-09-22T02:51:54.212Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:280d89c1f4f2470dfcd630f23d2ab2a54dc8d48654a2788a54a6b70c99819b4e",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_a66f64ff267243989e5b4bbc103576dd",
|
||||
"statement": "Forwarding controller runtime intent is shared by rules for one Host, captures its maximum at context creation, and retires on last Stop or route invalidation; macOS uses the Host-configured 1–64 limit while mobile uses single-connection policy.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindDomain/Hosts/Host.swift#L120-L122",
|
||||
"version": "repo-lines-v1:sha256:6a309e68ca7b6e789f3c3024def0c841d3bc08458ba5cb789864fe553710769b:eyJzZWxlY3RlZExpbmVDb3VudCI6MywiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiNWIzNzg1MTljNGU3YmQ5NmE1ZTE5MDY2NzdmZTJhM2IyMGFmOGRlYjg4YTcxZjMxNGZiY2VlNzQ0ZTI1NmNiNSIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiMDRmMGVhY2EyZDkyMjZiNTMwMjhhMWIxMmE4YWE2Mjc1YWY0MTZlYmIyMThmMzc0MTA2ODhhN2M1NzU1MzIwNSIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiMTkwZjVjNzE0YThkNjkwOWMzM2M0YzlmZTQwMmRiMDFiZWQ5MjczZDU5MzljNDk4NTE1OTViMTNlMzc1NGEzMiIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiY2ViYzA2NWIwZjZkMzIzMTlhNWU5NDhkMWUzMGU3M2ZiOGU3MGQzN2U3OWRjZDdiNjI5OTRjZDQ0NzA4MjM2OSJ9"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/PortForwardingController.swift#L68-L248",
|
||||
"version": "repo-lines-v1:sha256:bfb6a67f33a04985b488f4b55a8ae0a965cb59bf93630bb73127b1ba1a5b593d:eyJzZWxlY3RlZExpbmVDb3VudCI6MTgxLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJjYjRkNDU2MWRjN2E1NThmYzViYjdlNWI0MWViYzA4M2I5MjM0NjMxY2U0NWMzNjhlODgwZGUzNzFkNjIxODFhIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI3Y2IyMTQyMTg3NjZkMWZjNTAwYWQ1YjI5YmJkODc1OTg0NTM5NThjYmE2OWQ4OWE1Mzk5MTM4M2RlMWZlNzU5IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIxNGFkMjA0NmY3OTFlZTQwZmFmODY0NTk2MTljYWM4ZmY1MzcyYzBmYWY2ZjcyZGFjZGJiY2IzYTI3OTdkYjIzIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFI/App/MobileAppDependencies.swift#L35-L40",
|
||||
"version": "repo-lines-v1:sha256:2edc4b6fe39f94c07b59c5fb5666105b1ba555a0ada88a223ab7d6c70f6b5b24:eyJzZWxlY3RlZExpbmVDb3VudCI6NiwiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiYTRiOTk2YTA0YTJmZDBiZTlkZGNjMzY0NmUzMmY3MGYwOWJkZWYzODY0MjU1MDRkMjZiMmM3NmM3MDUyNDIxOSIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiNTUyMmM0MmNkMTljNmQwM2Q4MDhjNDUyNzIwNTUyODI1YjdlYTFjNWI0OTFiMjE4NTExY2FjNzQxNWNmOWQ5YiIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiNzc2ZDc1ZGY2OWU3MzY1NDY0OGQyOWRkY2JkZmRhMmYwMDVmOTM3MjA0ZjE5M2JmOTM2N2EzN2VmNzZlYzQ2NiIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiZmYwZDc1OTUwZGYwZmY5YTNlZTk2NjM5ZGNjOGZmNWVhZWRiNDBkNjgyYmVhOTI2MjJiNTIwZGQ4ODdkOTNlOSJ9"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFM/App/AppModel.swift#L206-L208",
|
||||
"version": "repo-lines-v1:sha256:dd8790286d4f56067c0a1d3b6f1f27ac13e2eed4af00886b40ff3de98969c0e8:eyJzZWxlY3RlZExpbmVDb3VudCI6MywiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiNjc1YjAwZmFlODFlNDcxZWVhNzRjYTMyMmEyOTI4N2IzMDY0ZDMyZTUxZGI4NTQzNTg4NWJkMWUwODg0MTE5MiIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiZDE2ZGFmNWEwNTY3NzMwZDA2OTUyZTczOTczMWU1NDIwNWQwMjVhMTZkMzk1OTBkMjBiM2E4NjhmOTU0NmQ3ZSIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiMTEzNmNmMGJjMjBhZWZlM2ViMjkzMzM4MGY0MmFmNWU5MWU0N2YxMDJkY2RhZmY3NjBhN2VkMDM0MTM5OWM5ZCIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiZGFkMGI5NWI5ZDkzN2I3ZGRhNTM5Yzk5MmNmYWYzZWI1NDA3Zjk4NjA0MDc0MDFkNmU1MmYxYmM0Mjg1OTY2ZiJ9"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_b96c94faec954db0bb19e1530d5a6eec",
|
||||
"statement": "Only local and dynamic rules demand auxiliary forwarding connections; a pool binds one shared local listener per such rule while remote listeners and their forwarded channels stay on the primary.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnection.swift#L503-L651",
|
||||
"version": "repo-lines-v1:sha256:8d4af7dc8a1482069b33b2753a202c7261ddffbe6d484ec4769dcc3c96cff703:eyJzZWxlY3RlZExpbmVDb3VudCI6MTQ5LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiJhZDk1YTBiOTk4MDUwYjhmMWI5MzJjMGQ2MTVkMzc3ZjYxYTUyNTk4YTZmZWVkZGQ1YWU2ZTQ4Zjc0OTk0NTk3IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI3NjQwZDRlN2UxYTA1OTMxMWNjMDlkODNkYjEwOWUzZGM2YWFmYjk4NmY4ZDQ0ZmQ4Y2I2N2IzMzRjMDhlMTBiIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI0YjlhMDMxYTFmYTc1NDU5ZTNmMjAzMjc5Y2ZlNWMyM2U5OWVmODBkZDk3Mzk3YWVlZDE0YTc3NzVjM2Y2OGFhIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnectionPool.swift#L65-L153",
|
||||
"version": "repo-lines-v1:sha256:01ab747c5c19d57484b6776e6dc4185349c238ec16a80eb9d6b730b693eb5fa3:eyJzZWxlY3RlZExpbmVDb3VudCI6ODksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk5MzNiOGJhNDg3MjFkMTc5MGRiMjZkY2VlYmY0MzM5OTAyYTI1MWQxMzViOGY2MjM3MzZkYmRmYmIyMWZlMTIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjdiZDIxMTIzNDYzMDc3Nzc4NDdjNzIwNjVlMTI0ZWY2MGQ3ZGE2Nzk0ZmI0ODhjNGQzYmU1MDg5MGFhN2ExMjgiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk5OWJkZWZlZWFjYTYzNDBlMDI5MGRjODZlODg5Yzg5ZDVlMTg5YWE1YmE0NGI1ODViM2I3MDczNGY0YTYyZDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjgwODkwOGYzZDExZmI2NjZlODRlNzcwMTQxOWM3OWY5ZjFkMjBlNjdlYjg1YjUyNDBjMjI2NzJhZmQ4NWRlNDUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_7fd5b40b2c264a658a32756d8dbafbf3",
|
||||
"statement": "Pool fill counts published, opening and installing slots against the target, caps concurrent opening plus installing work at four, and publishes auxiliaries after registration and stale-state checks.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnectionPool.swift#L167-L221",
|
||||
"version": "repo-lines-v1:sha256:85c70747e68b25477a46b019daaee40ac31940c8c14fcb2b12e662c91d7e7d4f:eyJzZWxlY3RlZExpbmVDb3VudCI6NTUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImQ0NTE3MzFlYzZhYWEyMmQwNDk1MjczYjdlOWIyMmVlNjY4YjFhODgyZjAwZDRmNmY3MDQzZTkxNzNkZDcwM2UiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImM0ZGMzNTE2YjZmYjY4ODUxOGIyZmRiZDVmYWFhODJiNzk2NjE1MDNhYjI5NDAzNjU2NTViMDU0NzUzZTM0NzciLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImZkYmEwZmQ3NDNmOWJhMmViYmNhY2UxNTUxODFjNDAxZGJkOTU1YTljZTUzYzUwMTU2NjkzZjhiOWRjZjYzNTgifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_62c62fe878ac485da32c2358658364ad",
|
||||
"statement": "Accepted local/dynamic sockets are assigned by least asynchronously reported flow count for that rule, with UUID-sorted round-robin ties and generation checks; assignment neither reserves an optimistic count nor retries another worker after rejection.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnection.swift#L314-L334",
|
||||
"version": "repo-lines-v1:sha256:0146c08abeae8270031daea34a25749e0d96e7c3a937821e92e69f70638fa848:eyJzZWxlY3RlZExpbmVDb3VudCI6MjEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImFmN2NjZTJiZThkYTJiZDg2NTlmYjFkMTNiZDM2MmFjOWYyYWJlYTU3NjI2Mzc5YTc5NWZhNTU5OWUxNjVmMmMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk5OWJkZWZlZWFjYTYzNDBlMDI5MGRjODZlODg5Yzg5ZDVlMTg5YWE1YmE0NGI1ODViM2I3MDczNGY0YTYyZDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjBjZWYwM2RmM2Y1MmZkNGJlMmQ4MmNmZmQ4NjUwNWNkYzUxZTJlMzk2MWFlYzRiNzZjMTY5MTg0YzQxNGY5NjAifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnectionPool.swift#L300-L338",
|
||||
"version": "repo-lines-v1:sha256:5fb9a448c89ad3739883debda96e61330e02ea3affa2fa801a00da40ecd2c2c2:eyJzZWxlY3RlZExpbmVDb3VudCI6MzksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjI4MjM5YTMxMTJiZWYyNjMzYTY4Yjg4Nzk1OWViYWZmNmY1ZjY3ODI3NzJlYTA1YTdmNjU0MzBjNGFjZTllOTUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjMzMTUwOTViMTU2YWFiYjc0YmI0Y2YwYWU5OWE3MzJmNDc1YWMyNjNlOTViNmIwZDNlNWZiOTJhZGQ0MmJiNTMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUxNGNiNjJmZjZiMjc5MDAzYjVhNzlkZTA2YmE0MTAxM2ZmY2FlZWE0M2EyZGViZjUxYTZkZTYwZjFlYjMzZDUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_9db6225ca15944d88cccba6819ad0c8a",
|
||||
"statement": "Dynamic forwarding supports no-auth SOCKS5 CONNECT with IPv4/domain/IPv6 targets, retains request-following bytes and bounds handshake buffering to 64 KiB.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnection.swift#L693-L717",
|
||||
"version": "repo-lines-v1:sha256:e16c0bbc716ca150b4e3332dfddf9420d077f97b1376e138f0d47611e050867f:eyJzZWxlY3RlZExpbmVDb3VudCI6MjUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjhiMGJjZTFkMzE2OWJjM2NkOWE1NGViMzIzYzE0ZDIzODg4NGM4MjY1YTIzMzYyZmUxNzEyYWJkZTYxM2Q0YWEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjU1MjJjNDJjZDE5YzZkMDNkODA4YzQ1MjcyMDU1MjgyNWI3ZWExYzViNDkxYjIxODUxMWNhYzc0MTVjZjlkOWIiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjUwZjVlODk3MmI4ZTZiOTQ2OGI3MDQyNWE3ZDY2YTlmOGNhMDE0NTk4OTMxZjljYzlkMWQyMTIxNWQ0YTc2YjciLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjQ0ZDY2OTNkMzQ1NGFiMDdiYzYyZmE3YTdkMDA5ODQ3MjIxMGM0YTU2ZDI1MDExMzEzOTQ0YmQ4ZTk2YmQ2YmQifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnection.swift#L861-L929",
|
||||
"version": "repo-lines-v1:sha256:253b411b7ed77b0c483869a4ce5483dba5928853137e722963304288b55c261e:eyJzZWxlY3RlZExpbmVDb3VudCI6NjksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjcyZGUwZjAzY2JjODVjM2JiNWUwNDIxYmQxODk4ZTIwNjQzZTgzMTY4YTFkMTY4NDYzOTY4MTMyMzhjNWUyYzMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjhkNDQ4OTZkZjU5ZmRkYzJlYTBjYjVhNTc1MGUzZjVhMGM3ZDAzYmQ5OGI5ZTA4NTAxYmJmMGU2ZWU3YzgyZmQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjFhOTQ1MzBmN2ViMDk1MGM1MTMxNmM1ZGM2MjdlZGNhMGIwYThjMzgyYWNhZTNlYTJiNDNlMzQ2NmFkZGFiM2EifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_ecf14ac9ddab49a0a83d675e19abac7e",
|
||||
"statement": "The forwarding worker services pending listener/channel control work and remote accepts before and after bounded flow I/O, rechecks buffered channel data and EOF, and reschedules on progress/budget exhaustion rather than waiting exclusively for another socket edge.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnection.swift#L374-L497",
|
||||
"version": "repo-lines-v1:sha256:c37050de1c091ef158cf2bdc1a9c1f9b113f56f97d4d2496c87e25dc937c31a9:eyJzZWxlY3RlZExpbmVDb3VudCI6MTI0LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI5N2Y4YjhlZmRhZjBkNTI0YmUwYjk0YTNkYmE1NTRmYTRiOGZmMTQzZDcyZGIyMGI1ZWNlZGRlNjkxMzJhNWI0IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI5OTliZGVmZWVhY2E2MzQwZTAyOTBkYzg2ZTg4OWM4OWQ1ZTE4OWFhNWJhNDRiNTg1YjNiNzA3MzRmNGE2MmQ4IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI0NDU5NjE1MjNkMGMyZDEzMDFiY2MzOGY1ZjgwN2U4ZjY4YTQzZjBlMWEwYjVjZGNiMzc2ODlmNWYwNTBhMmI5In0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_fdf5e77e1c1d456cab4f17a2bcc2c019",
|
||||
"statement": "Pool-local auxiliary recovery has a single 1/2/5/10/30-second retry progression reset after an auxiliary survives sixty seconds; primary failure can promote an existing slot and recreate remote rules, but does not migrate existing streams.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnection.swift#L825-L859",
|
||||
"version": "repo-lines-v1:sha256:364b4fea60821bf3a9ea89006d0d7e92b4486fb2f335db48b22edc12c123d0b7:eyJzZWxlY3RlZExpbmVDb3VudCI6MzUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImM1Zjk5NTg5YzlkYTMwODNlZmVkZmVhOGM4ZDYzYzAyZGY5NGU5YjFhOTQ0YmFkNTE1OGQzMzY0ZjE5M2NlNGYiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjY0ZTNiMDRiMDNhZjZhMDM2OTFlY2IwOTMxOTNiMTU0NjhlNTQ3MzNkM2YwOTczMWU5ZWI2ZmQ4NjI5Y2MzNGUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjUxNGE5NGQ3ZGNiNDI5MDM5NmEzMzE0ODY3Njc4MGM3OTIxN2RmYmJmZThlZjE0MTFjYWMyYmY2ZDFlYjRjNTQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6Ijg0YWE0MjI3MGRmZDkzOWQ3MWNkZTIyZmYzZGQ1YjJkYjk2Y2EzMTVmZWUzNjdkOGEwNzYwNzQ5MjQ1OWUwNjkifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnectionPool.swift#L189-L279",
|
||||
"version": "repo-lines-v1:sha256:53ba7124f38c7de9be376597677cc3be55c0ae053ec150621968ca249e9d170b:eyJzZWxlY3RlZExpbmVDb3VudCI6OTEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImM1NWE4YjEyYjk2ODU0NTQ4YmJjMDhjNDU3MWI2MGIyZTJkYThiMjI0NGY5Njk1MGYzY2Q4Mzc1MWFiNmZiOWYiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk5OWJkZWZlZWFjYTYzNDBlMDI5MGRjODZlODg5Yzg5ZDVlMTg5YWE1YmE0NGI1ODViM2I3MDczNGY0YTYyZDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImY5NWJjZWNiMDVkMGE5ZDdkOWIyNDIwOGZlYWRmNzRlMmEwZWU4NzRjMWQxMDM3ZTAzOTI5ZDk2MDgxMjE0M2UifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_efa9fe77322e415cb33d13e3d063049d",
|
||||
"statement": "Whole-context forwarding recovery requires prior readiness and a reusable snapshot, waits for old cleanup, restores surviving rule intent silently, and ends automatic recovery on interaction/trust/authentication requirements.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/PortForwardingController.swift#L419-L497",
|
||||
"version": "repo-lines-v1:sha256:5160ac502b9efb0eb2529c6182590ceee555f618bbf35b2d9f2aae716c6f19ed:eyJzZWxlY3RlZExpbmVDb3VudCI6NzksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjIzYTdlMGU5NDg5YzFkMTU2YjI3YWNkYzNiYjM5YWY1ZDY4NmE2ZjQ4NzdiMDVhZjg1MDNhODFmNzRkMDYwODMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjgyODM3NTllNTM5NmZkMGM3ZmQ2Yzc1Yjg2ODgzYWExZWQ5Y2M0NTk3M2U4Zjc4YTdhNTVkNGUyYzIxZTRlNTUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjNmMDhjNWRjY2E2YmU3YTc5ZWIyYWY1MjI0N2QwNWJkMjMyMTA2ZjA2MmRmZDI5MTBlMjA0NTVmMDk4YWRiY2MiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImZjZThkMTM3ZmE0NGFjNjY0OGIzYTRhNmY1NmY1MGJhYmE2NzczNDE0NWQwNDc0YTRlNTU1Njk3ZmQyNmJlYzgifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/PortForwardingController.swift#L570-L687",
|
||||
"version": "repo-lines-v1:sha256:622f9bfdcebe8935be7616d6686e66682ccb351b750eeaab6705dfba8932cb0a:eyJzZWxlY3RlZExpbmVDb3VudCI6MTE4LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIwYzc2MzZkMTFkOTA0MjI2NzlmZDUzOTI4ZGUyZGZmNWRkNjdjODE0M2E4ZWE3NDcxYTdjOGJhMzlmNWMyYzgyIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJhMDc3ODFiZWI1Yjc2Nzc1YTE0OWNkYWMxYjYwOWJjNDAyM2NmZWQ5NWNjMDE3NDQzNjgwMTZmZmYzZjQ2Zjg0IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MCwiZm9sbG93aW5nQ29udGV4dEhhc2giOiJlM2IwYzQ0Mjk4ZmMxYzE0OWFmYmY0Yzg5OTZmYjkyNDI3YWU0MWU0NjQ5YjkzNGNhNDk1OTkxYjc4NTJiODU1In0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/PortForwardingReconnectTests.swift#L149-L202",
|
||||
"version": "repo-lines-v1:sha256:7b93533f2176e723a712eba3ac44e31bbdd034ecbef3f6a472f70ecf5f7d71e4:eyJzZWxlY3RlZExpbmVDb3VudCI6NTQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjNkNDg3MDEzMWM4YWI2YWIwNGNiNWMyNzE5MThlZTUwMTBkYTJkM2IzMGNmM2UxODY4N2FjODE0ZTAxMmY4N2QiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjhlZjg4NTUyZmE5YjUzZDI2ZDY4NDE4MmZmNDEwODg4NTAxNzVhM2EzMTcyYmY5Mjg3ZDY0Y2UxMWZmNzkzYjgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImZiMTJjMTE3NGJjYmVkNDQ1OGNiNDE5NmQyZDJkMmUyZWVkNjI5ZjFlMTE5NjgwMWM2Mjg1NjNmZTI5YzAyOWEifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_bba6485942f7422eacf74adacb53f808",
|
||||
"statement": "Forwarding stop drains an in-flight remote-listen request before cancelling its resulting listener, and full disconnect waits for socket retirement; stream half-close drains pending bytes independently in each direction.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnection.swift#L336-L355",
|
||||
"version": "repo-lines-v1:sha256:db210ce817f81e609ff4274aa665d24d16a5f40fbe0139e2cd4e323841b82679:eyJzZWxlY3RlZExpbmVDb3VudCI6MjAsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImEzYjRkZWI4ZjZiYzZiMjFkYTc0ZWE0Mjc5ZjYwZWFlZmJkNWNmNmNjZDdhMzk0NzMwZWJhNjIwM2YwMWE3ODIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU2YjA0NDkxNDY5NzIyZTgzNjNhOTRlNDA0NDUzOGUwMTNhMmEyMTdlMzZiMWU1NjhiYTYwYWNiN2I0YzhmMmUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk5OWJkZWZlZWFjYTYzNDBlMDI5MGRjODZlODg5Yzg5ZDVlMTg5YWE1YmE0NGI1ODViM2I3MDczNGY0YTYyZDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImQ3N2EzNzMyOWQ4ODY0ODU4NDk4NDM3MDFkZjExODVhYzI4ZjYxNTA0ZDk4OGYyYTc3ZDRlOTNhYzY5NmM5NDAifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnection.swift#L732-L860",
|
||||
"version": "repo-lines-v1:sha256:0d8b56d419f0af0fbd673cde88c55c98bcec6d0a64577d29a9a579fb3d051acd:eyJzZWxlY3RlZExpbmVDb3VudCI6MTI5LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIyODBmOWQzZGE0YmI4M2NmMWRiZDg4MDAzZWYzMGIyYjgxNWU1NDgxODBjMjFmMWE5Y2Q0MmY5NzRmNjFiZmI3IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiJjNDlhNTE4NDI4Nzc1NmUwMmE2ZDliYmQ4OWMwY2M1ZTJhNjAzYTEzZTU3YTE5NGYwMjVmOGVkMTE4NDk3NzUyIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI4OWY5OTE2ZDBkMjVlNzg3OWYyNWRiNmI1Y2Y5M2FlNDU4OTM4YzgwMjM1NTUzOGI0OTVjZjgzZGE4YTVkMmNkIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHStreamPump.swift#L300-L455",
|
||||
"version": "repo-lines-v1:sha256:819fd2370c003e5dceb8ae760d9fdcdbce92d634035029db1ae30d6d44d09203:eyJzZWxlY3RlZExpbmVDb3VudCI6MTU2LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI1Yjk4ODEzNTM2ZGVhY2Y4NDYxMDM0Yzg0NmMwMmM1ZjI0NTRhMjQ2NzQzNWJlZTZmYjQyNTI0MTNjNTc4MzU1IiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiJiYWUyYTRiZDY0YzhjZGY1NDdlMjczOTE0ZmM4ZGY2NWI2N2U1MWRmMWU1NGRhNThjYjVmYzM0MzkzZjVkMzdiIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiIyNTdiZDUwYTljZDkxMDQ2NDA0NDc0YmZkNDRmNmY4ZTdiZDVmMzA2ZDg3NGMyODc2OGVhZGNlZGNkNGQzNTYyIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MSwiZm9sbG93aW5nQ29udGV4dEhhc2giOiI0MTJjYTM0NWNjZjc1YmY5YzA4MDZiY2U2OTViZThkZTgwOGI3OTk4NDI1MWE3YTU0ZDIwMmNmNjEwMWRkNDUxIn0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_4be36806a5c74a94a6f119ed193369b2",
|
||||
"statement": "Forwarding wire tests require TERMIND_SSH_FIXTURE and exercise stream concurrency, jump bridges, slow consumers and local-pool distribution; the pool distribution assertion proves use of multiple slots, not an exact equal flow split.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://TFMTests/SSHForwardingWireTests.swift#L275-L278",
|
||||
"version": "repo-lines-v1:sha256:c5202b50d3c60c87b9c11d87cc70c41a42429af9033db6301c64ea5f40e17d95:eyJzZWxlY3RlZExpbmVDb3VudCI6NCwiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiZGVhZjY4YzgzNWI5OTJkY2UxYWY4YzE5ZDUxZjhlMDU2Zjk3YzcxOTI1NGE4YWZjNTViNzM1MWQxNjk0YmYxMyIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiNDg5M2Y0MGUzNzgxZWI4OTZjODJkMDQ2YTA4MDY3YTExZTM1Y2RmMmYxZGZhZjI2ZmVhOTBiOGRiNjY3NjQxMyIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiNzVhYTgzOWZjNTEzYmM5MjBiZTUyNmEwYWQ4OTA2NzUzYzYyNTAyNDA1OTZmN2M2ZjZkYzYwMWRhMTdjYzllNSIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiOWY0NmZmOGJmNDY5Y2Y2MDQzNTc3NWEyYTk0NDYzMDM0NjIyNGRlZTA5NGQ3YWU4NTNjYWY3MjRjZmZmMTcwNSJ9"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/SSHForwardingWireTests.swift#L9-L154",
|
||||
"version": "repo-lines-v1:sha256:8fa6331a9486590c778a5ceb26be0a6df02c0c0e280ccf83a6d68df7a219298f:eyJzZWxlY3RlZExpbmVDb3VudCI6MTQ2LCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI1OGM1NzZkMmQxY2I1ZGU0MmE2MGQ1ZjJhMTczNDA3YzgyNDgyOWE3MWRjYjUwNDVmNGJhZGNmOWI2YmJjMmYyIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiIyMjRjNjk1ZTE3Yzk2YjdlODIyZWIwMjEwMDA3MGU5MWQ4M2Y5ZDc5OTdmOGFiNmFkNGIzYjk5NThjZTQ3NTdiIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIwYjQzMzIwOGM3NmE3N2VhMzJkNjg3ZDc1YjQyZGExYmE0MDk3MWNiY2RlZWFkZTMxMjBmNjI1YjNmNmVjNzhhIn0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T02:43:23.140Z"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:60656f471c069bc3da45fcdf15485094baa49bfd497d84743db6471bcafb6b87",
|
||||
"pageVersion": "sha256:ac1d6af9add7224acf9b9b467bccfe03d9c9632a41e2912a092e0346161f2a3f",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_5ca6241ea6cc4ebbb915ccbe304f8430",
|
||||
@@ -299,10 +299,130 @@
|
||||
"version": "repo-lines-v1:sha256:f0b3c63aa48580eccd3314edc9803bd670393ee8ed3d7842df171bbc4e4dbd1e:eyJzZWxlY3RlZExpbmVDb3VudCI6MzgsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImNhZGE1MTU3Nzc4ZjNjOTJhNmZjNjM0MmE1MjZlNmJjNzY3YTFkNWVlNTI2ZmRlYjM3MzlkNDJhZmI4MWJlMDMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjQ5MTRkNmJjZWRlMWQwYWIwNjFlZGYzZWNhN2U4NmVjYzY1NzIzODhiNjc4ZDlmNmJiN2U4ZDAzNjQ4NDgwNmEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjI5M2JlOTgzNDEyZjAwYmIwOGE5NDY5ODZkNWMwYzQ5MzY1N2YxNDg3MDZiOTRjOTk5NGJlNjhhZDkxMjhhODEifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_50364e3c343b4c14860121fe8d974dd2",
|
||||
"statement": "SFTP coordinator stores an admitted permit before reserving context slots and acquiring channel leases, and holds that file permit through I/O and lease cleanup; running can therefore include waiting for a channel.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferCoordinator.swift#L488-L552",
|
||||
"version": "repo-lines-v1:sha256:517342c98e35cff6cb998aecd82535e3ee5f3866f6b9ff6ce05fb886ed0eac4c:eyJzZWxlY3RlZExpbmVDb3VudCI6NjUsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijg1YjdjZWMyMGY5OWFlYzBhY2NkZTMwNTkwMjZmNjlkNDk3NDNhNWM0M2M2YThlMjMyNDdjZjBmZDRjNjgwY2IiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImRiNjcwZmIzOGY4NGVlMDAxM2IwMWVmM2JlMDc4N2ZmOGMxMzJmMzNjODVjMzY5MTM5YzIxNjFhNGU4Yjg3Y2MiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjAwNDU3Y2EwZThhZjE2NjNkMmM3NDg3NmQyNjJlOTUxOTNlOTEyNmFhZGY0ZmI4MmQ3NzVhN2VjOThmYmMxODQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjkyMWFjYmUwMzNiOWVmMGE2NWY3YjgxOTBjNzMxZWYyMTVkNzI5ZjkyZGUyZDk5NDMzMDEwMWY0NGE0YmY2ZDkifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferCoordinator.swift#L608-L613",
|
||||
"version": "repo-lines-v1:sha256:5abc9a99239cf0e648aca6f9bdde99188bbb7682f4e0f8863248b211374fc0be:eyJzZWxlY3RlZExpbmVDb3VudCI6NiwiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiOWE3NTg1MmRiMDQ1NzQ1NDMyZDEzMGJkMzY3NDdlMWM0MjYzYjJhNzMzNTM1NzdiZDNkZGFhMTQ0MTc5YjRkMyIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiZTZiMDQ0OTE0Njk3MjJlODM2M2E5NGU0MDQ0NTM4ZTAxM2EyYTIxN2UzNmIxZTU2OGJhNjBhY2I3YjRjOGYyZSIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiZGNlYWYwZmQ0NmYyMmQ2YjdiMTcxZWFkMWMzNmEzOGJiNjE1NmI3ZThiYzI3YjljNmE4N2YzYTA2MDc5YWQ1NCIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiYTIzODI4NzIxNTcyNDgzZDNlZTdiNzQ1ZjJhNmEyOThlMDQxZGQ2OTgxMzgyYjNhOWZiYzAwN2E5ZmY2MDQzOSJ9"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferCoordinator.swift#L797-L820",
|
||||
"version": "repo-lines-v1:sha256:7803e7ca55560ae90c3ad9c8ed278f6d9017bc4bdf64f724dc80fda02333ecaf:eyJzZWxlY3RlZExpbmVDb3VudCI6MjQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjBjYjk5M2U5ZDNkM2JlN2UwMjlmY2JjMzQwMjZkMzVmYTU5MmY3Y2QyNjFhNzMzNmEwODAzOGQxZGZiN2I3MjkiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQxMmNhMzQ1Y2NmNzViZjljMDgwNmJjZTY5NWJlOGRlODA4Yjc5OTg0MjUxYTdhNTRkMjAyY2Y2MTAxZGQ0NTEiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjRlMGE4YTQwY2U5NjQ1MzVlZGZiYmJkNTg4ZTkxMTE5YzU3NjUzODhlMmYzYjA5YzI2Y2EwOTZlOWVkOThhYjUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjowLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzYjBjNDQyOThmYzFjMTQ5YWZiZjRjODk5NmZiOTI0MjdhZTQxZTQ2NDliOTM0Y2E0OTU5OTFiNzg1MmI4NTUifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_e0db495813804a768f6dbfc8897da45e",
|
||||
"statement": "The SFTP scheduler examines only each source queue's head while rotating hosts then sources, skips blocked heads without reordering within that source, and selects mode using current preferences at grant time without preempting active permits.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPConcurrencyScheduler.swift#L133-L182",
|
||||
"version": "repo-lines-v1:sha256:e631c162e9dd40425e280c72ff63a78abaf5cf196a2f37306c090e5be7a9e26b:eyJzZWxlY3RlZExpbmVDb3VudCI6NTAsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijc3MTNjNjAzZWU5NjQ5OTU5OTJhMmUyZjYxY2ZkYTY5OTU2ZDM1MDU5YmU3ZDYzYjhkYjBhMDMwMmQ2OTUxMjgiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjM4NTExNDMwNzk3NTU2OWExNzJhZGZhNDAwMDdmOTFjNzE1NmE2MzU1MDZmZDAyNzIzM2FhMWU3MmVjZTdmNzUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjFmNjU1MDc5MjZlNjQ1MWUzZmYzNWIyNWUzNTM0MmU5N2ZiY2YzYTI2YTgwNzdmNzFjMTJkYmQ1YjM4OTYwMzMifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPConcurrencyScheduler.swift#L65-L105",
|
||||
"version": "repo-lines-v1:sha256:f74f001444e68ffd7b9c77854871027d44b214b4a28edd123b082782852c1937:eyJzZWxlY3RlZExpbmVDb3VudCI6NDEsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU2MjE1NzhlYTNkOGUxNThjYzdhNWY0MjhmODQzODExMWY5ZWQ3MWEyNWJhYmM1MWE3MzlkMDg3YTRkMmM0OTUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU2YjA0NDkxNDY5NzIyZTgzNjNhOTRlNDA0NDUzOGUwMTNhMmEyMTdlMzZiMWU1NjhiYTYwYWNiN2I0YzhmMmUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImJkNDk2MTA1ZGQ1OTM0MjRlZDFjNjAyNDQyZWRkZjllNDExYTA3Njg5MzgzYjkxOWI5NDQ5YTlhMmRmMGEwMjYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImNhNmQ0OTkxM2M5MzI0YjhhZTk1ZDE2YzdhNDBmMWY1YzUzMThiMzk0Zjc4ODg4ZTBmZjljNGExZmQwMmZkODcifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_7216181c050949d59b889f11ef147d07",
|
||||
"statement": "Coordinator copies anchor scheduling to the destination Host when available and use the destination managed context as workspace source, while ordinary managed transfers use their context and unmanaged transfers use batch identity.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferCoordinator.swift#L698-L719",
|
||||
"version": "repo-lines-v1:sha256:af8cf8711bf7b0d4ff65dd0cf6abd5331b89ad4c679b9c8947af2ef56ce4623c:eyJzZWxlY3RlZExpbmVDb3VudCI6MjIsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImVjYWEzY2E3NTVjMTNlZmJmNTMwMTJjZmRkZDE2MWU5NWJkMzVmYjM0Y2NiM2IwNjgxMGUxOGU1NTIwMWFjMjYiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImEyMzgyODcyMTU3MjQ4M2QzZWU3Yjc0NWYyYTZhMjk4ZTA0MWRkNjk4MTM4MmIzYTlmYmMwMDdhOWZmNjA0MzkiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImE3ODJlYWY5NGFhMTllNjk0YzI4YmNkM2YyNjM0YzQyNzA1MDUwMWVjYmRhMmVjZWU1ZmRhNmNlMTRkNTRkYTEifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_0ab70fa456234c0a9484a54fb0eb2641",
|
||||
"statement": "Control, donated-preflight and PTY-fallback primaries have different leasing priorities; admitted overlap can choose extra connections or siblings, and context fallback waiters are resumed together rather than implementing source FIFO.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferContext.swift#L235-L264",
|
||||
"version": "repo-lines-v1:sha256:c59536190b14a619d2cbc8842c2f28d75f693399c7824349ffc9721415ed3b10:eyJzZWxlY3RlZExpbmVDb3VudCI6MzAsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijk1NmJiZjM4ZDBlNTg1YjU0MGM1OTg2ZmIyODdiMmRjNGYxZmE2YTVmZjI4NjFkMmY0OTY3YzZiNmJlNjgxZWEiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijk5OWJkZWZlZWFjYTYzNDBlMDI5MGRjODZlODg5Yzg5ZDVlMTg5YWE1YmE0NGI1ODViM2I3MDczNGY0YTYyZDgiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjkyZDI0Y2NjMGY3MDRlMTMzOGQzYzIwZmUxODk1ZDExYzljNjliNDA5N2UzM2NkYzk0NWExNWViMmEzZWE1ZGYifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferContext.swift#L4-L45",
|
||||
"version": "repo-lines-v1:sha256:6b5d94cf17943dce56b7c6117c9da0ea0be3b8698da3a4a64bb8243caea2bf76:eyJzZWxlY3RlZExpbmVDb3VudCI6NDIsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjliOTRiMTE2Zjg4NmViMmNkMTY5OGY1MWM0NjkzZThmNTFiZjg5OWUzZjcyZGMyMTgxNTU2MWNmZmFkMDliZGIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImMzMDg2NTgzMmRjYTA5MjkzMmZlZDRhMWFkYWM2Zjg2OTczZGYxNDRhNDNmMTQzNWEyODVmYjdhYzE1NDMyMTQiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImM0NmY4Y2RkMDA0NDk4MWZkNzI0N2EwYzg5MzE2ODM0ZDNlZGFjOWU1MTAwNThkNGMwNGNhM2RkODczYzFhYTYiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImEzMmM0NDA0ZWY5YjA0MWRiOTc1MDVhNDVlYjFkODFiNTVhZTJmMzBiYjNjZTcyMDY2OTZlNzkwZGU2YjZiM2MifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferContext.swift#L99-L210",
|
||||
"version": "repo-lines-v1:sha256:08689c752caaebfd4a69fd5c73f49795a3af788fe65bc46dad372c010f1d3f38:eyJzZWxlY3RlZExpbmVDb3VudCI6MTEyLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIzNTQ1MDdmODRhMTdhMGQ2NmY3NTc1NGRiZmZhMmYyYTgzZmZmMDg4ODVlMjJhMjQyOWZkZTZkMzU5Yzc1ZjIyIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI4M2JkZTVkYzQ1MDFiOWU5NTVkMTdmY2U4ZTJmZDBhMmEyMDc5MDE0MGIzYWFlYzU0MGEyYTZmMjBmYWNjNTEzIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiI3ZmZjYjVhNzQxZGIyNDM2NDQzOWUwMzU3NTdlNDUyNzM3NDA5MmQyZGViMzAzOGMxZGM0YWUxYTg5YzY1NGM5In0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_1413875287384747adf5343a335b5d12",
|
||||
"statement": "Managed browser-context extra connections and siblings disconnect on operation lease release rather than staying warm; saved and borrowed transfer forms bypass context topology selection, and a detached context can recreate an absent primary silently on explicit resume.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferContext.swift#L266-L272",
|
||||
"version": "repo-lines-v1:sha256:83641429cf561bea741854d35b409eee62288b4d33bb0daa419add169f40555b:eyJzZWxlY3RlZExpbmVDb3VudCI6NywiZmlyc3RTZWxlY3RlZExpbmVIYXNoIjoiMzI5ZGY4NjM2NjEwZWE3NTQ0MDhkOTMyYmNlM2ZjOWY1YTEwNGJmZDRjOTQ4YjRjZTk2YjNmZTJkMzA0YTI0NiIsImxhc3RTZWxlY3RlZExpbmVIYXNoIjoiNDg5M2Y0MGUzNzgxZWI4OTZjODJkMDQ2YTA4MDY3YTExZTM1Y2RmMmYxZGZhZjI2ZmVhOTBiOGRiNjY3NjQxMyIsInByZWNlZGluZ0NvbnRleHRMaW5lQ291bnQiOjMsInByZWNlZGluZ0NvbnRleHRIYXNoIjoiMDUxZjYwM2ViMDM1M2U0MGUxMjg4OWQ2MTk1Mzc2OWFlODQwYjc3ZDFmYTUxZGY3YzNiYWZlNmFmZjIzY2NhYiIsImZvbGxvd2luZ0NvbnRleHRMaW5lQ291bnQiOjMsImZvbGxvd2luZ0NvbnRleHRIYXNoIjoiNmM0ZjYxZDRhYTM3OTExNDhhNTI0ZmY3MDZhYTlhODYyNDAwNmQ0Y2ExMjNlYzc1ZThiNDM5NGViZmRiN2E5ZSJ9"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferContext.swift#L99-L188",
|
||||
"version": "repo-lines-v1:sha256:66bc442c33d6cd347e25766a912d6e5aa904ff35fbd79cb65d9b0da8bdef9739:eyJzZWxlY3RlZExpbmVDb3VudCI6OTAsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjM1NDUwN2Y4NGExN2EwZDY2Zjc1NzU0ZGJmZmEyZjJhODNmZmYwODg4NWUyMmEyNDI5ZmRlNmQzNTljNzVmMjIiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjgzYmRlNWRjNDUwMWI5ZTk1NWQxN2ZjZThlMmZkMGEyYTIwNzkwMTQwYjNhYWVjNTQwYTJhNmYyMGZhY2M1MTMiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImNlMjMzODU2ZGRmZDZjYmUwMzUyNmJmZTEwMjcwYWYwMDc5MGZjZTQ4YTgwODQ0MzdmN2MwZGE4YzJhMTJmODcifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferCoordinator.swift#L721-L754",
|
||||
"version": "repo-lines-v1:sha256:38dcea035a2368e5cccf70caa2c7d5458fbc58b71a8ee0e3dd3ee8a939a53be6:eyJzZWxlY3RlZExpbmVDb3VudCI6MzQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6Ijg5NGNlMTJjYTMyYzRjOGQ4NTVjOWUxOTRhZTIyODM2MDQwMWRlNjE2MDg1NzU3YzhkZjM1ZjBmOTVmZDZjMGMiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjlmMDBiZDgzOTVjOWRhM2Q3Y2FiZTBhNjE1YzIxNTVlYTEzNDAzNTc4MDZhMGQ0OGQyZDRjZGYxZjc2MmRmZjQiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjAxMWFhZDQ2NWQ3ZjhmMzA2YzAyMzg0MDM5NTJiNGM5NTFmNGNiMDY5NTQ0NmYwMmU0YzI0MjI2ZGY1ZmNhMDMifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://TFMTests/SFTPTransferContextTests.swift#L280-L298",
|
||||
"version": "repo-lines-v1:sha256:1aa1aa82116bf71195ff88abfa3c2b9daa1a85bfbed0f5951bf05eb7de2fc39a:eyJzZWxlY3RlZExpbmVDb3VudCI6MTksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ0YmVjOWQyMDIzZDcwZmI0NDNkMGJmYTdjOTAyMGMxNzBmZGFiY2IxMDA2N2EzMzI1OWU0ZWEyYmI4NTgyYTUiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6Ijc3ODgxYTZiYWJjOTMwOGM3NWFkNGNiNTc5ZWU4OGE2NjY0YWM1YzMwYjlmMTMyYTdlZWYzYmZmMDNlZjY2NDciLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6ImUzODcyN2UzZmYxMmExMGJmNDZlMjM5MGU5MWUxZGJhZDQxYWI0MzQ5NjA1NTE5NDNkYTRmMmY3ZGFlZjkzMmEifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_af5b4b37dba24be185e165b1d440c746",
|
||||
"statement": "Agent SFTP data admission is conditional on schedulesDataTransfer, uses an agentRun identity, respects an externally supplied permit without double ownership, and obtains the authentication/channel lease within the admitted operation.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift#L907-L972",
|
||||
"version": "repo-lines-v1:sha256:5a410580423c6394bb0fab63097f1a9e1221d426db79714aac378eb51ccfe9a5:eyJzZWxlY3RlZExpbmVDb3VudCI6NjYsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImI1M2Y1MzM4NzkzNzlhMzZjMTYwNDNjMmI2OWM2Zjg1Nzk4MmY5OTJhM2Y5Y2YxM2IxYzdjMmQ1Zjg0MTlkY2QiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjgyMmMxM2EyZWU2Yjk4NTNjYWMxZDRkNzgwY2I4MDU0YmU5OGNlZGUxZjFiMzgzM2E0MmM2YWFlYjBjY2RiMzUiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjIyZmQ2NjcwOTZlMGU5YmE1ZGQxMjBlYzJjYjg2YTEwZGFmZWI3NjZlMmIxODdiMzM0ZjU4OTI5NzJmNTNiZWIifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_475d10a744a04273a828b72fdffa0ec1",
|
||||
"statement": "Agent SFTP reuses eligible idle pooled records, retains them on release and disconnects ephemeral siblings; its initial shared-probe catch records channel capability before rethrowing cancellation, unlike browser-context cancellation-before-downgrade behavior.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift#L1142-L1281",
|
||||
"version": "repo-lines-v1:sha256:a74b4b9874f3af6c4bad312db35d3bea98c783a92c75f2a115129e3c5deaece8:eyJzZWxlY3RlZExpbmVDb3VudCI6MTQwLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiIzZmNmODFjZTljZWNjN2Q4ZjljNmRmMDQzNzUxZDgwYjczMDZmZjU2ZTQ1NjEwZWQ0NzIyY2RlMDVlMGIzODJkIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI0Mjc3YWVmZGU3NDQ5MDFhNTUwOWUxYzc4ODBmYWJlODE1YzJhZjk3YjRjOTdjZjg4NjVkMWQ5YmZmZWRjNTQxIiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIyODQ1MjdlZGQ5NGRjZTBjNjE1MThjYTY3YmIzYWYwZjA0NTM4OWE5MTYxMDc2OTk0MjMzMTZjNTM0NzlmM2FkIn0"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift#L1473-L1501",
|
||||
"version": "repo-lines-v1:sha256:a29aed0a932d052ae3d487dccf8eea7d4c071dd34fc8e24e8b3c3fd40184704a:eyJzZWxlY3RlZExpbmVDb3VudCI6MjksImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6IjdhN2MwNmNiNzQyNDdlNDJlNWU0YWNkYTY5MjZlMzg1YzE1NDRmOTBiZDFjOWJkMTI3MDkyZmZhMzViYTRiM2EiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6IjQ4OTNmNDBlMzc4MWViODk2YzgyZDA0NmEwODA2N2ExMWUzNWNkZjJmMWRmYWYyNmZlYTkwYjhkYjY2NzY0MTMiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6ImU3NjYzYjliMDQyNzJkYWJiNWQ4YjIxMDc0ODM0MGRmY2ZiZTc5MDIwMTY1NjAwZTE3ZWMwNjYxNGQwMzU5MmIiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjM4ODhhNWZlZmE0ZGEyMTBjNGY5M2ZhZWNjYWM0ZGE0NjM3MTA1MGNlYmYyZWFiYTE1NmJjM2M5NzRlYjY0NWYifQ"
|
||||
},
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferContext.swift#L123-L146",
|
||||
"version": "repo-lines-v1:sha256:3f76dfb0dcee6ff882714420a066b08856e768567b67f368801f020051ef7a9f:eyJzZWxlY3RlZExpbmVDb3VudCI6MjQsImZpcnN0U2VsZWN0ZWRMaW5lSGFzaCI6ImY3YTIyNmI4M2YzYzY1MDc5ZWU2MzA4ZDdhMTFiZDg3Y2NhNTRlNmY2OGQ4YTFhNWVlZjVlNmQ2ZmE5YzdkMjkiLCJsYXN0U2VsZWN0ZWRMaW5lSGFzaCI6ImU2YjA0NDkxNDY5NzIyZTgzNjNhOTRlNDA0NDUzOGUwMTNhMmEyMTdlMzZiMWU1NjhiYTYwYWNiN2I0YzhmMmUiLCJwcmVjZWRpbmdDb250ZXh0TGluZUNvdW50IjozLCJwcmVjZWRpbmdDb250ZXh0SGFzaCI6IjEyOWZmMjIyOTVlZWJhMWQwNjlmYjEwNDY0MjQ2Y2JmMWEzMjVkODRiOTkyNTEwNTA2NDRjZjY1MWE0MjM4YmEiLCJmb2xsb3dpbmdDb250ZXh0TGluZUNvdW50IjozLCJmb2xsb3dpbmdDb250ZXh0SGFzaCI6IjYzYThkYjgxYmYyYjFiYzkzODYxODNkOTM3MDg3ZTliYWNkYTYzZTA2N2I2MjcxZjIyZTIwNWY5YjI0NGQ1MjkifQ"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "claim_31477862ec1f44c1b3f1a1b22ab70a55",
|
||||
"statement": "SFTP shared-transport copy compares driver identity rather than Host IDs and alternates reads of at most 64 KiB with writes; different driver identities use a concurrent socket-pair relay with coordinated cancellation.",
|
||||
"evidence": [
|
||||
{
|
||||
"resource": "repo://Frameworks/TermindRemoteInfrastructure/SSH/SFTPChannel.swift#L575-L676",
|
||||
"version": "repo-lines-v1:sha256:ff6eb3116725e204720090c8a2e6ec95d0cafcf3a288a7d3875a5de54e506ccc:eyJzZWxlY3RlZExpbmVDb3VudCI6MTAyLCJmaXJzdFNlbGVjdGVkTGluZUhhc2giOiI2ZWRlZjM2OGUzMDY2MGY5N2M2ZjBiODYwNTM0MWJiYWMyNWZjZWRhMzkyYWUyYWViNzc1YjVkMjcxNDc3MGZiIiwibGFzdFNlbGVjdGVkTGluZUhhc2giOiI0ODkzZjQwZTM3ODFlYjg5NmM4MmQwNDZhMDgwNjdhMTFlMzVjZGYyZjFkZmFmMjZmZWE5MGI4ZGI2Njc2NDEzIiwicHJlY2VkaW5nQ29udGV4dExpbmVDb3VudCI6MywicHJlY2VkaW5nQ29udGV4dEhhc2giOiI5OTliZGVmZWVhY2E2MzQwZTAyOTBkYzg2ZTg4OWM4OWQ1ZTE4OWFhNWJhNDRiNTg1YjNiNzA3MzRmNGE2MmQ4IiwiZm9sbG93aW5nQ29udGV4dExpbmVDb3VudCI6MywiZm9sbG93aW5nQ29udGV4dEhhc2giOiIyOTBlMDhjMTViMzY3ZmY3ZDY0OTUxNmQ1OTE4YmY1YjE5ZDI4MjEzMjYzYWE1MzExMWE4M2NjMmE4OWEyOGYyIn0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T01:13:21.371Z"
|
||||
"at": "2026-09-22T02:21:47.705Z"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pageVersion": "sha256:4b8cdc51488e32af2cd1987f942226c14584b4c00da61388e1e567c7dfb8c09b",
|
||||
"pageVersion": "sha256:bdb748dc4ba8eb5e1f311f8c6695e023e429c8d19fac4ed2443dac2bb50a8964",
|
||||
"claims": [
|
||||
{
|
||||
"id": "claim_69a9de4ce918417c8a44c6c87c9f6564",
|
||||
@@ -167,6 +167,6 @@
|
||||
],
|
||||
"verification": {
|
||||
"by": "openwiki/0.5.2",
|
||||
"at": "2026-09-22T01:13:21.371Z"
|
||||
"at": "2026-09-22T02:21:47.705Z"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"updatedAt": "2026-09-22T01:34:11.887Z",
|
||||
"updatedAt": "2026-09-22T03:08:43.734Z",
|
||||
"command": "update",
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
"model": "host-agent/codex",
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"model": "host-agent/omp",
|
||||
"status": "complete",
|
||||
"language": "en"
|
||||
}
|
||||
@@ -1,19 +1,33 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"pages": {
|
||||
"/openwiki/architecture/desktop-ui.md": {
|
||||
"pageVersion": "sha256:d3b79d8cc51a720b38f06a1c8dc127782900a85f704bee57b59abaf8bf3f8d30",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "a8323adb-a617-401f-bf5f-4dcc24de41b9",
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3"
|
||||
},
|
||||
"/openwiki/architecture/engineering-invariants.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
"sourceFingerprint": "sha256:af2a6bdb282660739034c16a2084d4badceb69466956e716e9f07108af38c0a7",
|
||||
"pageVersion": "sha256:d955bf8ea7e79e305ab97b3b669217079fa7d038ed7599d3ee8210a283b936f8",
|
||||
"completedBy": "codex",
|
||||
"completedRunId": "9d891a43-76f9-45f6-8f19-3f5b61e8da37",
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
"sourceFingerprint": "sha256:af2a6bdb282660739034c16a2084d4badceb69466956e716e9f07108af38c0a7"
|
||||
"completedRunId": "9d891a43-76f9-45f6-8f19-3f5b61e8da37"
|
||||
},
|
||||
"/openwiki/architecture/mobile-ui.md": {
|
||||
"pageVersion": "sha256:a662291087c13d029a1df20ca0146d683e78704cee78016e30152e3701dcfe4c",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "a8323adb-a617-401f-bf5f-4dcc24de41b9",
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3"
|
||||
},
|
||||
"/openwiki/architecture/platform-runtime.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
"sourceFingerprint": "sha256:2dabea7464c088c4b7158248f32c211e1c15a2d731f94a1b71ef603c6de8e27c",
|
||||
"pageVersion": "sha256:023da98f47ee307e4847967ad5bf01156edea72720624942c87f64e1a41cf401",
|
||||
"completedBy": "codex",
|
||||
"completedRunId": "c38e9577-d9ab-4c9b-aa03-fe351acada53"
|
||||
"pageVersion": "sha256:714b4eca157c6f95f4ef0792e6f173f13d9134413253216b19e74bc1fad3e833",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "a8323adb-a617-401f-bf5f-4dcc24de41b9",
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3"
|
||||
},
|
||||
"/openwiki/architecture/system-boundaries.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
@@ -44,11 +58,32 @@
|
||||
"completedRunId": "c38e9577-d9ab-4c9b-aa03-fe351acada53"
|
||||
},
|
||||
"/openwiki/concepts/remote-services-and-forwarding.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
"sourceFingerprint": "sha256:2dabea7464c088c4b7158248f32c211e1c15a2d731f94a1b71ef603c6de8e27c",
|
||||
"pageVersion": "sha256:a5119333dde48ffa8eb6bc9978c53286e04e316ad5ab041d1b989f56e5315d0c",
|
||||
"completedBy": "codex",
|
||||
"completedRunId": "c38e9577-d9ab-4c9b-aa03-fe351acada53"
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3",
|
||||
"pageVersion": "sha256:10ea95f6fb5ea0feb5b5f8460c1c8c84091a3d340782befcf5566bda2d187362",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "90d9a42c-23ff-4e6c-bd6f-46d9565a59bc"
|
||||
},
|
||||
"/openwiki/concepts/shell-integration.md": {
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3",
|
||||
"pageVersion": "sha256:3080e12d34f1ea00779670c9322ef8a881013cc0b9818b54ea393ff11c802b17",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "90d9a42c-23ff-4e6c-bd6f-46d9565a59bc"
|
||||
},
|
||||
"/openwiki/concepts/ssh-multiplexing-and-scheduling.md": {
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3",
|
||||
"pageVersion": "sha256:47c2d7e416b47c5104e7fa88cf33c353214d35e4e26759a0bff70dcbd3adda04",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "90d9a42c-23ff-4e6c-bd6f-46d9565a59bc"
|
||||
},
|
||||
"/openwiki/concepts/ui-design-principles.md": {
|
||||
"pageVersion": "sha256:d4f1f7d73a06d827f38ce7288a9b41c230491a7091ac8cc51be5f45c67272655",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "a8323adb-a617-401f-bf5f-4dcc24de41b9",
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3"
|
||||
},
|
||||
"/openwiki/integrations/mcp-server-and-bridge.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
@@ -93,11 +128,11 @@
|
||||
"completedRunId": "c38e9577-d9ab-4c9b-aa03-fe351acada53"
|
||||
},
|
||||
"/openwiki/quickstart.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
"sourceFingerprint": "sha256:af2a6bdb282660739034c16a2084d4badceb69466956e716e9f07108af38c0a7",
|
||||
"pageVersion": "sha256:d24179ca1c2b20df58b7397bac9751d16803f018d8a202587f430adc1bfabae3",
|
||||
"completedBy": "codex",
|
||||
"completedRunId": "614febfd-989e-4262-ad58-f000aebf3570"
|
||||
"pageVersion": "sha256:1a4657f6bcb6994d787c4a157adc6dea712f0eb0512567400e87efceb803eb7c",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "a8323adb-a617-401f-bf5f-4dcc24de41b9",
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3"
|
||||
},
|
||||
"/openwiki/testing/behavioral-boundaries-and-fixtures.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
@@ -106,6 +141,13 @@
|
||||
"completedBy": "codex",
|
||||
"completedRunId": "c38e9577-d9ab-4c9b-aa03-fe351acada53"
|
||||
},
|
||||
"/openwiki/workflows/port-forwarding-pool-and-dispatch.md": {
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3",
|
||||
"pageVersion": "sha256:280d89c1f4f2470dfcd630f23d2ab2a54dc8d48654a2788a54a6b70c99819b4e",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "90d9a42c-23ff-4e6c-bd6f-46d9565a59bc"
|
||||
},
|
||||
"/openwiki/workflows/settings-and-cloud-sync.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
"sourceFingerprint": "sha256:2dabea7464c088c4b7158248f32c211e1c15a2d731f94a1b71ef603c6de8e27c",
|
||||
@@ -114,18 +156,18 @@
|
||||
"completedRunId": "c38e9577-d9ab-4c9b-aa03-fe351acada53"
|
||||
},
|
||||
"/openwiki/workflows/sftp-transfer-and-external-edit.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
"sourceFingerprint": "sha256:2dabea7464c088c4b7158248f32c211e1c15a2d731f94a1b71ef603c6de8e27c",
|
||||
"pageVersion": "sha256:60656f471c069bc3da45fcdf15485094baa49bfd497d84743db6471bcafb6b87",
|
||||
"completedBy": "codex",
|
||||
"completedRunId": "c38e9577-d9ab-4c9b-aa03-fe351acada53"
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3",
|
||||
"pageVersion": "sha256:ac1d6af9add7224acf9b9b467bccfe03d9c9632a41e2912a092e0346161f2a3f",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "03c772f0-1f2f-46f6-b393-e32f369625e0"
|
||||
},
|
||||
"/openwiki/workflows/ssh-session-lifecycle.md": {
|
||||
"gitHead": "c8184c71249aceed74040582518e2e59f8e86b04",
|
||||
"sourceFingerprint": "sha256:2dabea7464c088c4b7158248f32c211e1c15a2d731f94a1b71ef603c6de8e27c",
|
||||
"pageVersion": "sha256:4b8cdc51488e32af2cd1987f942226c14584b4c00da61388e1e567c7dfb8c09b",
|
||||
"completedBy": "codex",
|
||||
"completedRunId": "c38e9577-d9ab-4c9b-aa03-fe351acada53"
|
||||
"gitHead": "bddc07d2e3b0eb6dd05abbf2acab6f7ff2bb22d1",
|
||||
"sourceFingerprint": "sha256:4869a4964de1bf177b90dc3f82240d72e710f5bffb10a0a71b41cbef7c2c81e3",
|
||||
"pageVersion": "sha256:bdb748dc4ba8eb5e1f311f8c6695e023e429c8d19fac4ed2443dac2bb50a8964",
|
||||
"completedBy": "omp",
|
||||
"completedRunId": "03c772f0-1f2f-46f6-b393-e32f369625e0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
type: architecture guide
|
||||
title: TFM Desktop UI Architecture
|
||||
description: "How the macOS app composes its native window shell, persistent workspace deck, split panes, management pages and Assistant surfaces, with explicit UI-state and runtime ownership."
|
||||
tags: [macos, tfm, ui, navigation, workspaces, swiftui, appkit, design]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T02:51:54.212Z
|
||||
sources:
|
||||
- id: openwiki-source-873894299539cce9a737a860
|
||||
resource: repo://TFM/App/RootView.swift
|
||||
- id: openwiki-source-6570374eaac2e0278fa84640
|
||||
resource: repo://TFM/App/TermindApp.swift
|
||||
- id: openwiki-source-95f72232fb896aa95dd5f6c7
|
||||
resource: repo://TFM/Features/AI/TranscriptListView.swift
|
||||
- id: openwiki-source-d35453512ef488d0cacdc06e
|
||||
resource: repo://TFM/Features/Assistant/AssistantView.swift
|
||||
- id: openwiki-source-0854be84b166268626a3cb08
|
||||
resource: repo://TFM/Features/Sidebar/WindowSidebarView.swift
|
||||
- id: openwiki-source-9cfd8531aa60dcfb31f04e04
|
||||
resource: repo://TFM/Features/Vault/VaultWorkspaceView.swift
|
||||
- id: openwiki-source-ba160208435f3410138a3539
|
||||
resource: repo://TFM/Features/Workspaces/PersistentWorkspaceDeckLayout.swift
|
||||
- id: openwiki-source-22b9fca540c3029c5ace451e
|
||||
resource: repo://TFM/Features/Workspaces/WindowModel.swift
|
||||
- id: openwiki-source-931aff66b28d38cd69ce2324
|
||||
resource: repo://TFM/Features/Workspaces/WorkspaceContentView.swift
|
||||
- id: openwiki-source-f6a967b4f14bf50d1af51b8b
|
||||
resource: repo://TFM/UI/Managed/ManagedCardPage.swift
|
||||
- id: openwiki-source-98505b843db3ce6b8e4ca024
|
||||
resource: repo://TFMTests/PersistentWorkspaceDeckLayoutTests.swift
|
||||
- id: openwiki-source-dceb8d7e7c5bb09359e70052
|
||||
resource: repo://TFMTests/ResponsivePageLayoutTests.swift
|
||||
generated: { by: "omp", at: "2026-09-22T02:51:54.212Z" }
|
||||
---
|
||||
|
||||
# TFM Desktop UI Architecture
|
||||
|
||||
TFM uses SwiftUI for composition and AppKit-backed surfaces where native identity, focus, text handling or incremental rendering matters. Its central design is **one Navigator column and one persistent detail deck per window**, not a separate horizontal tab system for every feature.
|
||||
|
||||
This guide describes the current implementation. See [TFI Mobile UI Architecture](/openwiki/architecture/mobile-ui.md) for the different mobile shell and [UI Design Principles](/openwiki/concepts/ui-design-principles.md) for the sharing boundary.
|
||||
|
||||
## Code structure: composition and ownership
|
||||
|
||||
Solid arrows below mean composition/ownership or routing, not necessarily inheritance. The model branch is shown separately because a view appearing in the diagram does not own every runtime it displays.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
App[TermindApp] --> Shared[AppModel and application services]
|
||||
App --> Scene[Main WindowGroup]
|
||||
Scene --> Root[RootView]
|
||||
Root --> Window[WindowModel per window]
|
||||
Root --> Shell[NavigationSplitView]
|
||||
Shell --> Sidebar[WindowSidebarView]
|
||||
Sidebar --> Navigator[WorkspaceNavigatorView]
|
||||
Sidebar --> Tools[AssistantPanelView / Snippets / History]
|
||||
Shell --> Deck[PersistentWorkspaceDeckLayout]
|
||||
Deck --> WorkspaceView[WorkspaceContentView]
|
||||
WorkspaceView --> Split[SplitNodeView / SplitBranchView]
|
||||
Split --> Pane[PaneView]
|
||||
Shell --> Destinations[Vault / Assistant / Metrics / Settings]
|
||||
Window --> WorkspaceModels[WorkspaceDeckModel and Workspaces]
|
||||
Window --> UIState[Sidebar / presentations / selections / queries]
|
||||
Window --> Cache[TranscriptListCache]
|
||||
Shared -. services .-> Window
|
||||
```
|
||||
|
||||
The main layers are:
|
||||
|
||||
| Layer | Responsibility | What should not move into it |
|
||||
| --- | --- | --- |
|
||||
| App composition | Persistence container, shared service graph, launch locale, main and external-authentication scenes, application commands. | One window's selected pane, query, or editor route. |
|
||||
| `WindowModel` | Workspace collection, selected destination, sidebar mode, presentation routes, page selection/search state, transcript cache and connection-service wiring. | A process-global assumption that all windows share the same active session. |
|
||||
| Workspace and pane models | Live session ownership, pane identity, split tree, focused pane and workspace-specific command context. | Temporary divider-drag coordinates or a view's hover state. |
|
||||
| Feature views | Render projected state, present interaction, dispatch intent to owners. | Recreating connections merely because a destination appears. |
|
||||
| Reusable renderers and native bridges | Collection interaction, layout, focus/native mounting, terminal/transcript presentation. | Resource-specific repository mutations hidden behind generic drawing code. |
|
||||
|
||||
`TermindApp` shares `AppModel` across main windows but creates a `WindowModel` for each. `RootView` exposes that model through the environment and focused scene values so commands can target the correct window. The dedicated external-authentication scene is not another normal workspace window and is removed from the ordinary scene-opening commands.
|
||||
|
||||
## The window shell owns chrome once
|
||||
|
||||
`RootView` owns the split view, the window toolbar, search host, native window registration, title reporting, Quick Open, onboarding and app-level presentation bridges. It supplies one leading creation area, a principal Metrics page picker when applicable, and one Find slot following the content in front.
|
||||
|
||||
The sidebar is one column whose mode rail switches between Navigator, Assistant, Snippets and History. `WindowModel.activateSidebarMode` is an **intent operation**, not just a property assignment: choosing Navigator from the full Assistant restores its prior destination, while choosing Assistant inside a workspace opens the contextual sidebar rather than hiding the terminal. Direct mode assignment remains available for presentation/restoration without these navigation side effects. History is unavailable for focused Telnet/serial sessions, and reconciliation moves away from an invalid mode.
|
||||
|
||||
Keep the following coordinates distinct:
|
||||
|
||||
- **Destination**: Vault, a workspace, full Assistant, Metrics or Settings.
|
||||
- **Sidebar mode**: what occupies the one shared left column.
|
||||
- **Focused pane**: the session targeted by workspace commands.
|
||||
- **Presentation route**: an editor, chooser, sheet, or other transient interaction.
|
||||
|
||||
They influence one another, but they are not interchangeable selections. `WindowModel` remembers return destinations for reversible trips to Assistant and Settings. Page searches, selections and archive presentation are window-local, so two windows may inspect the same shared data differently.
|
||||
|
||||
## Persistent workspace deck: hidden is not destroyed
|
||||
|
||||
Every open workspace remains a child of `PersistentWorkspaceDeckLayout`. The selected workspace becomes visible and interactive; parked workspaces are transparent, disabled, excluded from hit testing and hidden from accessibility. Other top-level destinations are overlaid in front of that deck.
|
||||
|
||||
The layout maintains a size cache keyed by workspace identity:
|
||||
|
||||
1. The active workspace receives the current container size and updates its cached size when usable.
|
||||
2. A hidden workspace keeps its last visible size.
|
||||
3. A never-visible workspace captures the first finite, positive parking size.
|
||||
4. Closed workspace IDs are pruned from the cache.
|
||||
|
||||
This is both a lifecycle rule and a layout-performance rule. Keeping views mounted protects terminal grids, scrollback and SFTP state; parking their geometry avoids recursively resizing every hidden split tree during a sidebar animation. Merely changing opacity would not prevent hidden views from receiving new layout proposals.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant Window as WindowModel
|
||||
participant Root as RootView
|
||||
participant Deck as PersistentWorkspaceDeckLayout
|
||||
User->>Window: select Assistant or another workspace
|
||||
Window->>Root: selected destination changes
|
||||
Root->>Deck: update active workspace flags
|
||||
Deck->>Deck: park hidden workspaces at cached sizes
|
||||
Root->>Root: show selected destination and gate interaction
|
||||
Note over Window,Deck: Session ownership is retained
|
||||
User->>Window: return to workspace
|
||||
Deck->>Deck: lay out active workspace at current size
|
||||
```
|
||||
|
||||
Do not replace this with an `if selected { WorkspaceContentView(...) }` that recreates the terminal hierarchy. Equally, do not let parked workspaces handle invisible keyboard shortcuts: broadcast and terminal-find shortcut owners are explicitly disabled unless their workspace is active.
|
||||
|
||||
The floating status bar overlays the current workspace rather than docking below it. This avoids changing the pane's available height when entering a workspace. Command-generation feedback reserves clearance above that capsule instead of competing for the same bottom edge.
|
||||
|
||||
## Split panes: stable identities, explicit fractions
|
||||
|
||||
`WorkspaceContentView` renders the model's recursive `SplitNode`: a leaf produces a stable-ID `PaneView`, while a branch produces a `SplitBranchView`. Branch geometry comes from its stored fraction rather than the divider state of a native `HSplitView` or `VSplitView`. That makes drop previews and later proportional resizing use the same model.
|
||||
|
||||
During divider dragging, a local preview fraction drives geometry. The gesture uses global coordinates and commits the model change once, instead of publishing the entire workspace tree for every mouse event. The divider's visible hairline and its wider hit region are separate design decisions.
|
||||
|
||||
Pane dragging also separates **preview** from **mutation**. The dragged branch is temporarily omitted from the preview geometry while its source view stays mounted; removing the native drag source can terminate the drag before it reaches the Navigator. The model tree changes only when the drop lands. `RootView` deliberately has no ancestor drop target that would compete with pane and Navigator targets for the same internal text payload.
|
||||
|
||||
## Vault and management pages
|
||||
|
||||
Vault management is a list/detail workspace, not a collection of unrelated sheets. `VaultWorkspaceContent` keeps the list and editor children stable across its width breakpoint:
|
||||
|
||||
- With enough space, the list and a fixed-width detail editor appear together.
|
||||
- In a narrow detail region, the editor covers the list; the list retains its last visible size and state.
|
||||
- Editor presentation animates position and reserved space, not the form's own width.
|
||||
|
||||
Resource pages plug into `ManagedCardPage` using typed sections, stable item IDs, externally owned selection, capabilities and page-specific presentation modifiers. `ManagedCardPageRenderer` handles the reusable interaction machinery; the page supplies business cards, section headers, drag ghosts, empty/no-results states and blank-canvas menu entries.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Feature[Resource-specific managed page] --> Spec[Sections / selection / capabilities]
|
||||
Feature --> Views[Cards / headers / empty states]
|
||||
Spec --> Renderer[ManagedCardPageRenderer]
|
||||
Views --> Renderer
|
||||
Renderer --> Geometry[CardPage and drop geometry]
|
||||
Geometry --> Intent[Stable IDs and destination sibling]
|
||||
Intent --> Action[Page-owned move or business action]
|
||||
```
|
||||
|
||||
The renderer resolves a pointer to a section and insertion slot; it does not need to know what a Host, key or snippet means. Selection and deletion state stay with their appropriate owners. Creation belongs in the window toolbar and contextual blank-area menus rather than reintroducing a special “New” tile into each data grid.
|
||||
|
||||
## Assistant: route state and native rendering are separate
|
||||
|
||||
The full Assistant destination and the workspace's compact Assistant are different presentation surfaces. Opening a conversation in the compact sidebar does not replace the foreground terminal. Its transcript region and interaction/composer region can be composed separately, and terminal context/actions are passed deliberately.
|
||||
|
||||
Native transcript ownership adds another boundary:
|
||||
|
||||
- `TranscriptListCache` is window-local.
|
||||
- Its key includes **conversation ID and surface** (`fullScreen` or `sidebar`), because one AppKit view cannot have two superviews.
|
||||
- A persistent owner retains the native list, presentation state, measured row heights and Markdown-related caches while a short-lived SwiftUI mount comes and goes.
|
||||
- The default LRU target is eight owners. Trimming evicts unmounted owners and protects the just-requested owner; if all candidates are mounted, it does not force their eviction merely to meet the target.
|
||||
|
||||
Do not merge this cache with the persistent workspace deck. Both preserve continuity, but workspaces remain mounted with parked geometry while transcripts can unmount their native list and remount a retained owner.
|
||||
|
||||
Escape handling is also scoped. In the compact Assistant, an approval or user-interaction form can own Escape; resolving it must not let the same key event fall through and close the conversation. The view captures the blocking-interaction state for that render before applying its back policy.
|
||||
|
||||
## Desktop design principles and change checklist
|
||||
|
||||
The implemented patterns suggest these rules for extending TFM:
|
||||
|
||||
1. **One owner for each kind of state.** Shared app data, window routes, workspace sessions, native view caches and temporary gestures have different lifetimes.
|
||||
2. **Preserve continuity without keeping everything active.** Park layout, disable invisible interaction, and bound expensive native caches.
|
||||
3. **Make geometry predictable.** Reuse stored split fractions and stable identities; do not let an animation resize editor content incidentally.
|
||||
4. **Use native desktop affordances.** Window-focused commands, keyboard equivalents, pointer selection, context menus and precise drop targets belong in the desktop composition.
|
||||
5. **Keep generic renderers capability-driven.** Share interaction machinery without moving resource-specific mutation or authorization into it.
|
||||
6. **Make reversible navigation explicit.** A trip to Settings or Assistant should not silently discard the workspace the user was using.
|
||||
|
||||
Before changing a UI owner, trace both what happens when its view disappears and what happens when the user explicitly closes its runtime. Those are different events.
|
||||
|
||||
## Verification map
|
||||
|
||||
| Change | Focused seams |
|
||||
| --- | --- |
|
||||
| Multi-window navigation, return routes or sidebar modes | `WindowModel`, `WindowSidebarTests`, `MultiWindowTests`, `SettingsNavigationTests`. |
|
||||
| Hidden workspace layout or drag geometry | `PersistentWorkspaceDeckLayoutTests`; split/pane interaction and broadcast tests. |
|
||||
| Narrow editor or Metrics detail layout | `ResponsivePageLayoutTests`, including native table identity and retained scroll positions. |
|
||||
| Managed selection/reordering | `ManagedCardDropResolver`, selection and marquee tests; resource-specific move tests. |
|
||||
| Transcript persistence, incremental updates or mounting | `TranscriptListViewTests`, rendering and performance suites. |
|
||||
| Focused toolbar and terminal commands | `WindowToolbarFindTests`, `TerminalFindTests`, `UserInputModalityTests`. |
|
||||
|
||||
Some rendering tests explicitly require a visible window; routine checks should not enable those globally. The narrow-editor rendering cases cover English, Simplified Chinese and Traditional Chinese. This guide was derived from implementation and tests; it does not report a new test run or visual approval. Use [Build, Test, and Release Operations](/openwiki/operations/build-test-and-release.md) for the appropriate verification commands.
|
||||
@@ -1,5 +1,7 @@
|
||||
# Files
|
||||
|
||||
- [TFM Desktop UI Architecture](desktop-ui.md) - How the macOS app composes its native window shell, persistent workspace deck, split panes, management pages and Assistant surfaces, with explicit UI-state and runtime ownership.
|
||||
- [Cross-Cutting Engineering Invariants](engineering-invariants.md) - Exhaustive architecture, ownership, lifecycle, security, persistence, remote-session, agent, sync, and mobile safety contracts that span Termind's specialized wiki pages.
|
||||
- [TFI Mobile UI Architecture](mobile-ui.md) - How the iPhone/iPad app composes registered feature stacks, scene-local navigation, shared runtimes, adaptive content regions, native terminal/transcript surfaces and mobile interaction policies.
|
||||
- [Platform Runtime, App Composition, and Lifetimes](platform-runtime.md) - How Termind composes shared services and persistence on macOS and iOS, and where app-wide, window-local, scene-local, and session state begin and end.
|
||||
- [System Boundaries and Dependency Ownership](system-boundaries.md) - Static framework layers, platform composition roots, persistence ownership, and the external AgentKit boundary that keep Termind changes dependency-safe.
|
||||
@@ -0,0 +1,206 @@
|
||||
---
|
||||
type: architecture guide
|
||||
title: TFI Mobile UI Architecture
|
||||
description: "How the iPhone/iPad app composes registered feature stacks, scene-local navigation, shared runtimes, adaptive content regions, native terminal/transcript surfaces and mobile interaction policies."
|
||||
tags: [ios, ipados, tfi, ui, navigation, adaptive-layout, swiftui, uikit]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T02:51:54.212Z
|
||||
sources:
|
||||
- id: openwiki-source-906678adb91c2fce2d3fcaed
|
||||
resource: repo://TFI/App/MobileAppModel.swift
|
||||
- id: openwiki-source-60d390fe6fbfea55a2a8230a
|
||||
resource: repo://TFI/App/MobileFeatureRegistry.swift
|
||||
- id: openwiki-source-c8d832474c03f5ebad7b0578
|
||||
resource: repo://TFI/App/MobileRootView.swift
|
||||
- id: openwiki-source-e43a0da5ab77c2fc3554244d
|
||||
resource: repo://TFI/App/MobileSceneModel.swift
|
||||
- id: openwiki-source-d44869be46c03fbd0ce9c64c
|
||||
resource: repo://TFI/Application/Agent/MobileAssistantModel.swift
|
||||
- id: openwiki-source-99e98ad50ba8a7c6df018977
|
||||
resource: repo://TFI/Design/MobileDesignTokens.swift
|
||||
- id: openwiki-source-0368ecce931d0fb26fe8f35f
|
||||
resource: repo://TFI/DesignSystem/MobileContentRegions.swift
|
||||
- id: openwiki-source-cbeb1570645eae169d495cbb
|
||||
resource: repo://TFI/DesignSystem/MobileLayoutEnvironment.swift
|
||||
- id: openwiki-source-bb7c576ff899dcdee98e37f9
|
||||
resource: repo://TFI/DesignSystem/MobileToolbarEnvironment.swift
|
||||
- id: openwiki-source-3dfad0e95bb7d66f292c20c9
|
||||
resource: repo://TFI/Features/AI/MobileAssistantConversation.swift
|
||||
- id: openwiki-source-d43ef236ba4bbb23d8dab797
|
||||
resource: repo://TFI/Features/Assistant/MobileAssistantView.swift
|
||||
- id: openwiki-source-a337b6f93e72977e59faaf14
|
||||
resource: repo://TFI/Features/Workspaces/MobileWorkspaceListView.swift
|
||||
- id: openwiki-source-4c2de67bfdb2238d765a642a
|
||||
resource: repo://TFI/Features/Workspaces/MobileWorkspaceView.swift
|
||||
- id: openwiki-source-ca0b3e6e839587396cdeaf54
|
||||
resource: repo://TFI/Platform/MobileTerminalSurface.swift
|
||||
- id: openwiki-source-c99ab42abad536ed4396933c
|
||||
resource: repo://TFI/UI/Managed/MobileCards.swift
|
||||
- id: openwiki-source-fffc181d864b6caea779a6f5
|
||||
resource: repo://TFITests/MobileAdaptiveLayoutTests.swift
|
||||
generated: { by: "omp", at: "2026-09-22T02:51:54.212Z" }
|
||||
---
|
||||
|
||||
# TFI Mobile UI Architecture
|
||||
|
||||
TFI is not a scaled-down copy of the desktop split-pane window. It uses system-adaptive top-level tabs/sidebar, a navigation stack for each registered feature, scene-local routing, and shared application-owned sessions. Adaptation changes presentation without automatically replacing the conversation, terminal or connection being presented.
|
||||
|
||||
Read [TFM Desktop UI Architecture](/openwiki/architecture/desktop-ui.md) for the desktop contrast and [UI Design Principles](/openwiki/concepts/ui-design-principles.md) for shared presentation boundaries.
|
||||
|
||||
## Code structure and ownership
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
App[MobileAppModel] --> Shared[Libraries / transfers / forwarding / metrics]
|
||||
App --> Workspaces[MobileWorkspace instances]
|
||||
App --> AssistantRuntime[MobileAssistantModel]
|
||||
Root[MobileRootView] --> Scene[MobileSceneModel per scene]
|
||||
Root --> Registry[MobileFeatureRegistry]
|
||||
Registry --> Tabs[Sidebar-adaptable TabView]
|
||||
Tabs --> Vault[NavigationStack: Vault]
|
||||
Tabs --> Metrics[NavigationStack: Metrics]
|
||||
Tabs --> WorkspaceList[NavigationStack: Workspaces]
|
||||
Tabs --> Assistant[NavigationStack: Assistant]
|
||||
Tabs --> Settings[NavigationStack: Settings]
|
||||
Scene --> Routes[Selection / editor / workspace route]
|
||||
Scene --> AssistantScene[MobileAssistantSceneModel]
|
||||
AssistantScene -. shared runs and store .-> AssistantRuntime
|
||||
WorkspaceList --> Detail[MobileWorkspaceView]
|
||||
Detail -. renders .-> Workspaces
|
||||
Assistant --> Conversation[MobileAssistantConversation]
|
||||
```
|
||||
|
||||
`MobileFeatureRegistry` is the single registration table for feature identity, order, localized title, symbol and view builder. Its standard order is Vault, Metrics, Workspaces, Assistant, Settings, and duplicate destination registration is rejected. `MobileRootView` iterates registrations rather than maintaining independent tab/sidebar/destination switches.
|
||||
|
||||
Each registered destination gets its own `NavigationStack`; the enclosing `TabView` uses `.sidebarAdaptable`. The system can change where navigation appears without the app rebuilding a different root tree for “phone” and “tablet.” `MobileLayout` supplies a compact/regular hint, defaulting to compact when size class is absent; it is not the whole adaptive layout algorithm.
|
||||
|
||||
### State lifetime matrix
|
||||
|
||||
| Owner | State or work | Expected lifetime |
|
||||
| --- | --- | --- |
|
||||
| `MobileAppModel` | Shared libraries, live/saved workspaces, transfers, synchronization and aggregate scene activity. | Application/service lifetime. |
|
||||
| `MobileSceneModel` | Selected destination, workspace route, pending activation, editor/rename presentation, scene-local recent selection. | One scene. |
|
||||
| `MobileAssistantModel` | Shared conversation store and execution services. | Survives scene navigation. |
|
||||
| `MobileAssistantSceneModel` | Selected conversation and New Chat draft through its own library model. | Independent per scene over the shared store. |
|
||||
| `MobileWorkspace` / `MobileTerminalSurface` | Connection/session state and owned native terminal view. | Workspace lifetime, not just the currently pushed detail. |
|
||||
| Feature view state | Temporary picker, preview, drop loading and focus-request state. | Current presentation. |
|
||||
|
||||
Two iPad scenes can navigate independently without creating two copies of an already-running conversation. Likewise, selecting a workspace looks up the shared instance; `MobileAppModel.openWorkspace` publishes a restored workspace before connection work so scenes do not race to create separate initial instances.
|
||||
|
||||
## Navigation is an intent sequence
|
||||
|
||||
Opening a Host from another feature is deliberately staged:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant Scene as MobileSceneModel
|
||||
participant App as MobileAppModel
|
||||
participant List as MobileWorkspaceListView
|
||||
User->>Scene: activate Host or open explicit connection
|
||||
Scene->>App: resolve or create workspace
|
||||
Scene->>Scene: store pending ID and select Workspaces
|
||||
List->>List: destination task yields once
|
||||
List->>Scene: activatePendingWorkspace
|
||||
Scene->>Scene: set workspaceID and update recent selection
|
||||
List->>List: push MobileWorkspaceView
|
||||
```
|
||||
|
||||
When already on Workspaces, the scene can present the route directly. When changing tabs, pending activation waits for the Workspaces destination to participate before pushing its detail. Selecting another top-level destination clears pending workspace activation rather than leaving a delayed push armed.
|
||||
|
||||
Host activation and explicit connection actions are different:
|
||||
|
||||
- `activateHost` prefers this scene's most recently selected matching terminal workspace, then another existing matching workspace, before creating one.
|
||||
- Explicit SSH/SFTP connection actions call the open path and can create independent workspaces.
|
||||
- The workspace title switcher replaces the pushed detail by workspace identity. This resets detail-specific state such as SFTP search without treating the owned terminal/session as a newly created runtime.
|
||||
|
||||
Unavailable saved workspace IDs produce an explicit unavailable state; a stale route does not silently open some other Host. Root-level deep links, quick actions and focused scene commands dispatch through that scene's model.
|
||||
|
||||
## Adaptation has three inputs, not one device check
|
||||
|
||||
| Input | Mechanism | What it controls |
|
||||
| --- | --- | --- |
|
||||
| System navigation placement | `MobileToolbarLayout`, read from tab placement and optionally vertical toolbar edge. | Icon versus title switcher and whether workspace detail keeps tabs visible. |
|
||||
| Available content geometry | `MobileRegionReader` → `MobileContentRegions`. | Continuous safe area and optional pair of regions around a division. |
|
||||
| Content/input needs | Measured card width, Dynamic Type, composer height, focus and marked text. | Grid density, scrolling and retained native input surfaces. |
|
||||
|
||||
### Content-region algorithm
|
||||
|
||||
`MobileContentRegions` starts with the local container bounds, filters active intersecting reserved regions, and computes the largest usable rectangle that avoids them. It retains overlapping candidate rectangles during subtraction; forcing candidates to be disjoint could discard the largest continuous solution. Equal-area candidates prefer earlier vertical then horizontal coordinates.
|
||||
|
||||
A **division** can additionally yield a pair of usable regions on either side. An **occlusion** reduces usable space but does not by itself request a two-pane layout. A division with one unusable side is not a valid split. This is region-based layout, not a hard-coded assumption that a particular device always has a hinge.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Bounds[Container bounds] --> Regions[MobileContentRegions]
|
||||
Reserved[Active divisions and occlusions] --> Regions
|
||||
Regions --> Continuous[Largest continuous rectangle]
|
||||
Regions --> Pair[Optional usable split pair]
|
||||
Continuous --> Terminal[Workspace terminal or SFTP content]
|
||||
Pair --> Assistant[Transcript and interaction regions]
|
||||
Continuous --> Assistant
|
||||
Assistant --> Layout[MobilePaneLayout with stable children]
|
||||
```
|
||||
|
||||
Production reserved-region and vertical-toolbar queries require both the `TERMIND_HAS_IOS_27_1_SDK` compilation gate and runtime availability. On older builds/systems the reader falls back to no reserved regions, while previews/tests can inject regions through the environment. The presence of deterministic fold-like tests is not a claim of verification on every physical device.
|
||||
|
||||
`MobilePaneLayout` retains a valid size per child index and places the same children into their new frames. Covered content keeps a valid size rather than replacing or reparenting its native surface. The layout must be paired with opacity, hit-testing and accessibility gates: parked geometry alone does not make a covered view noninteractive.
|
||||
|
||||
### Examples
|
||||
|
||||
- A terminal workspace uses the largest **continuous** region instead of splitting one terminal across a division.
|
||||
- Assistant uses the first split region for the transcript and bottom-aligns its interaction surface in the second. Without a split, it subtracts measured interaction height from the continuous transcript region.
|
||||
- A top or vertical navigation arrangement uses an icon-based workspace/conversation switcher; the ordinary arrangement can use the navigation title menu.
|
||||
- Cards adapt to their measured container width, not a global “iPad has two columns” rule. Accessibility Dynamic Type forces one column.
|
||||
|
||||
## Workspace UI: protocol-specific actions, retained terminal
|
||||
|
||||
`MobileWorkspaceView` composes the connection/content area, search, feedback overlays, toolbar and transient sheets. Its toolbar is capability-shaped:
|
||||
|
||||
| Workspace kind | Representative actions |
|
||||
| --- | --- |
|
||||
| SSH | Generate Command, Snippets, command History, terminal match navigation, same-directory action and workspace lifecycle. |
|
||||
| Telnet | Snippets, terminal match navigation and lifecycle; it does not inherit the SSH generation/history surface. |
|
||||
| SFTP | Back/forward directory, Transfers, SFTP History, upload/new folder/paste, sort/hidden files/refresh, same-directory action and lifecycle. |
|
||||
|
||||
These are not all enabled merely because the menu exists. Connection state, available history, refresh state and operation capability control individual actions.
|
||||
|
||||
`MobileTerminalSurface` owns the native terminal view even when SwiftUI navigates away. Its `MobileTerminalView` adds terminal Find key equivalents while preserving Ghostty's ordinary key commands. Escape is intercepted for Find dismissal only while Find is actually presented.
|
||||
|
||||
Presentation cleanup is narrower than session shutdown: workspace view disappearance disables external Open With presentation and window drop handling, clears drop targeting and cancels drop loading. It is not itself the instruction to disconnect the workspace. Drop handling is also gated by scene activity and destination changes, so an invisible detail does not accept a late upload as though it were foreground.
|
||||
|
||||
Command-generation and upload notices are overlays in the usable region; they do not take over hit testing. File previews, edit-copy export, transfer sheets and conflict alerts remain explicit temporary presentations over the workspace rather than new session owners.
|
||||
|
||||
## Assistant: stable transcript/input, independent run ownership
|
||||
|
||||
`MobileAssistantView` owns conversation navigation controls, library/archive routes and focus restoration requests. Replacing a conversation preserves composer focus only when it was already focused and the new state can accept focus. The asynchronous request rechecks the conversation ID after yielding, preventing an old request from focusing the wrong chat.
|
||||
|
||||
`MobileAssistantConversation` renders an incremental `MobileNativeList` plus a separately measured, scrollable interaction region. Stable entry IDs and per-row presentation revisions let disclosure changes target the relevant rows; viewport callbacks collapse offscreen work presentations. Transcript and interaction children remain stable through region changes, preserving native list identity and text-input composition.
|
||||
|
||||
The interaction region can contain more than the composer, so its height is measured rather than assumed from a fixed input-bar constant. It bottom-aligns and scrolls based on content size. Tapping the transcript can dismiss composer focus without changing the conversation or ending the run.
|
||||
|
||||
The application runtime owns execution, not `onDisappear` on the conversation view. The view's disappearance only removes its temporary preview directory. App background expiration is a separate boundary.
|
||||
|
||||
## Scene activity and background limits
|
||||
|
||||
`MobileRootView` reports its scene phase; `MobileAppModel` aggregates all scenes. Entering background handling occurs when **all tracked scenes** are backgrounded, not whenever one feature disappears or one scene resigns activity.
|
||||
|
||||
At that boundary the app pauses edit monitoring, memory/sync/Metrics/outbox work and recording, then starts its background allowance. Expiration suspends workspaces, stops forwarding, pauses transfers and expires Assistant background execution. An active scene ends the allowance and asks retained workspaces to resume, rechecks edited files, and restarts the appropriate services. This is best-effort mobile continuity, not unlimited background network execution.
|
||||
|
||||
Closing a workspace, navigating back from its detail, switching tabs, and exhausting background allowance are therefore four different actions with different owners. A UI refactor must preserve that distinction.
|
||||
|
||||
## Mobile design principles and verification
|
||||
|
||||
Implemented principles:
|
||||
|
||||
1. **Let the system adapt navigation.** Register each feature once and keep its stack stable.
|
||||
2. **Adapt to usable space and capability.** Size class alone is insufficient for divisions, occlusions, vertical toolbars and large text.
|
||||
3. **Preserve native input identity.** A layout transition should not discard marked text, keyboard focus or terminal scrollback.
|
||||
4. **Use mobile affordances without losing desktop parity of intent.** Primary card taps, context menus, swipe actions, title menus and hardware-keyboard commands can expose the same operation differently.
|
||||
5. **Keep app work out of transient view lifetimes.** Scene routes select shared work; they do not own every connection or Agent run.
|
||||
6. **Hide covered interaction as well as pixels.** Hit testing and accessibility must follow the visible region.
|
||||
|
||||
`MobileAdaptiveLayoutTests` exercises native tab identity across compact/regular widths, all five destinations, Dynamic Type and English/Chinese variants. It also checks that region changes retain the Metrics list and scroll position, and preserve Assistant conversation identity, native transcript, composer focus and marked Chinese text. These tests validate injected geometry and navigation behavior; platform availability and real-device presentation still need appropriate device verification.
|
||||
|
||||
For a change, inspect scene routing tests for navigation, region/layout tests for geometry, workspace/terminal tests for session continuity, and Assistant tests for run-versus-selection ownership. See [Platform Runtime Composition](/openwiki/architecture/platform-runtime.md) and [Build, Test, and Release Operations](/openwiki/operations/build-test-and-release.md) before changing the lifetime boundary.
|
||||
@@ -5,7 +5,7 @@ description: How Termind composes shared services and persistence on macOS and i
|
||||
tags: [architecture, runtime, macos, ios, lifecycle, dependency-injection]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T01:13:21.371Z
|
||||
at: 2026-09-22T02:51:54.212Z
|
||||
sources:
|
||||
- id: openwiki-source-cd0be716a2446029f345525a
|
||||
resource: repo://Termind.xcodeproj/project.pbxproj
|
||||
@@ -35,7 +35,7 @@ sources:
|
||||
resource: repo://TFMTests/ArchitectureBoundaryTests.swift
|
||||
- id: openwiki-source-531f6567ecf96fd4b0c5e97a
|
||||
resource: repo://TFMTests/ExternalConnectionURLTests.swift
|
||||
generated: { by: "openwiki/0.5.2", at: "2026-09-22T00:31:10.149Z" }
|
||||
generated: { by: "omp", at: "2026-09-22T02:51:54.212Z" }
|
||||
---
|
||||
|
||||
# Platform Runtime, App Composition, and Lifetimes
|
||||
@@ -44,6 +44,14 @@ Termind has separate native application targets—`TFM` for macOS and `TFI` for
|
||||
|
||||
The most important lifetime rule is: **stores, coordinators, and durable-data services are app-wide; navigation, presentation, and desktop workspace ownership are local to a window; mobile navigation is local to a scene; live transports belong to the workspace/session that opened them.** Do not move state across those boundaries merely to make a UI path convenient.
|
||||
|
||||
## UI structure and design guides
|
||||
|
||||
This page explains runtime composition and lifetime boundaries. For the component trees and user-facing presentation rules, continue with:
|
||||
|
||||
- [TFM Desktop UI Architecture](/openwiki/architecture/desktop-ui.md): window shell, persistent workspace deck, split panes, Vault list/detail, managed cards and native transcript ownership.
|
||||
- [TFI Mobile UI Architecture](/openwiki/architecture/mobile-ui.md): registered feature stacks, scene-local routes, shared workspaces, usable-region layout, mobile toolbars and native input continuity.
|
||||
- [UI Design Principles and Shared Presentation Boundaries](/openwiki/concepts/ui-design-principles.md): what the platforms share, where their visual/input policies intentionally differ, and how to extend them without merging runtime ownership.
|
||||
|
||||
## Lifetime map
|
||||
|
||||
| Scope | macOS | iOS/iPadOS | Examples |
|
||||
|
||||
@@ -3,4 +3,7 @@
|
||||
- [Assistant, Agent Runtime, Skills, and Memory](agent-runtime-and-assistant.md) - How Termind assembles AgentKit into durable assistant conversations, applies approval and host-security boundaries, and manages skills, scratch workspaces, and device-local Hermes memory.
|
||||
- [Commerce, Localization, and Product Surfaces](commerce-localization-and-product-surfaces.md) - Explains StoreKit-derived Pro access, native paywall and review ownership, localization completion rules, and the app, widget, screenshot, and marketing-site surfaces that present the product.
|
||||
- [Persistent Data, Migrations, and Secret Boundaries](persistence-and-secrets.md) - How Termind owns SwiftData and GRDB durable data, evolves compatible schemas, projects records through repositories, and keeps credentials in Keychain-backed and runtime-only boundaries.
|
||||
- [Remote services and forwarding](remote-services-and-forwarding.md)
|
||||
- [Remote services and forwarding](remote-services-and-forwarding.md) - Cross-service ownership of SSH terminal, metrics, SFTP, Agent, and forwarding runtimes, with routing to detailed channel scheduling, shell integration, and multi-connection dispatch mechanisms.
|
||||
- [Shell Integration: Bootstrap, OSC Events, and Terminal State](shell-integration.md) - How Termind installs session-local Bash, Zsh, and Fish hooks over the PTY, hides bootstrap exchanges, decodes OSC events, and drives cwd, history, startup commands, and command composition on macOS and iOS.
|
||||
- [SSH Multiplexing, Channel Admission, and I/O Scheduling](ssh-multiplexing-and-scheduling.md) - The concrete ownership and scheduling layers behind Termind SSH: per-connection session leases, serial libssh2 workers, exec state machines, multiplexed SFTP retries, readiness, backpressure, and feature-specific connection reuse.
|
||||
- [UI Design Principles and Shared Presentation Boundaries](ui-design-principles.md) - Source-backed UI principles for TFM and TFI: semantic visual systems, native interaction, shared forms and presentation values, stable rendering identity, accessibility, localization and safe extension boundaries.
|
||||
@@ -1,10 +1,12 @@
|
||||
---
|
||||
type: "Reference"
|
||||
title: "Remote services and forwarding"
|
||||
description: "Cross-service ownership of SSH terminal, metrics, SFTP, Agent, and forwarding runtimes, with routing to detailed channel scheduling, shell integration, and multi-connection dispatch mechanisms."
|
||||
tags: [ssh, terminal, metrics, sftp, port-forwarding, scheduling]
|
||||
openwiki_generated: true
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T01:13:21.371Z
|
||||
at: 2026-09-22T02:43:23.140Z
|
||||
sources:
|
||||
- id: openwiki-source-ca49232858afa421bf33a03b
|
||||
resource: repo://Frameworks/TermindApplication/Metrics/ServerMetricsModel.swift
|
||||
@@ -20,20 +22,45 @@ sources:
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHMaxSessionsPolicy.swift
|
||||
- id: openwiki-source-600c0f7b9ebcdcb58b4a0d05
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHMetricsSampler.swift
|
||||
- id: openwiki-source-f3c300fe43c8f1ceb0906ed3
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHMultiplexedSFTPChannelOwner.swift
|
||||
- id: openwiki-source-8c4abf5c09db535e2818e3c4
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift
|
||||
- id: openwiki-source-b347308e8c5cc6c0b0d29b7d
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferContext.swift
|
||||
- id: openwiki-source-c4b6e224fdbea6dcd393344d
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/Transfers/SFTPTransferCoordinator.swift
|
||||
- id: openwiki-source-52a93fdcfe9295de26f2b72d
|
||||
resource: repo://FrameworkTests/SSHMetricsSamplerTests.swift
|
||||
- id: openwiki-source-7468ad597251e97aa63a1c55
|
||||
resource: repo://TFMTests/PortForwardingReconnectTests.swift
|
||||
- id: openwiki-source-ec3ec372dd69a7df3113c6b1
|
||||
resource: repo://TFMTests/SSHMaxSessionsPolicyTests.swift
|
||||
generated: { by: "codex", at: "2026-09-22T01:13:21.371Z" }
|
||||
generated: { by: "omp", at: "2026-09-22T02:43:23.140Z" }
|
||||
---
|
||||
|
||||
|
||||
SSH is a shared transport substrate, not a single shared runtime. Terminal sessions, Metrics, port forwarding, SFTP, and Agent work can all use SSH, but each feature owns its own intent, connection lifetime, interaction surface, and recovery policy. In particular, a live authentication result or a forwarding listener is memory-only: it is not restored from saved Host or forwarding-rule data. See [SSH session lifecycle](/openwiki/workflows/ssh-session-lifecycle.md) for the general connection journey and [Agent runtime and assistant](/openwiki/concepts/agent-runtime-and-assistant.md) for Agent-specific transport ownership.
|
||||
|
||||
## Implementation deep dives
|
||||
|
||||
This page explains service ownership. Follow these guides when changing the actual algorithms:
|
||||
|
||||
- [SSH Multiplexing, Channel Admission, and I/O Scheduling](/openwiki/concepts/ssh-multiplexing-and-scheduling.md): distinguish a physical connection from its channels, trace exec/SFTP turns on the libssh2 owner, and understand readiness, retry buffers, and backpressure.
|
||||
- [Shell Integration: Bootstrap, OSC Events, and Terminal State](/openwiki/concepts/shell-integration.md): follow probe/install timeouts, Bash/Zsh/Fish hooks, output filtering, cwd/home, command history, and compose state.
|
||||
- [Port Forwarding: Multi-Connection Pool and Flow Dispatch](/openwiki/workflows/port-forwarding-pool-and-dispatch.md): follow pool warm-up, accepted-socket assignment, single-worker remote forwarding, per-flow pumping, recovery, and teardown.
|
||||
- [SFTP Transfer, Scheduling, and External Edit Workflow](/openwiki/workflows/sftp-transfer-and-external-edit.md): follow file admission through context topology selection, extra-connection fallback, transfer completion, and edit ownership.
|
||||
|
||||
### The limits count different resources
|
||||
|
||||
| Control | Scope and accounting unit | It does not mean |
|
||||
| --- | --- | --- |
|
||||
| `SSHMaxSessionsPolicy` / `SSHChannelBudget` | A shared preference creates a separate FIFO lease budget for shell, exec, and subsystem channels on each physical connection. | A process-wide socket limit or a cap on forwarded TCP flows. |
|
||||
| `SFTPConcurrencyScheduler` | One admitted logical file operation process-wide, with a slot on every distinct endpoint Host and optional exclusive borrowed resources. | One permit per SSH channel/socket; a two-endpoint copy still consumes one global permit. |
|
||||
| `SSHForwardingConnectionPool` | A Host-context target for physical connections; only local/dynamic registrations require auxiliary slots. | An SFTP file limit or multiple workers for one remote listener. |
|
||||
|
||||
These controls compose rather than replace each other. For example, an SFTP file can already hold its global/per-host permit while waiting for a session-channel lease on a busy primary connection.
|
||||
|
||||
## Service boundaries
|
||||
|
||||
| Service | Primary owner and connection shape | Interactive behavior | What it does not inherit |
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
type: implementation guide
|
||||
title: "Shell Integration: Bootstrap, OSC Events, and Terminal State"
|
||||
description: "How Termind installs session-local Bash, Zsh, and Fish hooks over the PTY, hides bootstrap exchanges, decodes OSC events, and drives cwd, history, startup commands, and command composition on macOS and iOS."
|
||||
tags: [ssh, terminal, shell-integration, osc, command-history, charset, lifecycle]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T02:43:23.140Z
|
||||
sources:
|
||||
- id: openwiki-source-209392b5f97bd72d0bd87a15
|
||||
resource: repo://Frameworks/TermindApplication/Agent/TerminalCommandDraftController.swift
|
||||
- id: openwiki-source-9302a1b0b7b0f5227d741afd
|
||||
resource: repo://Frameworks/TermindDomain/Hosts/HostShellIntegrationMode.swift
|
||||
- id: openwiki-source-9dfd0d1178e2ed5b33263580
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/RemoteCharsetConverter.swift
|
||||
- id: openwiki-source-8c4abf5c09db535e2818e3c4
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift
|
||||
- id: openwiki-source-492f738896225c6b3acf7d2f
|
||||
resource: repo://TFI/Features/Workspaces/MobileWorkspace.swift
|
||||
- id: openwiki-source-7e796927b780e67cc73f6a5b
|
||||
resource: repo://TFM/Features/Terminal/SSHSessionModel.swift
|
||||
- id: openwiki-source-b8ffa1b375037613d943e75b
|
||||
resource: repo://TFMTests/CommandHistoryTests.swift
|
||||
- id: openwiki-source-d94aebde8a56adf5ef02c658
|
||||
resource: repo://TFMTests/HostShellIntegrationSessionTests.swift
|
||||
generated: { by: "omp", at: "2026-09-22T02:43:23.140Z" }
|
||||
---
|
||||
|
||||
# Shell Integration: Bootstrap, OSC Events, and Terminal State
|
||||
|
||||
## Ownership and entrypoint
|
||||
|
||||
Shell integration is a **PTY feature**, not a prerequisite for authentication or a script run on every SSH connection. `SSHPTYChannelWorker.connect` opens the session channel, requests an `xterm-256color` PTY, sends configured environment requests, starts the shell, installs the nonblocking transport buffer, and only then queues `RemoteShellIntegrationBootstrap.startCommand` when enabled. Environment rejection is nonfatal only for `LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED`; other errors fail setup. Non-PTY exec, SFTP, forwarding, and Metrics use their own paths rather than this bootstrap.
|
||||
|
||||
`HostShellIntegrationMode` resolves `followGlobalSettings`, `enabled`, or `disabled` against the global terminal preference. Desktop and mobile capture that decision at the beginning of a connection attempt; changing settings does not retrofit hooks into the live shell. `HostShellIntegrationSessionTests.connectionRetainsItsPreferenceUntilTheNextAttempt` protects this boundary.
|
||||
|
||||
The value-type bootstrap and event filter are driven by the PTY's queue-confined worker behind its actor facade. Keep the pure parsing/state-machine seams separate from native feature state. For authentication and teardown context, start with [SSH Session Lifecycle](/openwiki/workflows/ssh-session-lifecycle.md); for shared I/O ownership, use [SSH Multiplexing and Scheduling](/openwiki/concepts/ssh-multiplexing-and-scheduling.md).
|
||||
|
||||
## End-to-end byte and event path
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Shell[Remote PTY output] --> Bootstrap[Bootstrap receive or poll]
|
||||
Bootstrap -->|probe or install command| Writes[PTY pending writes]
|
||||
Bootstrap -->|availability and system metadata| Events[Shell integration events]
|
||||
Bootstrap -->|visible bytes| Filter[Token-scoped OSC 777 filter]
|
||||
Filter -->|command prompt draft events| Events
|
||||
Filter -->|remaining bytes| Cwd[OSC 7 remote-charset rewrite]
|
||||
Cwd --> Charset[Streaming charset conversion to UTF-8]
|
||||
Charset --> Terminal[Native terminal backend]
|
||||
Terminal --> WorkingDirectory[Parsed working directory]
|
||||
Events --> Feature[Desktop session or mobile workspace]
|
||||
WorkingDirectory --> Feature
|
||||
```
|
||||
|
||||
`deliverOutput` first lets the bootstrap suppress its exchange. `applyShellIntegrationUpdate` queues any next command, emits availability/home/system events, and routes visible bytes through `deliverIntegratedOutput`. That method removes recognized OSC 777 frames, forwards remaining output, then emits its ordered event array. `emitConvertedOutput` rewrites OSC 7 before the streaming charset converter and terminal callback. Thus parsing is not performed by searching already-rendered terminal text, and ordering within the event array does not imply atomic ordering with native terminal rendering.
|
||||
|
||||
## Probe and install state machine
|
||||
|
||||
The bootstrap creates a per-instance UUID-derived token. The first command starts with an inert `__TRMD_<token>_PROBE__` argument to `command true`; that early marker survives common line-editor redraws better than matching the full command. A POSIX `sh` helper reads `/etc/os-release` or `/usr/lib/os-release` as **assignment text**, not by sourcing it, and reports selected fields plus `uname` values. A separate marker reports `$SHELL`; its basename selects Bash, Zsh, or Fish. This is detection from the environment's shell path, not an executable/process identity attestation.
|
||||
|
||||
The exchange uses tokenized text markers:
|
||||
|
||||
| Marker | Purpose |
|
||||
| --- | --- |
|
||||
| `__TRMD_<token>_PROBE__` | Identify probe echo, including a colorized/redrawn command line. |
|
||||
| `__TRMD_<token>_SYSTEM__…__` | Carry distribution and kernel fields. |
|
||||
| `__TRMD_<token>_SHELL__…__` | Select the shell-specific installer. |
|
||||
| `__TRMD_<token>_HOME__…` | Carry percent-encoded remote `$HOME`. |
|
||||
| `__TRMD_<token>_DONE__` | Complete installation and release the preserved banner/final prompt. |
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Probing
|
||||
Probing --> Installing: supported shell marker
|
||||
Probing --> Complete: unsupported shell
|
||||
Probing --> ScanningLate: 3 seconds without recognized echo
|
||||
Probing --> SuppressingLate: 3 seconds with probe echo
|
||||
ScanningLate --> SuppressingLate: late signature found
|
||||
SuppressingLate --> Installing: supported shell and no user write
|
||||
SuppressingLate --> Complete: unsupported shell or user already wrote
|
||||
SuppressingLate --> Complete: deadline or quiet timeout
|
||||
Installing --> Complete: DONE marker
|
||||
Installing --> Complete: installation deadline
|
||||
```
|
||||
|
||||
The first probe deadline is **3 seconds**. It restores ordinary output and reports home resolution unavailable, but intentionally does **not** mark the bootstrap complete: a late-signature scanner remains active. The scanner streams unrelated output through, retains only a possible signature suffix, and flushes an unresolved suffix after **500 ms** of quiet. Recognized late-probe suppression ends at its 3-second deadline or after 500 ms of quiet. Installation gets its own 3-second deadline.
|
||||
|
||||
`write(_:)` calls `noteUserInput` before appending user bytes. If a supported probe arrives **late** after any user write, the bootstrap skips installation so it does not inject a hook command into the user's new input. This check is specifically the late-probe branch; it is not a general rule that any early keystroke immediately cancels bootstrap. An unsupported shell likewise gets no installation command. Successful installation emits the saved banner plus bytes after the DONE line; timeout cleanup attempts to keep the latest prompt while hiding probe/installer echo.
|
||||
|
||||
Home parsing percent-decodes using the configured remote charset, accepts only an absolute path, and rejects control characters/newlines. Missing or invalid home metadata does not make a supported hook installation fail. System metadata is optional as well.
|
||||
|
||||
## Hooks installed in each remote shell
|
||||
|
||||
The installer defines functions and bindings in the **current shell session**; it does not edit `.bashrc`, `.zshrc`, or a Fish configuration file. A token variable guards repeat installation for that token. The scripts report cwd as standard `OSC 7;file://localhost<percent-encoded PWD>` and use private OSC 777 frames for other events.
|
||||
|
||||
| Shell | Command/prompt hooks | Compose bindings and compatibility details |
|
||||
| --- | --- | --- |
|
||||
| Bash | Uses `bash-preexec` arrays when present; otherwise composes the existing DEBUG trap and prepends its prompt function to array/string `PROMPT_COMMAND`. | Reads `READLINE_LINE`; supports emacs-standard, vi-insertion, and vi-command maps. Internal `__termind_*` calls are excluded from command-start reporting. |
|
||||
| Zsh | Adds `preexec` and `chpwd` hooks and prepends its prompt function to `precmd_functions` while retaining peers. | Reads `BUFFER`; binds emacs, viins, and vicmd. Uses `command_status`, not Zsh's read-only special parameter `status`, and returns the previous exit status. |
|
||||
| Fish | Uses `fish_preexec`, `fish_postexec`, `fish_prompt`, and PWD-variable events. | Reads `commandline`; binds default, insert, and visual maps. Completion uses `$status` and `$CMD_DURATION`. |
|
||||
|
||||
Bash/Zsh compute duration from whole-second `SECONDS` deltas expressed in milliseconds; Fish supplies `CMD_DURATION`. Do not interpret all reported durations as equally precise. Bash/Zsh prompt hooks emit completion when active, then cwd and prompt; Fish completion is reported by its postexec hook. The runtime Zsh tests exercise real interactive preexec/precmd chains and a prompt plugin that captures startup stdout, not merely syntax validity.
|
||||
|
||||
## OSC event protocol and parser limits
|
||||
|
||||
The following are descriptions of wire frames, not strings to paste into a terminal. `ESC` is `0x1B` and `BEL` is `0x07`:
|
||||
|
||||
| Frame between `ESC ]` and `BEL` | Local event |
|
||||
| --- | --- |
|
||||
| `777;TermindCommand=<token>;<encoded text>` | `commandStarted(String)`; empty commands are rejected. |
|
||||
| `777;TermindCommandFinished=<token>;<status>[;<milliseconds>]` | `commandFinished(Int32, duration:)`. |
|
||||
| `777;TermindPrompt=<token>` | `promptReady`; only an empty payload is accepted. |
|
||||
| `777;TermindDraft=<token>;<encoded text>` | `draft(String)`; an empty draft is valid. |
|
||||
|
||||
`RemoteCommandEventFilter` finds the earliest recognized prefix, preserves preceding output, waits for BEL, decodes the event, and repeats. It retains incomplete prefix suffixes across SSH reads, so a frame split at any byte still works. Command/draft payloads are percent-decoded to remote-charset bytes and then converted to text. Status must be `0...255`; a valid optional duration is an unsigned value no larger than `31_536_000_000` milliseconds and is converted to seconds. Invalid duration becomes absent rather than invalidating a valid status.
|
||||
|
||||
Payload retention is capped at **64 KiB** for recognized frames. An oversized unterminated frame is dropped so future output can resume; an oversized terminated frame is skipped. Ordinary output, OSC 0/2 titles, and wrong-token OSC 777 data remain on the terminal path and generate no local command events.
|
||||
|
||||
The token provides **session scoping and accidental/spoofed-frame rejection without the matching token**, not cryptographic authentication against the remote host: the installer sends the token to that host and stores it in shell state. Treat command text, paths, and system fields as remote input even after they pass this parser. Also, OSC 7 is a standard terminal signal and is not authenticated by the OSC 777 token.
|
||||
|
||||
## Cwd, home, history, and composition are different state
|
||||
|
||||
- **Cwd** comes through the terminal's OSC 7 handling. `RemoteOSC7CharsetFilter` recognizes `file://localhost`, decodes the remote-charset path and re-encodes it as percent-encoded UTF-8 before the terminal parses it. Desktop observes `TerminalViewState.workingDirectory`. **Home** comes from the bootstrap HOME marker and is stored separately for path display; an unresolved home is not evidence that cwd is absent.
|
||||
- **Availability** means installation completed. On desktop, `.available` sets integration available but leaves `isShellPromptReady = false`; `.promptReady` sets it true and `.commandStarted` clears it. Mobile intentionally also treats `.available` and `.commandFinished` as prompt-ready recovery boundaries, because a separate prompt marker may not reach mobile state. Do not merge these policies during a shared-state refactor.
|
||||
- **History** is driven by command-start/completion events, not by recording every keystroke. Both consumers normalize explicit line continuations and associate completion with the active recorded row. Their one-shot startup-command exclusion suppresses only the matching synthetic command rather than disabling subsequent history.
|
||||
- **Startup submission readiness** is separate from command-generator prompt readiness. Desktop can unblock a pending startup command on `.available`, `.promptReady`, or `.homeResolutionUnavailable`, so failed/late integration does not indefinitely withhold startup work.
|
||||
- **Composition** reads the current shell draft with `ESC [777;1~`. `TerminalCommandDraftController` allows one pending read, times it out after 2 seconds, and resolves it from a draft event. Replacement sends the clear binding `ESC [777;2~` followed by bracketed-paste start/content/end, with no submit newline. The feature gates reads on a live supported shell, enabled/available integration, and prompt readiness.
|
||||
|
||||
Desktop callbacks reject a mismatched `connectionAttemptID`. Mobile serializes exit and shell events through one `AsyncStream` consumer guarded by the workspace generation, preserving event consumption order across MainActor delivery. Closing the PTY clears bootstrap, command filter, converters, and pending input; the underlying SSH connection may remain alive if sibling SFTP channels still own it. See the transfer lifetime distinction in [SFTP Workflow](/openwiki/workflows/sftp-transfer-and-external-edit.md).
|
||||
|
||||
## Debugging and focused test map
|
||||
|
||||
| Symptom or change | First seam to inspect | Regression evidence |
|
||||
| --- | --- | --- |
|
||||
| Probe/installer text appears, or a slow login loses its prompt | `receiveProbe`, `scanForLateProbe`, `poll`, `cleanBufferedOutput` | `ShellIntegrationBootstrapTests`: redraw, chunked late probe, quiet timeout, user-input skip, unsupported shell. |
|
||||
| Zsh prompt or ordinary output disappears | Installer's prompt hook and exit-status preservation | `zshRunsPromptHooksAndPreservesCommandOutput`, including startup-output capture. |
|
||||
| History duplicates or has no completion | OSC token/parser, then feature's active history row | `CommandHistoryTests`, including split frames, order, wrong token, invalid status and oversized recovery. |
|
||||
| Cwd contains mojibake | OSC 7 rewrite before output conversion, not history decoding | `RemoteOSC7CharsetFilter` and `RemoteCharsetTests`. |
|
||||
| Compose is enabled while a command runs | Availability versus prompt-ready transitions | `TerminalCommandDraftControllerTests`; `MobileCommandGeneratorAndUploadTests` prompt/integration cases. |
|
||||
| Settings change an already connected shell | Attempt-time preference capture | `HostShellIntegrationSessionTests`; mobile `integrationUsesConnectionSnapshotUntilManualOrAutomaticReconnect`. |
|
||||
|
||||
The listed tests are source evidence, not a claim that live remote shells or the test suite were executed during this documentation update. Use the pinned-package commands in [Engineering Quickstart](/openwiki/quickstart.md) for implementation changes.
|
||||
@@ -0,0 +1,164 @@
|
||||
---
|
||||
type: implementation guide
|
||||
title: SSH Multiplexing, Channel Admission, and I/O Scheduling
|
||||
description: "The concrete ownership and scheduling layers behind Termind SSH: per-connection session leases, serial libssh2 workers, exec state machines, multiplexed SFTP retries, readiness, backpressure, and feature-specific connection reuse."
|
||||
tags: [ssh, multiplexing, scheduling, libssh2, backpressure, sftp, concurrency]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T02:43:23.140Z
|
||||
sources:
|
||||
- id: openwiki-source-8e06414c0a0a26e45de192bd
|
||||
resource: repo://Frameworks/TermindDomain/Connections/SSHPreferences.swift
|
||||
- id: openwiki-source-0c82bf45bc197f879a54fd3a
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift
|
||||
- id: openwiki-source-dd3df578da8881d8ba0638e6
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SFTPChannel.swift
|
||||
- id: openwiki-source-f45e107ba4ae15ff23a99333
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SFTPClient.swift
|
||||
- id: openwiki-source-a64952906d8293e001622624
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHConnectionBuffer.swift
|
||||
- id: openwiki-source-ab74624bdc6b7046d91bcbac
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHConnectionWorker.swift
|
||||
- id: openwiki-source-e1238fe17b752b7be1d13b6a
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHExclusiveConnectionAdapter.swift
|
||||
- id: openwiki-source-d371db64770fd2fcc301086b
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHMaxSessionsPolicy.swift
|
||||
- id: openwiki-source-f3c300fe43c8f1ceb0906ed3
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHMultiplexedSFTPChannelOwner.swift
|
||||
- id: openwiki-source-8c4abf5c09db535e2818e3c4
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHPTYChannel.swift
|
||||
- id: openwiki-source-e63615bc111f4678ec12525d
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHStreamPump.swift
|
||||
- id: openwiki-source-7364a5d16e49e89eb03bbee2
|
||||
resource: repo://TFMTests/SSHForwardingPumpTests.swift
|
||||
- id: openwiki-source-ec3ec372dd69a7df3113c6b1
|
||||
resource: repo://TFMTests/SSHMaxSessionsPolicyTests.swift
|
||||
generated: { by: "omp", at: "2026-09-22T02:43:23.140Z" }
|
||||
---
|
||||
|
||||
# SSH Multiplexing, Channel Admission, and I/O Scheduling
|
||||
|
||||
## What multiplexing means here
|
||||
|
||||
An authenticated **connection** owns a libssh2 session and routed byte transport. A **channel** is a protocol stream within that connection: a PTY shell, non-PTY exec, SFTP subsystem, or forwarded TCP stream. Termind's multiplexing reuses these in-process authenticated owners; the code described here is not OpenSSH `ControlMaster`/`ControlPath` process management. Opening another channel avoids another authentication exchange; opening another physical connection does not.
|
||||
|
||||
Concurrency therefore has several independent meanings:
|
||||
|
||||
| Layer | Unit and owner | Admission or scheduling |
|
||||
| --- | --- | --- |
|
||||
| Feature connection reuse | Terminal/session, Agent pool, forwarding Host context, or SFTP transfer context | Determines which authenticated connection an operation may use. |
|
||||
| SFTP file admission | Logical file, across distinct endpoint Hosts | `SFTPConcurrencyScheduler` rotates hosts and work sources; it is not a byte scheduler. |
|
||||
| Session-channel admission | PTY/exec/subsystem lease on one connection | `SSHChannelBudget` applies a FIFO ceiling, default 10. |
|
||||
| libssh2 ownership | A single session handle | The owning dispatch queue serializes every library call. |
|
||||
| I/O progression | Exec command, forwarding flow, or SFTP operation | Bounded nonblocking turns yield to peers; the exact wake/retry mechanism depends on the owner. |
|
||||
|
||||
Do not conflate an `SSHChannelLease` with an SFTP file permit or with a pool slot. More admitted files need not mean more sockets; more forwarding sockets do not increase the channel ceiling on an existing connection.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Feature[Feature chooses transport owner] --> Conn[One authenticated SSH connection]
|
||||
Conn --> Queue[Single serial libssh2 queue]
|
||||
Policy[Shared MaxSessions preference] --> Budget[Budget for this connection]
|
||||
PTY[PTY shell] --> Budget
|
||||
Exec[Independent exec requests] --> Budget
|
||||
SFTP[Sibling SFTP subsystems] --> Budget
|
||||
Budget --> Queue
|
||||
Forward[Forwarded TCP streams] -->|no session lease| Queue
|
||||
Queue --> Buffer[Encrypted connection buffer]
|
||||
Buffer --> Route[Routed socket or jump bridge]
|
||||
```
|
||||
|
||||
This is a conceptual layering diagram, not a claim that every owner supports every channel type. The PTY worker owns terminal plus sibling SFTP channels; `SSHConnectionWorker` owns exec plus SFTP; forwarding has its own worker.
|
||||
|
||||
## Serial ownership is not serial completion
|
||||
|
||||
`SSHConnection` is an actor facade, but `SSHConnectionWorker.queue` is the actual libssh2 owner. Async callers can have several outstanding exec commands; they do not each receive a blocking thread that independently enters the shared session. The worker keeps per-command state and advances it on a serial queue. SFTP drivers submit short operations to that same queue. The PTY worker constructs the same `SSHMultiplexedSFTPChannelOwner` with its own context/queue instead of creating a second libssh2 owner for the terminal transport.
|
||||
|
||||
Metrics deliberately opts out of concurrent operations: `SSHExclusiveConnectionAdapter.withConnection` uses a busy flag and FIFO continuations to serialize complete operations on its owned connection. That adapter has no topology/fallback policy. Similar-looking SSH usage does not authorize merging Metrics, terminal, Agent, and forwarding lifetimes.
|
||||
|
||||
The Agent has a separate higher-level reuse policy: `AgentConnectionPool` keys connections by Host ID plus route fingerprint, joins same-fingerprint in-flight opens, and opens primary SFTP on its pooled SSH connection. Reuse survives a follow-up Agent run; default idle expiry is 180 seconds, and active exec/SFTP leases prevent whole-host idle retirement. Missing/changed routes invalidate reuse. This is an Agent-owned pool, not the terminal or forwarding pool.
|
||||
|
||||
## Session-channel budget: local FIFO, not server discovery
|
||||
|
||||
`SSHMaxSessionsPolicy` shares the configured ceiling across weakly tracked budgets, but `makeBudget()` creates independent accounting for each connection. `SSHPreferences` normalizes the ceiling to `1...100`, default `10`. This is a **client-side ceiling**, not a discovered or negotiated value of the remote server's `MaxSessions`; the server can still reject a channel below the local limit.
|
||||
|
||||
`SSHChannelBudget.acquire` immediately grants only when capacity is available **and** no waiter is ahead. Otherwise it queues a continuation. Lease release is idempotent, and deinit also releases. Increasing the ceiling drains FIFO waiters; decreasing it does not revoke active channels. Task/token cancellation removes a queued waiter, and closing a budget fails all remaining waiters with cancellation. A waiter does not busy-spin inside libssh2 while it lacks a lease.
|
||||
|
||||
PTY setup retains one lease for the shell; exec retains one in its command object; each SFTP subsystem retains one beside its native pointer. Direct/forwarded TCP channels and remote listeners are outside this session-channel accounting. Consequently a terminal with ceiling 10 already uses one slot, leaving at most nine additional session channels on that transport under this local policy. Creating a sibling SFTP channel at capacity waits for admission; it does not itself trigger an extra connection.
|
||||
|
||||
## Exec: opening → starting → running → closing → freeing
|
||||
|
||||
`SSHConnectionWorker.execute` rejects an empty command, gets the current budget, acquires a lease, and checks on the queue that the connection still uses that same budget. It then creates `SSHExecChannel` and enqueues its ID in `pendingOpens`. The post-acquire identity check prevents admission on an old budget from attaching to a replacement connection.
|
||||
|
||||
Each command owns:
|
||||
|
||||
- A stable, charset-encoded C command string. It executes `/bin/sh -lc '<command>'`, optionally preceded by a shell-quoted `cd -- '<cwd>' &&`; there is no shared interactive shell cwd between exec channels.
|
||||
- Its own stdin byte queue with consumed-byte zeroization, stdout/stderr decoders and buffers, truncation counters, deadline, cancellation token, and completion continuation.
|
||||
- A deadline clamped to 1–900 seconds and created **after** channel-budget admission. Time waiting for admission is therefore not included in that command deadline.
|
||||
|
||||
Only one `opening` command is advanced through `libssh2_channel_open_ex` at a time; an EAGAIN leaves that pending open in place. Once opened, the command advances to exec startup and then running. A running turn writes queued stdin, sends EOF when appropriate, drains stdout/stderr within the quantum/deadline, and moves to closing when remote EOF arrives. Closing captures exit status/signal and freeing retries channel release before completing the continuation. Stream output limits count accepted **remote bytes per stream**, not a single combined decoded-character limit; excess is drained but marked truncated. The output callback runs on the serial owner and must return promptly.
|
||||
|
||||
The main pump can be read as this reduced control flow (not replacement code):
|
||||
|
||||
```text
|
||||
begin bounded encrypted-buffer pass; flush queued ciphertext
|
||||
if encrypted high-water reached: arm socket write, stop this pass
|
||||
advance one pending channel open
|
||||
while time remains and ready IDs exist: advance each command state
|
||||
advance pending open again; service keepalive; flush again
|
||||
detect socket loss; update read/write interest
|
||||
if anything progressed or receive budget yielded: wake another sweep
|
||||
```
|
||||
|
||||
`SSHReadyQueue` deduplicates IDs, pops FIFO, and places reinserted hot work behind peers. Socket readiness wakes commands; a 100 ms timer also checks command deadlines and keepalive. Thus exec scheduling is readiness-assisted **with periodic safety/deadline wakes**, not a promise of strict equal byte bandwidth or entirely timer-free progress.
|
||||
|
||||
## SFTP: the same owner, a different retry path
|
||||
|
||||
`SFTPClient.connect` opens an `SSHConnection`, creates its primary subsystem channel, and publishes both only if its generation still matches. `SFTPChannel.openSiblingChannel` reuses the driver's identity and open closure: a sibling gets another subsystem on the same transport, not another socket/login. Channel disconnect closes only that subsystem; client disconnect closes its primary channel and connection.
|
||||
|
||||
`SSHMultiplexedSFTPChannelOwner` centralizes this sequence:
|
||||
|
||||
1. Serialize subsystem initialization with `reserveOpen`/`releaseOpen`; acquire the connection's session-channel lease.
|
||||
2. On the owning queue, start a bounded buffer pass and flush encrypted output. Return `.again` under backpressure or `libssh2_sftp_init` EAGAIN; on success retain pointer and lease in `channels[id]`.
|
||||
3. For each raw SFTP operation, enter the same queue, validate the channel/context, begin/flush a pass, perform the operation, flush again, and update socket interest.
|
||||
4. On `.again`, leave the queue and **asynchronously sleep for 2 ms** before retrying. Shutdown uses the same retry interval. Closing releases the lease and can notify a PTY owner when its last sibling is gone.
|
||||
|
||||
This is important when reasoning about fairness: SFTP does **not** live in the exec worker's `ready` dictionary. Queue confinement and short retry turns allow PTY/exec and other channel calls to interleave; the SFTP path currently uses async retry sleeps rather than a single unified readiness queue for all operations. Do not describe every transport user as fully event-driven or as receiving a common weighted scheduling guarantee.
|
||||
|
||||
For file-level fairness, extra physical connections, and fallback after silent authentication failure, continue with [SFTP Transfer Scheduling](/openwiki/workflows/sftp-transfer-and-external-edit.md). Those choices happen above this channel owner.
|
||||
|
||||
## Bounded turns, immutable retry bytes, and backpressure
|
||||
|
||||
`SSHForwardingTuning.current` supplies a **256 KiB quantum**, **256 KiB encrypted receive allowance**, **2 ms slice**, **2 MiB high-water**, and **1 MiB low-water**. These are distinct controls: the receive allowance limits what libssh2 consumes during a pass; the deadline limits owner occupancy; the queue watermarks control accumulated bytes. `SSHStreamPump` resets its quantum for individual directional phases, so 256 KiB is not a hard total byte ceiling for a whole bidirectional turn.
|
||||
|
||||
`SSHByteQueue` uses separately allocated chunks so appending later data cannot move the pointer/length of a write awaiting libssh2 retry. A positive write consumes only acknowledged bytes. Forwarding-to-channel and exec-input chunks use 32,700 bytes because the pinned libssh2 write path clamps there; generic socket chunks use 32 KiB. Vectored socket flush uses up to 16 chunks without coalescing them.
|
||||
|
||||
There are two buffer layers:
|
||||
|
||||
| Buffer | Mechanism | Scope/caveat |
|
||||
| --- | --- | --- |
|
||||
| Plaintext flow queues (`SSHStreamPump.toChannel` / `toSocket`) | Stop source reads at high-water; resume at or below low-water; retain bytes across partial writes and EAGAIN. | Per direction of one forwarding flow, not a global process cap. |
|
||||
| Encrypted connection output (`SSHConnectionBuffer`) | Send callback accepts the full libssh2 packet, queues any unsent remainder, and applies backpressure **between** library calls. Receive callback returns EAGAIN when backpressured, out of read allowance, or past deadline. | Per SSH connection; packet acceptance can overshoot the watermark, so it is not an exact hard 2 MiB cap. |
|
||||
|
||||
The encrypted buffer is not merely a throughput optimization: its source comment documents a pinned-library forwarded-tcpip confirmation retry problem when the send callback returns EAGAIN. Accepting whole encrypted writes avoids losing that pending channel while later bounded flushes honor socket backpressure. Teardown switches the buffer into disposal mode: writes are discarded and reads return EOF so session freeing cannot wait for a remote peer.
|
||||
|
||||
## Wakeups and retirement are correctness mechanisms
|
||||
|
||||
Any libssh2 read can decode packets for another channel. The forwarding worker therefore services opens/listeners both before and after stream I/O, checks already-buffered channel data/EOF, and schedules another sweep on progress or budget exhaustion instead of requiring a new socket edge. A zero-window writer can be rescheduled after a window update even if no payload was read. See the exact forwarding algorithm in [Pool and Flow Dispatch](/openwiki/workflows/port-forwarding-pool-and-dispatch.md).
|
||||
|
||||
Socket dispatch sources are queue-confined. `SSHSocketEvents.cancel` resumes suspended sources after cancellation and runs the descriptor-close completion only after **both** cancellation handlers have retired. The exec worker increments its generation on cleanup, clears queued work, closes SFTP and the channel budget, and rejects stale scheduled pumps/events. Transport errors report connection failure once and fail outstanding commands; one command's channel-local error follows its own close/free path instead.
|
||||
|
||||
The Agent's automatic replacement retry is deliberately narrow: `AgentConnectionPool.execute` retries `SSHCommandExecutionError.connectionUnavailable` once, not arbitrary errors after a remote command may have started. Multiplexing is not permission to replay a command or an established TCP stream.
|
||||
|
||||
## Focused verification and diagnostic routing
|
||||
|
||||
| Question | Source/tests to inspect |
|
||||
| --- | --- |
|
||||
| Why is the eleventh session channel waiting? | `SSHMaxSessionsPolicyTests`: default capacity, FIFO, live decrease/increase, cancellation, independent transport budgets. |
|
||||
| Does EAGAIN preserve bytes and pointers? | `SSHForwardingPumpTests`: blocked write stability, partial writes, encrypted packet buffering and shared flush allowance. |
|
||||
| Can a busy/slow flow starve or corrupt a peer? | `SSHForwardingPumpTests`: ready-queue rotation, watermarks, window updates, half-close; `SSHForwardingWireTests`: concurrent streams and slow consumer. |
|
||||
| Why did SFTP open another socket rather than a sibling? | File permit's selected mode and `SFTPTransferContext.capability`, not the exec ready queue. |
|
||||
| Why does closing the terminal not close SSH yet? | PTY `closeTerminalSession` and last-sibling callback; an SFTP subsystem can still own the transport. |
|
||||
| Why was an Agent connection retained or rebuilt? | `AgentConnectionPool` route fingerprint, in-flight join, active leases and idle sweep; `AgentConnectionPoolTests`. |
|
||||
|
||||
Tests cited here are implementation evidence; they are not a performance guarantee for arbitrary servers/routes. Keep the pinned dependency graph when validating changes, and do not turn the [historical forwarding benchmarks](/openwiki/operations/port-forwarding-benchmarks.md) into general WAN latency claims.
|
||||
@@ -0,0 +1,212 @@
|
||||
---
|
||||
type: design guide
|
||||
title: UI Design Principles and Shared Presentation Boundaries
|
||||
description: "Source-backed UI principles for TFM and TFI: semantic visual systems, native interaction, shared forms and presentation values, stable rendering identity, accessibility, localization and safe extension boundaries."
|
||||
tags: [ui, design-system, presentation, accessibility, localization, macos, ios]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T02:51:54.212Z
|
||||
sources:
|
||||
- id: openwiki-source-400e4d9303a3f9d98f90660d
|
||||
resource: repo://Frameworks/TermindPresentation/AssistantTranscriptEntry.swift
|
||||
- id: openwiki-source-eec1a2bc6dfc2c60b2bee55c
|
||||
resource: repo://Frameworks/TermindPresentation/HostConnectionFields.swift
|
||||
- id: openwiki-source-db3eac4d3fbf63570c0e0d56
|
||||
resource: repo://Frameworks/TermindPresentation/SingleLineTextInput.swift
|
||||
- id: openwiki-source-906678adb91c2fce2d3fcaed
|
||||
resource: repo://TFI/App/MobileAppModel.swift
|
||||
- id: openwiki-source-c8d832474c03f5ebad7b0578
|
||||
resource: repo://TFI/App/MobileRootView.swift
|
||||
- id: openwiki-source-99e98ad50ba8a7c6df018977
|
||||
resource: repo://TFI/Design/MobileDesignTokens.swift
|
||||
- id: openwiki-source-0368ecce931d0fb26fe8f35f
|
||||
resource: repo://TFI/DesignSystem/MobileContentRegions.swift
|
||||
- id: openwiki-source-3dfad0e95bb7d66f292c20c9
|
||||
resource: repo://TFI/Features/AI/MobileAssistantConversation.swift
|
||||
- id: openwiki-source-fc448263e4e5ce330b8cbda1
|
||||
resource: repo://TFI/Features/HostEditor/MobileHostEditor.swift
|
||||
- id: openwiki-source-a4f3a690a8395e2ac9b065b9
|
||||
resource: repo://TFI/UI/Components/MobileNativeList.swift
|
||||
- id: openwiki-source-c99ab42abad536ed4396933c
|
||||
resource: repo://TFI/UI/Managed/MobileCards.swift
|
||||
- id: openwiki-source-fffc181d864b6caea779a6f5
|
||||
resource: repo://TFITests/MobileAdaptiveLayoutTests.swift
|
||||
- id: openwiki-source-873894299539cce9a737a860
|
||||
resource: repo://TFM/App/RootView.swift
|
||||
- id: openwiki-source-f490cb5bfbb8ce236a7f1bf4
|
||||
resource: repo://TFM/Design/DesignTokens.swift
|
||||
- id: openwiki-source-95f72232fb896aa95dd5f6c7
|
||||
resource: repo://TFM/Features/AI/TranscriptListView.swift
|
||||
- id: openwiki-source-1e0cf223ab8448c8eee3f345
|
||||
resource: repo://TFM/Features/HostEditor/HostEditorView.swift
|
||||
- id: openwiki-source-ba160208435f3410138a3539
|
||||
resource: repo://TFM/Features/Workspaces/PersistentWorkspaceDeckLayout.swift
|
||||
- id: openwiki-source-f6a967b4f14bf50d1af51b8b
|
||||
resource: repo://TFM/UI/Managed/ManagedCardPage.swift
|
||||
- id: openwiki-source-d3d065330c730839f5cc6112
|
||||
resource: repo://TFMTests/ArchitectureBoundaryTests.swift
|
||||
- id: openwiki-source-dceb8d7e7c5bb09359e70052
|
||||
resource: repo://TFMTests/ResponsivePageLayoutTests.swift
|
||||
generated: { by: "omp", at: "2026-09-22T02:51:54.212Z" }
|
||||
---
|
||||
|
||||
# UI Design Principles and Shared Presentation Boundaries
|
||||
|
||||
Termind aims for consistent meaning and behavior across platforms, not identical view trees. macOS uses a window-local Navigator, persistent workspace deck and pointer/keyboard-oriented interaction. iPhone/iPad uses registered feature stacks, scene-local routing, touch-native presentation and system-adaptive navigation.
|
||||
|
||||
This page separates **implemented policies** from **extension guidance inferred from them**. It is not a new visual redesign or a claim that every screen already enforces every principle uniformly. Start with [TFM Desktop UI Architecture](/openwiki/architecture/desktop-ui.md) or [TFI Mobile UI Architecture](/openwiki/architecture/mobile-ui.md) for the full component diagrams.
|
||||
|
||||
## 1. Share meaning; retain platform ownership
|
||||
|
||||
The useful sharing boundary is below the app shell but above repeated feature formatting and form fragments.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Domain[TermindDomain: value types and policies] --> Application[TermindApplication: state and use cases]
|
||||
Domain --> Presentation[TermindPresentation]
|
||||
Application --> Presentation
|
||||
Presentation --> Values[Stable rows / formatting / presentation state]
|
||||
Presentation --> Forms[Reusable SwiftUI fields and sections]
|
||||
Values --> Mac[TFM feature composition]
|
||||
Values --> Mobile[TFI feature composition]
|
||||
Forms --> Mac
|
||||
Forms --> Mobile
|
||||
Mac --> MacShell[Window routes and desktop interaction]
|
||||
Mac --> AppKit[AppKit terminal / list / focus adapters]
|
||||
Mobile --> MobileShell[Scene routes and mobile interaction]
|
||||
Mobile --> UIKit[UIKit terminal / list / input adapters]
|
||||
```
|
||||
|
||||
These arrows show conceptual dependencies and consumption, not an exhaustive target dependency graph. See [System Boundaries](/openwiki/architecture/system-boundaries.md) for the broader module structure.
|
||||
|
||||
`TermindPresentation` is allowed to contain SwiftUI views. It is **not** a transport-free name attached to an arbitrary bag of platform code: architecture tests forbid it from importing either app, AppKit, UIKit, SwiftData, GRDB, Persistence or RemoteInfrastructure. Native adapters remain app-owned. Shared non-presentation frameworks have their own boundaries; do not apply one blanket “no UI anywhere in Frameworks” rule.
|
||||
|
||||
Useful shared pieces include:
|
||||
|
||||
- Binding-driven Host, identity, forwarding, snippet and settings form sections.
|
||||
- Stable Assistant transcript entries and presentation/disclosure state.
|
||||
- Formatting and presentation values for history, metrics, remote files and tool output.
|
||||
- Shared input-editing policies and environment hooks through which an app supplies native behavior.
|
||||
|
||||
Not suitable for moving into a generic shared view are a window's selected pane, a scene's navigation stack, a native terminal owner, credential resolution, connection teardown or repository mutation. Sharing a form does not make its save, authorization or lifetime policy shared automatically.
|
||||
|
||||
## 2. Use semantic visual roles, not per-feature themes
|
||||
|
||||
### Desktop vocabulary
|
||||
|
||||
`Metrics` centralizes desktop spacing, radii, minimum sizes and feature geometry as plain constants. They are not a runtime theme object; terminal palettes are a separate user-controlled concern. The spacing vocabulary includes 2/4/6/8/12/16/24-point values, and related controls share rhythm rather than choosing unrelated literals.
|
||||
|
||||
Examples of deliberate geometry:
|
||||
|
||||
| Role | Implemented constraint | Design purpose |
|
||||
| --- | --- | --- |
|
||||
| Shared sidebar | 260 minimum, 320 ideal, 520 maximum before window-width constraints. | The same column must work as Navigator or compact Assistant without resetting its width. |
|
||||
| Navigator rows | 44-point row rhythm and fixed glyph column. | Align labels despite different SF Symbol widths. |
|
||||
| Split divider | 1-point visual line, 8-point hit band. | Thin appearance without an impractically thin pointer target. |
|
||||
| Desktop cards | 240–380 width range, 80-point minimum height. | Readable metadata and aligned rows. |
|
||||
| Full Assistant | Shared 840-point reading-column maximum. | Transcript, decisions and composer read as one conversation. |
|
||||
|
||||
`TermindColor` uses semantic AppKit colors for neutral surfaces, foregrounds, separators, accent and success/warning/danger roles. User-authored Host colors and terminal ANSI palettes are deliberate exceptions. When a native layer needs a concrete color, `resolvedNative` resolves it against the owning appearance rather than assuming a dynamic `NSColor` will remain correct after conversion to `CGColor`.
|
||||
|
||||
Selection is contextual, not one universal tint formula. Generic `Highlight` uses a quiet accent wash for selection and a neutral hover wash. Sidebar rows use a stronger accent fill and reversed foreground in the key window, then an accent wash/tinted foreground when inactive. Do not infer actual behavior from an older nearby comment claiming all selections ignore active-window state.
|
||||
|
||||
### Mobile vocabulary
|
||||
|
||||
Mobile surfaces use system/grouped UIKit colors through SwiftUI and a smaller set of mobile layout policies. `MobileCardLayout` supplies a 106-point minimum height, at most two visible tags and a column calculation based on measured width with 12-point spacing. Accessibility text sizes force one column. These are mobile choices, not desktop token values copied into an iPhone layout.
|
||||
|
||||
For example, desktop card density and mobile card density deliberately differ. The invariant is recognizable hierarchy and usable content, not identical point dimensions.
|
||||
|
||||
## 3. Prefer real system materials and explicit fallbacks
|
||||
|
||||
TFM's glass modifiers use system Liquid Glass on macOS 26 and native material backgrounds on older systems. The shared sidebar background covers the whole column, including empty space, so custom native rows do not look pasted over a separate background. Native material is the fallback rather than a hand-painted imitation highlight.
|
||||
|
||||
TFI's card surface similarly uses system glass where available, but keeps a nearly opaque grouped background behind dense text. Reduce Transparency or increased contrast selects an opaque fallback. Increased contrast also strengthens the border. The clipping, interaction shape and context-menu-preview shape are coordinated, so the visible card and the tappable/previewed object agree.
|
||||
|
||||
**Extension guidance:** add visual roles at the platform's existing semantic surface boundary. Do not give each feature its own arbitrary gradient, selection color or radius, and do not remove readability fallbacks to make screenshots look more translucent.
|
||||
|
||||
## 4. Reuse interaction machinery, not business ownership
|
||||
|
||||
Desktop `ManagedCardPage` is a protocol-oriented page composition seam. It supplies typed sections, externally owned selection, capabilities, card/header/ghost views and presentation modifiers to `ManagedCardPageRenderer`. The renderer handles geometry, selection and drag mechanics, then reports stable IDs back to the page's actions.
|
||||
|
||||
Mobile uses a simpler `MobileCardPage` / `MobileCardGrid` / `MobileActionCard` composition. A card's primary action fills the card, while secondary actions live in its context menu. Other mobile lists use swipe actions and navigation links. There is no requirement to reproduce the desktop marquee-selection renderer on touch devices merely because both display Hosts.
|
||||
|
||||
The intended separation is:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Data[Feature-owned items and selection] --> Policy[Capabilities and presentation values]
|
||||
Policy --> Renderer[Platform renderer]
|
||||
Renderer --> Intent[Stable-ID action intent]
|
||||
Intent --> Owner[Feature or application owner]
|
||||
Owner --> Update[Validated state change]
|
||||
Update --> Data
|
||||
```
|
||||
|
||||
Use capabilities to say what a renderer may offer; keep the operation's actual validity check with its owner. Disabled UI is useful feedback, not a replacement for business validation.
|
||||
|
||||
## 5. Share form fields; keep draft and route lifetimes explicit
|
||||
|
||||
Both Host editors reuse `HostOrganizationSection`, `HostProtocolProfileControls` and `HostConnectionFields`, but their containers are intentionally different:
|
||||
|
||||
- TFM edits a local Host draft in the Vault work column. Nested editing stays in that column; introducing another `NavigationStack` there can promote its destination into the enclosing split detail and cover the collection.
|
||||
- TFI edits a local Host draft in `MobileEditorSheet`, with mobile routes, dirty-state checking and save eligibility. Shared fields add platform-appropriate keyboard/autocorrection behavior where needed.
|
||||
- Group/tag controls are injected by each platform into the shared organization section rather than forcing one platform's picker into the other.
|
||||
|
||||
The data path is draft binding → shared fields → platform validation/save action. It is not shared fields → database or transport.
|
||||
|
||||
`SingleLineTextInput` illustrates a narrow shared policy. It replaces runs of newline scalars with one space, preserves attributed paste content, and normalizes only edits through the binding setter. Reading the original bound value does not rewrite stored data. This is not a general sanitizer for secrets, multiline commands, snippets or existing repository records. Native paste/input insertion is supplied by app-owned environment adapters so selection and input-method handling can stay platform-specific.
|
||||
|
||||
## 6. Native rendering is a deliberate workload boundary
|
||||
|
||||
SwiftUI composes pages, but terminal and high-update list workloads use native adapters. `ArchitectureBoundaryTests` restricts ListViewKit importers to a specific set of native-list workloads rather than permitting it throughout every feature.
|
||||
|
||||
Assistant is a useful example:
|
||||
|
||||
- `AssistantTranscriptEntry` shares stable IDs and typed row content derived from the timeline. Edit/fork eligibility is passed in rather than inferred by a renderer.
|
||||
- Desktop mounts persistent AppKit transcript owners from a window-local, surface-aware cache.
|
||||
- Mobile uses `MobileNativeList`, supplying locale, Dynamic Type, appearance, motion/scene state, row revisions and viewport callbacks through the adapter.
|
||||
|
||||
Sharing transcript values does not justify sharing AppKit/UIKit view instances or their caches. Native views have platform and mounting constraints; their owners must be reviewed separately from the value model.
|
||||
|
||||
**Extension guidance:** first extract deterministic row construction, formatting or policy. Only then consider shared SwiftUI content. Leave platform focus, mounting, text selection, scroll retention and lifecycle in the platform adapter unless there is concrete evidence that their contracts match.
|
||||
|
||||
## 7. Accessibility and localization are layout inputs
|
||||
|
||||
The implementation already treats accessibility as behavior, not a final label pass:
|
||||
|
||||
- Parked desktop workspaces and unusable mobile panes disable hit testing and hide from accessibility as well as becoming transparent.
|
||||
- Selected sidebar controls expose selected traits and accessible names; icon-only menus expose the current title as their accessible value.
|
||||
- Mobile card grids change density for accessibility text sizes; card materials respond to transparency/contrast preferences.
|
||||
- Motion helpers accept Reduce Motion, and native-list adapters propagate motion and scene activity into hosted rows.
|
||||
- Mobile geometry tests retain marked Chinese text and first responder status during region changes, not just the final draft string.
|
||||
|
||||
Localization likewise affects measurement and identity-sensitive presentation. The existing adaptive/rendering cases exercise English, Simplified Chinese and Traditional Chinese, including narrow desktop editors and the mobile tab set. A layout that works only with the shortest English label is not proven by a source-level logic test.
|
||||
|
||||
Do not claim all animation sites are already Reduce Motion-aware: the helpers make that policy available, but each changed call site still needs inspection. Likewise, an accessibility label does not prove that focus order, clipping, menu reachability or large-text layout is correct.
|
||||
|
||||
## 8. Continuity has a cost budget
|
||||
|
||||
The platform guides describe several different retention strategies:
|
||||
|
||||
| Mechanism | What is preserved | How unnecessary work is limited |
|
||||
| --- | --- | --- |
|
||||
| Desktop workspace deck | Mounted session views and native terminal state. | Hidden geometry is parked and invisible controls are disabled. |
|
||||
| Desktop transcript owner cache | Native list, measurements and presentation caches across remounts. | LRU trimming of unmounted owners; separate keys for sidebar/full screen. |
|
||||
| Mobile workspace registry | Shared session and native terminal across navigation. | Explicit close and app background-expiration policy, not unconditional foreground work. |
|
||||
| Mobile region layout | Native child identity during adaptive geometry changes. | Only usable regions accept input/accessibility; covered children keep valid sizes. |
|
||||
|
||||
“Keep state” does not mean “keep every view measuring, animating and accepting events forever.” Conversely, unmounting a view does not by itself authorize terminating the work it displays.
|
||||
|
||||
## Practical extension checklist
|
||||
|
||||
Before adding or refactoring a UI feature:
|
||||
|
||||
1. Name its app, window/scene, workspace and temporary-view owners.
|
||||
2. Choose the existing platform shell and presentation style; do not create a second navigation system for one feature.
|
||||
3. Reuse semantic surfaces and sizing policies, checking actual implementation rather than comments alone.
|
||||
4. Share values and field fragments where contracts match; preserve native adapter and runtime boundaries.
|
||||
5. Verify hidden/disabled/accessibility behavior together with geometry and focus.
|
||||
6. Check compact and spacious containers, large text, light/dark appearance, transparency/contrast, and relevant language variants.
|
||||
7. Add deterministic policy/identity tests first, then targeted native rendering or device verification where necessary.
|
||||
|
||||
This is engineering guidance derived from current patterns, not an additional runtime subsystem. Use the [platform runtime guide](/openwiki/architecture/platform-runtime.md), [engineering invariants](/openwiki/architecture/engineering-invariants.md) and [build/test guidance](/openwiki/operations/build-test-and-release.md) when the change crosses ownership or verification boundaries.
|
||||
@@ -5,7 +5,7 @@ description: A task-oriented guide to finding the right Termind owner, lifecycle
|
||||
tags: [engineering, architecture, routing, testing, macos, ios]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T01:31:00.738Z
|
||||
at: 2026-09-22T02:51:54.212Z
|
||||
sources:
|
||||
- id: openwiki-source-8037e2358a2c4f9b2c722a11
|
||||
resource: repo://AGENTS.md
|
||||
@@ -25,7 +25,7 @@ sources:
|
||||
resource: repo://TFM/Features/Workspaces/WindowModel.swift
|
||||
- id: openwiki-source-d3d065330c730839f5cc6112
|
||||
resource: repo://TFMTests/ArchitectureBoundaryTests.swift
|
||||
generated: { by: "codex", at: "2026-09-22T01:31:00.738Z" }
|
||||
generated: { by: "omp", at: "2026-09-22T02:51:54.212Z" }
|
||||
---
|
||||
|
||||
# Termind Engineering Quickstart
|
||||
@@ -46,8 +46,14 @@ Termind is one Xcode project with two native products: `TFM` for macOS and `TFI`
|
||||
| --- | --- | --- | --- |
|
||||
| App startup, dependency assembly, window/scene behavior, backgrounding, or shutdown | [Platform Runtime, App Composition, and Lifetimes](/openwiki/architecture/platform-runtime.md) | `TFM/App/TermindApp.swift`, `TFI/App/TermindIOSApp.swift` | Relevant `TFMTests` or `TFITests` lifecycle/window suite |
|
||||
| A module import, framework placement, SwiftData model, shared resource, or AgentKit-facing API | [System Boundaries and Dependency Ownership](/openwiki/architecture/system-boundaries.md) | `TFMTests/ArchitectureBoundaryTests.swift` and the owning composition root | `ArchitectureBoundaryTests` plus the affected feature tests |
|
||||
| TFM window chrome, Navigator modes, split panes, persistent workspaces, Vault editors, or desktop Assistant rendering | [TFM Desktop UI Architecture](/openwiki/architecture/desktop-ui.md) | Component and ownership diagrams; [UI Design Principles](/openwiki/concepts/ui-design-principles.md) | Window/sidebar, workspace layout, responsive editor and transcript tests |
|
||||
| TFI feature tabs, scene routes, mobile toolbars, adaptive regions, terminal continuity, or composer focus | [TFI Mobile UI Architecture](/openwiki/architecture/mobile-ui.md) | Scene-versus-runtime ownership and native surface identity across layout changes | `MobileAdaptiveLayoutTests` plus scene, workspace and Assistant behavior tests |
|
||||
| Shared form fields, presentation values, visual tokens, collection interaction, accessibility, or cross-platform UI reuse | [UI Design Principles and Shared Presentation Boundaries](/openwiki/concepts/ui-design-principles.md) | Platform-specific owners; architecture restrictions on shared presentation and native adapters | `ArchitectureBoundaryTests`, input/presentation tests, and targeted multilingual rendering checks |
|
||||
| SSH, Telnet, proxy/jump routing, trust prompts, credentials, or workspace reconnect | [SSH, Telnet, Trust, and Workspace Session Lifecycle](/openwiki/workflows/ssh-session-lifecycle.md) | Remote Infrastructure callers and the owning session feature | SSH preparation, host-key, authentication, journey, and session tests |
|
||||
| Terminal services, metrics, port forwarding, channel limits, or shared remote transport policy | [Remote Services: Terminal, Metrics, and Port Forwarding](/openwiki/concepts/remote-services-and-forwarding.md) | [Port Forwarding Benchmarks](/openwiki/operations/port-forwarding-benchmarks.md) for measurement semantics | The relevant terminal, metrics, or forwarding suite |
|
||||
| SSH connection reuse, session-channel admission, exec/SFTP queue turns, libssh2 retries, or backpressure | [SSH Multiplexing, Channel Admission, and I/O Scheduling](/openwiki/concepts/ssh-multiplexing-and-scheduling.md) | Separate file permits, channel leases, owner queues, and physical pools before changing a limit | `SSHMaxSessionsPolicyTests`, `SSHForwardingPumpTests`, and the affected Agent/SFTP tests |
|
||||
| Shell bootstrap, Bash/Zsh/Fish hooks, OSC parsing, cwd/home, command history, or prompt/draft readiness | [Shell Integration: Bootstrap, OSC Events, and Terminal State](/openwiki/concepts/shell-integration.md) | Preserve desktop/mobile differences in event delivery and prompt readiness | `ShellIntegrationBootstrapTests`, `CommandHistoryTests`, and mobile command-generator tests |
|
||||
| Forwarding pool warm-up, local/SOCKS distribution, remote listeners, silent recovery, or listener retirement | [Port Forwarding: Multi-Connection Pool and Flow Dispatch](/openwiki/workflows/port-forwarding-pool-and-dispatch.md) | Distinguish auxiliary repair from whole-context recovery; use the benchmark guide for measurements | Pump and reconnect suites; opt-in forwarding wire tests when the fixture is available |
|
||||
| SFTP browsing, transfer scheduling/topology, conflict behavior, resume, external editing, or cleanup | [SFTP Transfer, Scheduling, and External Edit Workflow](/openwiki/workflows/sftp-transfer-and-external-edit.md) | The feature owner plus `SFTPTransferContext`/scheduler callers | Matching SFTP transfer, edit, conflict, or mobile SFTP tests |
|
||||
| Assistant turns, approval, host tools, skills, scratch space, agent persistence, or Hermes memory | [Assistant, Agent Runtime, Skills, and Memory](/openwiki/concepts/agent-runtime-and-assistant.md) | AgentKit boundary in [System Boundaries](/openwiki/architecture/system-boundaries.md) | Agent, approval, scratch, skill, or memory suites in `TFMTests`/`FrameworkTests` |
|
||||
| Hosts, Vault records, migrations, Keychain references, repositories, or data compatibility | [Persistent Data, Migrations, and Secret Boundaries](/openwiki/concepts/persistence-and-secrets.md) | Persistence compatibility tests and schema owners | Persistence, repository, secret, and migration tests |
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Files
|
||||
|
||||
- [Port Forwarding: Multi-Connection Pool and Flow Dispatch](port-forwarding-pool-and-dispatch.md) - Trace forwarding rules through Host-scoped intent, primary and auxiliary SSH workers, local/SOCKS socket dispatch, remote-listener ownership, bounded flow pumps, silent recovery, and ordered teardown.
|
||||
- [Settings, Vault, Metrics, and Cloud Sync Workflow](settings-and-cloud-sync.md) - How Termind independently synchronizes Vault, Settings, and Metrics through CloudKit, including lifecycle gates, durable journals, account and environment transitions, conflict handling, and AI-secret upload authorization.
|
||||
- [SFTP Transfer, Scheduling, and External Edit Workflow](sftp-transfer-and-external-edit.md) - How SFTP browser operations become scheduled transfers, choose an SSH topology, resolve conflicts and resume safely, and support explicit external-file editing without durable staging or replay.
|
||||
- [SSH, Telnet, Trust, and Workspace Session Lifecycle](ssh-session-lifecycle.md) - Traces how Termind prepares SSH and Telnet connections, routes them through proxies and jump hosts, authorizes server identity, consumes credentials, and retires or restores live workspace sessions.
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
type: implementation workflow
|
||||
title: "Port Forwarding: Multi-Connection Pool and Flow Dispatch"
|
||||
description: "Trace forwarding rules through Host-scoped intent, primary and auxiliary SSH workers, local/SOCKS socket dispatch, remote-listener ownership, bounded flow pumps, silent recovery, and ordered teardown."
|
||||
tags: [ssh, port-forwarding, connection-pool, scheduling, socks5, backpressure, recovery]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T02:43:23.140Z
|
||||
sources:
|
||||
- id: openwiki-source-9bd2b93db78747d6956c2405
|
||||
resource: repo://Frameworks/TermindDomain/Hosts/Host.swift
|
||||
- id: openwiki-source-89716908f306ca7371832cce
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/PortForwardingController.swift
|
||||
- id: openwiki-source-079b35134aa7d0dc22681651
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnection.swift
|
||||
- id: openwiki-source-20118197848107cfa8e87aa9
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHForwardingConnectionPool.swift
|
||||
- id: openwiki-source-e63615bc111f4678ec12525d
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SSHStreamPump.swift
|
||||
- id: openwiki-source-dc9295278cc250ed20567540
|
||||
resource: repo://TFI/App/MobileAppDependencies.swift
|
||||
- id: openwiki-source-4dbea0ff2808163cb4ecdd8f
|
||||
resource: repo://TFM/App/AppModel.swift
|
||||
- id: openwiki-source-7468ad597251e97aa63a1c55
|
||||
resource: repo://TFMTests/PortForwardingReconnectTests.swift
|
||||
- id: openwiki-source-c70098228d301514a5a44981
|
||||
resource: repo://TFMTests/SSHForwardingWireTests.swift
|
||||
generated: { by: "omp", at: "2026-09-22T02:43:23.140Z" }
|
||||
---
|
||||
|
||||
# Port Forwarding: Multi-Connection Pool and Flow Dispatch
|
||||
|
||||
## Two scheduling decisions, three kinds of rule
|
||||
|
||||
Forwarding first decides **which physical SSH connection owns a newly accepted TCP flow**, then decides **when that connection's worker advances each channel**. Increasing the connection target changes the first layer; bounded queues/readiness/fair turns implement the second. Neither is SFTP file admission or SSH session-channel admission.
|
||||
|
||||
| Rule | Listener placement | Channel and target | Pool behavior |
|
||||
| --- | --- | --- | --- |
|
||||
| Local (`-L` shape) | On this device | `direct-tcpip` to the configured target through SSH | One pool-owned local listener; new accepted flows can use any eligible worker. |
|
||||
| Dynamic (`-D` shape) | On this device | SOCKS5 request chooses target, then `direct-tcpip` | Same fan-out; the chosen worker handles the SOCKS handshake and ensuing stream. |
|
||||
| Remote (`-R` shape) | On the SSH server | `forwarded-tcpip` accepted by the SSH worker; local connector dials the configured target from this device | The listener and all its accepted channels stay on the primary worker. |
|
||||
|
||||
The pool is **not** several sockets jointly carrying one TCP stream. Every flow keeps one worker/channel until closure; existing flows are not migrated or replayed if that worker fails. Remote forwarding does not become multi-worker just because a Host's maximum is greater than one.
|
||||
|
||||
## Intent, configuration, and runtime ownership
|
||||
|
||||
`PortForwardingController.start` validates a saved rule and SSH-enabled Host. It creates or joins a `PortForwardingConnection` context keyed by Host ID; the context contains the route snapshot, shared Journey/authentication surface, connection attempt, active rule presentations, and the maximum captured at context creation. Later rules on the same connected context call `startRule` instead of authenticating again. Stop removes that rule's generation; the last active rule retires the context. Route changes, including jumps, invalidate affected contexts. Saved rules themselves are not live listeners.
|
||||
|
||||
macOS `AppModel` selects `.hostConfigured`; Host values normalize to `1...64`, default `1`. The factory chooses a plain `SSHForwardingConnection` for one and `SSHForwardingConnectionPool` for more than one. Mobile composition uses the controller's default `.singleConnection` policy. Thus a synchronized Host setting can remain stored on mobile without producing the desktop multi-connection topology.
|
||||
|
||||
Three runtime numbers must be read separately:
|
||||
|
||||
- `activeConnections`: registered flows for one rule, aggregated across slots; these can include handshake/open/connect phases, not only streams already forwarding bytes.
|
||||
- `sshConnections`: published connected pool slots, excluding opening/installing slots.
|
||||
- `targetSSHConnections`: `maximumConnections` only while at least one non-remote rule needs a pool; otherwise `1`.
|
||||
|
||||
## Pool warm-up and publication
|
||||
|
||||
The pool actor owns `slots`, `primaryID`, rule `registrations`, `opening`, `installing`, per-slot/per-rule `counts`, retry state, and one local-listener manager. Each slot contains an independent `SSHForwardingConnection` and the rule IDs installed on that worker. Each worker has its own authenticated libssh2 session and serial queue.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Controller
|
||||
participant Pool
|
||||
participant Primary
|
||||
participant Listener as Pool local listener
|
||||
participant Auxiliary
|
||||
Controller->>Pool: connect initial request
|
||||
Pool->>Primary: authenticate
|
||||
Controller->>Pool: configure additional request resolver
|
||||
Controller->>Pool: start local or dynamic rule
|
||||
Pool->>Primary: registerShared rule and generation
|
||||
Pool->>Listener: bind once
|
||||
Pool->>Auxiliary: open silent connection
|
||||
Pool->>Auxiliary: install non-remote registrations
|
||||
Pool->>Pool: publish auxiliary slot
|
||||
Listener->>Pool: accepted descriptor and generation
|
||||
Pool->>Primary: or auxiliary acceptShared
|
||||
```
|
||||
|
||||
`connect` first disconnects any previous pool and opens only the primary. Configuring the additional-request resolver calls `fillPool`, but without a local/dynamic registration there is no auxiliary demand. Starting a local/dynamic rule registers it on the current slots, creates **one** listener at the pool level, then fills missing slots. A remote-only rule calls `primary.connection.start` and needs no auxiliaries.
|
||||
|
||||
`fillPool` computes:
|
||||
|
||||
```text
|
||||
missing = desiredConnections - slots.count - opening.count - installing.count
|
||||
launches = min(missing, max(0, 4 - opening.count - installing.count))
|
||||
```
|
||||
|
||||
The four-work cap covers **both authentication and registration installation**. An opened auxiliary moves from `opening` to `installing`, registers the non-remote rules visited by the install pass, then is published in `slots` only after membership/disconnect/target checks. New publication reports pool counts and fills further missing slots. Failed setup disconnects the slot rather than publishing it. These are explicit state checks around actor suspension points, not proof that arbitrary registration races have exhaustive test coverage.
|
||||
|
||||
Stopping the last non-remote rule removes auxiliary demand, cancels the retry timer, removes pending opens/installations from pool bookkeeping, and disconnects auxiliaries. If remote rules remain, the primary remains. Pool shutdown closes its local listeners before disconnecting the captured active/pending workers; a late opened slot whose opening ID is gone is disconnected rather than published.
|
||||
|
||||
## Accepted-socket dispatch: least reported flows per rule
|
||||
|
||||
The pool-local listener accepts up to 32 descriptors in one callback. `assign` then follows this algorithm:
|
||||
|
||||
1. Match the rule's current registration generation; close the descriptor if obsolete.
|
||||
2. Select published slots whose installed-rule set contains that rule ID.
|
||||
3. Find the minimum `counts[slotID][ruleID]`, treating absent counts as zero.
|
||||
4. Sort equal-minimum candidates by UUID string; choose `roundRobin % candidateCount`, then increment the pool-wide counter.
|
||||
5. Call that worker's `acceptShared`. The worker rechecks connection, rule, generation, non-stopped state and non-remote kind before registering the flow. If it rejects, the pool closes the socket; it does not retry assignment across every slot.
|
||||
|
||||
For a rule whose reported counts are `[3, 1, 1]`, the next choice is between the second and third eligible slots, not the first. This is **per-rule live-flow-count balancing**, not bytes-per-second, CPU-load or total-all-rules balancing. Counts arrive asynchronously from worker callbacks, and assignment does not reserve an optimistic count before awaiting the worker. Therefore burst distribution is not an exact equal-share guarantee; the wire test verifies that flows reach multiple physical connections, not a precise 3/3/3/3 split.
|
||||
|
||||
## What each worker does after assignment
|
||||
|
||||
A local flow begins in `opening`. A dynamic flow begins in `greeting`, then `request`, then `opening`. A remote accepted channel begins in `connecting` while `SSHForwardingConnector` resolves/dials its local target. All successful paths end in `forwarding`.
|
||||
|
||||
For dynamic forwarding, the handshake accepts SOCKS5 **no-authentication** and CONNECT requests with IPv4, domain-name, or IPv6 destinations; unsupported methods/commands/address kinds receive failure replies. Extra bytes after a complete request are preserved for the channel. Handshake buffering is capped at 64 KiB. Treat the bind address as a security choice: this SOCKS listener is not an authenticated application proxy.
|
||||
|
||||
The worker keeps separate control queues for remote-listen requests and channel opens, plus a deduplicated FIFO ready queue for flows. It retains one pending `listening` and one pending `opening` operation across EAGAIN. Local accept and remote channel accept each cap a callback/pass at 32. Remote target connection completion rejects retired flows and closes a late socket rather than reinstalling it.
|
||||
|
||||
### One bounded pump pass
|
||||
|
||||
`SSHForwardingWorker.pump` is ordered for correctness as well as throughput:
|
||||
|
||||
1. Begin a 2 ms encrypted-buffer pass and flush. If backpressured, disable flow socket interests and read interest on the transport, leaving transport write interest armed.
|
||||
2. Advance listener/open control work and accept forwarded-tcpip channels **before** bulk stream I/O spends the receive budget.
|
||||
3. Pop ready flows while time remains and the encrypted buffer is not backpressured. A flow whose turn yields goes back into the ready queue.
|
||||
4. Advance opens/listeners and remote accepts **again**: another channel's read/write can have decoded their replies already.
|
||||
5. Check buffered data/EOF on forwarding channels, reap retired resources, service keepalive, report counts, detect transport loss, flush, and update socket interests.
|
||||
6. On progress or exhausted receive budget, wake another sweep. If a ready ID remains without that condition, schedule another pump.
|
||||
|
||||
This post-I/O sweep is why a reply already buffered inside libssh2 does not have to wait for a new OS socket-read edge. Conversely, when unsolicited bytes are present but no channel/listener operation can consume them, the worker parks read interest to avoid repeatedly waking on the same packet. The one-second timer serves keepalive and pending control/retirement work, not regular data throughput.
|
||||
|
||||
`SSHStreamPump` applies per-flow 2 MiB high/1 MiB low watermarks, bounded directional turns and stable write chunks. Socket EOF sends channel EOF only after pending outbound bytes drain; channel EOF shuts down local writes only after returned bytes drain. Both directions can therefore finish independently. The worker reaps a retired channel only after dealing with any pending libssh2 write; a zero-window write can be abandoned without waiting indefinitely for a peer that will never read. See [SSH Multiplexing and Scheduling](/openwiki/concepts/ssh-multiplexing-and-scheduling.md) for buffer details.
|
||||
|
||||
## Failure and recovery: distinguish the two levels
|
||||
|
||||
| Event | Pool-local response | Controller consequence |
|
||||
| --- | --- | --- |
|
||||
| Transient auxiliary open/install failure or established auxiliary loss | Remove/unpublish failed slot; keep healthy peers; schedule a single retry timer. | Rules can remain running below target. |
|
||||
| Additional open needs trust/authentication/user presence, or is cancelled | `requiresManualRetry` suppresses scheduling an automatic retry for that error. | No surprise interaction form from an auxiliary; explicit user action may be required to restore capacity. |
|
||||
| Primary loss with a surviving published slot | Promote `slots.values.first` (not least-loaded election), recreate remote rules there, then refill. | Context can survive if recreation succeeds; prior flows on the lost worker are gone. |
|
||||
| Primary loss with no replacement, or failed remote-rule recreation | Report pool failure. | Controller handles whole-context recovery/failure. |
|
||||
| Stop, route retirement, or stale callback | Reject removed IDs/generations; close obsolete resources. | Do not reestablish retired intent. |
|
||||
|
||||
Auxiliary retry delays are **1, 2, 5, 10, 30 seconds**, capped at 30. A published auxiliary surviving 60 seconds resets the pool-wide retry progression. This is not an autonomous per-slot backoff: the pool has one `retryTask` and one `retryAttempt`. Other in-flight opens can still finish while a failed open schedules no retry.
|
||||
|
||||
Whole-context recovery is a separate path. The controller only recovers after a rule has made the context ready (`markConnected`) and a reusable snapshot exists. It closes the old transport, hides the Journey, marks remaining intent reconnecting, and delegates delay handling to `SessionReconnectController`. It waits for prior Host cleanup before opening the replacement and reinstalls the still-active rules. A listener-local failure can fail that rule without erasing peers' recovery intent.
|
||||
|
||||
The first connect may ask for host trust/credentials. Recovery and auxiliary opens use `SSHAdditionalConnectionSnapshot` and requests with interaction forbidden. The controller captures the snapshot after successful interactive connection, removes one-shot submissions and temporary host keys, and supplies a resolver for later physical opens. “Continue once” trust, temporary passwords and key passphrases are not reusable recovery authority; needing them ends silent recovery/degrades the pool instead of reopening a form. An explicit Retry is the new interactive boundary. See [SSH Session Lifecycle](/openwiki/workflows/ssh-session-lifecycle.md).
|
||||
|
||||
## Teardown ordering and stale-result guards
|
||||
|
||||
There are several different tokens, none interchangeable:
|
||||
|
||||
- Controller **attempt ID + context identity** rejects an old connection's progress/failure/count callback.
|
||||
- Controller/pool/worker **rule generation** rejects counts, accepted descriptors and listener-start completions from an old start of the same rule ID.
|
||||
- Worker **generation** invalidates already scheduled pump/timer/socket callbacks after transport cleanup.
|
||||
|
||||
`stop` waits for the worker's rule-close completion. Stopping an in-flight remote-listen request retains its completion until the request resolves and the resulting listener is cancelled; otherwise an immediate replacement could race the old remote bind. `reap` retries listener cancellation/channel freeing across EAGAIN. Full disconnect shuts down the transport, retires resources, and waits for socket cancellation completions before returning. Local listeners use `SO_REUSEADDR` for rebinding after closure, not `SO_REUSEPORT` to share a live bind.
|
||||
|
||||
This is not stream failover: recovery restores listeners and future connection opportunities, not application protocol state or bytes already sent on failed TCP streams.
|
||||
|
||||
## Focused tests, limits, and troubleshooting
|
||||
|
||||
- `SSHForwardingPumpTests` is the deterministic low-level seam: short writes, stable retry bytes, ready-queue order, watermarks, half-close, zero-window wakeups, encrypted-buffer allowance and source cancellation.
|
||||
- `PortForwardingReconnectTests` uses controlled connections/timers to check shared context recovery, silent authentication, remembered versus once-only trust, rule generations, late results, and cleanup-before-rebind ordering.
|
||||
- `SSHForwardingWireTests` is **opt-in** via `TERMIND_SSH_FIXTURE`, a path to the fixture JSON. It covers local/remote/dynamic streams with 1/16/64 concurrency, one/two jump bridges, slow consumers, listener restart, and local pool distribution. Source presence or a default suite pass does not mean these wire tests ran.
|
||||
|
||||
When investigating low throughput, first inspect whether the pool is actually above one connected slot, whether the rule is local/dynamic, and whether silent extra opens can authenticate. Then inspect stream backpressure and pump progress; increasing the target cannot make one stream span workers. For benchmark fixture setup and interpretation, use [Port Forwarding Benchmarks](/openwiki/operations/port-forwarding-benchmarks.md). The pool code and current test seams do not establish an exhaustive actor-interleaving proof or a WAN performance guarantee.
|
||||
@@ -5,10 +5,12 @@ description: How SFTP browser operations become scheduled transfers, choose an S
|
||||
tags: [sftp, file-transfer, ssh, scheduling, external-editing, lifecycle]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T01:13:21.371Z
|
||||
at: 2026-09-22T02:21:47.705Z
|
||||
sources:
|
||||
- id: openwiki-source-46ef2fcd9e3aba751015021b
|
||||
resource: repo://Frameworks/TermindDomain/Transfers/SFTPPreferences.swift
|
||||
- id: openwiki-source-0c82bf45bc197f879a54fd3a
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/Agent/AgentConnections.swift
|
||||
- id: openwiki-source-dd3df578da8881d8ba0638e6
|
||||
resource: repo://Frameworks/TermindRemoteInfrastructure/SSH/SFTPChannel.swift
|
||||
- id: openwiki-source-f45e107ba4ae15ff23a99333
|
||||
@@ -37,7 +39,7 @@ sources:
|
||||
resource: repo://TFMTests/SFTPEditTests.swift
|
||||
- id: openwiki-source-53e2b2fd2e661123f63e69e1
|
||||
resource: repo://TFMTests/SFTPTransferContextTests.swift
|
||||
generated: { by: "codex", at: "2026-09-22T01:13:21.371Z" }
|
||||
generated: { by: "omp", at: "2026-09-22T02:21:47.705Z" }
|
||||
---
|
||||
|
||||
## Scope and operating model
|
||||
@@ -101,6 +103,85 @@ A context keeps the browser **control** channel independent where possible. `cha
|
||||
|
||||
The coordinator acquires two endpoint leases in stable context-ID order for a remote copy and shares one lease when both endpoints are the same context. This avoids competing acquisition order and needless duplicate use of one transport. [^remote-copy-leases]
|
||||
|
||||
## Scheduling algorithm: admission is not transport capacity
|
||||
|
||||
The coordinator's `schedule()` creates an admission task for each eligible queued row, waits for any pending preference update, and calls `acquire`. Only after a permit arrives and the row/runtime still exists does it store that permit, reserve context slots, mark the transfer running, and ask for a channel lease. A row can therefore be **running but still waiting for a subsystem or serialized primary**; admitted file count is not the number of sockets currently transferring bytes. The permit remains held through channel acquisition, I/O and lease cleanup. `finish` releases context ownership and the active permit before scheduling again.
|
||||
|
||||
`nextEligibleRequest` is a two-level rotation, not one global FIFO:
|
||||
|
||||
```text
|
||||
while active file count < globalLimit:
|
||||
visit anchor hosts starting after lastGrantedHost
|
||||
within each host, visit sources starting after that host's lastGrantedSource
|
||||
inspect only the head request of each source queue
|
||||
skip if any endpoint is at its per-host limit or an exclusive resource is busy
|
||||
grant the first eligible head; update host/source rotation cursors
|
||||
stop when no eligible head exists
|
||||
```
|
||||
|
||||
Each request normalizes its endpoint set to include the anchor. A copy is anchored to its destination when available, while capacity is charged to both distinct endpoint Hosts. Workspace identity is the managed context's ID (destination context for a copy); otherwise the coordinator uses the batch ID. The Agent supplies an `agentRun` identity for scheduled data work.
|
||||
|
||||
This has three consequences:
|
||||
|
||||
- FIFO is preserved **within one source queue**. The scheduler can skip a blocked source to consider a different source/host, but does not look past that source's blocked head.
|
||||
- Rotation is a grant-order fairness policy, not preemption or a bandwidth reservation. Long-running files keep their permits until release. Lowering limits cannot revoke active permits; it only delays future grants until capacity fits again.
|
||||
- A remote copy consumes one global permit and one slot per distinct Host, regardless of whether it later needs one or two endpoint leases. A borrowed channel adds an exclusive resource ID so jobs cannot simultaneously use that same borrowed resource.
|
||||
|
||||
Tests make the policy concrete: after a workspace used the sole slot, a queued Agent source can precede more work from that workspace; another Host gets a turn before the previous Host; two workspace queues can split five same-host grants 3/2. These are controlled queued examples, not a guarantee that a later-arriving operation displaces an already active file.
|
||||
|
||||
### Smart mode is selected at grant time
|
||||
|
||||
The request retains its byte count, but `drain()` selects its mode using the **current preferences when admitted**. The returned permit's mode is immutable. The boundary is decimal **64,000,000 bytes** (64 MB), not 64 MiB: equal-to-boundary and unknown sizes use `channelsOnly`; strictly greater known sizes use `connectionsPreferred`. Mode decides the allowed topology preference, not extra file capacity.
|
||||
|
||||
## Topology decision table for a managed context
|
||||
|
||||
The full sequence lives in `SFTPTransferContext.acquire`; read it in order rather than treating the selected strategy as an unconditional socket-opening command. While an initial capability probe is in flight, other acquisitions wait for its result. After that, primary role and busy state determine reuse.
|
||||
|
||||
| Primary role | `channelsOnly` | `connectionsPreferred` |
|
||||
| --- | --- | --- |
|
||||
| `control` (browser) | Prefer a sibling subsystem, leaving the browser's control channel free. If sibling opening fails, wait for and serialize on the primary. | Try a silent additional connection unless capability already downgraded to channels; then try a sibling; final fallback serializes the primary. |
|
||||
| `donatedConnection` (successful independent preflight) | Lease the idle preflight primary first; overlapping work uses siblings. | Lease the idle preflight primary first; overlap can open independent connections, then downgrade to siblings/primary after failure. |
|
||||
| `ptyConnectionFallback` | Lease the idle SFTP primary on the PTY transport first; overlap uses siblings. | Starts with channel-only capability, so it does not re-probe extra connections for a large file while that primary generation is alive; uses primary/siblings. |
|
||||
|
||||
A context's capability is **unknown → connections** on a successful silent open, or **unknown/connections → channels** on a non-cancellation failure. The first unknown probe is serialized, but once connection capability is known later admitted jobs can attempt extra opens concurrently. Browser-context cancellation is checked before caching degradation; a cancelled probe does not condemn the generation to channel fallback. Successful sibling opening does not turn an unknown context into connection-capable.
|
||||
|
||||
These fallbacks include two distinct kinds of waiting:
|
||||
|
||||
1. `openSiblingChannel` can wait for the per-connection `SSHChannelBudget` before libssh2 ever tries initialization. A full local session budget is not automatically interpreted as failure, and does not cause the context to open a new socket by itself.
|
||||
2. If sibling initialization actually fails, the context waits on `primaryBusy` and leases the primary serially. Context waiters are a dictionary resumed together by `wakeWaiters`; do not attribute the scheduler's FIFO guarantee to this fallback waiter mechanism.
|
||||
|
||||
A browser-context extra connection or sibling is leased for the operation and disconnected on release, rather than kept in a warm auxiliary pool. The context primary is retained by owner/transfer references. If it was closed after detach/pause, a later explicit resume can silently recreate a primary from its snapshot and resets capability; `channelsOnly` cannot conjure an already-authenticated transport that no longer exists. The saved form always opens a fresh client and the borrowed form always returns the external channel with a no-op lease release; neither runs the managed-context topology table.
|
||||
|
||||
### Worked connection/channel counts
|
||||
|
||||
Assume setup succeeds, no other files consume the stated limits, and the SSH session-channel budget permits the requested siblings:
|
||||
|
||||
| Scenario | Active logical files | Physical connections and SFTP subsystems |
|
||||
| --- | --- | --- |
|
||||
| Browser control primary, three files, Channels Only | 3 | One connection with its browser control subsystem plus three sibling data subsystems; the control channel is not a fourth file permit. |
|
||||
| Donated primary, two files at exactly 64,000,000 bytes, Smart | 2 | One independent preflight connection; its primary subsystem plus one sibling. |
|
||||
| Same donated primary, two files strictly above the threshold, Smart | 2 | The donated connection plus one silently opened connection; no sibling is needed on the successful path. |
|
||||
| PTY fallback, three large files, Smart | 3 | The existing PTY connection with the terminal session channel plus three SFTP subsystems (the fallback primary and two siblings); no new connection probe. |
|
||||
| Donated preflight, seven files, per-host limit 5, Connections Preferred | At most 5 | Initially the donated connection plus four additional connections; remaining files wait for permits. |
|
||||
|
||||
`SFTPTransferContextTests` checks the sibling/open counts, the threshold, a five-file terminal batch, and two contexts sharing a five-file Host limit. With `MaxSessions = 10`, a browser control channel plus ten admitted Channels Only files cannot all have sibling subsystems at once: the extra acquisition waits for a channel lease even though it already holds a file permit. This is an example of independent limits, not permission to silently exceed either one.
|
||||
|
||||
## Agent SFTP reuse is related, not identical
|
||||
|
||||
Agent data work joins the same file-admission mechanism through `AgentSSHAuthenticationRegistry.withSFTP` when `schedulesDataTransfer` is true. Metadata calls can bypass a data permit and default to channel mode; callers with a supplied permit do not acquire/release it twice. Authentication and the channel lease are obtained inside that admitted operation.
|
||||
|
||||
`AgentConnectionPool.acquireSFTP` first reuses an eligible idle record, preferring least-recently-used idle records; channel-only mode limits record reuse to the primary. If that primary is busy, channel-only work opens a sibling and can wait/retry the primary on sibling failure. Connection-preferred overlap joins a per-Host unknown-capability probe or opens another silent connection after capability is known. Pooled records become idle on lease release; ephemeral siblings are disconnected. Idle auxiliaries can later be swept, unlike the coordinator context's operation-scoped extras.
|
||||
|
||||
Do not copy browser-context assumptions wholesale into this pool. In particular, the Agent's shared initial-probe catch updates capability before rethrowing cancellation, whereas the browser context checks cancellation before recording a downgrade. They also have different final fallback paths and cache lifetimes. Review the specific owner and tests for a scheduling change rather than inventing one universal SFTP pool.
|
||||
|
||||
## From a file lease to libssh2 turns
|
||||
|
||||
A sibling channel shares the same driver's transport identity. `SSHMultiplexedSFTPChannelOwner` serializes each raw libssh2 call on its SSH owner's queue, uses the encrypted buffer's bounded pass/backpressure, and returns to an async 2 ms retry sleep on EAGAIN. File fairness above does not imply strict round-robin ordering for every SFTP packet below. See [SSH Multiplexing and Scheduling](/openwiki/concepts/ssh-multiplexing-and-scheduling.md).
|
||||
|
||||
Copy's topology check is driver identity, **not merely equal Host IDs**. If both concrete `SFTPChannel` endpoints share it, `copyOnSharedTransport` alternates reads of at most 64 KiB with destination writes on the shared owner. Otherwise the socket-pair relay runs producer and consumer tasks concurrently; failure cancels the group and stops the relay. Stable lease acquisition order, the shared-driver fast path, and file-admission accounting solve different problems and should not be collapsed.
|
||||
|
||||
To compare with port forwarding, use [Forwarding Pool and Flow Dispatch](/openwiki/workflows/port-forwarding-pool-and-dispatch.md): forwarding prewarms a Host-level target and assigns accepted TCP flows to retained workers, rather than creating a connection-per-file lease. For terminal-to-SFTP cwd/availability prerequisites, use [Shell Integration](/openwiki/concepts/shell-integration.md).
|
||||
|
||||
## Transfer state, resume, cleanup, and ownership
|
||||
|
||||
The visible states are queued, running, paused, completed, failed, and cancelled. Pause before admission cancels the admission task and immediately changes to paused. Pause during I/O cancels the operation; recoverable connection errors also become paused except resume-validation failures, which are failed. Cancelled or failed non-paused work performs cleanup, while completed and paused work retain the checkpoint needed for their respective outcomes. [^transfer-control] [^coordinator-outcomes]
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Traces how Termind prepares SSH and Telnet connections, routes them
|
||||
tags: [ssh, telnet, connection-lifecycle, host-keys, proxy, workspace, security]
|
||||
verified:
|
||||
- by: openwiki/0.5.2
|
||||
at: 2026-09-22T01:13:21.371Z
|
||||
at: 2026-09-22T02:21:47.705Z
|
||||
sources:
|
||||
- id: openwiki-source-cb178f0d078ab3218679c80e
|
||||
resource: repo://Frameworks/TermindApplication/Connections/RemoteSessionConnectionController.swift
|
||||
@@ -39,7 +39,7 @@ sources:
|
||||
resource: repo://TFMTests/ConnectionJourneyTests.swift
|
||||
- id: openwiki-source-578f30372fe67f8688f44b76
|
||||
resource: repo://TFMTests/WindowStateTests.swift
|
||||
generated: { by: "openwiki/0.5.2", at: "2026-09-22T00:31:10.149Z" }
|
||||
generated: { by: "omp", at: "2026-09-22T02:21:47.705Z" }
|
||||
---
|
||||
|
||||
# SSH, Telnet, Trust, and Workspace Session Lifecycle
|
||||
@@ -150,6 +150,15 @@ The worker's generation token invalidates socket events, timers, and scheduled p
|
||||
|
||||
Feature models apply the same idea at the UI boundary. `RemoteSessionConnectionController.progressHandler(attemptID:isCurrent:)` forwards route progress to `ConnectionJourney` only for the current attempt. Mobile workspaces replace their UUID generation when connecting, backgrounding, exiting, or retiring work, and guard every asynchronous completion against it. Late connection, transfer-preparation, socket, and timer callbacks therefore cannot attach an obsolete transport, clear newer state, or enqueue work after explicit close.
|
||||
|
||||
### Continue into post-authentication mechanics
|
||||
|
||||
Authentication answers whether a transport may be installed. The next layer decides how its work progresses and how additional transports are obtained:
|
||||
|
||||
- [SSH Multiplexing, Channel Admission, and I/O Scheduling](/openwiki/concepts/ssh-multiplexing-and-scheduling.md) explains per-connection session leases, serial libssh2 ownership, exec state machines, SFTP retry turns, and buffer backpressure.
|
||||
- [Shell Integration: Bootstrap, OSC Events, and Terminal State](/openwiki/concepts/shell-integration.md) follows the PTY-only probe/install exchange, shell hooks, charset-aware event filtering, history, cwd/home, and platform-specific prompt readiness.
|
||||
- [SFTP Transfer, Scheduling, and External Edit Workflow](/openwiki/workflows/sftp-transfer-and-external-edit.md) explains file permits before channel acquisition, independent-connection preference, sibling/primary fallback, and detached transfer ownership.
|
||||
- [Port Forwarding: Multi-Connection Pool and Flow Dispatch](/openwiki/workflows/port-forwarding-pool-and-dispatch.md) follows pool publication, local/SOCKS flow assignment, primary-only remote listeners, and the distinction between auxiliary repair and whole-context recovery.
|
||||
|
||||
## Retry, retirement, and workspace behavior
|
||||
|
||||
A connection failure before the first successful session remains a failed journey requiring an explicit user retry. Once a session has connected, `RemoteSessionConnectionController` can schedule recovery through `SessionReconnectController`; it pauses recovery for trust or authentication interaction and resets recovery state on disconnect. Retiring a session cancels prompt queues, rejects pending host-key approval, clears temporary trust, stops reconnect work, and hides the journey.
|
||||
|
||||
Reference in new issue
Block a user