From fb93169d3fdd334d428061b074ba428621c0ada2 Mon Sep 17 00:00:00 2001 From: Omry Yadan Date: Tue, 3 Nov 2026 12:53:55 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20record=20reviewed=20authentication=20de?= =?UTF-8?q?sign=20for=20milestones=203=E2=80=9311?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record the reviewed and owner-approved authentication design in docs/authentication, including the canonical remaining-slice inventory, generated overview, durable review sidecars, preserved historical context and per-slice LOC comparison. Keep approved requirements and HLD choices, completed milestones 1–2, original IDs and review history. This planning checkpoint contains no product implementation. --- docs/authentication/.review/README.md | 22 +- .../.review/high-level-design.md | 20 +- .../.review/implementation-plan.md | 22 +- .../authentication/.review/milestone-3-lld.md | 26 +- docs/authentication/.review/overview.md | 30 + docs/authentication/.review/requirements.md | 12 +- docs/authentication/README.md | 122 +- docs/authentication/high-level-design.md | 301 +- docs/authentication/implementation-plan.md | 2285 ++++++------ docs/authentication/milestone-3-lld.md | 448 +-- docs/authentication/overview.md | 108 + docs/authentication/slices.json | 3106 +++++++++++++++++ .../historical-feasibility.md | 22 + .../.review/backend-evidence.md | 30 + .../.review/estimate-basis.md | 30 + .../.review/estimate-comparison.md | 30 + .../.review/historical-native-lld.md | 30 + .../implementation-plan/backend-evidence.md | 40 + .../implementation-plan/estimate-basis.md | 60 + .../estimate-comparison.md | 85 + .../implementation-plan/estimates-after.json | 1489 ++++++++ .../implementation-plan/estimates-before.json | 1188 +++++++ .../historical-native-lld.md | 436 +++ .../implementation-plan/historical-plan.txt | 1130 ++++++ 24 files changed, 9340 insertions(+), 1732 deletions(-) create mode 100644 docs/authentication/.review/overview.md create mode 100644 docs/authentication/overview.md create mode 100644 docs/authentication/slices.json create mode 100644 docs/authentication/supporting/high-level-design/historical-feasibility.md create mode 100644 docs/authentication/supporting/implementation-plan/.review/backend-evidence.md create mode 100644 docs/authentication/supporting/implementation-plan/.review/estimate-basis.md create mode 100644 docs/authentication/supporting/implementation-plan/.review/estimate-comparison.md create mode 100644 docs/authentication/supporting/implementation-plan/.review/historical-native-lld.md create mode 100644 docs/authentication/supporting/implementation-plan/backend-evidence.md create mode 100644 docs/authentication/supporting/implementation-plan/estimate-basis.md create mode 100644 docs/authentication/supporting/implementation-plan/estimate-comparison.md create mode 100644 docs/authentication/supporting/implementation-plan/estimates-after.json create mode 100644 docs/authentication/supporting/implementation-plan/estimates-before.json create mode 100644 docs/authentication/supporting/implementation-plan/historical-native-lld.md create mode 100644 docs/authentication/supporting/implementation-plan/historical-plan.txt diff --git a/docs/authentication/.review/README.md b/docs/authentication/.review/README.md index 80f5880..783d3ed 100644 --- a/docs/authentication/.review/README.md +++ b/docs/authentication/.review/README.md @@ -3,20 +3,20 @@ artifact: swe-design-review-attestation schema_version: 6 scope_key: c2ebaf06c49668e199e08bccef68303c5cd0925e79b8f635860bb8fa8494d61b scope: {"kind": "path", "primary_target": "docs/authentication/implementation-plan.md", "repository": ".", "selector": "docs/authentication/implementation-plan.md"} -review_content_identity_sha256: f46fc5843e78a8a5fd743a620ca1f795760d4e4d3d28bc7db44e7963eb32aaca -target_content_identity_sha256: 4edf646bb0369f9066ae6ae575c940373ef1595f1fb93965f7e450914ce66244 -baseline_content_identity_sha256: 8e02df1e7ff92b8aef06db429f86cd9b60ef8fdb1651422b9e6473cad85338a9 -target_documents: [{"executable": false, "path": "docs/authentication/README.md", "repository": ".", "sha256": "2bff627a30d975cbdde020b014638d6b061c2aba891815a2975998a1894a6ef9"}, {"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "38456f43776f8b47b1c5beb7cdbf5be5a34832267286a0135a489083980a4379"}] -baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] -design_dependency_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] -plan_binding: {"base_revision": "7ca9b3d2a556852672eedaaa264ed94a44ba38af", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "38456f43776f8b47b1c5beb7cdbf5be5a34832267286a0135a489083980a4379", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "b2899d82e5f0914b3a5088bdbbe0fa4dce7034ea6e8cc963d5b61df11acc3fcc"}]} -security_review: {"actual": "dbb", "binding_identity_sha256": "5357c8e3040ed8f3d37fa71fb3228a9a424b88332404fa6e576c478e40c33dad", "requested": "dbb", "reviewer": "/root/auth210_inventory_dbb_recovery", "schema_version": 1} +review_content_identity_sha256: 5893064257f1b8afd405898058d9b7fc9e9b957c95a40e9acd6fc018982f0869 +target_content_identity_sha256: 8a3289d4d765221e818ae1babfe09bbd0c1801a6eb9510d09761e7f87e1a9315 +baseline_content_identity_sha256: 36c6b33068c1ca88278d21f6e92eb299e77be6e00dce5ec2e8e7a4c2da85bc62 +target_documents: [{"executable": false, "path": "docs/authentication/README.md", "repository": ".", "sha256": "714a197db6b067167bf224c0fa45263b4e89b9caa605131ce58f6267b3b76224"}, {"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "7bf550552c24f8d66e7032ed1b25379ecd062dfc5e3e9db4de3b197ee66fc0f2"}, {"executable": false, "path": "docs/authentication/overview.md", "repository": ".", "sha256": "f0e95b138f566067c735898d2fdff3d02fad8d1c4369204266fe26ef89b8e212"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/slices.json", "repository": ".", "sha256": "995e7ed8c99dd2133188ba4ee5f8d9d5feaa1d175772f9dbba336755dedc533c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/backend-evidence.md", "repository": ".", "sha256": "fa1cd32632dbab696648369015c5c4ebd0762f27b81455548cf3bcb1545a9fa4"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-basis.md", "repository": ".", "sha256": "176283b0aa31cdfe3070508dd89c68e84457731d774bebd771f3718f01d0e46f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-comparison.md", "repository": ".", "sha256": "b64b26f9337c6be505f11319ef321dd647519d20527d45cf962b446835df84ba"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-after.json", "repository": ".", "sha256": "39393c7f902f9907415acbed0a861d5014997053ad2199f82215853ae94c1e80"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-before.json", "repository": ".", "sha256": "0570a8902bf55c255289cbb5ff3d48df17779b9e4fb66e352fca34446531545c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-native-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-plan.txt", "repository": ".", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a"}] +baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +design_dependency_documents: [] +plan_binding: {"base_revision": "4f6db43d72bd59705cdefd0851f6c25c63a699cf", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "26189fa66fc3804040b98edfd72ba346567c0280c5ebbca4f12ab5ebcaa421fe"}]} +security_review: {"actual": "dbb", "binding_identity_sha256": "477b0e2b315f79ce92dc2819d4046ea1e61fc6a9557cea8bb5462beca8044e62", "requested": "dbb", "reviewer": "/root/pr83_current_combined_dbb", "schema_version": 1} document_repository: "." document_path: "docs/authentication/README.md" -document_revision_provenance: "7ca9b3d2a556852672eedaaa264ed94a44ba38af" -document_sha256: 2bff627a30d975cbdde020b014638d6b061c2aba891815a2975998a1894a6ef9 +document_revision_provenance: "4f6db43d72bd59705cdefd0851f6c25c63a699cf" +document_sha256: 714a197db6b067167bf224c0fa45263b4e89b9caa605131ce58f6267b3b76224 verdict: clean -attested_at: 2026-10-28T11:48:40Z +attested_at: 2026-11-04T15:50:04Z --- diff --git a/docs/authentication/.review/high-level-design.md b/docs/authentication/.review/high-level-design.md index 2d9bbf6..2597e42 100644 --- a/docs/authentication/.review/high-level-design.md +++ b/docs/authentication/.review/high-level-design.md @@ -1,27 +1,29 @@ --- artifact: swe-design-review-attestation -schema_version: 4 +schema_version: 6 scope_key: 1c59c57e468919ccbf0a9fdf92edf389ea9c81643b070c7a5d5e806717ce0074 scope: {"kind": "path", "primary_target": "docs/authentication/high-level-design.md", "repository": ".", "selector": "docs/authentication/high-level-design.md"} -review_content_identity_sha256: fef33e137ee10af409a450dca99372954ed8259a12b62f9b822b19b1279c5f6e -target_content_identity_sha256: 16c8c6225b91d2cf19a98f33f93d2d691d0d7ab1eeed05831275ce616938be47 +review_content_identity_sha256: 0e27472024d4eaad831032e9609bb23d6a43f51ed90b8ad6a96fb65efea69cee +target_content_identity_sha256: b6852da36962fbccfe488a8a03f4e0a46b2ecf0618f533678c30109c0a9b4b1a baseline_content_identity_sha256: 95080c8129b4da2db4db318d829532ce16d721ef805c4a756c90a714c0262483 -target_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57"}] +target_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}] baseline_documents: [{"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] design_dependency_documents: [{"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +plan_binding: null +security_review: {"actual": "dbb", "binding_identity_sha256": "916310bfe0c6934c20ad721bb860af31ca3927f83bf3d35da2fe15bc16e6cb82", "requested": "dbb", "reviewer": "/root/pr83_focused_hld_dbb", "schema_version": 1} document_repository: "." document_path: "docs/authentication/high-level-design.md" -document_revision_provenance: "94994fafe8c568f608387fbecf2a32bd37fbc645" -document_sha256: b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57 +document_revision_provenance: "a7ffe71fd05388a23a2d30b06afd0eb6abb11e7b" +document_sha256: 5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe verdict: clean -attested_at: 2026-10-19T19:58:07Z +attested_at: 2026-11-04T05:38:55Z --- - + # SWE design-review attestation Review freshness binds target and baseline document bytes and executable state -listed in the version-4 header. Revisions are provenance only. +listed in the version-6 header. Revisions are provenance only. ## Durable review state diff --git a/docs/authentication/.review/implementation-plan.md b/docs/authentication/.review/implementation-plan.md index 0a93335..ec73f19 100644 --- a/docs/authentication/.review/implementation-plan.md +++ b/docs/authentication/.review/implementation-plan.md @@ -3,20 +3,20 @@ artifact: swe-design-review-attestation schema_version: 6 scope_key: c2ebaf06c49668e199e08bccef68303c5cd0925e79b8f635860bb8fa8494d61b scope: {"kind": "path", "primary_target": "docs/authentication/implementation-plan.md", "repository": ".", "selector": "docs/authentication/implementation-plan.md"} -review_content_identity_sha256: 32272b7fdf21b1aa8d19f720f7de16edf4262042130322944967af9350ab8a36 -target_content_identity_sha256: 447615f8354c3cfd6ac41dfda383b76856f4af7cadf624a50fecb91e66d7df6f -baseline_content_identity_sha256: 8e02df1e7ff92b8aef06db429f86cd9b60ef8fdb1651422b9e6473cad85338a9 -target_documents: [{"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a"}] -baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] -design_dependency_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] -plan_binding: {"base_revision": "e144661ff7049451365f0dccc80ba840f39d3433", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "38456f43776f8b47b1c5beb7cdbf5be5a34832267286a0135a489083980a4379"}]} -security_review: {"actual": "dbb", "binding_identity_sha256": "079c608ef4ca136286e8c683716683f015431ec1aa5d344af03d4da22c1824e4", "requested": "dbb", "reviewer": "/root/auth2104_round8_inventory_dbb", "schema_version": 1} +review_content_identity_sha256: 5893064257f1b8afd405898058d9b7fc9e9b957c95a40e9acd6fc018982f0869 +target_content_identity_sha256: 8a3289d4d765221e818ae1babfe09bbd0c1801a6eb9510d09761e7f87e1a9315 +baseline_content_identity_sha256: 36c6b33068c1ca88278d21f6e92eb299e77be6e00dce5ec2e8e7a4c2da85bc62 +target_documents: [{"executable": false, "path": "docs/authentication/README.md", "repository": ".", "sha256": "714a197db6b067167bf224c0fa45263b4e89b9caa605131ce58f6267b3b76224"}, {"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "7bf550552c24f8d66e7032ed1b25379ecd062dfc5e3e9db4de3b197ee66fc0f2"}, {"executable": false, "path": "docs/authentication/overview.md", "repository": ".", "sha256": "f0e95b138f566067c735898d2fdff3d02fad8d1c4369204266fe26ef89b8e212"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/slices.json", "repository": ".", "sha256": "995e7ed8c99dd2133188ba4ee5f8d9d5feaa1d175772f9dbba336755dedc533c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/backend-evidence.md", "repository": ".", "sha256": "fa1cd32632dbab696648369015c5c4ebd0762f27b81455548cf3bcb1545a9fa4"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-basis.md", "repository": ".", "sha256": "176283b0aa31cdfe3070508dd89c68e84457731d774bebd771f3718f01d0e46f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-comparison.md", "repository": ".", "sha256": "b64b26f9337c6be505f11319ef321dd647519d20527d45cf962b446835df84ba"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-after.json", "repository": ".", "sha256": "39393c7f902f9907415acbed0a861d5014997053ad2199f82215853ae94c1e80"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-before.json", "repository": ".", "sha256": "0570a8902bf55c255289cbb5ff3d48df17779b9e4fb66e352fca34446531545c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-native-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-plan.txt", "repository": ".", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a"}] +baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +design_dependency_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +plan_binding: {"base_revision": "4f6db43d72bd59705cdefd0851f6c25c63a699cf", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "26189fa66fc3804040b98edfd72ba346567c0280c5ebbca4f12ab5ebcaa421fe"}]} +security_review: {"actual": "dbb", "binding_identity_sha256": "477b0e2b315f79ce92dc2819d4046ea1e61fc6a9557cea8bb5462beca8044e62", "requested": "dbb", "reviewer": "/root/pr83_current_combined_dbb", "schema_version": 1} document_repository: "." document_path: "docs/authentication/implementation-plan.md" -document_revision_provenance: "e144661ff7049451365f0dccc80ba840f39d3433" -document_sha256: 3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a +document_revision_provenance: "4f6db43d72bd59705cdefd0851f6c25c63a699cf" +document_sha256: cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36 verdict: clean -attested_at: 2026-11-01T08:04:06Z +attested_at: 2026-11-04T15:50:04Z --- diff --git a/docs/authentication/.review/milestone-3-lld.md b/docs/authentication/.review/milestone-3-lld.md index 79f66f8..1dd5c69 100644 --- a/docs/authentication/.review/milestone-3-lld.md +++ b/docs/authentication/.review/milestone-3-lld.md @@ -1,22 +1,22 @@ --- artifact: swe-design-review-attestation schema_version: 6 -scope_key: 66489811874712090b8cf783e2912a2c30971230158f693f9f856c843a312941 -scope: {"kind": "path", "primary_target": "docs/authentication/milestone-3-lld.md", "repository": ".", "selector": "docs/authentication/milestone-3-lld.md"} -review_content_identity_sha256: e0867deabcd610323cc406bc446579d94be5a1a851a23920805d0646d3f267d7 -target_content_identity_sha256: 3d8711b943bcc9225b635788047b92db86c772b42c43f82bf1d2ce71e7566099 -baseline_content_identity_sha256: 0c7c67fcd4a67e4cf2005caadd444b25aeb2082ecd8bc449d1424386a27cd631 -target_documents: [{"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}] -baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] -design_dependency_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] -plan_binding: null -security_review: {"actual": "dbb", "binding_identity_sha256": "c8a75df1717837e705d4821342d107fd1bf278fee889d7188a7561d02754d813", "requested": "dbb", "reviewer": "/root/pr75_e48c_inventory_dbb", "schema_version": 1} +scope_key: c2ebaf06c49668e199e08bccef68303c5cd0925e79b8f635860bb8fa8494d61b +scope: {"kind": "path", "primary_target": "docs/authentication/implementation-plan.md", "repository": ".", "selector": "docs/authentication/implementation-plan.md"} +review_content_identity_sha256: 5893064257f1b8afd405898058d9b7fc9e9b957c95a40e9acd6fc018982f0869 +target_content_identity_sha256: 8a3289d4d765221e818ae1babfe09bbd0c1801a6eb9510d09761e7f87e1a9315 +baseline_content_identity_sha256: 36c6b33068c1ca88278d21f6e92eb299e77be6e00dce5ec2e8e7a4c2da85bc62 +target_documents: [{"executable": false, "path": "docs/authentication/README.md", "repository": ".", "sha256": "714a197db6b067167bf224c0fa45263b4e89b9caa605131ce58f6267b3b76224"}, {"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "7bf550552c24f8d66e7032ed1b25379ecd062dfc5e3e9db4de3b197ee66fc0f2"}, {"executable": false, "path": "docs/authentication/overview.md", "repository": ".", "sha256": "f0e95b138f566067c735898d2fdff3d02fad8d1c4369204266fe26ef89b8e212"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/slices.json", "repository": ".", "sha256": "995e7ed8c99dd2133188ba4ee5f8d9d5feaa1d175772f9dbba336755dedc533c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/backend-evidence.md", "repository": ".", "sha256": "fa1cd32632dbab696648369015c5c4ebd0762f27b81455548cf3bcb1545a9fa4"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-basis.md", "repository": ".", "sha256": "176283b0aa31cdfe3070508dd89c68e84457731d774bebd771f3718f01d0e46f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-comparison.md", "repository": ".", "sha256": "b64b26f9337c6be505f11319ef321dd647519d20527d45cf962b446835df84ba"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-after.json", "repository": ".", "sha256": "39393c7f902f9907415acbed0a861d5014997053ad2199f82215853ae94c1e80"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-before.json", "repository": ".", "sha256": "0570a8902bf55c255289cbb5ff3d48df17779b9e4fb66e352fca34446531545c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-native-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-plan.txt", "repository": ".", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a"}] +baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +design_dependency_documents: [] +plan_binding: {"base_revision": "4f6db43d72bd59705cdefd0851f6c25c63a699cf", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "26189fa66fc3804040b98edfd72ba346567c0280c5ebbca4f12ab5ebcaa421fe"}]} +security_review: {"actual": "dbb", "binding_identity_sha256": "477b0e2b315f79ce92dc2819d4046ea1e61fc6a9557cea8bb5462beca8044e62", "requested": "dbb", "reviewer": "/root/pr83_current_combined_dbb", "schema_version": 1} document_repository: "." document_path: "docs/authentication/milestone-3-lld.md" -document_revision_provenance: "e48c2feeee01707218733fe46e40cdd61fcbc9c6" -document_sha256: 566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f +document_revision_provenance: "4f6db43d72bd59705cdefd0851f6c25c63a699cf" +document_sha256: 7bf550552c24f8d66e7032ed1b25379ecd062dfc5e3e9db4de3b197ee66fc0f2 verdict: clean -attested_at: 2026-10-28T12:41:34Z +attested_at: 2026-11-04T15:50:04Z --- diff --git a/docs/authentication/.review/overview.md b/docs/authentication/.review/overview.md new file mode 100644 index 0000000..d8e084a --- /dev/null +++ b/docs/authentication/.review/overview.md @@ -0,0 +1,30 @@ +--- +artifact: swe-design-review-attestation +schema_version: 6 +scope_key: c2ebaf06c49668e199e08bccef68303c5cd0925e79b8f635860bb8fa8494d61b +scope: {"kind": "path", "primary_target": "docs/authentication/implementation-plan.md", "repository": ".", "selector": "docs/authentication/implementation-plan.md"} +review_content_identity_sha256: 5893064257f1b8afd405898058d9b7fc9e9b957c95a40e9acd6fc018982f0869 +target_content_identity_sha256: 8a3289d4d765221e818ae1babfe09bbd0c1801a6eb9510d09761e7f87e1a9315 +baseline_content_identity_sha256: 36c6b33068c1ca88278d21f6e92eb299e77be6e00dce5ec2e8e7a4c2da85bc62 +target_documents: [{"executable": false, "path": "docs/authentication/README.md", "repository": ".", "sha256": "714a197db6b067167bf224c0fa45263b4e89b9caa605131ce58f6267b3b76224"}, {"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "7bf550552c24f8d66e7032ed1b25379ecd062dfc5e3e9db4de3b197ee66fc0f2"}, {"executable": false, "path": "docs/authentication/overview.md", "repository": ".", "sha256": "f0e95b138f566067c735898d2fdff3d02fad8d1c4369204266fe26ef89b8e212"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/slices.json", "repository": ".", "sha256": "995e7ed8c99dd2133188ba4ee5f8d9d5feaa1d175772f9dbba336755dedc533c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/backend-evidence.md", "repository": ".", "sha256": "fa1cd32632dbab696648369015c5c4ebd0762f27b81455548cf3bcb1545a9fa4"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-basis.md", "repository": ".", "sha256": "176283b0aa31cdfe3070508dd89c68e84457731d774bebd771f3718f01d0e46f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-comparison.md", "repository": ".", "sha256": "b64b26f9337c6be505f11319ef321dd647519d20527d45cf962b446835df84ba"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-after.json", "repository": ".", "sha256": "39393c7f902f9907415acbed0a861d5014997053ad2199f82215853ae94c1e80"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-before.json", "repository": ".", "sha256": "0570a8902bf55c255289cbb5ff3d48df17779b9e4fb66e352fca34446531545c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-native-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-plan.txt", "repository": ".", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a"}] +baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +design_dependency_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +plan_binding: {"base_revision": "4f6db43d72bd59705cdefd0851f6c25c63a699cf", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "26189fa66fc3804040b98edfd72ba346567c0280c5ebbca4f12ab5ebcaa421fe"}]} +security_review: {"actual": "dbb", "binding_identity_sha256": "477b0e2b315f79ce92dc2819d4046ea1e61fc6a9557cea8bb5462beca8044e62", "requested": "dbb", "reviewer": "/root/pr83_current_combined_dbb", "schema_version": 1} +document_repository: "." +document_path: "docs/authentication/overview.md" +document_revision_provenance: "4f6db43d72bd59705cdefd0851f6c25c63a699cf" +document_sha256: f0e95b138f566067c735898d2fdff3d02fad8d1c4369204266fe26ef89b8e212 +verdict: clean +attested_at: 2026-11-04T15:50:04Z +--- + + +# SWE design-review attestation + +Review freshness binds target and baseline document bytes and executable state +listed in the version-6 header. Revisions are provenance only. + +## Durable review state + +No standing rejected or deferred decisions. diff --git a/docs/authentication/.review/requirements.md b/docs/authentication/.review/requirements.md index f5bea3a..b0e9e13 100644 --- a/docs/authentication/.review/requirements.md +++ b/docs/authentication/.review/requirements.md @@ -1,6 +1,6 @@ --- artifact: swe-design-review-attestation -schema_version: 4 +schema_version: 6 scope_key: 235a91e02daa5c9e8dfd8100063367f8dbae41f71d74157b793e582fd88cd33b scope: {"kind": "path", "primary_target": "docs/authentication/requirements.md", "repository": ".", "selector": "docs/authentication/requirements.md"} review_content_identity_sha256: 9b2655a2922e88eb8be3072e6656916b4937d4d5ef79d0e93ff2ca5ab1376d19 @@ -9,19 +9,21 @@ baseline_content_identity_sha256: null target_documents: [{"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] baseline_documents: [] design_dependency_documents: [] +plan_binding: null +security_review: {"actual": "dbb", "binding_identity_sha256": "4893e7d74d17dfcd97cae84da1da22d2cd0eced54a1155daff93d48c268178e1", "requested": "dbb", "reviewer": "/root/auth_rest_requirements_dbb", "schema_version": 1} document_repository: "." document_path: "docs/authentication/requirements.md" -document_revision_provenance: "94994fafe8c568f608387fbecf2a32bd37fbc645" +document_revision_provenance: "d52f8bc0acadc1de0dcb53fb1a96eb3e822e174a" document_sha256: d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929 verdict: clean -attested_at: 2026-10-19T18:03:35Z +attested_at: 2026-11-02T16:27:18Z --- - + # SWE design-review attestation Review freshness binds target and baseline document bytes and executable state -listed in the version-4 header. Revisions are provenance only. +listed in the version-6 header. Revisions are provenance only. ## Durable review state diff --git a/docs/authentication/README.md b/docs/authentication/README.md index dac773b..11f26c8 100644 --- a/docs/authentication/README.md +++ b/docs/authentication/README.md @@ -1,100 +1,22 @@ -# Authentication and enrollment - -Read the [requirements](requirements.md), [HLD](high-level-design.md), -[portable enrollment LLD](portable-enrollment-lld.md), -[milestone-3 LLD](milestone-3-lld.md), then the -[implementation plan](implementation-plan.md). The requirements/HLD remain the -unchanged governing design. The two LLDs specify the next proposed work, its -complete acceptance and already sized implementation cuts; the plan owns delivery -ordering and stable identities. This page summarizes those four design inputs -and the plan; it adds no separate product requirements. - -Review evidence lives beside documents in `.review/`, including the -[requirements](.review/requirements.md), [HLD](.review/high-level-design.md), -[portable enrollment](.review/portable-enrollment-lld.md), -[milestone 3](.review/milestone-3-lld.md) and -[plan](.review/implementation-plan.md) attestations. A stamp binds exact bytes, -explicit design dependencies and its actual review evidence. An older stamp does -not approve changed text; every changed design must complete DBB/general review -and receive a current stamp before acceptance. Review approval is separate from -implementation authorization, merge and publication. - -## Current state and proposed next work - -Merged baseline: `25a8cf2196f36499ff92ce890f313901b51b4f2b`. -Authority/setup/local control and the milestone-2 fresh-pairing/activation/receipt -stack are merged; [PR74](https://github.com/omry/arbiter/pull/74) closed the latter. -All 13 reported post-merge checks passed in the -[baseline workflow run](https://github.com/omry/arbiter/actions/runs/40579826766). -That is source-baseline evidence, not -completion of all authentication requirements or publication approval. - -Existing-portable-identity reuse remains unimplemented. Fresh-key proof and -same-selector receipt resume do not preserve one agent across two servers. -The portable LLD's proposed `2.10.1–2.10.4` closes that gap with independently -registered issuer trust, original portable-key possession and fresh per-server -access/approval/grants. It retains the existing pairing and private publisher; -no key broker or second enrollment service is proposed. The first upgraded cut -also maintains unique agent bindings during fresh-v1 activation; safe intermediate -state is not deferred until v2 cutover. The old milestone-2 -22-attempt allowance is exhausted and does not authorize these four new cuts. - -Milestone 3 is also unimplemented. Its LLD specifies strict native mTLS, existing -ASGI/policy integration, live grants/denial and closed artifact behavior until the -encrypted store. It proposes 13 complete cuts, ordered so denial is ready before -public ordinary cutover. The server request-body deadline and shared enrollment -denial/contact fields are design specifications, not applied runtime changes. -The existing agent binding remains canonical. The production CLI switch and -server enablement share the same cut; earlier private-peer coverage preserves -the working product route. The first live enrollment-deny control and fixed-receipt -output guard share the same coordinator and cut; ordinary admission extends it -in the following cut. - -The next design-reviewed implementation proposals are: - -| Work | Proposed PRs | Handwritten production/test/CI estimate | -| --- | ---: | ---: | -| `2.10` portable reuse | 4 | 2,150–3,015 | -| `3` native API/grants/denial | 13 | 6,790–9,410 | - -Detailed ownership, acceptance and per-cut estimates live once in their LLDs. -Docs/news/lock data are separate. Counts include code motion, fixtures and review -headroom; no later dynamic split is assumed. These are reviewable estimates, -not approved delivery allowances or guarantees. Preserve the existing 1,000-line -handwritten-code cap, including tests. The original 60-PR plan and milestone-3 -seven-PR estimate are historical. Milestones 4–11 retain scope/outlines, but need -source-based LLD sizing/review before execution; no credible total remaining-PR -forecast is claimed yet. - -Design and local/PR review do not authorize implementation. Starting `2.10`, -milestone 3 or later implementation requires separate operator authorization. All eleven milestones and -the combined publication gate remain required; a merged development stack is -not releasable authentication support. - -The [earlier synthesis](design.md) and [candidate security contracts](security-contracts.md) -are historical HLD inputs. The closed interview and earlier findings remain -provenance, not additional binding requirements or instructions to reopen questions. -These design documents themselves grant no product implementation authorization. - -## Supporting material - -- [Decision and experiment evidence](evidence.md): provenance for the 104 recorded - decisions and limits of the retained compatibility experiments. -- [Review history](reviews/README.md): completed fidelity and DBB assessments. - The [requirements DBB report](reviews/requirements-dbb.md) gives the current - requirements-level verdict; the [HLD DBB report](reviews/hld-dbb.md) gives the - exact-byte HLD pass. Earlier reports concern candidate architecture. - The [initial plan review](reviews/plan-dbb.md) records the safe artifact-prefix - and certificate-renewal repairs. The [plan sizing review](reviews/plan-sizing-dbb.md) - records the original child-PR estimates and repaired activation/denial order; - it does not review the new LLD forecasts. -- [Original draft and interview](../archive/authentication-and-enrollment/README.md): - immutable historical evidence, not required reading or instructions to resume - questioning. - -The HLD covers B1–B5 and shared boundaries. Its fourteen retained Python/Go -feasibility checks were design inputs, not proof of the later ordinary transport. -Native implementation, race/crash and installed-prefix evidence belongs to each -owning implementation cut. The reviewed LLDs retain receipt-before-activation, -denial-before-public-cutover and safe artifact-prefix obligations. This revision -updates the design and status; it implements no product behavior. +# Authentication design + +Start with the [overview](overview.md). + +- [Requirements](requirements.md): approved outcomes R01–R25, unchanged. +- [High-level design](high-level-design.md): reviewed architecture and approved public interfaces. +- [Implementation plan](implementation-plan.md): current detailed engineering for all remaining milestones3–11. +- [Canonical slice inventory](slices.json): one ordered definition set; planning states are not delivery status. +- [Before/after LOC comparison](supporting/implementation-plan/estimate-comparison.md): every cut and milestone, with different historical/current units explicit. + +Authority/setup and fresh plus reused portable enrollment are merged, including +2.10.1–2.10.4. No authentication milestone3–11 product work starts through this +design revision. Original consumed allowances and immutable review/receipt +history remain in their original records. + +The [portable enrollment LLD](portable-enrollment-lld.md) remains historical +delivery authority for that merged correction. The old native LLD now points +to the current plan; [historical planning](supporting/implementation-plan/historical-plan.txt) +and [historical native detail](supporting/implementation-plan/historical-native-lld.md) +retain exact former text. Earlier design/security contracts, [decision evidence](evidence.md), +[review reports](reviews/README.md) and [archived interview](../archive/authentication-and-enrollment/README.md) +remain provenance. They do not reopen requirements or approve new design bytes. diff --git a/docs/authentication/high-level-design.md b/docs/authentication/high-level-design.md index 0b16965..32bc2fd 100644 --- a/docs/authentication/high-level-design.md +++ b/docs/authentication/high-level-design.md @@ -1,6 +1,7 @@ # Authentication and mutual enrollment: high-level design -Stage: HLD candidate, 2026-10-20. The [stamped requirements](requirements.md) +Stage: existing approved architecture under revision for milestones 3–11, +2026-11-03. The [stamped requirements](requirements.md) are normative; their SHA-256 is `d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929`. This document selects components, responsibilities, state transitions and failure @@ -8,7 +9,257 @@ boundaries. It is not a wire specification, sliced implementation plan, implemen security fix or release approval. Actual DBB must approve these exact bytes before a durable design stamp. Review verdicts live in separate evidence, not in this document's mutable status text. The earlier synthesis and H1–H5 contracts are -context; choices retained below become this HLD's design decisions. +context; choices retained below become this HLD's design decisions. The new +public command contract below is a proposal until affected review and explicit +owner acceptance. Earlier approval does not approve previously unspecified +interfaces. Product implementation is not authorized by this revision. + +## Current source and remaining scope + +Source baseline is merged main `d52f8bc0acadc1de0dcb53fb1a96eb3e822e174a`. +Authority setup, OS-authenticated administration, fresh enrollment and portable +identity reuse are implemented and merged. Preserve their IDs, custody, bounded +pairing, activation and receipt behavior. This revision designs all of milestones +3–11; it does not reopen the requirements interview or reimplement milestones 1–2. + +| Existing primitive | Remaining architectural responsibility | +| --- | --- | +| `authority.py`, enrollment transactions and OS local control | Extend the same authority with live grants, denial and lifecycle state. Do not add another policy engine or an independently authoritative cache. | +| `generations.py` | Reuse its private selector, instance lock and crash reconciliation. It currently publishes the initial authority DB; complete configuration/secret generations and restore/undo are still work. | +| `recovery.py` | Preserve the existing external signer/decryptor file and public-origin registration. Their existence does not implement recovery commands, backup or restore. | +| Pairing carrier, fixed `ControlTLS`, native limits and actual-worker pools | Reuse bounded ownership and exporter-capable controls. Ordinary streaming TLS/HTTP and live denial are not implemented yet. | +| Existing Go HTTP API, timeout wrappers, WebSocket adapter and artifact process helpers | Keep operation schemas and established timeout/process behavior. Add the selected native transport rather than a second HTTP stack or client daemon. | +| Existing artifact store and consuming GET | Reuse quota, publication and process ownership. Creator/account binding, encryption and verified processing remain milestones 7–8. | + +Keep the existing Go WebSocket dependency and adapter unless source evidence +requires an affected design change. The old feasibility probe's use of a different +WebSocket library does not select another production dependency. Python already +uses `pyOpenSSL==26.2.0` with `cryptography>=42,<49`; old probe versions below are +historical evidence, not a request to downgrade or a current dependency audit. + +The simpler alternatives remain deliberate: outer HTTPS alone cannot satisfy +proxy-independent native confidentiality; one shared carrier owner and ordinary +Go HTTP transport avoid a second transport stack; standard age avoids a new +cipher format; the existing generation selector avoids a second restore registry; +the approved cooperative migration procedure avoids distributed fencing. + +## Public contract for milestones 3–11 + +This section makes the interface proposal reviewable. It preserves accepted +behavior and the working command families. Command names and new arguments in +this section are not claims that those commands already exist. Detailed internal +message fields, database migrations and platform publication adapters belong to +the implementation plan. The public contract must be accepted before that detail +is called ready. + +### Selection and authenticated operations — milestone 3 + +Keep existing `info`, `plugins`, `op` and artifact request/response shapes. +Add `arbiter.enrollment: SELECTOR` to client configuration and the explicit +`enrollment=SELECTOR` override. The override wins over configuration; there is no +environment-derived, first-record or URL-derived identity selection. Empty or +malformed selection fails before dialing with enrollment/configuration guidance. +An override applies to that invocation; it does not rewrite the saved selection. + +```text +arbiter info enrollment=SELECTOR +arbiter op OPERATION existing-arguments enrollment=SELECTOR +arbiter-server enrollment list --state-dir STATE --enrolled +arbiter-server enrollment grant add --state-dir STATE --enrollment-id ID --grant PLUGIN/ACCOUNT +arbiter-server enrollment grant remove --state-dir STATE --enrollment-id ID --grant PLUGIN/ACCOUNT +arbiter-server enrollment deny --state-dir STATE --enrollment-id ID +``` + +`SELECTOR` is the existing canonical client enrollment selector; `ID` is the +server's durable enrollment UUID. They are not interchangeable. Existing +`enrollment list` continues to list pending requests; `--enrolled` explicitly +selects enrolled records. Grant add/remove operates on one exact configured +account and is set-like on retry. Denial is idempotent and affects every account +and connection for that enrollment. These commands use the existing local +OS-authenticated control boundary, not a new public administrator API. They never +repair credentials, erase denials or create an operation allowlist. + +The ordinary carrier is `/api/v1/native/api`, with TLS 1.3, +`arbiter-native-v1` ALPN and one HTTP/1.1 request per connection. Existing inner +HTTP methods, paths and operation schemas remain. Dedicated pairing and fixed +control endpoints retain their existing roles. At the milestone-3 cutover, +ordinary anonymous API and legacy artifact routes close together; only minimal +health and bounded enrollment bootstrap remain anonymous. Artifact-producing +operations fail through the closed adapter until milestone 7 supplies the real +encrypted dependency; there is no plaintext/ownerless substitute. + +Changing `url` changes location, never selected identity or remembered trust. +Verify the selected durable server before sending credentials or capabilities. +Grant removal stops affected admission and further delivery across connections; +already delivered bytes and committed upstream effects cannot be undone. Retain +existing structured error envelopes and safe human diagnostics. A transport +failure alone does not establish revocation, and no failure replays an uncertain +operation or consuming GET. + +### Credential lifecycle and owner repair — milestones 4–6 + +Routine access-key rotation is automatic on authenticated contact; it adds no +required daemon, periodic job or operator approval. The existing 30-day age, +24-hour fixed grace and 180-day inactivity defaults remain. Reconnect, retry, +candidate withholding and incomplete controls reset none of them. The fixed +control carrier completes only the recorded transition after grace/expiry; +ordinary mTLS remains strict. No user-facing `force`, validity bypass or +automatic recovery flag is introduced. + +Owner-authorized repair uses public request/authorization files, while new +private keys remain in protected client state and the operator file stays on the +operator's machine: + +```text +arbiter enrol repair --enrollment SELECTOR +arbiter enrol recover-request --enrollment SELECTOR --output REQUEST +arbiter-server recovery authorize --recovery-file OPERATOR --request REQUEST --output AUTHORIZATION +arbiter enrol recover --enrollment SELECTOR --authorization AUTHORIZATION +arbiter identity replace-request --identity SELECTOR --output PORTABLE_REQUEST +arbiter enrol recover-request --enrollment SELECTOR --portable-request PORTABLE_REQUEST --output REQUEST +``` + +`repair` uses the existing owner-approved pairing journey for the existing +enrollment. It does not silently create a new agent or enrollment. The independent +recovery path obtains a fresh server-specific challenge and prepares replacement +keys without activation. The offline owner command signs only that exact +server/identity/key/revision/purpose/expiry request. Completing it consumes the +authorization once and reconciles a lost result without a second operator +approval or resetting grants/denials. Wrong, expired or stale requests fail; +the caller obtains a fresh request rather than retrying an uncertain mutation. + +An explicit portable replacement prepares one shared replacement key in private +client custody; its public request can be bound into separate authorizations for +each existing enrollment. It does not confer ordinary access or register a new +issuer at other servers. Issuing a normal portable certificate still requires an +authorized issuer with its private key available. Missing issuer authority gives +restore/issuer-registration guidance, not a forged old-issuer certificate or an +automatic trust-store change. Existing-enrollment owner recovery and fresh +enrollment's independent issuer-registration rule remain distinct. LLD must +resolve the exact issuing and multi-server reconciliation sequence before this +cut is ready. + +Server replacement also prepares before applying: + +```text +arbiter-server authority replace-request --state-dir STATE --reason planned --output REQUEST +arbiter-server authority replace-request --state-dir STATE --reason compromised --output REQUEST +arbiter-server recovery authorize --recovery-file OPERATOR --request REQUEST --output AUTHORIZATION +arbiter-server authority replace --state-dir STATE --request REQUEST [--authorization AUTHORIZATION] +``` + +Planned replacement requires old endorsement and new-key possession. +Compromise replacement requires the independently registered owner authorization; +the compromised key alone cannot bless a successor. The optional authorization +argument is mandatory for the compromised reason and never switches that reason +silently. Keep server ID, enrollments, grants and denials. Clients durably adopt +verified transitions before credentials; unavailable history or independent +trust gives explicit repair guidance. Stopped-instance repair and live local +administration use their existing exclusive owners; no direct concurrent DB +writer is added. Certificate renewal retains identity/key roles and does not +turn URL/outer HTTPS renewal into scheduled identity-key replacement. + +### Artifact processing — milestones 7–8 + +Keep explicit process selection and existing child-output bounds, argument-vector +execution and `{}` path substitution. There is no universal processing default: + +```text +arbiter artifact with-stdin URL --stream true -- ARGV... +arbiter artifact with-stdin URL --stream false -- ARGV... +arbiter artifact with-temp URL --allow-plaintext-temp -- ARGV... +arbiter artifact save-decrypted URL PATH +``` + +Each command uses the configured enrollment or its explicit override. +`with-stdin` requires an explicit `--stream true` or `--stream false`; omission, +an invalid value or combining stream/path options fails before consuming GET. +No default is selected. With `true`, the client decrypts incoming data directly +into the tool while downloading. A valid partial prefix and tool effects can +precede a final origin/digest/EOF failure. With `false`, the client downloads an +encrypted temporary file, decrypts and checks it while discarding plaintext, +then decrypts the same immutable ciphertext again into the tool. The tool starts +only after the complete-file checks pass. Neither path writes a plaintext input +file to disk. The tool can still create its own output or fail during execution; +checking the download does not make the tool's work atomic. +`with-temp` requires the explicit plaintext flag, fully verifies before exposing +the path, and performs best-effort cleanup. `save-decrypted` verifies private +staging before publishing a persistent plaintext file; an existing output path +fails without overwrite. The old ambiguous `artifact save` has no compatibility +alias, as already required by the approved design. + +Retain bounded textual `artifact get URL --stdout` as an explicitly selected +immediate output sink, with final-verification failure reported honestly; it is +not a verified-before-output mode. No raw private key, descriptor/capability or +artifact content enters routine diagnostics. A failed consuming GET remains +consumed; no mode resumes it from an orphan file. Choosing storage/latency versus +partial delivery is explicit at invocation time, not an agent-chosen default. + +### Backup, restore, undo and migration — milestones 9–11 + +```text +arbiter-server backup export --state-dir STATE --output BUNDLE +arbiter-server backup restore --state-dir STATE --recovery-file OPERATOR --input BUNDLE +arbiter-server backup undo --state-dir STATE +arbiter-server backup undo-discard --state-dir STATE +arbiter-server maintenance begin --state-dir STATE +arbiter-server maintenance end --state-dir STATE +arbiter-server handoff --state-dir STATE --url DESTINATION +``` + +Export uses the running server's authenticated local boundary. One job captures +a coherent saved generation and publishes only a complete signed/encrypted bundle +to the explicitly selected output; replacing that designated bundle is atomic +and failure preserves the last good file. An external job supplies startup and +periodic scheduling, storage/retention and alerting. It receives no private +operator file. No scheduler/cloud integration or first-enrollment backup gate is +added. The registered public recipient/verifier come from existing trusted setup. + +Restore, undo and undo-discard run locally with the instance stopped, including +when the application cannot start. Restore verifies the entire bundle against +external trust before one coherent activation, preserving the prior state as +the latest undo point. Failed restore changes neither active state nor that +point. Undo remains available after use, without expiry; there is no redo or +mandatory acceptance phase. Before activation/discard, print prominent snapshot, +lost-change, restored-authorization and irreversible-upstream-effect warnings. +Explicit invocation selects the action; do not add a separate required approval +ceremony. Configured paths are not merged, and saved deadlines are not reset. +Different-host adjustments use ordinary configuration edits before startup. + +Maintenance begin commits source dispatch/admin-write inhibition, drains or +cancels real owners, and returns completion only after their actual cleanup. +Read-only export remains available. Failures retain the disabled source until +the operator deliberately ends maintenance or completes migration. The operator +exports the final state, restores the stopped destination, adjusts host settings, +then starts only that destination in its restored maintenance state. The operator +runs `maintenance end` locally on the destination before verifying paired clients; +this does not clear maintenance on the source. `maintenance end` is an explicit +local action, not automatic rollback after destination use. + +Optional `handoff` serves only remembered source identity and a fixed authenticated +destination URL while ordinary source service remains disabled. It has no +enrollment, grant, rotation or authority-mutation handler. The client obtains +handoff before operation submission, verifies destination identity/authorized +transition, then durably adopts the URL. Destination key rotation does not require +rewriting the URL. No HTTP redirect sends credentials or replays an operation. +If the old URL is unavailable, the operator sets the client URL explicitly; the +same durable identity checks still apply. The operator prevents two writable +copies; no epoch, fencing service or permanent retirement is introduced. + +### Acceptance and remaining decisions + +Already settled: product outcomes R01–R25, trust roles, fixed grace/inactivity, +four artifact choices, rollback warnings and cooperative migration. The command +spellings and grouping above incorporate the focused interface decisions. The +complete architecture and its visible behavior still require affected review +and HLD acceptance. No requirement has been removed +to obtain a cleaner design or a smaller LOC estimate. + +The LLD must resolve exact message/certificate schemas, shared coordinator and +worker ownership, portable recertification, renewal schedules, physical quota +accounting, saved-config capture and native durable publication. It must assign +each obligation and integration check once to a concrete slice. These are pending +engineering tasks, not a new requirements interview or implementation readiness. ## Shared architecture and trust @@ -481,7 +732,7 @@ timestamps; stale snapshots can require owner repair and never reset deadlines. No extra permissions review, paused mode or acceptance ceremony is imposed. Undo is only of the latest successful restore, with no automatic expiry. It is -allowed offline after the service has run, with very prominent confirmation of +allowed offline after the service has run, with very prominent warnings about lost post-restore local configuration/identity/grant changes and unchanged upstream effects. Switch coherently to the saved pre-restore generation, not a merge. There is no redo history or mandatory acceptance step. The next successful @@ -501,8 +752,9 @@ their surviving durable agent identities need not be replaced. Document a maintenance window: disable ordinary source dispatch and state-changing administration; drain/cancel actual work; capture the final bundle; restore stopped -destination; adjust host configuration; start only the destination. Keep the -source ordinary service disabled. There is no automated fencing, authority epoch, +destination; adjust host configuration; start only the destination in its restored +maintenance state; explicitly end maintenance on the destination; verify paired +clients. Keep the source ordinary service disabled. There is no automated fencing, authority epoch, permanent retirement or prohibition on deliberately restoring older state. The operator is responsible for not starting two writable copies. @@ -526,22 +778,11 @@ recorded separately under `temp/authentication-hld/probes/`; durable review evidence must record their results and limits. No claim of product integration, real mail/account testing, production throughput or release security follows. -Local evidence, 2026-10-20: fourteen synthetic checks passed on Linux amd64, -CPython 3.13.12 and Go 1.26.8, using pyOpenSSL 25.3.0, cryptography 46.0.7, -pyrage 1.3.0, websockets 15.0.1, Go age 1.2.1 and coder/websocket 1.8.14. -Results JSON SHA-256: -`34071a913ba400e79242ebe0b4481214a953f14fb78815e0f62ab82b180e789b`. -Checks covered TLS-over-WebSocket/exporter agreement, ordinary expired-certificate -rejection, separate expired-key control proofs and cross-channel replay rejection; -age both directions, second recipient, wrong key, tamper/truncation, immutable -snapshot/path replacement and 50 MiB plaintext; ES256 fixed-width JWS signing-byte -compatibility and changed-byte rejection. `go vet` passed and the peer compiled -with Go 1.24.13 (execution used 1.26.8). These fixtures are not complete profile, -JWS schema, recovery, overload or crash implementations. pyOpenSSL 26.3.0 was -rejected for this design's compatibility assessment because it requires -cryptography 49 outside Arbiter's current `<49` range. The compatible probe pair -is a tested candidate, not permission to freeze old versions indefinitely; resolve -production versions/advisories and platform builds in the implementation plan. +The [historical feasibility record](supporting/high-level-design/historical-feasibility.md) +retains the exact old probe versions, fourteen-check result, source digest and +limitations. This revision does not rerun or relabel those checks as current +implementation evidence. Current source reuse is identified above; new package +adoption and native-platform evidence remain implementation-plan obligations. Compared with current code, this preserves native operation schemas, existing policies, plugin isolation and error/timeout behavior. The significant work is @@ -567,13 +808,29 @@ be represented as completing these requirements. | R21–R22 | B5 coherent snapshot, actual configured secrets, authenticated encrypted export and external job. | | R23–R25 | B5 offline activation/undo, warning-based stale restore and cooperative migration/handoff. | +### Finite engineering investigations before slice readiness + +These investigations refine the retained architecture. They do not authorize +dropping a requirement or marking an incomplete slice ready. + +| Investigation | Owner and evidence required | Decision affected if it fails | +| --- | --- | --- | +| Streaming and live authority composition | Milestone 3: trace one shared carrier owner, crypto admission, body/dispatch reservation, committed denial and final output through actual worker cleanup. Execute real Python/Go and native-platform failure peers. | Ordinary native cutover remains closed until the coordinator and resource ownership are demonstrated. A second permission cache is not a fallback. | +| Exact lifecycle and recovery states | Milestones 4–6: bind keys, purposes, revisions, challenges, renewal times and exact retained results. Resolve portable recertification under available registered issuer authority and per-server owner authorization. Test lost results, expiry, denial and concurrent recovery. | Missing issuer/private authority or legitimate transition history yields explicit repair guidance; it cannot justify an automatic new root or a credential-validity bypass. | +| Encrypted file backend and immutable input | Milestones 7–8: prove bounded age streaming in the selected Python/Go implementations; account for headers/metadata/staging and actual readers; verify POSIX and Windows stable-byte handling or the bounded memory fallback. | No streaming or checked-before-start claim may rely on a whole-file unbounded API, mutable staging path or untested platform assumption. Compare maintained existing bindings before adding a custom crypto format. | +| Complete saved configuration and secrets | Milestone 9: extend existing generation capture to actual configured policies/secrets and a SQLite-consistent snapshot. Detect concurrent source changes; prove exclusions and bounded signed/encrypted publication. | The current initial-authority generation is not sufficient proof of a useful complete backup. Export must remain unavailable rather than produce a misleading partial recovery bundle. | +| Native durable activation and latest undo | Milestone 10: resolve active/undo control publication, flush ownership, available-disk checks and restart reconciliation on POSIX and Windows with process termination at each boundary. | A single rename without native evidence does not establish coherent restore/undo. No silent settings merge or loss of the prior undo point is allowed. | +| Cooperative migration and read-only handoff | Milestone 11: prove maintenance inhibition/draining, final capture, stopped destination restore and fixed URL handoff across later key rotation with real paired clients. | No automated takeover, hidden epoch/fencing service or replaying redirect may be added to conceal a failed cooperative journey. | +| Complete slice and estimate accounting | Implementation plan: map every parent outcome and cross-area check to an owner, count shared foundations once, and provide production/test final-content ranges plus original-forecast comparison. | A smaller count produced by omitted integration, platform or failure work is not an acceptable plan. Preserve historical IDs and completed milestones. | + The next stage, only after DBB approval and a validated HLD stamp, is a separately reviewed implementation plan. It must assign independently reviewable slices, wire/certificate/configuration schemas and fixtures, supported-platform dependency checks, overload/cancellation/crash fault injection and combined end-to-end tests. Full Python/Go checks and applicable release fragments belong to implementation. Future browser UI gets its own compatibility/security evidence before delivery. -No implementation plan or product change is authorized by this HLD run. +HLD acceptance does not approve the later detailed plan or authorize product +implementation, merging, publication or deployment. Primary mechanism references: [X.509 validation](https://www.rfc-editor.org/rfc/rfc5280.html), diff --git a/docs/authentication/implementation-plan.md b/docs/authentication/implementation-plan.md index fd0f895..316a164 100644 --- a/docs/authentication/implementation-plan.md +++ b/docs/authentication/implementation-plan.md @@ -1,1130 +1,1165 @@ --- plan_key: arbiter-authentication slice_convention: hierarchical-v1 +slice_inventory: {"executable": false, "path": "slices.json", "sha256": "995e7ed8c99dd2133188ba4ee5f8d9d5feaa1d175772f9dbba336755dedc533c"} --- -# Authentication and mutual enrollment: implementation plan - -Stage: design-update candidate after the milestone-2 stack merge, 2026-10-28. -Governing documents are the -[requirements](requirements.md), SHA-256 -`d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929`, -and [HLD](high-level-design.md), SHA-256 -`b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57`. -Their exact reviewed stamps, the [portable enrollment LLD](portable-enrollment-lld.md) -and the [milestone-3 LLD](milestone-3-lld.md) are explicit design dependencies of -this plan's stamp. The LLDs own their detailed schemas, state transitions, -acceptance cases and already sized cuts. Neither requirements nor HLD changes. -This plan authorizes no -implementation, release, live-account operation or deployment by itself. -DBB must approve the exact final plan before its SWE design stamp. - -## Current delivery state and next design scope - -Source baseline is merged main `25a8cf2196f36499ff92ce890f313901b51b4f2b`. -Milestone 1 authority/setup/local control and the milestone-2 fresh enrollment, -single activation and receipt stack are merged. The latter closed with -[PR74](https://github.com/omry/arbiter/pull/74); its 21 delivered PRs consumed the -22-attempt allowance, including one unshipped parent attempt. Those delivery -identities, approvals and spent allowance remain history, not permission for -additional work. All 13 reported post-merge checks passed in the -[baseline workflow run](https://github.com/omry/arbiter/actions/runs/40579826766). - -Milestone 2 still lacks the approved existing-portable-identity journey. Current -Go provisional creation always generates a new portable key; Python prepare -always assigns a new agent. Fresh-key possession and same-selector receipt -resume do not satisfy reuse of a registered portable identity at a second server. -This is an implementation gap, not an accepted scope deferral. Proposed `2.10` -closes it through the portable LLD before milestone 3 starts. These documents -specify that fix; no product fix is implemented by this design update. - -The original milestone-3 seven-PR estimate lacks the streaming, authority -integration and failure-test detail needed for a credible execution cut. Its approved -behavior is retained, with the LLD's 13 already sized proposed cuts replacing the -old boundaries. Milestones 4–11 retain their ordered scope and historical child -outlines below; their old estimates are not newly validated execution forecasts. -Refine them into source-based, reviewed LLDs with bounded complete cuts before -implementing each milestone. No cumulative remaining-PR or LOC promise follows -from adding those old outline counts to the newly sized work. - -This design and its local/PR review confer no implementation authorization. -Implementing `2.10`, milestone 3 or a later milestone requires separate operator authorization. No old -allowance is reset; no merge, release, deployment or live account work is authorized. -The [original plan at the merged baseline](https://github.com/omry/arbiter/blob/25a8cf2196f36499ff92ce890f313901b51b4f2b/docs/authentication/implementation-plan.md) -preserves the exact earlier text, forecasts and original cuts. - -## Delivery identities and rules - -`arbiter-authentication` owns this plan. Its numbered slices are `1` through `11`; -references below use `arbiter-authentication/1`, for example. Under -`hierarchical-v1`, an approved later split of `4` becomes `4.1`, `4.2`, etc.; never -renumber another slice or reuse a completed identity. The parent retains the -aggregate acceptance obligation. Delivery records bind exact PR URL, revision, -dependencies, checks, reviews and state for each canonical identity. Merged -deliveries are not renumbered or reclassified as unstarted by this plan revision. - -The eleven numbered slices are milestones, not individual PRs. The current LLD -cuts are proposed reviewable PRs with bounded behavior, failure tests and relevant -guidance/fragments. Older child tables are historical outlines as labeled. Work -serially in milestone order and then the listed child order (not numeric sort). Complete local review, checks, -submission and the approved remote review cycle for the current PR before advancing; approval binds -the final PR head, with restacking invalidating affected evidence as appropriate. -This document does not launch those cycles. An LLD must produce already sized -implementable slices; dynamic resizing should be rare. If source evidence shows -a cut is insufficient, revise and review the design before implementing it rather -than treating an execution split as routine capacity. A foundation PR must implement a real consumed boundary -(setup/status, registered pending work or an executable protocol peer), not empty -interfaces, permissive stubs or a throwaway intermediate protocol. A synthetic -peer may exercise a not-yet-public transport; it cannot authorize product traffic. -The historical 2.7/2.8 cuts used synthetic already-activated fixture rows only in -tests before 2.6 enabled real activation; this is not a production trust initializer. -Ordinary public dispatch on the new native boundary remains closed until `3.5.2`. -Both `3.6.1` and `3.6.2` install and test complete live denial first through -private real peers and synthetic accounts. -The eventual cutovers cannot rely on development-only publication policy as their -safety mechanism; the respective runtime routes must actually remain closed. - -Outside the typed portable-correction inventory below, every implementation and -review-fix commit subject, and its PR title, starts with the short slice label in brackets. For example: -`[authentication/1.1] Private authority initialization`. The repository already -identifies Arbiter; do not repeat its name in the title prefix. This display label -maps to canonical ledger identity `arbiter-authentication/1.1`; the plan key and -tracking identities remain unchanged. Use the deeper child ID after an approved -further split, and preserve the label through restacks and corrections. A title or -PR number does not replace the execution-ledger identity. This does not rename -historical commits. - -### Milestone stacks and merge boundary - -Deliver one connected PR stack per milestone. Review and approve its child PRs -serially as described above, retaining the stack until the milestone is complete. -Before merging, require current approval and required checks for every final PR -head, the parent milestone's full acceptance and integration checks, and relevant -integration with completed milestones. Reconcile approval/check evidence after -any correction or restack. Safe intermediate behavior remains mandatory. - -Present the verified milestone stack for operator-authorized merge, bottom-up. -Do not merge automatically. Verify the resulting main-branch state before basing -the next milestone on it; do not carry the previous milestone's unmerged stack -into the next one. A delivery request may stop with the approved stack ready for -the operator to merge. Merging is separate from publishing authentication support: -all eleven milestones and the combined publication gate remain required. No -milestone merge authorizes a package release, deployment or live-account operation. - -Use existing towncrier release surfaces: `server/news/` for core/native-client -integration behavior, `plugins/imap/news/` or `plugins/smtp/news/` for changed plugin -contracts, and `meta/arbiter-suite/news/` only for bundle dependency changes. -Current release tooling associates the native client with the server release -surface; do not invent an unconfigured `client/news/` directory. Internal planning -documents themselves do not need a user-facing release fragment. - -All intermediate revisions are development work, not publishable authentication -support. Use isolated synthetic servers/accounts/state for prefix integration. -Do not add an anonymous compatibility mode, bypass switch, dummy production -identity, second policy layer or temporary protocol that must later be removed. -Product activation of the complete upgrade requires all eleven slices and the -combined gate below. Existing public API exposure is not declared fixed merely -because setup/enrollment exists. Once ordinary native authentication is cut over -in slice 3, anonymous legacy operation/artifact paths stay closed; an incomplete -artifact path must fail safely rather than emit an ownerless/plaintext substitute. -Missing authority state fails closed and directs the operator to trusted setup. - -## Ordered milestone queue - -Dependencies below are direct semantic prerequisites. Serial delivery additionally -requires the preceding PR to finish its review cycle. Final integration covers -cross-milestone interactions, not just each milestone in isolation. The historical -milestone-2 parent order was 2.1–2.5, 2.7, 2.8, 2.6, 2.9. Proposed next work is -`2.10.1 -> 2.10.2 -> 2.10.3 -> 2.10.4`, then the exact displayed milestone-3 -LLD order: `3.1.1–3.1.4`, `3.2.1–3.2.2`, `3.3`, `3.4`, `3.6.1–3.6.2`, -`3.5.1–3.5.2`, `3.7`. Existing parents retain their aggregate obligations. The explicit -child dependencies below are technical prerequisites; serial delivery also -requires the preceding child PR to finish its review cycle. An external dependency -on a milestone means all of that milestone's children, not just its first PR. - -| Slice | Observable result | Direct dependencies | Governing coverage | -| --- | --- | --- | --- | -| 1 | Operator initializes durable authority and uses authenticated local control. | None | R01–R06, R11–R12; HLD shared/B2/B3 | -| 2 | Owner pairs a real Go client with one secret handoff and durable single activation. | 1 | R04–R09, R10–R12; HLD B1/B2/B3 | -| 3 | Enrolled clients discover/invoke only granted accounts; live removal stops affected delivery. | 1, 2 | R10–R14; HLD shared/B2/B3 | -| 4 | Due client keys rotate, reconcile lost replies and complete safely after grace/expiry. | 1, 2, 3 | R15–R17; HLD B2/B3 | -| 5 | Owner repairs client identity/access without losing grants or clearing denials. | 1, 2, 3, 4 | R04–R06, R16–R17; HLD B2 | -| 6 | Planned or independently authorized server-key replacement preserves durable trust. | 1, 2, 4, 5 | R06, R10, R17; HLD B2/B3 | -| 7 | Server retains and delivers encrypted creator-bound artifacts with existing quotas. | 1, 2, 3 | R14, R18, R20; HLD B4 | -| 8 | Client offers all four artifact processing modes with honest verification/cleanup behavior. | 3, 4, 7 | R18–R20; HLD B4 | -| 9 | External local/SSH jobs obtain coherent, signed encrypted application backups. | 1, 3, 4, 5, 6, 7 | R21–R22; HLD B5 | -| 10 | Operator restores offline and can undo the latest restore, including after use. | 4, 5, 6, 9 | R23–R24; HLD B5 | -| 11 | Operator migrates paired clients during maintenance with verified URL handoff. | 3, 4, 6, 9, 10 | R10, R14, R17, R25; HLD B5 | - -## PR sizing and estimation basis - -The original 2026-10-20 breakdown contained **60 planned PRs**; the earlier -30–45 conversation estimate was preliminary. Both are historical, not the -current remaining queue. Only `2.10` and milestone 3 have newly sized LLDs here: - -| Proposed work | Cuts | Production | Tests/fixtures | Handwritten CI | Total | -| --- | ---: | ---: | ---: | ---: | ---: | -| `2.10` portable reuse | 4 | 850–1,220 | 1,300–1,770 | 0–25 | 2,150–3,015 | -| `3` native API/grants/denial | 13 | 2,350–3,360 | 4,440–5,980 | 0–70 | 6,790–9,410 | - -These are engineering estimates for review and later authorization, not approved -delivery allowances or guaranteed future diffs. Each full cut includes code -motion, helpers, fixtures, negative/race/native composition tests and correction -headroom. Shared harness code is charged once. The LLDs own the per-cut tables; -the plan does not maintain a second detailed sizing copy. - -Target **about 600 changed handwritten code lines** per PR. The **hard maximum is -1,000**, counting additions plus deletions in production code, tests and handwritten -fixtures across Python and Go combined. This is not 1,000 per language or per -category. Count moved/reformatted code too; avoid incidental cleanup. Do not drop -negative tests, move a PR's tests into a later PR, compress code, label handwritten -fixtures generated or weaken a boundary to fit. Estimate and report documentation, -generated fixtures/code, lockfiles and tooling output separately in the PR; they -still contribute review burden. Do not introduce new generation tooling merely to -avoid the limit. A large mechanical change should be a separate coherent PR. - -The target is flexible; the maximum is not. Before coding each child, check its -source-based forecast against predecessor changes. Do not begin an overlarge or -underspecified cut expecting to split it later. If actual evidence invalidates -the cut, stop expansion and return to the design boundary before submission. -A rare changed split needs focused review -and updated dependency/acceptance mapping; changes to the stamped plan require -DBB/SWE re-review and replacement stamp before treating that revision as approved. -No additional owner interview is required for a mechanical split that preserves -approved requirements, HLD, size policy and acceptance. - -Historical ranges below estimate handwritten churn, including assertions/helpers and fixture -construction. Production and test ranges are separate; the total is their sum. -They are task-by-task engineering estimates, not statistical confidence intervals -or a guarantee that the implementation will stay within the forecast. `Medium` -means there is a close existing implementation to extend. `Low` means new protocol, -durable state, platform custody or fault behavior dominates. No high-confidence -estimate is claimed. Exact files/modules follow implementation style, not a promise -to create one file for each PR. Existing code/tests are reused rather than copied; -only new/changed lines count. Shared harness work is charged to the first child -that uses it, and later children budget their own scenario additions. - -Historical inspection basis for the original forecast (2026-10-20, -checkout `9d5cfc198bb4`): - -| Existing surface | Measured lines | Consequence for estimates | -| --- | ---: | --- | -| `server/src/arbiter_server/artifacts.py` / `server/tests/unit/test_artifacts.py` | 570 / 810 | Extend the real store and tests; encryption, quota and access cutovers need separate boundaries. | -| `server/src/arbiter_server/http_work.py` / `server/tests/unit/test_artifact_http_admission.py` | 170 / 497 | Reuse bounded streaming owners and real contention barriers; do not budget cancellation as a few happy-path assertions. | -| `server/src/arbiter_server/blocking.py` / `server/tests/unit/test_blocking_pool.py` | 93 / 138 | Preserve the existing worker pool; add authority coordination rather than replace it. | -| `client/go-cli/internal/arbiterhttp/client.go` / `client/go-cli/internal/arbiterhttp/client_test.go` | 212 / 251 | Preserve API construction/error shape while changing the carrier. | -| `client/go-cli/internal/arbiterhttp/timeouts.go` / `client/go-cli/internal/arbiterhttp/timeouts_test.go` | 306 / 368 | Reuse budgets; extend real socket coverage at transport cutover. | -| `client/go-cli/internal/cli/cli.go` / `client/go-cli/internal/cli/artifact_commands_test.go` | 2,306 / 869 | Change relevant command paths; avoid an unrelated whole-file rewrite. | -| `server/tests/unit/test_native_http_protocol.py` / `server/tests/integration/test_cli_entrypoint.py` | 1,394 / 1,245 | Reuse synthetic ASGI and installed Go-wheel fixtures; charge new authenticated/process scenarios separately. | -| `server/src/arbiter_server/storage.py` / `server/src/arbiter_server/config.py` | 57 / 376 | Private generation/authority/ACL recovery is mostly new work, not an existing backup subsystem. | - -Read-through of these paths and the retained HLD probes informed the original -estimates. The two new LLDs use actual merged `25a8cf2` primitives and their named -missing work; old source-line counts above are not measurements of that baseline. -Probe code is not assumed production-ready or copied wholesale. No product code -or product tests were created/run by this design revision. Future streaming, -race/crash and installed-native acceptance remains implementation work, not proof -supplied by design checks or the existing baseline's green CI. - -The per-child tables define scope, a focused minimum acceptance check, code ranges, -confidence and direct dependencies. Every child also owns relevant tests from the -shared contracts and its parent milestone: a parent acceptance requirement is not -postponed until its final closure PR when the behavior already exists. Closure PRs -exercise composition, native builds and additional process-level failure cases; -they are not permission to submit earlier untested behavior. Any new runtime -setting/format is documented and tested where first consumed. Each child includes -its applicable package fragment and command/operator guidance; final documentation -passes only reconcile the complete journey. Documentation effort is not included -in the handwritten-code totals, and must be called out before each PR starts. - -### Historical estimate summary (2026-10-20) - -The following table preserves the original 60-PR forecast for comparison. It is -not a statement that those cuts remain unstarted, an actual delivered-LOC count, -or a newly reviewed forecast for the remaining milestones. In particular, the -old rows for 2 and 3 are superseded for future work by the status and LLDs above. - -| Milestone | Planned PRs | Production churn | Test churn | Combined churn | -| --- | ---: | ---: | ---: | ---: | -| 1 | 6 | 1,340–2,240 | 1,520–2,630 | 2,860–4,870 | -| 2 | 9 | 2,160–3,490 | 2,600–4,380 | 4,760–7,870 | -| 3 | 7 | 1,400–2,410 | 1,950–3,430 | 3,350–5,840 | -| 4 | 5 | 960–1,640 | 1,420–2,440 | 2,380–4,080 | -| 5 | 5 | 960–1,650 | 1,320–2,280 | 2,280–3,930 | -| 6 | 4 | 840–1,430 | 1,080–1,880 | 1,920–3,310 | -| 7 | 6 | 1,160–2,000 | 1,680–2,920 | 2,840–4,920 | -| 8 | 5 | 810–1,430 | 1,300–2,290 | 2,110–3,720 | -| 9 | 5 | 990–1,700 | 1,420–2,450 | 2,410–4,150 | -| 10 | 5 | 920–1,580 | 1,460–2,520 | 2,380–4,100 | -| 11 | 3 | 480–860 | 860–1,500 | 1,340–2,360 | -| **Total** | **60** | **12,020–20,430** | **16,610–28,720** | **28,630–49,150** | - -These totals sum estimated PR churn, including edits to previously introduced code; -they are not final repository size or time estimates. Existing fixtures are reused. -Generated/binary fixtures, dependency locks and documentation have no credible -line forecast yet: quantify them at each child kickoff and separate them in the -review summary. Their absence here is uncertainty, not zero work. No fixed delivery -date or throughput promise follows from these ranges. - -## Shared implementation contracts - -### Code ownership and schemas - -Add cohesive server identity/authority/transport/control modules beneath -`server/src/arbiter_server/`; add Go identity/state/carrier code beneath -`client/go-cli/internal/`. The exact module decomposition follows existing code -style; do not create a plugin/provider framework. `main.py` remains the ASGI -composition point, with immutable verified caller context and shared admission. -Existing `http_work.py`, `blocking.py`, artifact storage and account policies keep -their behavior except for the expressly planned identity/encryption checks. - -Each slice commits its versioned schemas and shared positive/negative Python/Go -fixtures with the implementation that consumes them. Put synthetic protocol -fixtures in a clearly test-only shared location; fixed test keys never initialize -product trust. Schemas reject duplicate identities/JSON fields, unknown critical -fields, invalid lengths/encodings and trailing input. Sign/verify exact bytes; -ES256 is fixed-width `R || S`, not an ASN.1 signature or a reserialized payload. -No unspecified schema field may silently grant authority or select an algorithm. - -Slice 1 fixes X.509/SAN URI/purpose/key-usage profiles, role trust stores, key-file -and recovery-file formats, authority row/revision semantics, and certificate -validity/renewal schedule specifications. Slice 5 owns owner-issuer and portable -certificate renewal; slice 6 owns server-authority and inner server-leaf renewal, -including trust-expiry recovery. Routine certificate renewal preserves the -appropriate key and durable IDs; it is not periodic server identity-key replacement. -Slice 2 fixes -Noise prologue/transcript/messages, pending/receipt state and inner-carrier ALPN. -Slice 4 fixes rotation/control proofs and acceptance state. Slice 5 fixes owner -recovery JWS and fresh challenge consumption. Slice 6 fixes server transition -proofs/history. Slice 7 fixes the authenticated artifact descriptor/age profile. -Slice 9 fixes backup records/manifest/signature and coherent snapshot semantics. -Slice 10 fixes durable active/undo publication and offline lock behavior. -Fixtures are reviewable parts of those PRs, not later unspecified integration work. - -### Dependencies, platforms and defaults - -Keep Python 3.10–3.14 and Go 1.24 as current compatibility floors; preserve the -existing Linux/macOS/Windows x64/arm64 CI matrix. Before adding each dependency, -select an exact tested compatible version set, review advisories/reachable uses, -record wheel/source-build needs and run its affected native matrix. The fourteen -Linux HLD probes are evidence of feasibility, not production dependency approval. -In particular, do not install pyOpenSSL26.3/cryptography49 under the current -`cryptography<49` constraint; evaluate a supported compatible set. Age's Rust -binding and the older Python Noise wrapper require explicit packaging/boundary -tests. Source builds may need build tools but must not create a separately -operated runtime service. Failure blocks the affected slice/release; changing -supported platforms or the HLD mechanism requires alignment, not silent narrowing. - -Use structured named config fields owned by their domain. Carry HLD defaults -unchanged: 16 total carriers, 4 handshakes, 10-second handshake/control budgets, -256 KiB buffers and total handshake bytes per direction, 32 KiB headers/cert -chain, 64 KiB controls/WebSocket messages, no compression, five-minute idle with -active-operation exceptions, four client transfers and one administrative job. -Retain the Noise wire/plaintext limits, twenty pending requests, five authenticated -attempts, ten-minute enrollment lifetime, 30-day rotation, 24-hour fixed grace, -180-day inactivity and 365-day access certificates. Do not turn U53 into a -64-carrier default. Preserve existing worker/body/artifact limits and separate -connect/API/download-idle semantics. Validate types/ranges and expose effective -nonsecret settings through authenticated diagnostics. - -For every public input, enforce aggregate byte/work limits before expensive -decode/crypto or allocation, including fragmentation, age headers, certificate -chains and backup manifests. Library convenience APIs are not admission control. -Reject overload without an unbounded queue; retain ownership until actual cleanup. - -### Test layers and review evidence - -Each PR has focused server/Go unit tests and a real Python-server/Go-client -prefix integration test for its behavior. Include real loopback sockets, a test -TLS-terminating WebSocket relay, restartable temporary directories and deterministic -clock/fault barriers. Isolated mock upstream SMTP/IMAP services supply fixtures; -no personal accounts or external mail effects. Library fixtures alone do not -prove application authorization, resource ownership or crash consistency. - -Run relevant regressions, repository lint/type checks and required CI checks for -that PR. Commands include repo-local pytest targets, `.venv/bin/nox -s lint` -(Black uses one worker), and `go test ./...`/`go vet ./...` in `client/go-cli`. -Use existing supported test runners instead of bypassing their setup. The final -combined gate runs the full Python suite, server/Go integration and complete -supported matrix. Unavailable checks remain unverified and block relevant claims. - -Before each PR is treated as complete, review its final code locally, resolve -findings, run its checks, checkpoint, submit and finish its remote PR review -cycle. Use actual DBB for security-sensitive changes with exact reviewed revision -evidence; if the optional reviewer workflow feature is unavailable, keep explicit -DBB orchestration. Changes after approval need appropriate re-review. No silent -reviewer substitution. This plan does not authorize automatic merging/deployment. - -## Slice 1 — operator authority and local control - -Historical note: the original child table in this section records the design cuts, not an unstarted queue. Authority/setup/local-control implementation is already merged at the source baseline above. - - -Deliver a complete operator setup/status journey: create durable owner/server IDs, -issuer and role-separated keys, external operator recovery file/public trust and -private SQLite authority state; inspect/manage it through authenticated Unix -socket or Windows named-pipe control. Recovery material stays outside running -server/agent/job storage. Status reports setup state without printing private keys. -An ordinary loopback connection cannot administer the instance. Initialize only -through trusted OS/SSH tooling; repeat setup cannot overwrite existing authority. - -Scope includes OS ownership/ACL validation, private atomic file publication, -single-writer instance lock, exact credential profiles and shared Python/Go profile -fixtures. Keys/profile functions are exercised by real initialization and local -control, not a standalone abstraction PR. Register owner public trust before use. -Agent `NEVER SHARE THIS` custody and recovery-file combined powers are documented. - -Acceptance: restart preserves IDs/trust; injected file/DB failures leave either -complete setup or safely recoverable unpublished staging; concurrent init/start -cannot create two writers. Wrong OS user, permissive ACL, unregistered owner, -wrong EKU/issuer/role/SAN, duplicate IDs and generic valid certs fail. Owner/recovery -private material never appears in server state, logs, argv, env or ordinary APIs. -Test native POSIX and Windows control boundaries. Add setup/trust documentation, -operator command help and an `arbiter-server` news fragment. - -### Child PRs - -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `1.1` — Private authority initialization | Create UUID-backed owner/server records and versioned SQLite authority schema through stopped-instance init/status; reject a second initialization. **Check:** Reopen preserves IDs; concurrent init and partial DB writes cannot publish two instances. | 200–340 | 220–380 | 420–720 | Medium | None | -| `1.2` — Role-separated credential profiles | Issue and validate setup credentials with explicit SAN/EKU/issuer profiles, exact certificate bounds and validity/renewal schedules. Publish shared profile fixtures consumed by Python now and Go in 2.1. **Check:** Reject cross-role, duplicate SAN, unregistered issuer, malformed DER and wrong key usage; verify profile time boundaries. | 260–420 | 280–450 | 540–870 | Low | 1.1 | -| `1.3` — External operator recovery file | Extend initialization with external recovery signer/decryptor, backup public configuration and registered public trust; keep private recovery material out of server state. **Check:** No overwrite or secret leakage; interrupted publication never reports successful setup with missing recovery trust. | 200–330 | 230–400 | 430–730 | Low | 1.2 | -| `1.4` — Durable application-state publication | Put initialized authority in a private generation with a durable active selector, instance lock and restart reconciliation; validate native ownership and ACLs. **Check:** Faults around flush/reference changes leave one coherent active state; Windows/POSIX locking prevents concurrent start. | 260–420 | 300–500 | 560–920 | Low | 1.3 | -| `1.5` — POSIX authenticated local control | Serve setup/status and bounded administrative messages over a private Unix socket; verify peer credentials and keep live DB writes server-owned. **Check:** Wrong UID, path replacement, oversized input and disconnect fail without loopback authority or leaked slots. | 190–330 | 230–400 | 420–730 | Medium | 1.4 | -| `1.6` — Windows authenticated local control | Provide the same real setup/status journey via named-pipe ACL and caller-token checks, with platform selection and trusted SSH instructions. **Check:** Native unauthorized caller, permissive ACL and pipe replacement fail; installed local commands work on both OS families. | 230–400 | 260–500 | 490–900 | Low | 1.5 | - -## Slice 2 — pairing a real client and reconciling activation - -Historical note: the original child table below retains parent identities and initial forecasts. The delivered stack used reviewed descendant cuts and is merged; existing-portable reuse remains the explicit `2.10` gap below. - - -Deliver `enrol` from a real Go CLI against a real initialized Python server: -generate provisional per-server/portable/recipient keys and 32-byte secret; closed -server explains opening; trusted operator opens a bounded window, lists/selects -request, supplies protected PSK and approves exact keys/grants once. Existing -portable identity requires registered issuer/fresh possession but no automatic -access. Client receives prepared trust/certs directly and durably saves before -ready proof; one authority transaction activates and returns its recorded receipt. - -Implement production Noise framing and bounded WebSocket adapter together with -the minimal inner server-authenticated TLS receipt/status control required to -recover committed activation without PSK. Python/Go fixtures exercise exact -transcript/key/role/request bindings. This slice includes the real encrypted -transport dependency and platform checks; it does not defer a lost-reply path to -an unspecified future carrier. Ordinary operation dispatch is slice 3. - -Acceptance: one secret handoff/approval, no return bundle or extra fingerprint -step; anonymous/wrong-PSK traffic cannot spend five attempts; identical authenticated -replays share one owner; five distinct failed/abandoned exchanges exhaust without -reset. Enforce original ten-minute deadline and twenty pending records across -reconnect/open/approval races. Fault/crash tests before ready, after client flush, -before/after commit and after lost reply prove one durable identity/grant/result. -Restart invalidates uncommitted PSKs only; denial beats stale completion. Abandoned -client/server state cleans within bounds. Add enrollment/recovery diagnostics, -custody guidance and fragments for server and native client packaging as applicable. - -### Child PRs -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `2.1` — Client provisional identity custody | Add real enrol key generation, private atomic client state and closed-server diagnostics; Go consumes 1.2 profile fixtures. **Check:** Restart, failed save and bad permissions leave recoverable provisional state; keys/PSK never reach argv, env or logs. | 240–380 | 260–430 | 500–810 | Low | 1.6 | -| `2.2` — Pending requests and operator approval | Add bounded public request registration and local open/list/approve/reject; bind immutable proposed keys/grants, protected PSK input and original deadlines. **Check:** Closed enrollment cannot open remotely; twenty pending entries include approved work; reopen/expiry races never reset deadlines. | 240–400 | 280–460 | 520–860 | Low | 2.1 | -| `2.3` — Bounded Python pairing responder | Wire binary WebSocket framing and Noise responder into approved pending requests with carrier/crypto reservations and authenticated first-flight accounting. **Check:** Anonymous failures spend no attempts; authenticated duplicates share one owner; five distinct attempts, byte limits and cancellation retain correct ownership. | 300–450 | 300–500 | 600–950 | Low | 2.2 | -| `2.4` — Go pairing initiator and transcript proof | Connect the real enrol command through the bounded WebSocket/Noise adapter; prove proposed keys and exact role/request transcript to the Python responder. **Check:** Wrong PSK/prologue/selector/key or fragmented oversized input cannot advance; a real Python/Go exchange verifies both peers. | 260–420 | 280–470 | 540–890 | Low | 2.3 | -| `2.5` — Prepared enrollment and durable client ready | Issue the owner-approved prepared result, verify it at the client and flush complete keys/trust/result before emitting ready proof. **Check:** Tampered prepared data, wrong issuer/IDs and save failures prevent ready; prepared certificates alone cannot authorize ordinary work. | 260–430 | 300–500 | 560–930 | Low | 2.4 | -| `2.7` — Server-authenticated inner TLS carrier | Implement bounded Python memory-BIO and Go TLS-over-WebSocket streams for fixed receipt control; verify remembered server and exporter, with no ASGI dispatch. No live activation is reachable yet; activated state exists only in synthetic test fixtures. **Check:** Wrong server/ALPN, overrun, blocked writes and cancellation fail; dedicated outer TLS exception leaks no inherited credentials or redirects. | 300–450 | 300–500 | 600–950 | Low | 2.5 | -| `2.8` — Authenticated receipt reconciliation | Implement exact-result receipt control and client reconciliation against synthetic already-activated fixture rows; no product activation route exists until 2.6. **Check:** Test lost reply, restart, wrong key, replay and denial using exact stored results without PSK; synthetic fixtures cannot become product trust or create another activation. | 200–340 | 260–450 | 460–790 | Low | 2.7 | -| `2.6` — Single activation and receipt | With 2.7/2.8 present, wire the first reachable ready/activation commit: conditionally persist identity, credential, grants and result; promote only from authenticated receipt/retrieval. **Check:** Real Python/Go crash/lost-reply/restart at ready/commit/receipt proves one durable result, authenticated promotion and denial precedence; retries create no second identity or grant. | 280–440 | 320–520 | 600–960 | Low | 2.8 | -| `2.9` — Pairing installation and overload closure | Complete prefix packaging/platform checks and process-level pairing failures, reusing earlier fixtures rather than deferring core assertions here. **Check:** Installed CLI pairs/reconciles; dependency builds, proxy fragmentation and simultaneous expiry/shutdown release real owners and keep health responsive. | 80–180 | 300–550 | 380–730 | Low | 2.6 | - -### Proposed corrective parent `2.10` — existing portable identity enrollment - -The [portable enrollment LLD](portable-enrollment-lld.md) owns the exact source -selection, independently registered issuer, v2 schema, custody/proof, unique -agent binding, migration and receipt contract. Its P01–P10 acceptance and four -complete implementation cuts are normative for this proposed correction: -`2.10.1 -> 2.10.2 -> 2.10.3 -> 2.10.4`, then `3.1.1`. -The first schema/backfill cut also installs binding maintenance in every fresh-v1 -activation transaction; intermediate enrollments cannot evade later uniqueness or -denial. P05/P09 cover active/denied/inactive records created on both intermediate -prefixes. Each cut has its own real consumer and failure tests; `2.10.4` adds -installed fresh/reuse closure to the existing driver. The total is 2,150–3,015 handwritten -production/test/CI lines with all per-cut upper bounds below 1,000. This is no -reset of the exhausted milestone-2 allowance and no implementation authorization. -Existing-enrollment repair stays in milestone 5 and does not substitute for P01. - -## Execution inventory for the portable correction - -This inventory records only the already reviewed `2.10.1–2.10.4` cuts. -The retained `2` and `2.10` entries are aggregate planning parents, not -unstarted replacements for merged work. Original `2.1–2.9` delivery IDs, -findings, approvals and spent counters remain in their immutable history; -they are not re-admitted by this inventory. The two `replaced` states below -mean that executable responsibility is assigned to the four children, not that -completed deliveries were removed. Milestones 3–11 are not selected or admitted. - -The full canonical ID in each inventory title is the exact prefix required by -the current typed-delivery tools for these new cuts. Historical short display -labels stay unchanged. Paths bind the reviewed implementation ownership; a -necessary change outside them returns to reviewed inventory preparation. The -portable LLD remains the authority for behavior, acceptance and estimates. - -```swe-slice-inventory -{ - "schema_version": 1, - "slices": [ - { - "id": "arbiter-authentication/2", - "parent": null, - "state": "replaced", - "role": "implementation", - "intent": { - "title": "[arbiter-authentication/2] Pairing and durable enrollment", - "responsibility": "Retain the original milestone-2 aggregate acceptance and immutable merged 2.1-2.9 delivery history; only its unimplemented 2.10 correction is admitted here.", - "paths": [ - ".github/workflows/ci.yml", - "client/go-cli/internal/cli/enrollment.go", - "client/go-cli/internal/cli/enrollment_test.go", - "client/go-cli/internal/identity/enrollment.go", - "client/go-cli/internal/identity/enrollment_receipt.go", - "client/go-cli/internal/identity/enrollment_receipt_test.go", - "client/go-cli/internal/identity/enrollment_test.go", - "client/go-cli/internal/identity/pairing_peer_test.go", - "client/go-cli/internal/identity/portable.go", - "client/go-cli/internal/identity/portable_test.go", - "client/go-cli/internal/identity/prepared.go", - "client/go-cli/internal/identity/prepared_test.go", - "client/go-cli/internal/identity/provisional.go", - "client/go-cli/internal/identity/provisional_store.go", - "client/go-cli/internal/identity/provisional_test.go", - "client/go-cli/internal/identity/registration_peer_test.go", - "docs/enrollment.md", - "server/news/+portable-enrollment-activation.feature.md", - "server/news/+portable-enrollment.feature.md", - "server/news/+portable-identity-codecs.feature.md", - "server/news/+portable-issuer-controls.feature.md", - "server/src/arbiter_server/authority.py", - "server/src/arbiter_server/enrollment.py", - "server/src/arbiter_server/enrollment_activation.py", - "server/src/arbiter_server/generations.py", - "server/src/arbiter_server/issuer_admin.py", - "server/src/arbiter_server/local_control.py", - "server/src/arbiter_server/main.py", - "server/src/arbiter_server/owner_issuers.py", - "server/src/arbiter_server/prepared.py", - "server/tests/integration/enrollment_terminal_driver.py", - "server/tests/integration/test_enrollment_cli_peer.py", - "server/tests/integration/test_enrollment_receipt_peer.py", - "server/tests/integration/test_installed_enrollment.py", - "server/tests/integration/test_provisional_peer.py", - "server/tests/unit/test_authority.py", - "server/tests/unit/test_enrollment_activation.py", - "server/tests/unit/test_enrollment_requests.py", - "server/tests/unit/test_local_control.py", - "server/tests/unit/test_main.py", - "server/tests/unit/test_owner_issuers.py", - "server/tests/unit/test_prepared.py", - "server/tests/unit/test_windows_control.py" - ], - "dependencies": [], - "acceptance": [ - "Preserve merged fresh pairing and receipt behavior; ordinary milestone-3 API remains unchanged." - ] - } - }, - { - "id": "arbiter-authentication/2.10", - "parent": "arbiter-authentication/2", - "state": "replaced", - "role": "implementation", - "intent": { - "title": "[arbiter-authentication/2.10] Existing portable identity enrollment", - "responsibility": "Close only portable LLD P01-P10 through the four already reviewed cuts; preserve original 22 spent attempts and all historical delivery identities.", - "paths": [ - ".github/workflows/ci.yml", - "client/go-cli/internal/cli/enrollment.go", - "client/go-cli/internal/cli/enrollment_test.go", - "client/go-cli/internal/identity/enrollment.go", - "client/go-cli/internal/identity/enrollment_receipt.go", - "client/go-cli/internal/identity/enrollment_receipt_test.go", - "client/go-cli/internal/identity/enrollment_test.go", - "client/go-cli/internal/identity/pairing_peer_test.go", - "client/go-cli/internal/identity/portable.go", - "client/go-cli/internal/identity/portable_test.go", - "client/go-cli/internal/identity/prepared.go", - "client/go-cli/internal/identity/prepared_test.go", - "client/go-cli/internal/identity/provisional.go", - "client/go-cli/internal/identity/provisional_store.go", - "client/go-cli/internal/identity/provisional_test.go", - "client/go-cli/internal/identity/registration_peer_test.go", - "docs/enrollment.md", - "server/news/+portable-enrollment-activation.feature.md", - "server/news/+portable-enrollment.feature.md", - "server/news/+portable-identity-codecs.feature.md", - "server/news/+portable-issuer-controls.feature.md", - "server/src/arbiter_server/authority.py", - "server/src/arbiter_server/enrollment.py", - "server/src/arbiter_server/enrollment_activation.py", - "server/src/arbiter_server/generations.py", - "server/src/arbiter_server/issuer_admin.py", - "server/src/arbiter_server/local_control.py", - "server/src/arbiter_server/main.py", - "server/src/arbiter_server/owner_issuers.py", - "server/src/arbiter_server/prepared.py", - "server/tests/integration/enrollment_terminal_driver.py", - "server/tests/integration/test_enrollment_cli_peer.py", - "server/tests/integration/test_enrollment_receipt_peer.py", - "server/tests/integration/test_installed_enrollment.py", - "server/tests/integration/test_provisional_peer.py", - "server/tests/unit/test_authority.py", - "server/tests/unit/test_enrollment_activation.py", - "server/tests/unit/test_enrollment_requests.py", - "server/tests/unit/test_local_control.py", - "server/tests/unit/test_main.py", - "server/tests/unit/test_owner_issuers.py", - "server/tests/unit/test_prepared.py", - "server/tests/unit/test_windows_control.py" - ], - "dependencies": [], - "acceptance": [ - "Real A/B/Go journey preserves agent ID/portable key/certificate and fresh independent B access/grants." - ] - } - }, - { - "id": "arbiter-authentication/2.10.1", - "parent": "arbiter-authentication/2.10", - "state": "planned", - "role": "implementation", - "intent": { - "title": "[arbiter-authentication/2.10.1] Local issuer trust and unique agent bindings", - "responsibility": "Implement the portable LLD first cut: OS-local issuer controls, exact certificate fingerprint trust, atomic schema/backfill and binding maintenance in every fresh-v1 activation/replay. Requires the merged 25a8cf2 fresh-enrollment baseline. No public reuse or milestone-3 work.", - "paths": [ - "server/src/arbiter_server/authority.py", - "server/src/arbiter_server/generations.py", - "server/src/arbiter_server/owner_issuers.py", - "server/src/arbiter_server/issuer_admin.py", - "server/src/arbiter_server/local_control.py", - "server/src/arbiter_server/main.py", - "server/src/arbiter_server/enrollment_activation.py", - "server/tests/unit/test_owner_issuers.py", - "server/tests/unit/test_authority.py", - "server/tests/unit/test_local_control.py", - "server/tests/unit/test_windows_control.py", - "server/tests/unit/test_main.py", - "server/tests/unit/test_enrollment_activation.py", - "server/news/+portable-issuer-controls.feature.md", - "docs/enrollment.md" - ], - "dependencies": [], - "acceptance": [ - "P02/P06/P09: exact issuer registration, removal/reactivation and revision; invalid profile rejected and local control remains OS authenticated.", - "Atomic migration preserves real old results/denial and rejects duplicate or malformed bindings.", - "Real post-upgrade fresh-v1 activation/replay/rollback maintains one agent/enrollment mapping, including later denied or inactive enrollments.", - "Retain 610-865 changed handwritten code/test/CI estimate and <=1000 hard cap." - ] - } - }, - { - "id": "arbiter-authentication/2.10.2", - "parent": "arbiter-authentication/2.10", - "state": "planned", - "role": "implementation", - "intent": { - "title": "[arbiter-authentication/2.10.2] Portable source custody and versioned codecs", - "responsibility": "Implement the portable LLD second cut: strict enrolled-source loading and v2 private/public codecs consumed by executable Python/Go peers; reuse the native publisher and shared decoder with purpose-specific checks. Public reuse remains unreachable.", - "paths": [ - "client/go-cli/internal/identity/provisional.go", - "client/go-cli/internal/identity/provisional_store.go", - "client/go-cli/internal/identity/prepared.go", - "client/go-cli/internal/identity/portable.go", - "client/go-cli/internal/identity/provisional_test.go", - "client/go-cli/internal/identity/prepared_test.go", - "client/go-cli/internal/identity/portable_test.go", - "client/go-cli/internal/identity/enrollment_receipt.go", - "client/go-cli/internal/identity/enrollment_receipt_test.go", - "server/src/arbiter_server/enrollment.py", - "server/tests/unit/test_enrollment_requests.py", - "server/tests/integration/test_provisional_peer.py", - "server/news/+portable-identity-codecs.feature.md", - "docs/enrollment.md", - "client/go-cli/internal/identity/pairing_peer_test.go", - "client/go-cli/internal/identity/registration_peer_test.go" - ], - "dependencies": [ - "arbiter-authentication/2.10.1" - ], - "acceptance": [ - "P03/P08: reject altered source ID/key/certificate/hash, unsafe custody and prepared-only source; source bytes stay unchanged.", - "Source loading accepts a currently valid portable identity without A online or an A access-lifetime requirement.", - "Preserve old v1 stored-record/result receipt decoding and its historical portable validation; never relax ordinary TLS or new-enrollment validity.", - "Retain 490-695 changed handwritten code/test/CI estimate and <=1000 hard cap." - ] - } - }, - { - "id": "arbiter-authentication/2.10.3", - "parent": "arbiter-authentication/2.10", - "state": "planned", - "role": "implementation", - "intent": { - "title": "[arbiter-authentication/2.10.3] Prepared reuse and single activation", - "responsibility": "Implement the portable LLD third cut through existing preparation/proofs and atomic activation, extending the same binding writer. Exercise real A/B/Go peers with fresh B access, explicit issuer trust/approval and exact receipt recovery. Public v2 remains closed.", - "paths": [ - "server/src/arbiter_server/prepared.py", - "server/src/arbiter_server/enrollment_activation.py", - "server/src/arbiter_server/enrollment.py", - "server/src/arbiter_server/owner_issuers.py", - "server/tests/unit/test_prepared.py", - "server/tests/unit/test_enrollment_activation.py", - "server/tests/integration/test_enrollment_cli_peer.py", - "server/tests/integration/test_enrollment_receipt_peer.py", - "client/go-cli/internal/identity/prepared.go", - "client/go-cli/internal/identity/prepared_test.go", - "client/go-cli/internal/identity/enrollment.go", - "client/go-cli/internal/identity/enrollment_test.go", - "client/go-cli/internal/identity/enrollment_receipt.go", - "client/go-cli/internal/identity/enrollment_receipt_test.go", - "server/news/+portable-enrollment-activation.feature.md", - "docs/enrollment.md", - "client/go-cli/internal/identity/pairing_peer_test.go", - "client/go-cli/internal/identity/registration_peer_test.go" - ], - "dependencies": [ - "arbiter-authentication/2.10.2" - ], - "acceptance": [ - "P01/P03/P05/P06/P07: preserve original agent/portable identity, generate independent B access/enrollment/recipient state; A may be offline.", - "Existing active/denied/inactive B binding rejects reuse, including real fresh-v1 enrollments created on both earlier upgraded prefixes.", - "Trust-revision removal/ready/commit races fail or reconcile once; lost final reply/restart/expiry returns the exact committed result.", - "Retain 550-745 changed handwritten code/test/CI estimate and <=1000 hard cap." - ] - } - }, - { - "id": "arbiter-authentication/2.10.4", - "parent": "arbiter-authentication/2.10", - "state": "planned", - "role": "implementation", - "intent": { - "title": "[arbiter-authentication/2.10.4] Public CLI reuse and installed acceptance", - "responsibility": "Implement the portable LLD fourth cut: explicit identity source selection, atomic v2-only public registration switch, installed A/B and fresh regression journeys, final migration/help/news and complete P01-P10 acceptance. Preserve all platforms and existing test harnesses.", - "paths": [ - "client/go-cli/internal/cli/enrollment.go", - "client/go-cli/internal/cli/enrollment_test.go", - "client/go-cli/internal/identity/provisional_session.go", - "client/go-cli/internal/identity/registration_peer_test.go", - "client/go-cli/internal/identity/enrollment.go", - "client/go-cli/internal/identity/enrollment_test.go", - "server/src/arbiter_server/main.py", - "server/src/arbiter_server/enrollment.py", - "server/tests/unit/test_enrollment_requests.py", - "server/tests/unit/test_enrollment_admin.py", - "server/tests/unit/test_main.py", - "server/tests/integration/enrollment_terminal_driver.py", - "server/tests/integration/test_installed_enrollment.py", - ".github/workflows/ci.yml", - "server/news/+portable-enrollment.feature.md", - "docs/enrollment.md" - ], - "dependencies": [ - "arbiter-authentication/2.10.3" - ], - "acceptance": [ - "P04/P08/P10 and all P01-P10: installed CLI completes fresh/reused enrollment and recovery on native CI; existing admission/time/attempt limits remain.", - "Reject identity plus resume, same-server reuse, unknown/invalid source and old public wire with actionable diagnostics and no saved identity deletion.", - "Confirm public server/client switch together, v1 saved receipt recovery survives, no live accounts and no milestone-3 API changes.", - "Retain 500-710 changed handwritten code/test/CI estimate and <=1000 hard cap." - ] - } - } - ] -} -``` - -## Slice 3 — native API, account grants and live denial - -Route every ordinary CLI discovery/schema/invocation/download constructor through -the expected-server-verified inner TLS 1.3 transport, including errors and tool -paths. Preserve API shape and existing policies after `(plugin, account)` grants. -Exercise the native factory through private peers in `3.5.1`; keep production -constructor selection on its working route until the atomic client/server switch -in `3.5.2`, with no anonymous fallback after that cut. -Reject anonymous/proxy-header callers and hide ungranted account information from -discovery and direct routes. Provide local grant add/remove and enrollment denial. -Creator/account caller context is mandatory for subsequent artifact work. - -Implement shared coordinator admission and output cancellation across connections; -ordinary TLS checks exact live enrollment/accepted key, certificate and role. -Use `agent_enrollments` as the sole agent-to-enrollment relation; live admission -must not create an independently authoritative `enrollments.agent_id` copy. -Remove anonymous legacy API/artifact routing in the same cutover, invalidate -server-managed ownerless artifacts without guessing ownership or touching mail/ -client files. No artifact storage fallback may bypass caller context. Keep -setup/health/bootstrap separate, and missing authority fails closed. - -Until slice 7 installs the encrypted store, slice 3 must replace the plugin-facing -artifact creation/inspection dependencies with an explicitly closed adapter. -Reject artifact creation before calling the legacy store or creating a payload -file; never delegate to it, return a usable descriptor or expose nonce-only access. -This is an implementation-readiness boundary, not a client policy/allowlist or -operator bypass flag. Errors report any already-completed upstream effect honestly -and never trigger automatic operation replay. Slice 7 replaces this closed adapter -with the encrypted creator-bound adapter through the same caller-context boundary. - -Acceptance: verified enrolled Go client invokes a granted synthetic operation; -portable/cross-server credentials cannot. Denial/grant removal wins races against -queued admission, request bodies, upstream dispatch and ongoing output; retained -blocking work keeps its slot until exit. Password renewal does not require grants; -repointed names keep deliberate grants. Test substituted server, changed outer -cert/proxy, malicious headers/redirects, byte/control limits, slow/chunked bodies -and unchanged timeout budgets; no native secret reaches the relay. Add account -grant/transport/proxy documentation, server/client fragments and skill guidance -where discovery/enrollment instructions change. - -The slice-3 prefix test must also invoke an artifact-producing operation through -the real authenticated Python/Go path before slice 7. Assert the closed adapter -rejects before legacy store entry/payload publication, no plaintext or ownerless -file/metadata/nonce/usable descriptor is created, no legacy route can read one, -and cancellation/repeated failure release bounded staging and worker ownership. -Use a legacy-store spy plus filesystem inspection, including restart cleanup; -the final no-publication gate alone is not this acceptance evidence. - -### Current proposed cuts and dependencies - -The [milestone-3 LLD](milestone-3-lld.md) owns exact N01–N12 acceptance, complete -per-cut scope and production/test/CI ranges. Its 13 cuts replace the historical -seven rows; do not add the two forecasts together. All work remains unimplemented. - -| Cut | Direct implementation prerequisite | Owning result / acceptance | -| --- | --- | --- | -| `3.1.1` | `2.10.4` | Shared carrier/pump with real existing-control and streaming consumers; N03/N04. | -| `3.1.2` | `3.1.1` | Strict Python ordinary mTLS peer; N01. | -| `3.1.3` | `3.1.2` | Go native identity/dial and standard HTTP transport peer; N01/N02/N11. | -| `3.1.4` | `3.1.3` | Bounded single-request HTTP/ASGI, absolute request-receipt timer and pre-body admission; N03/N04. | -| `3.2.1` | `3.1.4` | Existing enrollment-row live fields/grants and migration; first OS enrollment-deny control and minimal shared coordinator guard the real fixed receipt through final output/actual-owner cleanup; N05/N07 receipt races. | -| `3.2.2` | `3.2.1` | Extend the same coordinator, writer/read epochs and actual worker ownership to ordinary authority; OS grant add/remove controls; N04/N05/N06/N07. | -| `3.3` | `3.2.2` | Discovery/direct/policy/error filtering; N06. | -| `3.4` | `3.3` | Real dispatch caller context, closed artifact dependency/inline/legacy cleanup; N09. | -| `3.6.1` | `3.4` | Cross-connection body/dispatch denial and retained actual workers; N07/N08. | -| `3.6.2` | `3.6.1` | Final output permission after backpressure and abort without revoked flush; N03/N07/N08. | -| `3.5.1` | `3.6.2` | Every CLI constructor and explicit enrollment selection through private real peers; production selection retains its working route. N10/N11. | -| `3.5.2` | `3.5.1` | Atomic production CLI/native server switch, anonymous closure and first installed denial/artifact prefix; N01/N04/N07/N09/N10/N12. | -| `3.7` | `3.5.2` | Installed relay/timeouts/native composition and full N01–N12 closure. | - -All `3.1` descendants close parent 3.1, both `3.2` descendants close 3.2, both -`3.6` descendants close 3.6 before cutover, and both `3.5` descendants close 3.5. -Later references to a parent still require all its descendants and aggregate -acceptance. The first public ordinary prefix includes denial and safe artifact -failure; final 3.7 is not a budget for missing earlier mechanisms or tests. - -## Slice 4 — rotation, late completion and bounded fallback - -Milestones 4–11 below retain their approved scope/order and historical outlines. -Their child boundaries and estimates require source-based LLD refinement/review -before implementation. This design revision does not claim those future cuts -are already sized or predictive after milestone-2 implementation changes. - -Deliver on-contact due rotation, fixed grace, durable candidate save/confirmation -and lost-response reconciliation. A pending deadline is recorded before asking -for candidate; withholding/retry/old ordinary use cannot move it. Current, -predecessor and pending candidate form coherent client state. Use the separate -fixed control carrier to finish the exact rotation after grace or cert expiry; -ordinary mTLS stays strict. Control proofs bind both stored keys, fresh challenge, -TLS exporter, identities, purpose and pending revision. Reissue only that same -candidate certificate; no general expired-credential exception. - -Acceptance: test 30-day/24-hour/180-day boundaries, old/candidate expiration, -candidate-withholding, disconnect and restart at every save/commit/receipt point. -Ordinary access remains until grace, then only pending completion is possible; -incomplete controls cannot refresh inactivity. Revocation/owner repair wins every -activation race. Receipt survives needed expiry/reconciliation intervals. One -predecessor authentication attempt requires unambiguous authenticated rejection -by the same verified server; never after denial/timeout/unverified peer or operation -submission, and never replay uncertain mutation/GET. Test across both languages -with real controlled clocks/sockets and malicious control transcripts. Add lifecycle -configuration/help, repair guidance and server/client fragments. - -### Child PRs - -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `4.1` — Server pending rotation and fixed grace | Prepare a due transition on authenticated contact, bind one candidate and preserve current ordinary access until its original deadline. **Check:** Controlled 30-day/24-hour/180-day boundaries, withheld candidates and restart cannot slide grace or inactivity. | 220–360 | 260–450 | 480–810 | Low | 3.7 | -| `4.2` — Durable candidate confirmation | Save candidate state in Go, prove possession and conditionally activate/promote with one retained predecessor and idempotent result. **Check:** Crash/lost reply at save/activate/promote cannot install an unsaved key, clear denial or duplicate transition. | 240–400 | 300–500 | 540–900 | Low | 4.1 | -| `4.3` — Expired-key restricted completion | Add the fixed exporter-bound old-plus-candidate control and reissue only that pending candidate after grace/certificate expiry. **Check:** Ordinary TLS remains strict; wrong pending purpose/revision, replay, inactivity and denial cannot complete or refresh deadlines. | 260–420 | 300–520 | 560–940 | Low | 4.2 | -| `4.4` — Authenticated predecessor assistance | Return authenticated credential status and permit one authentication-only predecessor attempt after the same verified server rejects current credentials. **Check:** Never fallback after timeout, unverified peer, denial or submitted operation/consuming GET; superseding recovery discards history. | 160–280 | 240–420 | 400–700 | Low | 4.3 | -| `4.5` — Lifecycle race and clock closure | Exercise the implemented transitions through process restarts and competing denial/recovery, with final lifecycle diagnostics and retained-receipt cleanup. **Check:** Full Python/Go boundary matrix preserves unattended completion where permitted; incomplete exchanges cannot keep an inactive enrollment alive. | 80–180 | 320–550 | 400–730 | Low | 4.4 | - -## Slice 5 — owner-authorized client recovery - -Deliver trusted owner tooling to authorize a fresh per-server access key or -portable-key repair for an existing durable identity. Consume a server-specific, -fresh challenged ES256 authorization and replacement-key possession proof in one -conditional authority transaction. Signature supplies approval; no second remote -operator approval or grant recreation. Preserve suspensions/revocations. Local -pairing repair of the existing enrollment remains the simple alternative. - -Acceptance: two isolated servers register the same owner trust but distinct access -keys; owner tooling produces per-server proofs and repairs both without sharing -issuer private keys or trusting another server's credential. Portable possession -alone fails. Wrong algorithm/key/purpose/server/revision/expiry, replay, concurrent -recovery/rotation/denial and lost response fail or reconcile exactly once. Revoked -enrollment remains revoked after repair. Owner/recovery file stays outside agent -and server custody; missing proof offers explicit repair, not identity reset. -Add recovery-file theft consequences, CLI journey and server/client fragments. - -This slice also implements owner-issuer and portable-leaf certificate renewal -using slice 1's selected schedules, registered signer and live-state checks while -preserving owner/agent IDs and purpose separation. Controlled-clock tests cover -before-expiry renewal, signer/key mismatch, denial and renewal races, rejection -of portable credentials on ordinary TLS, restart and missed-renewal diagnostics. -Certificate renewal must not become an automatic access-key replacement or grant. - -### Child PRs - -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `5.1` — Owner-approved pairing repair | Extend local pairing for an existing enrollment with explicit owner selection while retaining durable identity, grants and denial. **Check:** New-client enrollment cannot silently select an existing identity; repair invalidates superseded pending/current credentials without regranting. | 180–300 | 240–420 | 420–720 | Low | 4.5 | -| `5.2` — External owner challenge proofs | Implement strict ES256 recovery statements, externally held signer tooling and fresh server-bound challenge with replacement possession proof. **Check:** Shared Python/Go fixtures reject wrong algorithm, purpose, signer, server, expiry, duplicate fields and changed signed bytes. | 220–370 | 280–480 | 500–850 | Low | 5.1 | -| `5.3` — Atomic access-key recovery | Consume the exact challenge and replace access state in one conditional live-authority transaction; reconcile lost response. **Check:** Recovery/rotation/denial races consume once; revoked state stays revoked; no second per-server approval or issuer private-key sharing. | 200–330 | 260–450 | 460–780 | Low | 5.2 | -| `5.4` — Portable identity repair across servers | Apply the owner-authorized portable replacement and orchestrate distinct per-server recovery proofs using the same external owner trust. **Check:** Two real isolated servers keep independent access keys and grants; portable possession alone cannot replace access or trust another server credential. | 180–320 | 280–480 | 460–800 | Low | 5.3 | -| `5.5` — Owner and portable certificate renewal | Implement authorized before-expiry owner-issuer/portable-leaf renewal under 1.2 schedules, keeping purpose and durable IDs. **Check:** Controlled time, wrong signer, denial, concurrent renewal and restart cannot grant native access or masquerade as access-key rotation. | 180–330 | 260–450 | 440–780 | Low | 5.4 | - -## Slice 6 — server identity replacement - -Deliver operator-triggered planned authority replacement with old endorsement, -new-key possession, stable server ID and durable client adoption/transition -history. Separately deliver compromise repair using the independently registered -external owner verifier, never compromised server key alone. URL/HTTPS renewal -does not trigger identity rotation. Private/public-key roles remain distinct. - -Acceptance: online and offline clients recognize legitimate replacement, including -lost transition response/restart and later key changes. Wrong ID, missing history, -expired/untrusted chain or endorsement by compromised key alone cannot install new -trust; missing independent authority gives explicit owner pairing guidance. Client -never sends credentials/capabilities before verifying the expected server or -authorized repair. Neither path clears enrollment denial or duplicates grants. -Test installed-client state and preserved history with real Python/Go peers. -Document planned versus compromised-key procedure and add server/client fragments. - -This slice separately implements server-authority and inner-server-leaf certificate -renewal under slice 1's validity/schedule profiles, without scheduled identity-key -rotation. Test authorized before-expiry renewal with stable server ID/key, -appropriate issuer/live-state checks and clients retaining remembered trust. -Controlled-clock negative tests reject peer-provided renewal of an expired server -trust anchor; missing the trust-validity deadline requires the independently -authorized owner recovery path (or explicit pairing when that trust is missing). -Test expiry/restart/renewal races and ensure HTTPS renewal/URL changes do not replace -native identity or silently extend authority. Keep these tests distinct from -access-key rotation and planned server-key replacement. - -### Child PRs - -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `6.1` — Planned server transition publication | Produce old endorsement plus new possession with stable server ID and durable transition history through operator tooling. **Check:** Wrong identity/key, incomplete publication and restart cannot install unsigned trust or lose the prior complete history. | 200–340 | 260–450 | 460–790 | Low | 5.5 | -| `6.2` — Client transition adoption | Fetch and verify legitimate transition chains, then durably adopt server trust for online and long-offline clients. **Check:** Missing/interleaved history, replay and failed save reject safely; credentials are withheld until destination identity is verified. | 200–340 | 260–450 | 460–790 | Low | 6.1 | -| `6.3` — Independent compromise recovery | Use registered external owner authorization for server-key compromise recovery and propagate explicit client repair diagnostics. **Check:** Stolen old server key alone cannot bless a replacement; owner proof cannot clear client denial, change server ID or duplicate grants. | 220–370 | 280–480 | 500–850 | Low | 6.2 | -| `6.4` — Server authority and leaf renewal | Renew server-authority and inner-server-leaf certificates before expiry without scheduled identity-key replacement; use independent owner recovery after missed trust validity. **Check:** Controlled clocks reject expired peer-driven trust renewal; stable IDs/keys, restart and renewal races work; outer HTTPS renewal changes no native trust. | 220–380 | 280–500 | 500–880 | Low | 6.3 | - -## Slice 7 — encrypted server artifacts and ownership - -Deliver server-side age encryption for the creator's registered recipient and -server storage recipient, authenticated origin descriptors and ciphertext delivery -through the native API. Thread immutable caller/account context into all plugin -artifact creation, including inline native descriptors; a plugin cannot choose -another creator. Keep server-readable inspection possible without adding scanning. -Recipient registration needs authenticated proof/new-key challenge and retained -key history is bounded by active artifact lifetime; auth rotation cannot discard -needed recipient keys. No persistent plaintext staging is introduced as a shortcut. - -Acceptance: creator plus nonce plus live enrollment/account grant is required for -metadata/HEAD/GET; shared account, copied URL or revoked grant fails. HEAD is -non-consuming; GET atomically consumes before open, including failed streams. -Test nonce/consume/revoke/store-lock races, slow writer/disconnect, restart, orphan -cleanup and quota reservations through actual cleanup. Preserve 50 MiB plaintext, -2,000 artifacts, 1 GiB physical, ten-minute idle and 24-hour maximum; count all -crypto/metadata/staging overhead without lowering plaintext cap. Mock IMAP/SMTP -flows exercise real artifact adapters. Legacy cleanup is idempotent and confined -to server-managed ownerless files. Add storage/ownership docs and affected server/ -plugin fragments; server encryption is not whole client-processing completion. - -### Child PRs - -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `7.1` — Artifact recipient registration and retention | Register fresh recipient possession through authenticated identity, persist bounded client/server recipient history and separate it from access-key rotation. **Check:** Wrong origin/key/version or unauthenticated change fails; keys needed by active artifacts survive access rotation until bounded expiry. | 220–370 | 260–450 | 480–820 | Low | 6.4, 3.6 | -| `7.2` — Encrypted payload and metadata writing | Add streaming age dual-recipient creation and encrypted descriptors behind the closed plugin adapter; preserve server inspection capability. **Check:** Python/Go fixtures prove both recipients, wrong-key/tamper/truncation failure and no persistent plaintext staging; disabled delivery cannot publish a usable nonce. | 240–400 | 280–480 | 520–880 | Low | 7.1 | -| `7.3` — Physical quota and encrypted-store recovery | Integrate ciphertext/metadata/staging reservations, 50 MiB plaintext and existing count/storage/retention limits, plus restart orphan cleanup. **Check:** Near-cap overhead, full disk, concurrent writers, cancellation and open readers hold reservation until actual cleanup; no cap is silently lowered. | 220–360 | 280–480 | 500–840 | Low | 7.2 | -| `7.4` — Creator-bound HEAD and consuming GET | Authorize descriptors/HEAD/GET by creator, account grant and nonce, with atomic consume-before-open and authenticated origin. **Check:** Shared account/copied URL/revocation fails; HEAD never consumes; failed/slow GET stays consumed across restart. | 220–370 | 300–500 | 520–870 | Low | 7.3 | -| `7.5` — Plugin adapter and descriptor activation | Replace the closed adapter with creator-bound encrypted creation for all artifact-producing and inline result paths, retaining legacy-route closure. **Check:** Real mock IMAP/SMTP and Python/Go dispatch cannot choose another creator or return a legacy descriptor; ownerless cleanup stays confined. | 180–320 | 260–460 | 440–780 | Low | 7.4 | -| `7.6` — Artifact contention and packaging closure | Complete real storage-lock/consume/revoke/stream races and age dependency/install checks on supported platforms. **Check:** Health stays responsive under valid/invalid nonces; disconnect/shutdown retain file/crypto owners until cleanup; no replay reopens GET. | 80–180 | 300–550 | 380–730 | Low | 7.5 | - -## Slice 8 — four client artifact paths - -Deliver immediate plaintext stdin, fully verified encrypted-temp-to-stdin, -explicit plaintext-temp pathname and deliberate `artifact save-decrypted`. -Authenticated descriptor and key remain private process state; downloaded metadata -cannot nominate origin. Verified modes finish digest/length/age finalization and -source checks before tool launch/publication. Keep stable ciphertext between -passes through proven platform handles or the HLD's bounded immutable snapshot. -Do not select a universal mode/default or preserve an ambiguous `save` alias. - -Acceptance: tamper, truncation, wrong origin/creator/recipient and changed staging -path cannot start a tool in verified modes. Immediate stdin may deliver valid -prefix, but reports final failure honestly. Test POSIX writable-alias removal, -Windows sharing/ACL constraints, fallback reservation, four-transfer saturation, -full disk, child failure, signals/cancellation and crash cleanup. No orphan file -resumes a consumed GET; plaintext temp/export require explicit action and no -partial final export. Access/recipient rotation and grant denial during download -compose with slices 3/4/7. Explain delay/storage/partial-effects/plaintext exposure -in both client reference and operation help, discourage persistent agent exports, -and add native-client fragments and affected skill updates. - -### Child PRs - -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `8.1` — Immediate authenticated plaintext stdin | Decrypt the one native GET directly to child stdin using the authenticated descriptor and bounded process ownership. **Check:** Final digest/EOF failure reports honestly after any valid prefix; no automatic retry, sensitive stdout or default plaintext file. | 180–320 | 260–450 | 440–770 | Medium | 7.6 | -| `8.2` — Verified encrypted-temp stdin | Reserve ciphertext staging, fully verify to a discard sink, then process exact immutable bytes via native handles or bounded memory fallback. **Check:** Path replacement/writable aliases, tamper/truncation and failed verification cannot start tools on POSIX or Windows; four transfers bound fallback memory. | 260–420 | 300–520 | 560–940 | Low | 8.1 | -| `8.3` — Explicit plaintext-temp path | Require explicit selection, privately stage and fully verify plaintext before tool launch, and clean up on exit/cancellation. **Check:** Bad origin, child failure, signals and path abuse cannot expose unverified files or publish a final artifact; document best-effort crash cleanup. | 150–260 | 220–400 | 370–660 | Medium | 8.2 | -| `8.4` — Deliberate save-decrypted export | Rename intentional persistent plaintext export without the ambiguous save alias; verify private staging before atomic final publication. **Check:** No partial output on full disk/tamper/cancellation; overwrite permissions and explicit user-facing warnings are tested. | 140–250 | 220–400 | 360–650 | Medium | 8.3 | -| `8.5` — Four-mode process and platform closure | Finish CLI/skill tradeoff guidance and real child-process, cleanup and rotation/revocation composition checks without adding a universal mode default. **Check:** Installed tools demonstrate all four paths; consumed GET cannot be resumed from an orphan; native platform process/handle limits are enforced. | 80–180 | 300–520 | 380–700 | Low | 8.4 | - -## Slice 9 — useful consistent encrypted export - -Deliver local/SSH export usable by an external startup/periodic job: capture one -saved config/policy/actual-secret/authority generation, briefly fence mutations, -take coherent SQLite snapshot, then stream signed manifest/records through age to -the registered external recipient. Capture configured secret-file values without -arbitrary environment dumps; changed source during capture aborts before publish. -Exclude the HLD omissions, especially sessions, PSKs, client private keys and -transient artifact payloads. Operator file/public metadata and encrypted bundle -are clearly distinct; server/job has no private recovery signer/decryptor. - -Acceptance: enroll/grant/revoke/rotate/config reload during export yields one -coherent snapshot. Secret-source changes, output failure/cancellation/disk full, -oversize/header/manifest abuse and crash preserve the previous complete export; -never expose partial final bundle or plaintext staging. One admin job at a time, -4 GiB total plaintext/10,000 entries/64 MiB per entry/1 MiB manifest and bounded -encrypted header/overhead parsing are enforced before growth. Verify exact signed -manifest/file digests using external trusted metadata in a round-trip harness, -not a signer supplied by the bundle. Include job examples for durable storage and -failure reporting without adding scheduler/cloud integration/first-enrollment -gate. Add backup CLI/docs and an arbiter-server fragment. - -### Child PRs - -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `9.1` — Saved configuration and real secret capture | Extend private generations to active config/policies and materialized configured file-backed secrets on activation/reload. **Check:** Changed-source capture aborts before publication; arbitrary environment/host files never enter saved state; normal reload remains coherent. | 240–400 | 280–480 | 520–880 | Low | 8.5, 1.4 | -| `9.2` — Coherent authority snapshot | Fence live mutations briefly and capture SQLite plus the exact saved config/key/secret generation, releasing the fence before encrypted streaming. **Check:** Concurrent enroll/grant/revoke/rotate/reload yields one coherent snapshot; failure/shutdown releases the real admin owner and preserves service state. | 200–340 | 280–470 | 480–810 | Low | 9.1 | -| `9.3` — Signed bounded recovery records | Write versioned uncompressed records and exact-byte ES256 manifest; provide strict verification primitives consumed by export self-checks and later restore. **Check:** Reject duplicate paths/fields, links, traversal, oversized entries/count/manifest and bundle-supplied verifier substitution in shared synthetic fixtures. | 250–420 | 300–520 | 550–940 | Low | 9.2 | -| `9.4` — Encrypted local and SSH export | Stream the coherent snapshot through age to external recipient with one admin job and safe publication of complete outputs. **Check:** Private recovery signer/decryptor never enters server/job/bundle; 4 GiB limit, disconnect/full disk and cancellation preserve last good bundle. | 220–360 | 280–480 | 500–840 | Low | 9.3 | -| `9.5` — External job and concurrent-export closure | Document startup/periodic external scheduling, durable destination/alerting and round-trip verifier usage; finish process-level snapshot contention tests. **Check:** Real local/verified-SSH jobs produce usable signed encrypted snapshots; excluded transient artifacts/PSKs/client keys remain absent across failures. | 80–180 | 280–500 | 360–680 | Low | 9.4 | - -## Slice 10 — offline restore and latest undo - -Deliver offline restore while the server is broken/stopped, using the external -operator file to decrypt/authenticate a complete bundle privately. Verify strict -records/manifest/origin/hashes/key correspondence/config before publishing a fresh -saved generation. Use exclusive stopped-instance lock and one durable transaction -for active/undo references; failed restore preserves current state and previous -undo point. Preserve saved deadlines, not restore-time authority extensions. - -Deliver offline undo of that latest successful restore, without expiry or a -post-use hard cutoff; explicit discard or next successful restore replaces it. -Warn very prominently about snapshot date, lost post-snapshot/post-restore local -changes, restored grants/revocations and upstream effects that cannot be undone. -No silent merge, restore wizard, redo history, paused-access mode or acceptance -ceremony. Ordinary different-host edits remain available before start. - -Acceptance: real process termination/fault injection before/after flush and each -reference update leaves an old or new coherent generation on native POSIX/Windows. -Reject malformed/duplicate/traversing/link/device/oversized records and wrong -external verifier; no partial activation. Restore to an empty host and over an -existing instance; test old snapshots, client current/predecessor divergence, -pairing repair, revocation preservation within the selected snapshot, repeated -restore failure, undo after use and explicit discard. Show clear repair diagnostics -without claiming to know unseen client history. Add full restore/undo examples, -host-configuration exclusions and arbiter-server fragment. - -### Child PRs - -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `10.1` — Strict offline bundle validation | Decrypt against external trust, validate all record/hash/EOF/certificate/key/config constraints before exposing a restorable generation. **Check:** Malformed/traversing/duplicate/oversized records, wrong verifier and incomplete stream fail with bounded I/O and no active-state changes. | 240–400 | 300–520 | 540–920 | Low | 9.5 | -| `10.2` — Stopped-instance private restore staging | Require exclusive stopped-instance lock, available-disk reservation and same-filesystem private staging; reconcile incomplete restore on restart. **Check:** Concurrent server start/restore, disk failure and real process termination preserve active generation and existing undo. | 200–340 | 280–480 | 480–820 | Low | 10.1 | -| `10.3` — Atomic full restore activation | Publish verified generation with active/undo references in one durable control transaction, retaining saved lifecycle timestamps and host exclusions. **Check:** Empty/existing hosts restore coherently; faults at flush/reference boundaries choose only old or new complete state, never merge or extend authority. | 220–360 | 300–520 | 520–880 | Low | 10.2 | -| `10.4` — Latest undo and explicit discard | Implement offline undo without expiry or post-use hard cutoff; retain the point through ordinary operation and warn prominently before discarding later changes. **Check:** Failed restore preserves undo; next successful restore replaces it; undo after use and discard have no redo/history or upstream rollback promise. | 180–300 | 260–450 | 440–750 | Low | 10.3 | -| `10.5` — Restore-client and native crash closure | Complete controlled process-crash and native durability tests, stale client/predecessor diagnostics and useful full restore/undo examples. **Check:** Multiple paired clients either recover within bounded fallback or require explicit repair; old snapshot denial/deadlines reflect snapshot, not guessed unseen history. | 80–180 | 320–550 | 400–730 | Low | 10.4 | - -## Slice 11 — cooperative migration and handoff - -Deliver maintenance/migration tooling and runbook: disable source ordinary work -and state-changing admin, drain/cancel real owners, export final snapshot, restore -stopped destination, edit host settings, start destination only and keep source -disabled. Optional source handoff is a fixed authenticated URL response using -saved source identity, without ordinary dispatch/enrollment/grant/rotation writes. -Client obtains URL before operation submission, verifies the same durable identity -and legitimate current key-transition chain at destination, then stores the URL. -No HTTP redirect or repair replays uncertain mutation/consuming GET. - -Acceptance: multiple previously paired clients migrate with distinct grants, -pending/completed rotations and receipt state. Test destination identity mismatch, -later destination key replacement without changing old handoff URL, offline/old -URL failure, lost response and explicit URL edits. Clients send no credentials/ -nonces to an unverified destination. Source mode cannot mutate authority. Post-use -undo/fallback warns of stale state and never automatically starts the old host. -The operator, not a new epoch/fencing/cluster mechanism, prevents two writable -copies. Run actual Reploy staging on its separate port using synthetic state; -no live installation migration is authorized by this plan. Add maintenance/handoff -docs, client diagnostics and affected server/client fragments. - -### Child PRs - -| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | -| --- | --- | ---: | ---: | ---: | --- | --- | -| `11.1` — Cooperative maintenance and migration | Disable source ordinary work/admin mutations, drain real owners, export final snapshot and restore stopped destination under documented operator coordination. **Check:** Source stays disabled through failures; no new fencing/epoch/cluster mechanism or automatic old-host restart is introduced. | 180–300 | 260–450 | 440–750 | Low | 10.5 | -| `11.2` — Verified source URL handoff | Serve only a fixed authenticated destination URL from disabled source; client verifies same durable identity/transition chain before adopting and sending any credential. **Check:** Mismatch/unavailable URL/later destination replacement/lost response never replays submitted mutation or GET; handoff cannot mutate authority. | 220–380 | 280–500 | 500–880 | Low | 11.1 | -| `11.3` — Migration and combined release evidence | Finish synthetic multi-client Reploy staging on its separate port and the full combined journey/matrix; reconcile release/help/skill/dependency metadata. **Check:** Migration with grants/pending rotations and post-use undo is honest; all required checks pass or remain explicitly unverified and block publication. | 80–180 | 320–550 | 400–730 | Low | 11.2 | - -## Combined acceptance and publication gate - -Every slice runs prefix integration; do not defer first Python/Go composition, -platform packaging or cancellation testing until this gate. Once all child PRs across the eleven milestones -have approved final heads and required checks, run the complete synthetic journey: - -1. Fresh private setup with no public CA/DNS or external identity account; enroll - first and additional clients with one handoff/approval, restart and reconcile. - Reuse one portable identity at a separately registered second server with - distinct access/grants and no source-server availability requirement (P01–P10). -2. Authenticated discovery/direct invocation of mock SMTP/IMAP accounts with - distinct grants, existing policies, grant change/denial and concurrent output. -3. Due rotation, fixed grace, expired-certificate control completion, inactivity, - predecessor fallback, owner client repair, owner-issuer/portable/server-authority/ - server-leaf certificate renewal and server-key replacement, including refused - expired peer-driven trust renewal and explicit owner recovery after missed validity. -4. Encrypted artifacts through all four modes with origin/recipient checks, - failed consuming GET, full limits, quota contention and real cancellation. -5. Concurrent-state export, offline restore, failed restore preserving undo, - after-use undo/repair, maintenance migration and non-mutating URL handoff. - -Run combined contention/cancellation/deadline/cleanup checks so carrier, crypto, -HTTP/body, plugin worker, file/quota and admin ownership cannot each pass while -their composition leaks work. Run all Python tests and Go tests/vet, lint/type -checks, client/server builds/install smoke, supported Python/OS/CPU matrix and -Reploy staging regressions. Public proxy tests include TLS termination with an -untrusted inspecting relay, changed outer cert, and TCP passthrough; future -browser administration remains unimplemented, with its documented trust boundary. - -Published help/docs/skill, package dependency metadata, release notes and upgrade -guidance must agree with the final implementation. Existing pre-auth clients get -actionable enrollment guidance, not an unauthenticated fallback. Do not require -live accounts to prove safety or mark unavailable checks as passed. Remaining -failures require fixes/re-review or an explicit requirements/HLD decision; no -scope reduction, platform drop or readiness claim is hidden in release wording. - -Approval of this revision attests its design, ordering and verification -obligations. Implemented/merged state is reported explicitly above; the newly -proposed work begins only on separate implementation authorization. Reviews and exact-byte stamp evidence are stored outside this -document so recording its verdict does not invalidate the reviewed plan. +# Authentication: remaining implementation design + +This is the detailed design for all remaining milestones **3–11**, based on +merged source `d52f8bc0acadc1de0dcb53fb1a96eb3e822e174a`. +[Requirements](requirements.md) remain exactly +`d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929`. +The reviewed and owner-approved [HLD](high-level-design.md) is exactly +`5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe`. +Those are the explicit governing design dependencies. This plan, its referenced +inventory and the current overview require affected review and final owner +approval. Neither design approval nor a planning state authorizes product work. + +## Current boundary and navigation + +Milestones 1–2, including portable enrollment `2.10.1–2.10.4`, are merged. +The original 21-PR enrollment stack consumed **22 attempts**, including its +unshipped parent attempt. That history, the subsequent four-slice correction, +old findings, original approval methods and receipts remain immutable. There is +no new allowance, campaign, enrollment or reservation in this design revision. + +Use [overview](overview.md) for the map and [slices.json](slices.json) for the +**one canonical ordered inventory**. Its original `2`/`2.10` parents and four +children retain their exact intent, paths, dependencies and planning states; +new display ranges of zero mean no remaining work in those merged cuts, not +zero historical effort. The generated definition-only overview is not an +execution ledger. Future delivery must reconcile completed work through its +original receipts, not execute those four children again. + +The [frozen prior plan](supporting/implementation-plan/historical-plan.txt), +[prior native LLD](supporting/implementation-plan/historical-native-lld.md) and +[original estimates](supporting/implementation-plan/estimates-before.json) +retain earlier text and IDs. Old stamps attest old bytes, not this revision. +The [estimate comparison](supporting/implementation-plan/estimate-comparison.md) +provides every old/new cut and parent rollup. None of that historical material +adds requirements to the current specification. + +## Order, scope and size rules + +The milestone order is 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 → 11. Within milestone 3, +retain `3.1.1–3.1.4`, `3.2.1–3.2.2`, `3.3`, `3.4`, `3.6.1–3.6.2`, +`3.5.1–3.5.2`, `3.7`. The remaining child IDs and order stay as previously +issued. Exact leaf dependencies include the preceding leaf, so each prerequisite +result is complete before its consumer starts. A replaced parent retains its +aggregate responsibility; it is not an executable work item or extra reservation. +There are **51 remaining cuts**. This is a draft planning proposal, not an +approved PR-count allowance or guaranteed future diff. + +Each leaf in `slices.json` names its complete ID, concrete title, consumed result, +scope, exact implementation/test/document paths, prerequisites and focused +completion check. Shared contracts and parent acceptance below also apply to +that leaf when first consumed. Public activation is deferred until its complete +boundary is safe; internal foundations always have an executable real consumer. +No empty framework, permissive placeholder, new policy engine or test-only +production authorization is permitted. + +Display estimates mean **incremental final delivered nonblank physical lines**: +production and tests are separate; comment-only lines are excluded; physical +multiline statements and docstrings count. Shipped configuration, package data +and instructions count as production by role, not extension. Test-only helpers, +generators and integration drivers count as tests. Development design documents, +static fixture data, generated files, locks and dependencies are separate. +Handwritten CI is reported separately in the comparison and included in combined +ranges, not silently omitted from cost. No hour/day conversion is used. + +The original **1,000 authored changed code/test-line maximum per PR** remains, +counting additions plus deletions across both languages, code motion and +handwritten fixtures. The approximate 600-line target is flexible. Final-content +estimates are not this edit-churn measure. The separate forecast envelope includes +replacement/motion/comment headroom; all current cuts fit. Recheck against the +actual predecessor before work. If evidence invalidates a cut, revise its affected +design and admission before implementation; do not remove tests or hide a split. +Relevant release fragments/help belong to their owning cuts. Development-only +planning changes do not require a published-package news fragment. + +## Shared engineering contracts + +Reuse `authority.py`, the existing private instance lock, SQLite authority DB, +`agent_enrollments`, `enrollments.prepared`, private file primitives and local +OS control. Keep original prepared bytes and opaque approval revision immutable. +Only the live revision is monotonic. Extend existing workers, carrier and HTTP +admission rather than add another executor, permission cache or operation engine. +Server source stays under `server/src/arbiter_server`; Go under its existing +`internal` packages. Proposed filenames identify ownership; do not create a +module solely because a slice has a name. + +All new wire messages use version 1 with purpose, exact IDs, expected live +revision and bounded payload. Encode canonical UUIDv4 strings and unpadded +canonical Base64url for binary fields. Reject duplicate JSON fields, extra fields +unless an explicit versioned extension permits them, trailing input, wrong types, +non-finite numbers and oversize encodings before expensive work. JWS uses the +exact retained payload bytes, ES256 fixed-width 64-byte R||S and fixed purpose +`typ`; reject `jku`, `jwk`, algorithm substitution and unknown critical headers. +Registered verifier selection is independent of incoming headers. Bind public +key possession to a fresh 32-byte challenge, exact purpose, IDs, revision and +RFC9266 exporter. Comparison and commit recheck occur in the same live writer. + +Every state mutation has a stable random operation ID and expected revision. +Exact completed retries return the original bounded result after verifying the +request/key context; conflicting reuse fails. Retain one latest result per +purpose/enrollment and the one active pending transition. Supersession retains +necessary history but cannot resurrect authority. Bounded authenticated receipt +retrieval, rather than replaying the original operation, resolves a lost result. +Ordinary plugin mutations and consuming GETs are never automatically repeated. + +Keep Python 3.10–3.14, Go 1.24 and the current Linux/macOS/Windows x64/arm64 +support matrix. Existing pins are `pyOpenSSL==26.2.0`, `cryptography>=42,<49` +and Gorilla WebSocket 1.5.3. Add binary X25519 age only; do not enable passphrase, +SSH, plugin or armored parsing through untrusted application data. Candidate +streaming backends are pyrage 1.3.0 and Go age 1.2.1 with existing compatible +transitive versions. Age 1.3.2 requires Go 1.25 and is not selected under the +current floor. Candidate versions are not a clean advisory/install verdict: +the owning first-use cut must verify reachable advisories, exact locks, supported +wheels/source builds and native execution. Failure blocks that cut; it does not +permit a platform drop, whole-file API or custom cipher format. See +[backend inspection and probe](supporting/implementation-plan/backend-evidence.md). + +Reserve slots and byte/disk credits before crypto, copying or consuming GET. +Run blocking work off-loop through bounded existing owners. A canceled waiter +never releases actual thread/file/crypto ownership. For pyrage, use caller-owned +read/write adapters that bound every chunk, retain a sticky error even when the +binding swallows a final flush error, and record actual bytes/hashes. Check that +state, library result, finalization, flush/fsync and expected content before +publishing. The synthetic probe demonstrates why a return value alone is not +sufficient. Native progress/cancellation tests must demonstrate event-loop +responsiveness while the binding runs; no unbounded background queue is allowed. + +## Milestone 3 — native transport, live grants and denial + +The following contracts refine R10–R14 without changing the accepted public +interfaces. Ordinary native requests retain existing HTTP shapes and account +policy. Their anonymous predecessors close at the complete cutover. + +### One ordinary channel and one selected enrollment + +The outer carrier is a binary WebSocket at `/api/v1/native/api`. Ordinary inner +TLS is exactly TLS 1.3 with ALPN `arbiter-native-v1`; the existing fixed control +endpoint keeps `arbiter-control-v1` and never reaches ASGI. Pairing remains Noise. +Disable compression, TLS tickets/resumption, early data, HTTP/2, pipelining and +redirects. Use one HTTP/1.1 request per inner connection, then close. This is a +simple subset of the HLD's one-in-flight rule and needs no connection pool or +operation replay protocol. + +Add the public selector setting `arbiter.enrollment` to existing client YAML and +the `enrollment=SELECTOR` override. It uses the existing canonical 22-character +selector, not a filename, key, URL or display name. Explicit override wins over +the config value. Missing selection gives enrollment/configuration guidance before +dial; never scan for a first identity or derive authority from URL. Enrollment +prints its final selector and this configuration guidance after durable promotion. +Changing `url=...` changes location only. Loading the selected record fixes the +expected server ID, remembered server authority and exact access key for this +logical request. Another server's record cannot authenticate a redirected URL. + +Reuse the strict stored-record decoder from portable enrollment with a distinct +`LoadNativeIdentity` validator. Accept only final `enrolled/` native-owned state, +validate current server authority, exact access profile/IDs/key correspondence and +complete receipt/promotion. The portable leaf is historical enrollment evidence; +its later expiry is not ordinary access authority. Never accept portable proof, +prepared-only state or a lifecycle time exception as ordinary authentication. +Owner recovery and current/predecessor rotation remain milestones 4/5, not an +authentication retry added here. + +Go's existing WebSocket `net.Conn` adapter carries `crypto/tls`. Verify the exact +remembered server authority, server-role SAN/ID, validity, key usage, EKU and +critical extensions before returning the stream. `GetClientCertificate` requires +the per-connection expected-server-verified marker before it supplies access +credentials. Do not put enrollment IDs, account names, application headers, +cookies, proxy authorization or nonces in the outer request. The dedicated native +outer dial may tolerate unverified carrier HTTPS; general/browser constructors +do not inherit that exception. Reject outer redirects and inherited proxy auth. + +Return the verified inner connection from standard `http.Transport.DialTLSContext`. +Set `DisableKeepAlives`, disable HTTP/2 and proxy use, and reject all redirects in +the owning `http.Client`. Retain existing `TimeoutTransport` around that standard +transport; do not build a custom HTTP RoundTripper or duplicate phase timers. +The original connect budget covers outer TCP/HTTPS, upgrade and inner handshake. +`GotConn` means inner verification completed. API response time, plugin overrides +and download header/idle-progress time keep their current semantics. No phase, +reconnect, ping or wrapper restarts a logical deadline. No automatic retry after +request submission, uncertain result or consuming artifact GET. + +### Shared bounded carrier and TLS stream + +Extract only the common private carrier ownership/pump from `pairing_carrier.py` +and `control_tls.py`. Existing pairing/control behavior remains consumed by real +regression peers after extraction; fixed control framing is not generalized into +HTTP. Ordinary TLS adds a stream consumer on that same owner. Serialize every +memory-BIO operation in the existing bounded crypto pool, including handshake, +read, write, outgoing BIO drain and teardown. Handle partial writes, `WantRead` +and `WantWrite`; do not assume one send consumes one buffer. No OpenSSL private +API, TLS-record parser or new cryptographic dependency is needed. + +Python ordinary TLS requires a client certificate. Verify its exact server-issued +access profile and remembered server IDs in the crypto worker. The resulting +immutable candidate identity is not yet an authorized caller: live enrollment, +accepted key, denial, inactivity and grants are checked through the coordinator +before ASGI admission. Portable and cross-server certificates fail even with a +generic valid clientAuth chain. No caller is reconstructed from HTTP headers, +outer TLS or WebSocket metadata. Expose only the server's selected ordinary leaf; +keep owner issuer and lifecycle-control trust selection separate. + +The existing `arbiter.limits.native_transport` bounds remain: + +| Owner/resource | Limit and release condition | +| --- | --- | +| Native carrier | 16 shared by pairing, fixed control and ordinary; reserve before upgrade, no wait queue. Release after stream cleanup and every actual crypto/plugin owner ends. | +| Handshake/crypto | Four concurrent bounded crypto workers; ordinary handshake uses the same gate, 10-second handshake deadline, 256-KiB cumulative ciphertext each direction, 32-KiB chain cap. | +| Pending native data | 256 KiB in each direction, including owned adapter, WebSocket, inner TLS and transport-pending copies. Reserve before a copy or feed; release only when its owner drains/discards. | +| WebSocket | Binary only, no compression, at most 64 KiB per message including fragmentation; existing byte/time control-frame limiter. | +| HTTP | 32-KiB header section, one request, 1-MiB configured operation-body ceiling; reserve actual operation work before pulling body data. | +| Request receipt | Server-owned absolute 30-second default from inner TLS completion through complete headers/body; configurable positive `arbiter.limits.native_transport.request_receive_timeout`. Fragments/pings never restart it. | +| Operation work | Existing configured eight actual blocking workers. A canceled waiter does not release a running worker or its carrier. | +| Client transfer | Existing four-per-process admission before GET/temp reservation; closed artifact paths do not create another transfer pool. | + +Handshake totals and ordinary pending-data credits are different counters. Do not +retain the fixed control's lifetime `_control_tls_fed` counter for a long HTTP +stream or reset a cumulative counter and claim that buffers are bounded. Use one +moving credit ledger per direction, on the existing carrier owner. It accounts +for simultaneous parser fragments, queued WS chunks, BIO input/output, decrypted +pending data, header assembly and transient copies. One held WS message and one +active BIO call per carrier suffice; no background read-ahead queue is needed. + +Feed/return TLS application chunks of at most 16 KiB. Drain outgoing BIO data +before offering more input or another application write. Because `pending()` +reports decrypted bytes rather than encrypted BIO occupancy, retain credits for +all fed ciphertext until the worker reaches `WantRead` with no pending plaintext; +then, only after the initial handshake completes, retain conservative space for +one incomplete TLS 1.3 record and its copy +(36 KiB total), in addition to still-owned adapter data. Disable post-handshake +client authentication and renegotiation; control/pairing keep their existing +cumulative limits. Never discount that +reserve while a partial record remains. If credits cannot be proved available, +pause input and drain; if the peer overruns the finite pending budget, abort +before another copy. An actual worker retains its input/output credit until its +completion callback, even after cancellation. + +Use public `asyncio.Protocol`, `pause_reading`, `pause_writing` and transport +write-buffer APIs. Do not require `BufferedProtocol` at the Python 3.10 floor: +its outer SSL implementation still calls application `data_received`. Handle a +borrowed callback in bounded slices without retaining the full callback or feeding +wsproto past available credit. Reject over-budget delivery before copying it; +OS/kernel buffers and allocator capacity are not a claimed total-process heap +limit. The implementation must test actual pending-copy accounting under plain +and outer-TLS callbacks, fragmentation, coalescing and both slow directions. + +The five-minute authenticated idle timer runs only with no admitted application +work or transfer progress. A long operation remains subject to its existing +operation timeout, not this idle timer. Control pings extend no deadline. Every +timeout/abort wakes blocked readers/writers; nothing retries an operation. +The independent request-receipt timer still runs while a worker waits for a body; +admission does not exempt that wait. Stop it only on complete bounded body receipt +or request termination. One absolute timer, rather than a second sliding idle +mechanism, bounds silent and drip-fed bodies. A smaller client budget may fail +first; raising a client budget does not extend the server's configured deadline. +After body completion this timer does not cut off an admitted long plugin call. + +### HTTP/1.1 to the existing ASGI application + +Reuse the installed HTTP parser (`h11` through the existing Uvicorn dependency) +for framing, not a new HTTP grammar. The private stream adapter builds one ASGI +scope with immutable `arbiter.caller`, verified server/agent/enrollment/key IDs and +the coordinator token. Only the server transport can construct that value. Reject +Upgrade, CONNECT, absolute-form targets, unsupported transfer encodings, ambiguous +Content-Length/Transfer-Encoding, trailers that change routing/authority, and a +second request. Preserve ordinary route paths, JSON envelopes and error codes. +The outer URL's Host and identity headers have no authorization role. + +Parse a bounded complete header before choosing a route. Reserve the existing +worker and a provisional coordinator token before ASGI `receive` can supply body +data. A coalesced early body stays within pending carrier credit; excess closes +without invoking the plugin. Enforce both declared Content-Length and cumulative +decoded/chunked bytes; a missing length does not bypass the 1-MiB ceiling. Do not +emit `100 Continue` before reservation. Streaming responses use the same bounded +send/backpressure path; never concatenate an unbounded response. +If the receipt timer expires, stop ASGI body delivery, wake the existing bridge +with timeout and abort the carrier. The underlying worker remains reserved until +its actual completion callback. It must not reach schema/plugin dispatch after +timeout, even if a delayed final body fragment arrives. Missing body bytes never +receive a fresh deadline through another request or connection wrapper. + +An operation ID selects a plugin before the body identifies its account. Before +body admission require a live enrollment with at least one grant for that plugin; +after bounded JSON decode require an explicit string `account`, check that exact +configured `(plugin, account)` grant, then use the existing schema validation and +account policy. There is no default first account or new operation allowlist. +Do not call plugin validation, account lookup or upstream work for a hidden +account. The existing IMAP/SMTP operations use this account argument; a synthetic +test plugin must use the same contract. Catalog-only requests use bounded work +with a token scoped to their returned visible accounts. + +### Live authority and local administration + +Keep exact `enrollments.prepared` bytes as immutable receipt history. Extend that +existing enrollment row, not a second denial/contact table, with `server_id`, +exact accepted access DER/SPKI fingerprint, `last_contact` and a +positive monotonic integer `live_revision`. Retain existing `denied` and +`inactive_after` as the single authoritative fields read by both ordinary access +and the fixed enrollment-receipt path. Existing opaque `revision` is immutable +approval provenance bound in the prepared result; never reinterpret it as a +monotonic live revision. Below, live token/revision checks mean `live_revision`. +Grant rows have unique `(enrollment_id, plugin, account)` and reference that same +enrollment. Do not add independently authoritative caches, mirror denial/cutoff +columns or mutate grants inside historical results. +Use portable enrollment's existing indexed `agent_enrollments` relation as the +sole agent-to-enrollment mapping; do not copy `agent_id` into `enrollments`. +Admission resolves the certificate's exact agent/enrollment pair through that +relation and the same enrollment row. Missing, conflicting or corrupt bindings +fail closed before ASGI admission. Migration validates the already backfilled +relation; fresh activation and exact replay retain its existing atomic writer. +No future key-version/rotation framework is implemented in this milestone. + +One atomic startup schema upgrade backfills current key/grants and preserves each +existing denial, deadline and exact prepared/result. Initial `last_contact` is +derived from that enrollment's recorded activation/inactivity origin, not startup +time. Bound each parsed result, iterate rather than load all enrollments, reject +duplicate/malformed relationships and unknown future versions, and reuse the +existing stopped-instance/publication reconciliation rules. No serving mixed +old/new authority schemas. Fresh portable-enrollment activation populates these +columns and grants in its existing commit transaction; no interim activated row +lacks live authority. Existing receipt reads continue using the same row's exact +prepared result and live denied/inactive_after. Deny atomically blocks both paths; +authenticated ordinary contact refreshes their shared cutoff without changing +historical approval/result bytes. Receipt retrieval itself keeps its existing +contact semantics; incomplete retrieval never advances the cutoff. + +Extend trusted `arbiter-server enrollment` controls with `grant add`, `grant remove` +and `deny`, as accepted in the HLD. Inputs are one exact enrollment ID and, for grant actions, +one configured plugin/account pair. Use bounded existing local-control messages +and peer credentials/Windows caller token. Add validates configured account and +does not clear enrollment denial/inactivity. Existing add/remove/deny is +idempotent; only an effective change advances live revision. Read summaries use +32-row keyset pages by enrollment ID and never expose private key material. +There is no remote grant endpoint, automatic regrant on password change, or +implicit different account when a configured name is repointed. + +Authenticate contact only after strict mTLS and current accepted-key/live-state +verification. Atomically refresh `last_contact` and the existing 180-day cutoff +for an active enrollment; an already inactive or denied record cannot renew itself. +Malformed unauthenticated traffic or incomplete control exchange cannot refresh +contact. Rotation/grace-specific contact behavior is added by milestone 4. + +### Coordinator, dispatch and denial linearization + +Use one event-loop-owned coordinator with at most one fail-fast authority writer +reservation and live tokens bounded by the carrier/worker caps. Reuse the existing +local-control worker for its SQLite writes and existing crypto worker for +activation. A writer acquires its loop reservation, performs DB work off-loop, +then publishes commit or rollback on the loop. No event-loop SQLite, waiting +thread lock, new executor, unbounded writer queue or per-request global policy +snapshot. All writes that affect ordinary authority use this reservation; busy +writers fail safely rather than wait behind blocked plugin calls. + +Read one bounded enrollment/grant snapshot in an existing worker, carrying the +coordinator's observed write epoch. Before issuing a token or accepting a new +account-specific read, the loop requires that epoch and exact live revision still +match and no writer barrier blocks the token. Stale/busy reads fail retryably +before dispatch, never retry an upstream operation. Already live tokens use the +coordinator's explicit validity/barrier state. On a committed unrelated change, +carry those bounded tokens forward to the new revision without widening their +account scope; affected tokens are invalidated. Do not reject unrelated running +output merely because a global epoch advanced. A read-only snapshot never +independently authorizes a request. + +| Token transition | Owner and required check | +| --- | --- | +| Reserved | Real worker has started; live enrollment and plugin grant permit bounded body reads. It is not yet upstream dispatch. | +| Body complete | Parse only bounded JSON; choose the exact account and live revision, validate input through the existing schema. | +| Dispatched | At the already executing worker's plugin-entry boundary, bridge to the loop for the final exact enrollment/account/revision check. That successful handoff is the dispatch linearization point. The worker's next action calls the existing plugin; no queue, task spawning, await or alternative-account selection follows it. | +| Output | Before every response chunk and final ciphertext write, recheck the token after any wait/backpressure. | +| Canceled/waiter ended | Stop body/output and abort carrier; retain real worker, bridge, token and carrier ownership until actual work ends. | +| Actual worker finished | Existing pool `on_finished` callback retires worker ownership on the loop; release carrier only after all crypto/stream owners also finish. | + +A deny/remove writer first places an affected-token barrier on admission, final +dispatch and output. It then performs the conditional SQLite transaction in the +existing admin worker. On commit, publish revision, invalidate affected tokens +on all connections, wake waiters and abort their carriers before reporting local +success. On rollback, remove the provisional barrier and permit old authority +again without replaying canceled or uncertain operations. A grant removal cancels +that account and catalog tokens whose visible output depends on it; enrollment +denial cancels all enrollment tokens. An unrelated grant does not widen or revoke +another token. Temporarily pausing admission for one authority writer is allowed; +unaffected in-flight plugin work is not canceled merely for a global epoch change. + +The final plugin-entry handoff, not TLS acceptance or early body reservation, +orders dispatch against denial. Denial's barrier first means no later dispatch. +Handoff first means already dispatched work: OS scheduling or upstream completion +may occur after denial and cannot be undone. Report that boundary honestly; never +promise to undo mail effects. Waiting for eight blocked workers is not a condition +of committing denial or suppressing their output. + +At output, drain TLS into bounded unsent buffers, await write readiness, then +check permission immediately before synchronous `transport.write`, with no await +between check and write. Do the same at plaintext/ASGI boundaries. Denial drops +unsent BIO/WS data and aborts raw transport without flushing close-notify or queued +application bytes. Bytes already handed to transport before the barrier cannot +be recalled. A late worker result cannot recreate caller authority or send a new +error after response/cancellation. `HTTPWork` waiter cleanup stops delivery but +does not discard its bridge/token until the pool's actual completion callback. + +Fixed enrollment-receipt control uses this same coordinator. After its existing +proof and exact enrollment/result verification, return the observed write epoch +with the bounded result. Acquire an enrollment-scoped receipt token on the loop +only if the epoch and current denial/inactivity state still permit it. This token +does not grant ordinary account authority or change historical result bytes. +Retain token and carrier ownership through actual crypto/send completion. + +The enrollment-deny barrier blocks new receipt admission and unsent receipt +output. Commit invalidates affected receipt tokens and aborts their carriers +without flushing queued application data. Rollback removes the provisional +barrier; unrelated enrollment or grant changes do not revoke receipt permission. +After every output wait/backpressure, check permission immediately before the +final synchronous raw ciphertext write through the same shared carrier owner, +with no await between check and write. The receipt's database snapshot alone is +not delivery permission. Bytes already handed to transport cannot be recalled. +Inactivity also blocks fresh receipt admission under the shared live state; +existing receipt contact semantics remain unchanged. + +Ship the fixed-receipt guard with the first live enrollment-deny control in +`3.2.1`. That cut introduces the minimal shared coordinator with the real fixed +receipt as its consumer, including its final-write barrier and actual-owner +cleanup. `3.2.2` extends this same coordinator to ordinary grant/body/dispatch +work and owns ordinary grant add/remove controls. Do not expose live denial and +defer receipt output integration to `3.6` or public ordinary cutover. No second +coordinator, authority table, executor, protocol or production bypass is needed. + +### Discovery, policy and artifact closure + +Use the same token/grant projection for overview, plugin/accounts, operation/schema, +policy summaries, previews, test/info routes and direct invocation. Show a plugin +only with visible granted accounts; filter counts/examples/guidance as well as +names. Direct hidden/unknown account and policy lookup returns the same generic +not-found response before account-specific validation or upstream work. A policy +is visible only through a granted account using it; this does not create a policy +grant. Current account policy remains the only operation policy. Preserve grants +for deliberate repointing; password changes require no grant edit. + +Before ordinary public cutover, supply a small closed `ArtifactStore` implementation +through the existing plugin dependency and `for_plugin` wrapper. Current concrete +type checks remain usable. It must not invoke the legacy constructor or any legacy +create/inspect/open/read/nonce method. Keep only inert limit properties needed by +schema responses; creation fails before payload staging with an authenticated +`artifact_unavailable` error. No bypass/config flag and no plaintext fallback. +Caller identity is fixed in ASGI scope and set through a scoped `ContextVar` in +the actual synchronous plugin worker, reset in `finally`; shared runtime context +is never mutated. The later encrypted store consumes this same caller boundary. + +Also close descriptor projection and inline extraction before legacy lookup: +`_operation_artifacts`, `_native_artifact_from_descriptor` and +`_inline_artifact_payload` cannot turn a plugin-supplied old URL/path/nonce into +usable bytes or a descriptor. Close old metadata/HEAD/GET and raw artifact routes, +including guessed paths. A synthetic artifact-producing operation must fail +before any legacy-store entry, payload, metadata or nonce; inspect both a legacy +spy and actual filesystem. Report prior upstream effects without retrying them. + +Under the existing exclusive startup owner, invalidate and incrementally remove +only server-managed ownerless legacy artifact index entries and their validated +files in the configured managed store. Do not instantiate its serving store, +follow links, scan mail or touch client files. Unknown/corrupt managed metadata +fails closed with operator guidance; no guessed ownership. Cleanup is bounded +per entry and repeatable across restart; deletion failure never re-enables serving. + +### Cutover and acceptance + +Private real peers exercise ordinary TLS/ASGI/coordinator paths before public +activation. No public bypass flag or test fixture creates product authority. +Build and exercise every Go discovery/schema/error/invocation/artifact constructor +with the selected native factory through private real peers first. Keep production +constructor selection on the existing path until the same cut switches it to the +native factory, closes ordinary anonymous API and legacy artifact routes, and +enables the complete reviewed ordinary channel. That cut is `3.5.2`; `3.5.1` +does not switch the product to an unavailable server route. After cutover there +is no anonymous fallback or bypass flag. +Only minimal health and bounded enrollment bootstrap remain anonymous. Missing +authority or projection fails closed. Fixed controls stay distinct. The first +installed ordinary prefix includes denial and closed-artifact acceptance; these +are not deferred to a final release checklist. + +| ID | Required real acceptance, assigned to the owning cuts below | +| --- | --- | +| N01 | Python/Go strict mutual TLS; wrong server/ALPN/role/issuer/key/time, portable/cross-server/prepared-only state and forged proxy headers never dispatch. | +| N02 | Real outer relay observes no access identity, account, operation, body or secret; changed outer cert/URL and TCP passthrough preserve expected inner trust; wrong server fails before client credentials. | +| N03 | Exact moving pending-byte accounting, all framing/chain/handshake caps, slow bidirectional peers, fragmented/coalesced WS/TLS/HTTP and valid 1-MiB body; no lifetime-byte cap on ordinary streams. | +| N04 | Pre-body eight-worker admission, Content-Length/chunked limits and Expect behavior. Fill all eight with silent/drip-fed bodies; the absolute server deadline, delayed final fragment, denial and shutdown wake waits, prevent dispatch and recover capacity only on actual worker exit. Fragments/pings/reconnect wrappers do not extend it. Health/admin denial remain responsive. | +| N05 | Existing rows, exact receipts, opaque approval revision, denies, grants and original inactivity survive one-way upgrade/restart. Admission uses the existing canonical agent binding after old-row backfill, fresh activation and exact replay; missing/conflicting/corrupt relations fail closed without a second agent-ID copy. Ordinary access and receipt read one denial/cutoff authority; denial blocks both, and active contact refresh changes their shared cutoff without changing historical bytes. | +| N06 | Discovery/count/schema/policy/error/preview/direct paths reveal only granted accounts and use existing policies; account repoint and password renewal preserve grants. | +| N07 | Controlled real-socket deny/remove races at queued read, body, final dispatch and cross-connection output. Fixed receipts also race snapshot return, token admission, blocked output and final raw write against deny commit; cover rollback, unrelated enrollment/grant changes, disconnect and actual-owner cleanup. No post-barrier dispatch or unsent delivery; already handed-off bytes cannot be recalled. Receipt cases run with the first live deny control in 3.2.1. | +| N08 | Denial/disconnect with blocked upstream calls retains all eight workers and carrier owners until actual exit; no automatic retry or false promise to recall prior effects. | +| N09 | Actual artifact-producing plugin/Go request rejects before legacy store entry or filesystem/nonce/descriptor/inline publication; old routes fail, restart cleanup is confined and failure stays closed. | +| N10 | Every real CLI constructor, including error/tool/artifact paths, uses explicit selected enrollment and verified native factory after atomic client/server cutover; the preceding product prefix keeps its working route while private peers exercise the new factory. No general outer TLS exception, URL identity inference, redirect or uncertain-operation replay. | +| N11 | Existing connect/API/plugin/download idle budgets through real peers: slow connect, no early headers, long active call, ping-only traffic, slow progressing stream and cancellation. | +| N12 | Installed supported Python/Go/native OS/CPU prefix actually executes N01/N04/N07/N09/N10 plus focused relay/timeouts; CI required variables are present and tests do not silently skip. | + +Reuse `test_native_http_protocol`, `test_artifact_http_admission` real-socket +fixtures and the existing Python/Go peer, installed-CLI and terminal drivers. +Own shared harness additions once; add targeted later cases. No live mail account, +full duplicated installed adversarial matrix or production prototype is authorized +by this design. Dependency/source inspection establishes API feasibility only; +native execution is implementation acceptance, not evidence already obtained. + + +## Milestone 4 — rotation, late completion and fallback + +Extend the same live enrollment row with current credential version/DER/SPKI, +one predecessor version/DER and one pending rotation reference. A separate +`pending_rotation` row, keyed by enrollment, contains operation UUID, expected +live revision, current-key fingerprint, `prepared_at`, fixed `grace_until`, +candidate SPKI/certificate or null and phase. One conditional transaction creates +it on due authenticated contact **before** requesting the candidate. Contact +updates last-contact/inactivity only for a currently accepted, active key; it +never moves an existing grace. A candidate is bound once. Preparation, retries, +invalid candidates and partial controls cannot extend its deadlines. + +The Go enrolled record becomes one private version-2 lifecycle record, atomically +replaced under its existing per-selector lock. It retains immutable enrollment +provenance separately from current/predecessor/pending keys and trusted-server +state. Migrate an exact valid version-1 record once; do not overwrite an unknown +version or delete the only durable recovery source on ambiguous publication. +Use existing POSIX custody checks/flush and Windows ACL/handle/WRITE_THROUGH +primitives. Save the candidate private key and exact certificate/result before +sending confirmation. After server activation, a lost receipt is recovered with +candidate possession and the recorded operation ID; the client never needs the +old certificate to remain unexpired merely to retrieve its completed result. + +### Normal rotation exchange and operation ordering + +Normal rotation is an internal authenticated HTTP control, not the restricted +late-completion carrier. Under the ordinary strict native channel add exactly +`POST /api/v1/lifecycle/rotation/prepare`, `/bind`, `/confirm` and `/result`. +Each opens a separate ordinary connection with exactly one request; each request +and reply is at most 32 KiB, uses the shared strict decoder, coordinator and +bounded existing worker, and never enters a plugin or consumes an artifact. +An active enrollment needs no account grant to maintain its own credentials. +It still needs its exact accepted current access key, ordinary certificate +validity, no denial and time before inactivity/grace cutoff. + +The version-1 envelope carries purpose `arbiter-rotation-{phase}-v1`, server, +agent and enrollment IDs, operation UUID, expected live revision, pending UUID +(or null only on initial prepare), and the phase fields below. No public URL or +header supplies these identities. Prepare is an authentication-only preflight: +its reply is either not-due with current version/revision, or the exact pending +ID, immutable prepared/grace times, current-key fingerprint, phase, candidate +certificate/hash if bound, and a 32-byte server challenge. At first due prepare, +the writer creates that pending ID/challenge before asking for a candidate; +repeated prepare returns the same pending state and never extends time. Retain +the preparation revision as history. A later grant revision can return a fresh +current live-revision snapshot for the same pending ID; confirmation must sign +that current snapshot and the writer rechecks it. An actual key replacement, +denial or inactivity cannot be papered over by updating the snapshot. + +Bind adds candidate SPKI and new-key signature over the envelope, stored challenge +and fresh exporter. The authenticated current key plus new possession permits +one candidate certificate, issued through the current server authority. Return +and retain that exact certificate/phase/result, without activating it. Same +operation/key retries return it; another key or pending ID fails. Confirm carries +the old-and-new signatures specified below, only after candidate custody is +saved. Result carries the same operation/pending IDs and fresh candidate-key +proof; before activation it reports only authenticated pending state, and after +activation it returns the exact committed receipt. A completed result requires +candidate possession through the fixed result control if ordinary current-key +TLS is no longer possible. That fixed control cannot prepare or bind a new key. + +In 4.2, every selected client constructor runs one shared lifecycle preflight +under the existing per-selector lock before submitting a user request. It reads +state, prepares/resumes, saves a candidate before bind, saves the returned exact +certificate before confirm, and durably promotes only a verified receipt. A +fresh ordinary connection then submits the user request once with the resulting +credential. All exchanges share the invocation's existing absolute connect/API +budget; their connections, phase transitions and authentication-only retries do +not restart it. Do not serialize a user body, capability or consuming nonce into +any lifecycle exchange. No new background job or second HTTP/timer stack exists. + +If prepare/bind is incomplete before grace, authenticated state may still prove +the current key usable; the next invocation resumes the same pending transition. +A network error is not such proof. If confirm may have committed, persist the +ambiguous phase and reconcile via result with the saved candidate before sending +any user work; never blindly confirm again or fall back to an unproven old key. +An exhausted budget fails this invocation without user-operation submission. +After grace, only the recorded late-completion journey can proceed. Save failure, +concurrent clients, writer busy/stale revision, denial and every lost reply get +real peer tests at their first owner, not only the final integration cut. + +Confirmation binds purpose `arbiter-rotation-v1`, server/enrollment/agent IDs, +pending ID, expected revision, both key fingerprints, candidate certificate hash, +server challenge and exporter. Verify old and candidate signatures, then recheck +pending identity, grace/inactivity/denial and candidate correspondence under the +live writer. Commit new current, one predecessor and exact result together; +invalidate superseded sessions before returning success. A repeated completed +confirmation returns its original result only to the activated candidate proof. + +After grace, old ordinary access is refused; the fixed control endpoint can +only complete the recorded pending rotation. Verify the stored issuer/signature, +exact DER/SPKI/IDs and possession. Relax **only certificate time** for this exact +old/candidate pair; require fresh channel binding, no denial and current time +before inactivity cutoff. Reissue a valid certificate for that same candidate +key without changing the pending ID or grace. The control may not prepare a +new rotation, issue another key or construct an ordinary caller. A completion +that misses inactivity requires the accepted owner repair journey. + +Credential-status control authenticates the remembered server and the presented +current key before returning a purpose-bound cause. Only unambiguous rejection +of that current credential by this verified server permits one authentication-only +predecessor attempt. That attempt must satisfy ordinary validity, live accepted +key, grace, denial and inactivity checks. It occurs before submission, carries no +operation body or artifact nonce and does not restart logical timeouts. Discard +predecessor on expiry, completed superseding recovery or unenrollment. No receipt +cleanup deadline may shorten the required completion interval. + +Ownership: 4.1 owns server pending state and ordinary prepare/bind/confirm/result +handlers with real private peers/clock fixtures; 4.2 owns the client replaceable +record, shared pre-operation constructor integration and activation; 4.3 owns restricted proofs/reissue; 4.4 owns +status/fallback; 4.5 extends their shared process/clock harness. Each earlier cut +has its own real peer and failures. Parent acceptance is the complete due → save +→ activate → lost receipt → expired-key completion journey, with simultaneous +denial, withholding, 30-day/24-hour/180-day boundaries and actual restarts. + +## Milestone 5 — owner-authorized client recovery + +Local `enrol repair` reuses bounded Noise pairing with an explicit existing +enrollment selected by OS-authorized administration. Bind its stable identity, +current live revision and unchanged grants/denial into approval. New enrollment +cannot smuggle that selector into its own approval. Commit replacement and +invalidate stale access/pending/completion sessions through the same coordinator. +An owner may replace credentials on a denied enrollment; it remains denied. + +### Non-monopolizing request, offline authorization and access commit + +`recover-request` generates replacement access keys in private client custody, +then obtains a **stateless** challenge cookie over the verified server's fixed +recovery control. Its version-1 public request binds purpose, request/operation +UUIDs, server/owner/agent/enrollment IDs, expected live revision, a random 32-byte +challenge, creation/expiry and exact replacement SPKI plus optional portable +binding. It expires after ten minutes and is at most 64 KiB including certificates +and proofs. A purpose-separated ES256 JWS with typ +`arbiter-recovery-challenge-v1` authenticates those exact bytes using the existing +server-held backup-origin signing key. This key cannot authorize recovery. The +offline owner file already pins that server's origin SPKI; the offline command +verifies this signature through that pinned key, never an incoming JWK/root. +No new operator key, trust store or secret export is introduced. + +Request issuance allocates **no per-enrollment pending slot**, row or durable +candidate. It only uses the existing globally bounded carrier/crypto admission +while serving the request. Multiple proposed keys may obtain independent cookies; +one cannot exclude another. New-key possession bounds a usable request but is +not owner authority. Unknown enrollment gets the same bounded cookie-shaped reply +with non-authoritative dummy revision/identity values; only successful completion +confirms a real binding. Unknown, stale, invalid, inactive and denied diagnostic +failures reveal no accounts or specific private state. Transient busy is generic, +not a per-enrollment reservation. Expiry or stale revision requires a fresh public +request and corresponding authorization; retries never slide an existing expiry. + +The existing offline `recovery authorize` command verifies cookie signature, +registered owner/server binding, strict purpose/schema and expiry. It displays +the exact identity/change, reads the private operator file and signs only these +exact bytes with typ `arbiter-owner-recovery-v1`. Private owner material never +leaves that machine. Completion carries this JWS, original signed cookie and a +fresh replacement-key/exporter signature. Under the live writer, independently +select the enrolled recovery verifier; recheck both signatures, current revision, +expiry, IDs and new key before creating any durable state. In one conditional +transaction, advance the live credential, consume the operation/cookie digest +and retain its exact result. First valid owner-authorized completion wins; another +cookie for the old revision is stale. Arbitrary unauthenticated requests cannot +create or overwrite this receipt. Preserve grants, denial and historical bytes; +owner-authorized replacement can repair expired/inactive access, but cannot clear +denial. At completed owner repair, set last-contact/inactivity from the actual +completion time under the unchanged180-day policy; incomplete or unauthenticated +traffic cannot refresh it. Replace current access and discard compromised +predecessor/pending authority. Stale rotations/completion sessions lose authority +atomically. + +The activated replacement key can reconcile the exact result through fresh +possession after a lost reply without reapplying the mutation. After completion, +this receipt lookup does not depend on the ten-minute authorization expiry; +superseding recovery invalidates obsolete receipt authority. It never clears a +later denial. Use the existing latest-result retention and bounded decoder. +Tests continuously issue attacker-generated valid new-key requests while the +legitimate owner completes, and cover competing valid owner completions, +expiration, grant/deny races, restart and lost results. + +### Portable signing and partial multi-server recovery + +Portable replacement is **one key, separate server authorizations** through the +already accepted `identity replace-request` → `enrol recover-request +--portable-request` → offline `recovery authorize` → `enrol recover` journey. +The private client replacement record stores one new portable key and the public +binding: stable agent/owner IDs, original issuer certificate/SPKI fingerprints, +old portable certificate hash, new SPKI, operation UUID and new-key possession. +Each server's cookie and owner JWS covers that complete binding as well as its +own replacement access key. An owner signature is authorization, not an X.509 +issuer signature. Neither ordinary enrolled access nor portable possession alone +can request a different portable key or another agent's certificate. + +At the original issuing server, `recover-request` identifies signing eligibility +only if its **locally held owner-issuer private key** matches the original issuer +SPKI/owner ID and still-valid registered issuer certificate. A remotely registered +public issuer is never enough. The server's registered recovery verifier must be +the verifier for that owner; do not let this server's administrator authorize a +different owner's identity. There is no existing signing control to reuse: +5.4 adds this narrowly purpose-bound handler to the fixed recovery control and +live writer, within the existing public request/authorize/complete commands. + +Completion verifies the independent owner JWS, replacement access/exporter and +replacement portable-key signatures, exact original agent/enrollment binding, +expected live/issuer revisions and original certificate provenance. Only a live +non-denied enrolled identity with that original legitimate issuer may receive +normal portable certification. Owner access repair remains allowed for a denied +identity but returns portable-pending without issuing a leaf or removing denial. +Prepare the exact normal-profile leaf for the new portable key, then atomically +commit access replacement, issued certificate/result and portable-binding +revision under the same writer; failure before commit activates neither. A +simultaneous denial/issuer removal/recovery makes the guarded transaction fail, +not a partial issue. Stable operation retries retrieve this exact certificate +only after new access **and portable** key possession; they cannot mint again. + +The client verifies normal role/issuer/agent/key/time correspondence, privately +saves the returned certificate and receipt, then atomically publishes that same +portable key/certificate under its identity lock. Record a completed receipt +before selector publication so a crash/lost reply reconciles without another +owner authorization or replacement key. Per-server access records are promoted +only from their own exact verified results. No second enrollment approval occurs. + +Other already-enrolled servers consume their own challenges and owner signatures +and replace only their local access credentials. They neither sign for the +original issuer nor trust a new issuer automatically. These recoveries may finish +before the original issuer is reachable: keep the public old certificate as +history and new portable credential explicitly pending; ordinary access does not +require a currently valid portable leaf. Once the original issuer's exact result +is saved, publish the shared portable certificate once and record each server's +independent completion. Retry only unfinished authentication/result exchanges, +never user operations. Fresh enrollment elsewhere waits for legitimate issuer +certification and that server's independent issuer-registration rule. An absent +original enrollment, unavailable/expired issuer, missing signer or wrong owner +leaves portable certification pending with restore/issuer-registration guidance; +never mint a replacement CA or attach the old leaf to a new key. + +### Same-key issuer and portable renewal + +Keep issuer validity 3,650 days, leaf365, five-minute backdate and renewal windows +366 days/30 days before expiry. In5.5, local authenticated lifecycle maintenance +renews an owner issuer using **that same locally held key**, owner ID and CA +profile while the current issuer is still valid. Sign the new self-signed root +and a bounded purpose `arbiter-owner-issuer-renewal-v1` statement over exact old +and new certificate hashes, unchanged SPKI/owner, issuer revision and operation +ID. Persist the new certificate, statement and result atomically before serving +it; a lost result returns identical bytes. This is certificate-time renewal, +not a new identity/key authorization or a general remote CA-issue interface. + +An enrolled client fetches this public statement from the remembered issuing +server before supplying credentials to a changed certificate. Verify the actual +channel's unchanged authority/key and old trust, both exact certificate profiles, +same SPKI/owner, old certificate still valid locally, monotonic issuer revision +and the signed old→new binding before saving it. For another server's exact- +fingerprint public registry, forward this same bounded public statement through +an authenticated lifecycle renewal control. Its writer must find the exact old +active registered certificate, still valid **at that receiving server**, and +verify unchanged owner/SPKI/CA constraints, statement and self-signature. Retain +the old fingerprint as provenance and add the exact renewed-certificate alias +under the same trust identity/revision. Removal/denial of the original trust +blocks this transition; it cannot resurrect inactive trust, change issuer key, +register an unrelated CA or authorize new accounts. No incoming root authenticates +its own first registration. A missed validity window needs explicit legitimate +registration/restore guidance, not automatic expired-root acceptance. + +For same-key portable leaf renewal, the original issuer's strict ordinary +`POST /api/v1/lifecycle/portable/renew` consumes a bounded version-1 request with +purpose `arbiter-portable-renew-v1`, exact server/owner/agent/enrollment IDs, +current issuer/leaf hashes, unchanged portable SPKI, expected live/issuer revisions, +operation ID and portable-key/exporter proof. Require accepted active access, +no denial/inactivity, recorded agent binding, matching locally held issuer key +and still-valid original portable leaf/registered issuer. Issue only the same +agent/key/profile with renewed dates; atomically save the exact result and +recorded portable-certificate revision. Wrong key, missed leaf validity or issuer +loss requires owner recovery, never access-only recertification. Client checks +and saves issuer continuity first, then the leaf, using existing private custody. +Lost result uses the same operation and both-key proof, not another issuance. +Renewal does not rotate access, change grants or make portability native authority. + +Ownership:5.1 pairing repair;5.2 stateless request/JWS/offline authorizer;5.3 live +once-only commit/result;5.4 original-issuer signing and partial multi-server +client orchestration;5.5 same-key issuing/registry/leaf renewal. Focused tests in +each owning cut use the actual fixed/ordinary controls and durable client state. +The two-server parent journey preserves independent grants and denial, survives +attacker request floods, loses every result/save boundary, removes original +issuer availability and races renewal/removal/recovery without a second approval. + +## Milestone 6 — server identity and certificate continuity + +Store server transitions in the same authority DB, keyed by monotonic local +transition revision and operation UUID. This is local trust-history ordering, +not a migration epoch/fencing system. Each bounded signed record contains version, +purpose, durable server ID, prior authority SPKI/certificate hash, next authority +SPKI/certificate hash, revision, operation ID and reason. Staging verifies the +new key/certificate and immutable old state before publication. New authority +possession signs the same statement; planned transition also carries old authority +endorsement. Compromise transition instead requires the independent registered +owner signature on the exact replacement/challenge and cannot be authorized by +the old key alone. Retain at most 32 records per reply and page by exact prior +fingerprint/revision; retain history needed within the allowed client lifecycle. +Missing or conflicting history stops with repair guidance, not arbitrary roots. + +The live local-control owner reserves the same coordinator writer, stages key +material privately and publishes active authority plus transition/result together. +The stopped owner uses the same exclusive instance lock; there is no concurrent +direct DB writer. Existing access leaves keep their exact accepted DER, live +revision and recorded issuing-authority verification until legitimate access +rotation. Historical issuer **public** keys verify those exact records only; +they cannot issue new accepted credentials or authorize the successor server. +Do not require all clients to rotate simultaneously or trust arbitrary leaves +signed by an old compromised CA. + +Clients retrieve only bounded nonsecret transition material before sending access +credentials/capabilities. Verify the chain from remembered trust or independently +registered owner proof to the actual new channel key, including fresh new-key +exporter possession. Persist trust under the existing selector lock before any +ordinary credential is supplied. After adopting an owner-authorized compromise +transition, reject superseded old-authority transitions and forks. Before learning +an independent compromise repair, a client cannot magically diagnose compromise +of its still-trusted peer; this protocol does not claim retroactive detection. +A replayed record cannot roll client trust backwards. Failed save retains prior +trust and explicit repair guidance; no operation is submitted or replayed. + +Same-key certificate renewal uses the existing issuer/leaf windows and purposes, +not a scheduled identity-key replacement. Verify the matching key/ID and store a +new certificate only through still-valid registered authority. Missed trust-root +validity needs independent owner recovery or explicit pairing; do not accept a +peer-supplied expired root's self-renewal. Outer HTTPS and URL changes are separate. + +Ownership: 6.1 server publication, 6.2 client adoption, 6.3 independent compromise +repair, 6.4 same-key renewal. Parent acceptance runs online and long-offline +clients, lost result/restart, multiple replacements, missing/forked history, +missed validity and retained access/grants/denial without exposing credentials +to a substituted server. + +## Milestone 7 — encrypted creator-bound server artifacts + +Register one current X25519 recipient version per enrollment through live access. +The server encrypts a fresh 32-byte challenge to the proposed recipient; return +its hash through the authenticated request and bind both access signature and +new recipient proof to enrollment/version/revision/exporter. Only then replace +current recipient. Retain old private recipient keys locally and server storage +keys while referenced by unexpired artifacts; a bounded 24-hour artifact maximum +and no replacement while another retained predecessor is needed prevent unbounded +key history. Recovery may explicitly lose old transient artifacts; do not turn +access rotation into recipient deletion. Public keys never authorize service. + +A synchronous plugin receives immutable creator/enrollment/account context from +the coordinator. It cannot nominate another creator. Reserve artifact count, +50-MiB plaintext and worst-case ciphertext/metadata disk before reading producer +bytes. Use binary age X25519 for exactly the registered client recipient and +server storage recipient; bound header parsing to 16 KiB and expected stanza +count/size before general recipient handling. No passphrase/plugin/KDF attacker +input. For up to two recipients, reserve at most plaintext + 64 KiB total payload +overhead, plus bounded encrypted metadata/index; verify this bound against the +selected backend before activation and fail closed on unexpected overhead. +Actual bytes, including incomplete staging and consumed files retained by readers, +count toward 1 GiB and 2,000 slots. Do not lower the 50-MiB plaintext limit. + +Write ciphertext privately, hash measured ciphertext and plaintext incrementally, +check sticky backend errors/finalization, flush and publish atomically. Encrypt +metadata/content details separately for the same recipients. The private index +contains only artifact/enrollment/account/recipient-version references, nonce +verifier, consumption/deadlines, lengths/hashes, file/quota references needed for +authorization and cleanup. Metadata is not plaintext in an outer sidecar. Server +inspection decrypts under its retained storage key into a bounded reader; no +persistent plaintext payload is created. Cleanup holds physical reservation until +all actual readers/writers stop and the file is deleted. + +The authenticated descriptor has version, durable server/agent/enrollment IDs, +origin account, artifact UUID, recipient version, age format identifier, plaintext +and ciphertext lengths/SHA256, expiry and capability. Hold it privately in client +memory; never learn trusted origin from incoming ciphertext metadata or public +HEAD. It is delivered only to the authenticated creator under native TLS. +Bound metadata/descriptors to 64 KiB. Untrusted cipher/header errors are generic; +no descriptor, nonce or content enters routine logs. + +HEAD and descriptor reads recheck creator + account grant + nonce + live revision +without consumption. GET commits consumption under the existing store lock and +coordinator token **before** opening output. Crash/failure after that point stays +consumed. The same final-write barrier blocks further delivery on grant removal +or denial. A backup intentionally omits transient artifacts; restore cannot +resurrect their capabilities. Preserve ten-minute idle and 24-hour maximum TTL. +Only after encrypted writer, quotas and authorized GET pass do 7.5 activate the +plugin adapter. Legacy ownerless files/routes remain closed and confined cleanup +never scans mail, arbitrary state or client files. + +Ownership: 7.1 recipient custody; 7.2 streaming encryption/backend; 7.3 quotas and +restart; 7.4 origin/consume; 7.5 all plugin/inline activation; 7.6 native contention +and packaging extension. Parent check covers both recipients, genuine 50-MiB +boundary, tamper/truncation, shared-account nonce theft, slow/revoked GET, +full-disk/orphan recovery and real mock SMTP/IMAP creation/inspection. + +## Milestone 8 — four explicit client processing paths + +Use the HLD commands exactly. `with-stdin` consumes a required literal string +`true` or `false` after `--stream`; do not use a parser whose Boolean flag leaves +`false` as an argv item. Reject omission, duplicates, mixed path flags, invalid +values and bad child argv **before consuming GET**. The `--` separator begins +child argv; child flags are not Arbiter flags. Use existing argv execution and +`{}` path substitution; no shell-string evaluation. Configured enrollment and +its explicit override apply to all four modes. + +One process-wide four-transfer gate reserves worst-case staging/fallback before +GET. Reuse existing connect/header/idle-progress budgets and child stdout cap. +Child stdout/stderr handling remains bounded with concurrent pipe draining; +backpressure and cancellation must not leak a child or actual file/crypto owner. +No timeout or verification failure repeats consuming GET. + +With `--stream true`, validate descriptor/server/key context first and decrypt +age chunks straight into child stdin. Hash/length/finalization are checked to EOF. +On failure, close input/cancel the child under existing policy, return nonzero +and disclose possible already-performed effects. This is authenticated chunk +processing, not complete origin verification before first input. No plaintext +input file exists, although the selected tool can write its own output. + +With `--stream false`, download once into reserved private ciphertext staging, +then establish the immutable read-only handle or bounded snapshot described below. +Fully verify that exact immutable source: cipher hash/length, age decryption into +a discard/hash sink, origin, plaintext hash/length and finalization. Only after +those checks pass may the child start and receive a second decryption of that +same immutable source. Before the verification pass, on POSIX, close all writable +handles, reopen and verify the same inode read-only, +unlink its pathname and retain only the read-only descriptor; on Windows use +private ACL and exclusive sharing after closing writable aliases. If the platform +cannot establish stable bytes, copy into one reserved immutable byte snapshot +before the verification pass. Do not verify a mutable file and snapshot afterward. +Keep the exact descriptor/key/version in memory through both passes. Four maximum +50-MiB snapshots plus bounded overhead are reserved before GET. Path replacement, +a late writable alias or a reopened filename cannot switch verified bytes. + +`with-temp --allow-plaintext-temp` writes private plaintext staging and verifies +fully before giving the pathname to the child. Remove it after actual child/file +owners finish; crash cleanup is best effort, not secure erase. `save-decrypted` +uses private same-filesystem staging, full verification and native atomic +**no-clobber** publication; a preexisting final path, symlink or publication race +fails without overwriting. On POSIX use link/no-replace publication and directory +flush; on Windows use the existing no-replace WRITE_THROUGH adapter. No ambiguous +`save` alias. Explicit bounded `get --stdout` remains immediate output with honest +final failure, not a fifth verified-before-start promise. + +Ownership: 8.1 strict parser/immediate pipe; 8.2.1 encrypted temp/immutability; +8.3 plaintext temp; 8.4 persistent export; 8.5 installed process composition. +The original 8.2 remains replaced history; 8.2.1 retains its paths, acceptance +and estimates with the corrected immutable-source order. Future 8.3 depends on +8.2.1. No milestone 8 work is selected by the current milestone 3 delivery. +Parent check runs real path-only/stdin tools for all choices, wrong descriptor, +truncation/EOF, path aliases, child failure/signals, four-transfer saturation, +rotation/denial and crash orphan cleanup on the supported native platforms. + +## Milestone 9 — complete consistent application backup + +Extend `generations.py`; its existing initial-authority DB selector is not a +complete backup implementation. A saved configuration generation contains the +selected effective application configuration, configured policies and materialized +actual secrets. Resolve only configured `oc.env` and `secret_file` references; +never dump environment or recursively copy an arbitrary host tree. Bound reads, +use private regular-file no-follow handles, compare identity/stat and content on +both ends of capture, and retry only the pre-publication capture on changed +sources. Fail if an application-required resolver/source cannot be captured. +Normalize saved secret references into private generation-relative files or +resolved protected configuration fields, so restore never depends on the old +host's secret path. Preserve nonsecret host-dependent application settings for +ordinary operator edits; OS/service/proxy/deployment wiring remains excluded. + +Publish saved configuration only after schema/policy/secret validation under the +same writer barrier as authority changes. Runtime reload and its saved-generation +reference change together before new requests see it; failed reload keeps old +runtime and saved state. Export captures that reference while holding the writer +barrier, takes a SQLite `backup` snapshot including its keys/accepted credentials/ +contact/deadlines/grants/completion history, then releases the barrier before +hashing/encrypting the immutable private snapshot. There is no snapshot made by +copying a live SQLite file or pairing independently chosen config/authority times. +Read-only export remains available during maintenance. + +One admin job owns snapshot, staging/disk credits and output until actual cleanup. +Private source snapshots may contain plaintext server secrets; they remain in +server-owned protected temporary generation storage and are removed afterward. +Only the **encrypted bundle** is published to the external job destination. The +external job gets the public recipient; the owner file's private signer/decryptor +is never required for export and never bundled. + +Use one uncompressed record grammar inside binary age. Prefix is fixed magic +`ARBITER-BACKUP-1\n`, a big-endian u32 manifest length, exact manifest bytes and +bounded fixed-width ES256 signature; then files in manifest order, each u64 length +and exact bytes, and a fixed terminator followed by age-authenticated EOF. +The signed manifest identifies format, owner/server IDs, snapshot UTC time, +schema/config generation, registered backup-origin key ID, explicit omissions, +and sorted unique relative path/size/SHA256 entries. Signature verifies exact +manifest bytes. Incoming key IDs only select among the external file's already +registered verifiers; the bundle may not supply trust. No general archive reader, +compression, links, devices, absolute paths, duplicate/case-colliding paths, +traversal, Windows reserved/device/alternate-stream names or platform-ambiguous +separator/normalization is permitted. Use a fixed ASCII managed-path grammar. + +Limits: one admin job, 4 GiB total plaintext records, 10,000 entries, 64 MiB per +entry and 1 MiB manifest. Reject before allocation/stream growth; length counters +use checked 64-bit arithmetic. Age header is bounded to the selected one-recipient +profile. Validate all hashes, signature and authenticated EOF; reject extra bytes. +The 64-MiB per-entry bound applies to the captured DB as well; an overlarge saved +application fails export honestly instead of silently omitting rows. Reserve disk +for immutable snapshot, encrypted staging and retained final output first. + +Export writes a private same-directory temporary output, checks all backend +sticky errors/length/finalization, flushes and atomically replaces the explicitly +selected bundle path. It never follows an arbitrary destination symlink. A failed +job leaves the last good file intact; lost local command receipt is resolved by +that operation's recorded result/output hash, not blindly replacing it again. +The external scheduler owns startup/cadence/off-host storage/retention/alerts; +document verified SSH invocation and nonzero failure reporting, without cloud +integration, a built-in scheduler or a first-enrollment backup gate. + +Ownership: 9.1 complete saved config/secrets; 9.2 coherent SQLite snapshot; +9.3 format/strict shared verifier; 9.4 local encrypted publication; 9.5 external +job and round-trip/concurrency extension. Parent acceptance changes grants, +rotation and configured file secrets while exporting, verifies a coherent +restorable result through external trust, and tests final-write/full-disk/ +cancellation with exact omissions and last-good preservation. + +## Milestone 10 — offline full restore and latest undo + +The CLI loads recovery/restore primitives before application configuration/plugin +startup. Broken ordinary startup must not prevent restore. Acquire the existing +exclusive instance lock before reading mutable state; concurrent server start, +restore and undo fail busy. Validate safe parents/ACLs and reserve disk for staged +new generation, active state and retained undo. Never use hard links between +mutable active state and an immutable recovery snapshot. + +Decrypt into a new private same-filesystem generation. Bound every record before +writing; accept only allowlisted managed files. Verify complete signed manifest, +all hashes and age EOF against the separate operator file, certificate/key/role +correspondence, DB integrity/schema and configuration/policy validity before any +active reference changes. Restore runs no plugin/network/mail operation. Incomplete +staging is unreferenced and removed under the stopped owner on restart. Unknown +schema or required migration outside the supported version range fails before +activation. No target-configuration merge or saved deadline reset. + +Upgrade the existing control selector to one bounded record: +`{version:2, active:UUID, undo:UUID|null, publication:UUID}`. All three references +are published in **one** durable control replacement after referenced files and +generation directories are flushed. Record publication intent and exact target +hash using the existing restart reconciliation; recovery accepts only the exact +old complete or new complete control. A malformed/missing referenced generation +fails closed. POSIX uses same-filesystem replace plus directory flush; Windows +uses the existing WRITE_THROUGH publication adapter with private handles/ACLs. +Native process-termination tests, not mocked rename success, prove each boundary. + +On successful restore, the stopped previous active generation becomes the latest +immutable undo snapshot; the staged restored generation becomes active. Only +then may unreferenced older undo data be removed. Failure before committed control +publication preserves both prior active and prior undo references. Saved contact, +expiry, denial and grants reflect the selected snapshot; warnings explain stale +restored authorization and later excluded changes. + +Undo after use clones that immutable pre-restore snapshot into **another fresh +active generation**, validates and flushes it, then changes only active/publication +while retaining the same undo UUID. Running the server after undo cannot mutate +that retained point. Repeated undo after more changes restores that same point; +it does not toggle into redo. Next successful restore replaces the point; +`undo-discard` atomically clears the reference before deleting only its now +unreferenced data. No expiry, hard post-use cutoff, acceptance phase or redo +history is introduced. + +Before restore/undo/discard print snapshot time, excluded later changes, restored +credentials/grants/denials, lost post-restore local edits and irreversible upstream +effects. Explicit invocation selects the action without another mandatory approval +ceremony. Ordinary host-specific configuration edits precede startup. Clients +retain identity but may need bounded predecessor authentication or explicit owner +repair; diagnostics must not claim knowledge of unseen newer client state. + +Ownership: 10.1 offline decoder/trust; 10.2 lock/staging; 10.3 active+undo durable +publication; 10.4 repeatable undo/discard; 10.5 native kill/client composition. +Parent acceptance covers empty/existing host, malformed bundles, failed restore +preserving an existing undo, after-use repeated undo, disk/ACL failure and process +termination around every flush/intent/control switch on supported platforms. + +## Milestone 11 — cooperative migration and authenticated handoff + +Maintenance begin takes the existing live writer barrier, commits persistent +ordinary-dispatch/admin-mutation inhibition, invalidates affected tokens and +drains/cancels actual owners. Return completion only after real cleanup. Restart +reads this persistent inhibition before route admission. Export/status and explicit +maintenance end remain available; failed capture/destination startup does not +automatically clear maintenance. Fixed controls that mutate credentials are also +inhibited. The operator controls the one writable installation; no epoch, takeover, +cluster state or automatic fencing is added. + +The runbook is: begin maintenance → export final coherent bundle → keep source +disabled → restore stopped destination → edit ordinary host settings → start only +destination in restored maintenance mode → run `maintenance end` locally on the +destination only → verify paired clients. Destination verification must prove that +ordinary dispatch stays inhibited before that explicit step and becomes available +after it, while the source remains disabled. Rollback after destination use can lose later +state; show the same stale-restore warnings and never restart source automatically. +Use isolated synthetic staging on its separate port when implementing the runbook; +no live account or installation migration is authorized here. + +`handoff` configures a fixed destination URL on the disabled source. Its service +loads only the saved source identity/transition evidence and the immutable URL; +no ordinary API, enrollment, grant, rotation, receipt-write or recovery mutation +handler is registered. A bounded fixed control authenticates the remembered source +and returns that URL before operation submission. The client then verifies the +destination's same durable ID/current authorized key chain, persists URL under +its existing custody owner and only then starts ordinary credential negotiation. +No access certificate, account, capability or operation body is forwarded by the +handoff. Later destination key replacement uses its legitimate chain/owner proof +and needs no edit to the old fixed URL. Invalid/unavailable old URL gives explicit +configuration guidance; no arbitrary redirect or uncertain operation replay. + +Ownership: 11.1 maintenance/drain/runbook; 11.2 fixed handoff/client adoption; +11.3 multi-client and whole-auth installed staging/matrix. Parent acceptance +migrates several clients with different grants, pending/completed rotations and +receipts; tests wrong destination, later replacement, offline old URL, failed +URL save/lost control result and post-use undo. Source remains non-mutating. + +## Integrated acceptance, reviews and delivery boundary + +| Governing parent outcomes | First owning work and integrated completion | +| --- | --- | +| R01–R03 | Preserve merged setup/enrollment; each new CLI stays lightweight and owner-separated; 11.3 checks the complete installation without external identity service, daemon or browser/provider framework. | +| R04–R06 | 3.2.1 retains identities/bindings; 5.1–5.5 own exact client repair and issuer authority; 6.3 owns independent server compromise repair; 11.3 checks two-server custody/grants/denials. | +| R07–R09 | Existing merged pairing/result evidence stays valid; 3.1.1/3.2.1 regress shared carrier/receipt, 5.1 tests repair without a second identity; 11.3 includes restart/lost-result fresh and reused enrollment. | +| R10–R12 | 3.1.1–3.1.4 transport/admission, 3.5.2 safe cutover, 3.7 real proxy/native budgets; each new control/backend owns its aggregate bounds and actual cleanup. | +| R13–R14 | 3.2.1–3.6.2 live grant/admission/output linearization, 3.5.2 installed cutover; 7.4/7.5 compose creator/account artifact access; 11.3 checks full cross-connection denial. | +| R15–R17 | 4.1–4.5 fixed lifecycle/fallback; 5.5/6.4 renewal; 6.1–6.3 server continuity; 10.5 and 11.3 cover stale restored clients and no uncertain replay. | +| R18–R20 | 7.1–7.6 encrypted origin/store/quota and 8.1–8.5 all four paths; 8.5/11.3 exercise native real-child behavior, cleanup and partial-effect truth. | +| R21–R22 | 9.1–9.5 useful complete signed encrypted snapshot/external job, verified round trip into 10.1; 11.3 checks ongoing post-enrollment/config-change backup. | +| R23–R24 | 10.1–10.5 stopped full restore, failure preservation, immutable latest undo after use and warnings; 11.3 checks multiple stale client histories. | +| R25 | 11.1–11.3 cooperative maintenance, final capture, stopped destination and non-mutating verified handoff across destination replacement. | + +Each cut owns focused positive/negative/failure tests and real Python/Go prefix +integration before submission. Reuse `test_native_http_protocol`, +`test_artifact_http_admission`, installed enrollment/terminal drivers and custody +fixtures; add each shared harness once in its first consumer. Later closure cuts +extend cross-area scenarios; they do not postpone an earlier boundary's first test. +Use mock upstream SMTP/IMAP accounts only. New CLI/config/format/platform behavior +gets help, applicable package fragment and skill guidance in its owning cut. + +During later authorized delivery, run applicable Python/Go tests, lint/type checks, +Go vet and required native CI. Use repository-local runners and Black with one +worker. Every final candidate needs current general, actual DBB, fresh independent +history-aware review and the applicable remote PR cycle/checks; retain immutable +original findings/responses/reports and cumulative limits. A correction/restack +invalidates affected evidence rather than inheriting the earlier head's approval. +No design review or synthetic probe here claims those implementation checks ran. + +Deliver one connected stack per milestone. Complete each child review cycle in +order, then require full parent and completed-prefix integration on every final +head before presenting the stack for operator merge. No automatic merge. Verify +main after an authorized merge before starting the next milestone. A typed +checkpoint must separate planning authority from product ownership; no plan file +or sidecar is silently added to a product slice. Current design migration requires +fresh affected review/admission before any future delivery uses it. + +The final 11.3 gate runs complete setup/enrollment at two isolated servers, +authenticated policy/grants/denial, clocks/recovery/renewal/server replacement, +all four encrypted artifact paths, concurrent export/offline restore/repeated undo, +and maintenance/handoff with real previously paired clients. Run full supported +Python/Go/OS/CPU install and execution matrices, contention and failure peers, +required checks, isolated staging, dependency/release metadata and docs/help/skill +consistency. Unavailable tests remain unverified and block the corresponding +publication claim. Completing a milestone is not package release, deployment, +live-account authorization or permission to implement another scope. diff --git a/docs/authentication/milestone-3-lld.md b/docs/authentication/milestone-3-lld.md index e4732b8..3d7200f 100644 --- a/docs/authentication/milestone-3-lld.md +++ b/docs/authentication/milestone-3-lld.md @@ -1,436 +1,12 @@ -# Native API, grants and live denial: low-level design - -Status: design candidate; no product implementation or delivery authorization. -This refines [requirements](requirements.md) R10–R14 and [HLD](high-level-design.md) -B2/B3. It consumes the reviewed [portable enrollment LLD](portable-enrollment-lld.md). -Those three documents are its explicit design dependencies. Requirements/HLD bytes -remain unchanged. The original milestone-3 seven-PR forecast is historical; the -already sized proposal below replaces its cuts, not its approved product scope. - -Source basis: merged main `25a8cf2196f36499ff92ce890f313901b51b4f2b` plus the -unimplemented portable-enrollment contract. Current `ControlTLS` is a fixed -64-KiB exchange, not an ordinary stream. `PairingProtocol` owns carrier bounds; -`BlockingOperationPool` already retains actual threads after waiter cancellation; -`HTTPWork` supplies a worker/loop bridge. `main.py` still exposes anonymous API -and legacy artifact routes. Go `configuredHTTPClient` still constructs ordinary -HTTP clients. This document specifies changes to those paths, not a second API, -transport daemon, policy engine or authorization cache. - -## One ordinary channel and one selected enrollment - -The outer carrier is a binary WebSocket at `/api/v1/native/api`. Ordinary inner -TLS is exactly TLS 1.3 with ALPN `arbiter-native-v1`; the existing fixed control -endpoint keeps `arbiter-control-v1` and never reaches ASGI. Pairing remains Noise. -Disable compression, TLS tickets/resumption, early data, HTTP/2, pipelining and -redirects. Use one HTTP/1.1 request per inner connection, then close. This is a -simple subset of the HLD's one-in-flight rule and needs no connection pool or -operation replay protocol. - -Add the public selector setting `arbiter.enrollment` to existing client YAML and -the `enrollment=SELECTOR` override. It uses the existing canonical 22-character -selector, not a filename, key, URL or display name. Explicit override wins over -the config value. Missing selection gives enrollment/configuration guidance before -dial; never scan for a first identity or derive authority from URL. Enrollment -prints its final selector and this configuration guidance after durable promotion. -Changing `url=...` changes location only. Loading the selected record fixes the -expected server ID, remembered server authority and exact access key for this -logical request. Another server's record cannot authenticate a redirected URL. - -Reuse the strict stored-record decoder from portable enrollment with a distinct -`LoadNativeIdentity` validator. Accept only final `enrolled/` native-owned state, -validate current server authority, exact access profile/IDs/key correspondence and -complete receipt/promotion. The portable leaf is historical enrollment evidence; -its later expiry is not ordinary access authority. Never accept portable proof, -prepared-only state or a lifecycle time exception as ordinary authentication. -Owner recovery and current/predecessor rotation remain milestones 4/5, not an -authentication retry added here. - -Go's existing WebSocket `net.Conn` adapter carries `crypto/tls`. Verify the exact -remembered server authority, server-role SAN/ID, validity, key usage, EKU and -critical extensions before returning the stream. `GetClientCertificate` requires -the per-connection expected-server-verified marker before it supplies access -credentials. Do not put enrollment IDs, account names, application headers, -cookies, proxy authorization or nonces in the outer request. The dedicated native -outer dial may tolerate unverified carrier HTTPS; general/browser constructors -do not inherit that exception. Reject outer redirects and inherited proxy auth. - -Return the verified inner connection from standard `http.Transport.DialTLSContext`. -Set `DisableKeepAlives`, disable HTTP/2 and proxy use, and reject all redirects in -the owning `http.Client`. Retain existing `TimeoutTransport` around that standard -transport; do not build a custom HTTP RoundTripper or duplicate phase timers. -The original connect budget covers outer TCP/HTTPS, upgrade and inner handshake. -`GotConn` means inner verification completed. API response time, plugin overrides -and download header/idle-progress time keep their current semantics. No phase, -reconnect, ping or wrapper restarts a logical deadline. No automatic retry after -request submission, uncertain result or consuming artifact GET. - -## Shared bounded carrier and TLS stream - -Extract only the common private carrier ownership/pump from `pairing_carrier.py` -and `control_tls.py`. Existing pairing/control behavior remains consumed by real -regression peers after extraction; fixed control framing is not generalized into -HTTP. Ordinary TLS adds a stream consumer on that same owner. Serialize every -memory-BIO operation in the existing bounded crypto pool, including handshake, -read, write, outgoing BIO drain and teardown. Handle partial writes, `WantRead` -and `WantWrite`; do not assume one send consumes one buffer. No OpenSSL private -API, TLS-record parser or new cryptographic dependency is needed. - -Python ordinary TLS requires a client certificate. Verify its exact server-issued -access profile and remembered server IDs in the crypto worker. The resulting -immutable candidate identity is not yet an authorized caller: live enrollment, -accepted key, denial, inactivity and grants are checked through the coordinator -before ASGI admission. Portable and cross-server certificates fail even with a -generic valid clientAuth chain. No caller is reconstructed from HTTP headers, -outer TLS or WebSocket metadata. Expose only the server's selected ordinary leaf; -keep owner issuer and lifecycle-control trust selection separate. - -The existing `arbiter.limits.native_transport` bounds remain: - -| Owner/resource | Limit and release condition | -| --- | --- | -| Native carrier | 16 shared by pairing, fixed control and ordinary; reserve before upgrade, no wait queue. Release after stream cleanup and every actual crypto/plugin owner ends. | -| Handshake/crypto | Four concurrent bounded crypto workers; ordinary handshake uses the same gate, 10-second handshake deadline, 256-KiB cumulative ciphertext each direction, 32-KiB chain cap. | -| Pending native data | 256 KiB in each direction, including owned adapter, WebSocket, inner TLS and transport-pending copies. Reserve before a copy or feed; release only when its owner drains/discards. | -| WebSocket | Binary only, no compression, at most 64 KiB per message including fragmentation; existing byte/time control-frame limiter. | -| HTTP | 32-KiB header section, one request, 1-MiB configured operation-body ceiling; reserve actual operation work before pulling body data. | -| Request receipt | Server-owned absolute 30-second default from inner TLS completion through complete headers/body; configurable positive `arbiter.limits.native_transport.request_receive_timeout`. Fragments/pings never restart it. | -| Operation work | Existing configured eight actual blocking workers. A canceled waiter does not release a running worker or its carrier. | -| Client transfer | Existing four-per-process admission before GET/temp reservation; closed artifact paths do not create another transfer pool. | - -Handshake totals and ordinary pending-data credits are different counters. Do not -retain the fixed control's lifetime `_control_tls_fed` counter for a long HTTP -stream or reset a cumulative counter and claim that buffers are bounded. Use one -moving credit ledger per direction, on the existing carrier owner. It accounts -for simultaneous parser fragments, queued WS chunks, BIO input/output, decrypted -pending data, header assembly and transient copies. One held WS message and one -active BIO call per carrier suffice; no background read-ahead queue is needed. - -Feed/return TLS application chunks of at most 16 KiB. Drain outgoing BIO data -before offering more input or another application write. Because `pending()` -reports decrypted bytes rather than encrypted BIO occupancy, retain credits for -all fed ciphertext until the worker reaches `WantRead` with no pending plaintext; -then, only after the initial handshake completes, retain conservative space for -one incomplete TLS 1.3 record and its copy -(36 KiB total), in addition to still-owned adapter data. Disable post-handshake -client authentication and renegotiation; control/pairing keep their existing -cumulative limits. Never discount that -reserve while a partial record remains. If credits cannot be proved available, -pause input and drain; if the peer overruns the finite pending budget, abort -before another copy. An actual worker retains its input/output credit until its -completion callback, even after cancellation. - -Use public `asyncio.Protocol`, `pause_reading`, `pause_writing` and transport -write-buffer APIs. Do not require `BufferedProtocol` at the Python 3.10 floor: -its outer SSL implementation still calls application `data_received`. Handle a -borrowed callback in bounded slices without retaining the full callback or feeding -wsproto past available credit. Reject over-budget delivery before copying it; -OS/kernel buffers and allocator capacity are not a claimed total-process heap -limit. The implementation must test actual pending-copy accounting under plain -and outer-TLS callbacks, fragmentation, coalescing and both slow directions. - -The five-minute authenticated idle timer runs only with no admitted application -work or transfer progress. A long operation remains subject to its existing -operation timeout, not this idle timer. Control pings extend no deadline. Every -timeout/abort wakes blocked readers/writers; nothing retries an operation. -The independent request-receipt timer still runs while a worker waits for a body; -admission does not exempt that wait. Stop it only on complete bounded body receipt -or request termination. One absolute timer, rather than a second sliding idle -mechanism, bounds silent and drip-fed bodies. A smaller client budget may fail -first; raising a client budget does not extend the server's configured deadline. -After body completion this timer does not cut off an admitted long plugin call. - -## HTTP/1.1 to the existing ASGI application - -Reuse the installed HTTP parser (`h11` through the existing Uvicorn dependency) -for framing, not a new HTTP grammar. The private stream adapter builds one ASGI -scope with immutable `arbiter.caller`, verified server/agent/enrollment/key IDs and -the coordinator token. Only the server transport can construct that value. Reject -Upgrade, CONNECT, absolute-form targets, unsupported transfer encodings, ambiguous -Content-Length/Transfer-Encoding, trailers that change routing/authority, and a -second request. Preserve ordinary route paths, JSON envelopes and error codes. -The outer URL's Host and identity headers have no authorization role. - -Parse a bounded complete header before choosing a route. Reserve the existing -worker and a provisional coordinator token before ASGI `receive` can supply body -data. A coalesced early body stays within pending carrier credit; excess closes -without invoking the plugin. Enforce both declared Content-Length and cumulative -decoded/chunked bytes; a missing length does not bypass the 1-MiB ceiling. Do not -emit `100 Continue` before reservation. Streaming responses use the same bounded -send/backpressure path; never concatenate an unbounded response. -If the receipt timer expires, stop ASGI body delivery, wake the existing bridge -with timeout and abort the carrier. The underlying worker remains reserved until -its actual completion callback. It must not reach schema/plugin dispatch after -timeout, even if a delayed final body fragment arrives. Missing body bytes never -receive a fresh deadline through another request or connection wrapper. - -An operation ID selects a plugin before the body identifies its account. Before -body admission require a live enrollment with at least one grant for that plugin; -after bounded JSON decode require an explicit string `account`, check that exact -configured `(plugin, account)` grant, then use the existing schema validation and -account policy. There is no default first account or new operation allowlist. -Do not call plugin validation, account lookup or upstream work for a hidden -account. The existing IMAP/SMTP operations use this account argument; a synthetic -test plugin must use the same contract. Catalog-only requests use bounded work -with a token scoped to their returned visible accounts. - -## Live authority and local administration - -Keep exact `enrollments.prepared` bytes as immutable receipt history. Extend that -existing enrollment row, not a second denial/contact table, with `server_id`, -exact accepted access DER/SPKI fingerprint, `last_contact` and a -positive monotonic integer `live_revision`. Retain existing `denied` and -`inactive_after` as the single authoritative fields read by both ordinary access -and the fixed enrollment-receipt path. Existing opaque `revision` is immutable -approval provenance bound in the prepared result; never reinterpret it as a -monotonic live revision. Below, live token/revision checks mean `live_revision`. -Grant rows have unique `(enrollment_id, plugin, account)` and reference that same -enrollment. Do not add independently authoritative caches, mirror denial/cutoff -columns or mutate grants inside historical results. -Use portable enrollment's existing indexed `agent_enrollments` relation as the -sole agent-to-enrollment mapping; do not copy `agent_id` into `enrollments`. -Admission resolves the certificate's exact agent/enrollment pair through that -relation and the same enrollment row. Missing, conflicting or corrupt bindings -fail closed before ASGI admission. Migration validates the already backfilled -relation; fresh activation and exact replay retain its existing atomic writer. -No future key-version/rotation framework is implemented in this milestone. - -One atomic startup schema upgrade backfills current key/grants and preserves each -existing denial, deadline and exact prepared/result. Initial `last_contact` is -derived from that enrollment's recorded activation/inactivity origin, not startup -time. Bound each parsed result, iterate rather than load all enrollments, reject -duplicate/malformed relationships and unknown future versions, and reuse the -existing stopped-instance/publication reconciliation rules. No serving mixed -old/new authority schemas. Fresh portable-enrollment activation populates these -columns and grants in its existing commit transaction; no interim activated row -lacks live authority. Existing receipt reads continue using the same row's exact -prepared result and live denied/inactive_after. Deny atomically blocks both paths; -authenticated ordinary contact refreshes their shared cutoff without changing -historical approval/result bytes. Receipt retrieval itself keeps its existing -contact semantics; incomplete retrieval never advances the cutoff. - -Extend trusted `arbiter-server authority` controls with `grant add`, `grant remove` -and `enrollment deny`. Inputs are one exact enrollment ID and, for grant actions, -one configured plugin/account pair. Use bounded existing local-control messages -and peer credentials/Windows caller token. Add validates configured account and -does not clear enrollment denial/inactivity. Existing add/remove/deny is -idempotent; only an effective change advances live revision. Read summaries use -32-row keyset pages by enrollment ID and never expose private key material. -There is no remote grant endpoint, automatic regrant on password change, or -implicit different account when a configured name is repointed. - -Authenticate contact only after strict mTLS and current accepted-key/live-state -verification. Atomically refresh `last_contact` and the existing 180-day cutoff -for an active enrollment; an already inactive or denied record cannot renew itself. -Malformed unauthenticated traffic or incomplete control exchange cannot refresh -contact. Rotation/grace-specific contact behavior is added by milestone 4. - -## Coordinator, dispatch and denial linearization - -Use one event-loop-owned coordinator with at most one fail-fast authority writer -reservation and live tokens bounded by the carrier/worker caps. Reuse the existing -local-control worker for its SQLite writes and existing crypto worker for -activation. A writer acquires its loop reservation, performs DB work off-loop, -then publishes commit or rollback on the loop. No event-loop SQLite, waiting -thread lock, new executor, unbounded writer queue or per-request global policy -snapshot. All writes that affect ordinary authority use this reservation; busy -writers fail safely rather than wait behind blocked plugin calls. - -Read one bounded enrollment/grant snapshot in an existing worker, carrying the -coordinator's observed write epoch. Before issuing a token or accepting a new -account-specific read, the loop requires that epoch and exact live revision still -match and no writer barrier blocks the token. Stale/busy reads fail retryably -before dispatch, never retry an upstream operation. Already live tokens use the -coordinator's explicit validity/barrier state. On a committed unrelated change, -carry those bounded tokens forward to the new revision without widening their -account scope; affected tokens are invalidated. Do not reject unrelated running -output merely because a global epoch advanced. A read-only snapshot never -independently authorizes a request. - -| Token transition | Owner and required check | -| --- | --- | -| Reserved | Real worker has started; live enrollment and plugin grant permit bounded body reads. It is not yet upstream dispatch. | -| Body complete | Parse only bounded JSON; choose the exact account and live revision, validate input through the existing schema. | -| Dispatched | At the already executing worker's plugin-entry boundary, bridge to the loop for the final exact enrollment/account/revision check. That successful handoff is the dispatch linearization point. The worker's next action calls the existing plugin; no queue, task spawning, await or alternative-account selection follows it. | -| Output | Before every response chunk and final ciphertext write, recheck the token after any wait/backpressure. | -| Canceled/waiter ended | Stop body/output and abort carrier; retain real worker, bridge, token and carrier ownership until actual work ends. | -| Actual worker finished | Existing pool `on_finished` callback retires worker ownership on the loop; release carrier only after all crypto/stream owners also finish. | - -A deny/remove writer first places an affected-token barrier on admission, final -dispatch and output. It then performs the conditional SQLite transaction in the -existing admin worker. On commit, publish revision, invalidate affected tokens -on all connections, wake waiters and abort their carriers before reporting local -success. On rollback, remove the provisional barrier and permit old authority -again without replaying canceled or uncertain operations. A grant removal cancels -that account and catalog tokens whose visible output depends on it; enrollment -denial cancels all enrollment tokens. An unrelated grant does not widen or revoke -another token. Temporarily pausing admission for one authority writer is allowed; -unaffected in-flight plugin work is not canceled merely for a global epoch change. - -The final plugin-entry handoff, not TLS acceptance or early body reservation, -orders dispatch against denial. Denial's barrier first means no later dispatch. -Handoff first means already dispatched work: OS scheduling or upstream completion -may occur after denial and cannot be undone. Report that boundary honestly; never -promise to undo mail effects. Waiting for eight blocked workers is not a condition -of committing denial or suppressing their output. - -At output, drain TLS into bounded unsent buffers, await write readiness, then -check permission immediately before synchronous `transport.write`, with no await -between check and write. Do the same at plaintext/ASGI boundaries. Denial drops -unsent BIO/WS data and aborts raw transport without flushing close-notify or queued -application bytes. Bytes already handed to transport before the barrier cannot -be recalled. A late worker result cannot recreate caller authority or send a new -error after response/cancellation. `HTTPWork` waiter cleanup stops delivery but -does not discard its bridge/token until the pool's actual completion callback. - -Fixed enrollment-receipt control uses this same coordinator. After its existing -proof and exact enrollment/result verification, return the observed write epoch -with the bounded result. Acquire an enrollment-scoped receipt token on the loop -only if the epoch and current denial/inactivity state still permit it. This token -does not grant ordinary account authority or change historical result bytes. -Retain token and carrier ownership through actual crypto/send completion. - -The enrollment-deny barrier blocks new receipt admission and unsent receipt -output. Commit invalidates affected receipt tokens and aborts their carriers -without flushing queued application data. Rollback removes the provisional -barrier; unrelated enrollment or grant changes do not revoke receipt permission. -After every output wait/backpressure, check permission immediately before the -final synchronous raw ciphertext write through the same shared carrier owner, -with no await between check and write. The receipt's database snapshot alone is -not delivery permission. Bytes already handed to transport cannot be recalled. -Inactivity also blocks fresh receipt admission under the shared live state; -existing receipt contact semantics remain unchanged. - -Ship the fixed-receipt guard with the first live enrollment-deny control in -`3.2.1`. That cut introduces the minimal shared coordinator with the real fixed -receipt as its consumer, including its final-write barrier and actual-owner -cleanup. `3.2.2` extends this same coordinator to ordinary grant/body/dispatch -work and owns ordinary grant add/remove controls. Do not expose live denial and -defer receipt output integration to `3.6` or public ordinary cutover. No second -coordinator, authority table, executor, protocol or production bypass is needed. - -## Discovery, policy and artifact closure - -Use the same token/grant projection for overview, plugin/accounts, operation/schema, -policy summaries, previews, test/info routes and direct invocation. Show a plugin -only with visible granted accounts; filter counts/examples/guidance as well as -names. Direct hidden/unknown account and policy lookup returns the same generic -not-found response before account-specific validation or upstream work. A policy -is visible only through a granted account using it; this does not create a policy -grant. Current account policy remains the only operation policy. Preserve grants -for deliberate repointing; password changes require no grant edit. - -Before ordinary public cutover, supply a small closed `ArtifactStore` implementation -through the existing plugin dependency and `for_plugin` wrapper. Current concrete -type checks remain usable. It must not invoke the legacy constructor or any legacy -create/inspect/open/read/nonce method. Keep only inert limit properties needed by -schema responses; creation fails before payload staging with an authenticated -`artifact_unavailable` error. No bypass/config flag and no plaintext fallback. -Caller identity is fixed in ASGI scope and set through a scoped `ContextVar` in -the actual synchronous plugin worker, reset in `finally`; shared runtime context -is never mutated. The later encrypted store consumes this same caller boundary. - -Also close descriptor projection and inline extraction before legacy lookup: -`_operation_artifacts`, `_native_artifact_from_descriptor` and -`_inline_artifact_payload` cannot turn a plugin-supplied old URL/path/nonce into -usable bytes or a descriptor. Close old metadata/HEAD/GET and raw artifact routes, -including guessed paths. A synthetic artifact-producing operation must fail -before any legacy-store entry, payload, metadata or nonce; inspect both a legacy -spy and actual filesystem. Report prior upstream effects without retrying them. - -Under the existing exclusive startup owner, invalidate and incrementally remove -only server-managed ownerless legacy artifact index entries and their validated -files in the configured managed store. Do not instantiate its serving store, -follow links, scan mail or touch client files. Unknown/corrupt managed metadata -fails closed with operator guidance; no guessed ownership. Cleanup is bounded -per entry and repeatable across restart; deletion failure never re-enables serving. - -## Cutover and acceptance - -Private real peers exercise ordinary TLS/ASGI/coordinator paths before public -activation. No public bypass flag or test fixture creates product authority. -Build and exercise every Go discovery/schema/error/invocation/artifact constructor -with the selected native factory through private real peers first. Keep production -constructor selection on the existing path until the same cut switches it to the -native factory, closes ordinary anonymous API and legacy artifact routes, and -enables the complete reviewed ordinary channel. That cut is `3.5.2`; `3.5.1` -does not switch the product to an unavailable server route. After cutover there -is no anonymous fallback or bypass flag. -Only minimal health and bounded enrollment bootstrap remain anonymous. Missing -authority or projection fails closed. Fixed controls stay distinct. The first -installed ordinary prefix includes denial and closed-artifact acceptance; these -are not deferred to a final release checklist. - -| ID | Required real acceptance, assigned to the owning cuts below | -| --- | --- | -| N01 | Python/Go strict mutual TLS; wrong server/ALPN/role/issuer/key/time, portable/cross-server/prepared-only state and forged proxy headers never dispatch. | -| N02 | Real outer relay observes no access identity, account, operation, body or secret; changed outer cert/URL and TCP passthrough preserve expected inner trust; wrong server fails before client credentials. | -| N03 | Exact moving pending-byte accounting, all framing/chain/handshake caps, slow bidirectional peers, fragmented/coalesced WS/TLS/HTTP and valid 1-MiB body; no lifetime-byte cap on ordinary streams. | -| N04 | Pre-body eight-worker admission, Content-Length/chunked limits and Expect behavior. Fill all eight with silent/drip-fed bodies; the absolute server deadline, delayed final fragment, denial and shutdown wake waits, prevent dispatch and recover capacity only on actual worker exit. Fragments/pings/reconnect wrappers do not extend it. Health/admin denial remain responsive. | -| N05 | Existing rows, exact receipts, opaque approval revision, denies, grants and original inactivity survive one-way upgrade/restart. Admission uses the existing canonical agent binding after old-row backfill, fresh activation and exact replay; missing/conflicting/corrupt relations fail closed without a second agent-ID copy. Ordinary access and receipt read one denial/cutoff authority; denial blocks both, and active contact refresh changes their shared cutoff without changing historical bytes. | -| N06 | Discovery/count/schema/policy/error/preview/direct paths reveal only granted accounts and use existing policies; account repoint and password renewal preserve grants. | -| N07 | Controlled real-socket deny/remove races at queued read, body, final dispatch and cross-connection output. Fixed receipts also race snapshot return, token admission, blocked output and final raw write against deny commit; cover rollback, unrelated enrollment/grant changes, disconnect and actual-owner cleanup. No post-barrier dispatch or unsent delivery; already handed-off bytes cannot be recalled. Receipt cases run with the first live deny control in 3.2.1. | -| N08 | Denial/disconnect with blocked upstream calls retains all eight workers and carrier owners until actual exit; no automatic retry or false promise to recall prior effects. | -| N09 | Actual artifact-producing plugin/Go request rejects before legacy store entry or filesystem/nonce/descriptor/inline publication; old routes fail, restart cleanup is confined and failure stays closed. | -| N10 | Every real CLI constructor, including error/tool/artifact paths, uses explicit selected enrollment and verified native factory after atomic client/server cutover; the preceding product prefix keeps its working route while private peers exercise the new factory. No general outer TLS exception, URL identity inference, redirect or uncertain-operation replay. | -| N11 | Existing connect/API/plugin/download idle budgets through real peers: slow connect, no early headers, long active call, ping-only traffic, slow progressing stream and cancellation. | -| N12 | Installed supported Python/Go/native OS/CPU prefix actually executes N01/N04/N07/N09/N10 plus focused relay/timeouts; CI required variables are present and tests do not silently skip. | - -Reuse `test_native_http_protocol`, `test_artifact_http_admission` real-socket -fixtures and the existing Python/Go peer, installed-CLI and terminal drivers. -Own shared harness additions once; add targeted later cases. No live mail account, -full duplicated installed adversarial matrix or production prototype is authorized -by this design. Dependency/source inspection establishes API feasibility only; -native execution is implementation acceptance, not evidence already obtained. - -## Already sized implementation proposal - -Numbers are handwritten added + deleted production, tests/fixtures and CI, -including code motion, shared helper ownership and review-correction headroom. -Docs/news/lock data are separate. These bottom-up ranges replace the historical -3350–5840 code/test forecast; they are estimates for review, not measured future -diffs, approved delivery counts or a dynamic-splitting allowance. Each upper bound -fits the existing 1000-line cap before implementation starts. If source evidence -invalidates a cut, return to design rather than hide a late split in execution. - -| ID | Complete consumed result, scope and focused checks | Production | Tests/fixtures | CI | Total | -| --- | --- | ---: | ---: | ---: | ---: | -| `3.1.1` | Shared bounded carrier/lease/TLS pump extracted and consumed by existing pairing/control and real streaming Python/Go peers. Own shared streaming harness. N03/N04; no ordinary public route. | 320–440 | 300–420 | 0–5 | 620–865 | -| `3.1.2` | Strict Python ordinary mTLS and immutable candidate identity consumed by real peer; live admission still private. N01 and handshake limits. | 170–240 | 310–420 | 0–5 | 480–665 | -| `3.1.3` | Go strict native identity/dial plus standard HTTP transport, exercised against real Python; reuse stored decoder and existing timeout wrapper. N01/N02/N11. | 190–260 | 300–410 | 0–5 | 490–675 | -| `3.1.4` | One-request bounded HTTP/ASGI stream with immutable scope, real body/response peers and no public cutover. N03/N04, parser/body admission. | 230–320 | 350–470 | 0–5 | 580–795 | -| `3.2.1` | Live row extension/atomic backfill and OS enrollment-deny control with minimal shared coordinator consumed by the real fixed receipt. Guard receipt admission and final output, retain actual owners and test N07 receipt races/rollback/cleanup. Use the existing agent binding without a row copy; validate old/fresh/replay and corrupt relations. Extend activation once; preserve original receipt. N05. | 230–330 | 420–610 | 0–5 | 650–945 | -| `3.2.2` | Extend the same coordinator/writer reservation to ordinary authority and actual-worker callbacks, consumed by private real ASGI peer. Own OS grant add/remove controls. N04/N05/N06/N07 dispatch, busy/rollback and no stale snapshot authorization. | 220–300 | 330–430 | 0–5 | 550–735 | -| `3.3` | All discovery/direct-account/policy projections use exact live grants with current schemas and private peer. N06 including negative information leaks. | 160–230 | 320–440 | 0–5 | 480–675 | -| `3.4` | Real authorized plugin dispatch with caller context, closed concrete artifact dependency, descriptor/inline closure and confined startup invalidation. N09 with spy plus filesystem; reuse shared harness. | 230–320 | 350–460 | 0–5 | 580–785 | -| `3.6.1` | Denial closes all affected body/dispatch paths across actual sockets; actual blocked work retains slots/carriers. N07/N08, cutoff/rollback and admin responsiveness. | 190–270 | 350–470 | 0–5 | 540–745 | -| `3.6.2` | Permission after backpressure and final ciphertext-write boundary, abort without flushing revoked output. N03/N07/N08 streaming/late-worker cases. | 150–220 | 330–450 | 0–5 | 480–675 | -| `3.5.1` | Explicit selector/config/help and every CLI constructor exercises the verified native factory through complete private real peers; production selection stays on the existing working route. N10/N11. | 130–180 | 320–410 | 0–5 | 450–595 | -| `3.5.2` | Atomic production CLI constructor switch, public ordinary enablement and anonymous API/artifact closure, with no fallback; first installed authenticated prefix executes denial and closed-artifact journey. N01/N04/N07/N09/N10/N12. | 110–190 | 380–510 | 0–5 | 490–705 | -| `3.7` | Focused installed relay/outer-cert/passthrough and timeout composition, native prefix/packaging closure; add no deferred core mechanism. N02/N11/N12 and all parent N01–N12. | 20–60 | 380–480 | 0–10 | 400–550 | - -Order follows the displayed rows; existing 3.1/3.2/3.5/3.6 parents retain their -identities and acceptance. `2.10.4` precedes `3.1.1`; `3.6.2` precedes public -cutover. Each source/peer foundation has an executable current consumer, not an -empty interface. 3.1.1 owns shared carrier/harness code motion; later cuts own -only incremental scenarios. 3.5.2 owns the first installed ordinary journey; -3.7 extends it, not creates a second harness. The revised cut ranges move -20–40 production and 30–50 focused regression lines from -`3.5.1` into `3.5.2` for their atomic production switch; they are not counted twice. -Receipt/coordinator ownership moves a net 20–30 production and 20–30 test lines -from `3.2.2` into `3.2.1`; ordinary grant controls move the other way. Existing -fixed-control real-socket fixtures support 100–150 additional receipt-race test -lines in `3.2.1`. These are estimates, counted once; later ordinary and installed -coverage extends the shared harness rather than repeating the receipt matrix. -The proposed 13 PRs and aggregate range require separate implementation -authorization. No milestone-2 allowance is -reused and no milestone-3 product work begins as part of this design PR. -Aggregate: 2,350–3,360 production, 4,440–5,980 tests/fixtures and 0–70 handwritten -CI lines, or 6,790–9,410 total. The larger test share includes real streaming, -revocation/worker-lifetime and cross-language composition at their owning cuts. - -Primary API references supporting the adapter choice: -[Python 3.10 protocol API](https://docs.python.org/3.10/library/asyncio-protocol.html), -[Python 3.10 SSL protocol source](https://github.com/python/cpython/blob/v3.10.19/Lib/asyncio/sslproto.py), -[pyOpenSSL memory-BIO API](https://pyopenssl.org/en/stable/api/ssl.html). -The implementation must validate the installed pinned versions and supported Go -floor rather than treat newer local library/source inspection as native proof. +# Native API detailed design: current location + +The current milestone-3 engineering contract is the [milestone-3 section of the +implementation plan](implementation-plan.md#milestone-3--native-transport-live-grants-and-denial). +Its ordered cuts are in the single [canonical inventory](slices.json). + +The [exact former native LLD](supporting/implementation-plan/historical-native-lld.md) +is retained as historical evidence, including its 13-cut churn forecast and prior +source baseline. Its old sidecar applies to those historical bytes only; this +navigation change does not transfer approval. The current design retains its +parent obligations and IDs, with current public interfaces and estimate units +defined by the requirements, approved HLD and current implementation plan. diff --git a/docs/authentication/overview.md b/docs/authentication/overview.md new file mode 100644 index 0000000..4170395 --- /dev/null +++ b/docs/authentication/overview.md @@ -0,0 +1,108 @@ +# Authentication: remaining work + +The goal is authenticated, owner-controlled Arbiter access with encrypted artifacts +and usable recovery. Milestones1–2 are merged, including portable enrollment at +a second server. The remaining design covers all milestones3–11. + +The [approved requirements](requirements.md) and [reviewed HLD](high-level-design.md) +keep identity separate from URL, local owner administration separate from client +access, live account grants, fixed credential deadlines, four explicit artifact +paths, offline owner recovery, complete backup/restore/undo and cooperative migration. + +The [detailed plan](implementation-plan.md) orders native transport/grants/denial, +lifecycle, owner recovery, server continuity, encrypted artifacts, client processing, +backup, restore/undo and migration. It reuses the current authority DB, carrier, +HTTP client, custody, generation and test-driver primitives. Shared foundations +and tests are charged once. [Before/after estimates](supporting/implementation-plan/estimate-comparison.md) +retain all51 cut IDs; old edit churn and new final-content lines are different units. + +**Next step:** affected review and owner approval of the complete detailed plan, +then separate implementation authorization. No product implementation is authorized. +No new material owner choice is pending in the draft. + +The generated table is a **definition-only view**, rendered without a delivery +campaign. Its Pending label means no execution evidence is attached to this +revised inventory, not that historical merged work should run again. The four +entries explicitly labelled Already merged retain their original planning state +and have zero remaining estimates. Replaced parents are rollups and are excluded +from project totals. A later delivery must use verified original completion receipts. + +Line ranges below are incremental final delivered production/test content, not +added-plus-deleted churn. The separate handwritten-CI forecast is in the comparison. + + +| Status | Slice ID | Short description | Production lines | Test lines | +| --- | --- | --- | ---: | ---: | +| ↪ Replaced | `arbiter-authentication/2` | Already merged: Pairing and durable enrollment | 0–0 | 0–0 | +| ↪ Replaced | `arbiter-authentication/2.10` | Already merged: Existing portable identity enrollment | 0–0 | 0–0 | +| ⏳ Pending | `arbiter-authentication/2.10.1` | Already merged: Local issuer trust and unique agent bindings | 0–0 | 0–0 | +| ⏳ Pending | `arbiter-authentication/2.10.2` | Already merged: Portable source custody and versioned codecs | 0–0 | 0–0 | +| ⏳ Pending | `arbiter-authentication/2.10.3` | Already merged: Prepared reuse and single activation | 0–0 | 0–0 | +| ⏳ Pending | `arbiter-authentication/2.10.4` | Already merged: Public CLI reuse and installed acceptance | 0–0 | 0–0 | +| ↪ Replaced | `arbiter-authentication/3` | Aggregate 3; execute its children | 2,020–2,990 | 3,730–5,210 | +| ↪ Replaced | `arbiter-authentication/3.1` | Aggregate 3.1; execute its children | 750–1,060 | 1,060–1,500 | +| ↪ Replaced | `arbiter-authentication/3.2` | Aggregate 3.2; execute its children | 410–590 | 650–900 | +| ↪ Replaced | `arbiter-authentication/3.5` | Aggregate 3.5; execute its children | 210–340 | 570–790 | +| ↪ Replaced | `arbiter-authentication/3.6` | Aggregate 3.6; execute its children | 290–440 | 580–810 | +| ↪ Replaced | `arbiter-authentication/4` | Aggregate 4; execute its children | 930–1,430 | 1,360–1,990 | +| ↪ Replaced | `arbiter-authentication/5` | Aggregate 5; execute its children | 1,150–1,730 | 1,440–2,120 | +| ↪ Replaced | `arbiter-authentication/6` | Aggregate 6; execute its children | 730–1,170 | 970–1,430 | +| ↪ Replaced | `arbiter-authentication/7` | Aggregate 7; execute its children | 960–1,540 | 1,470–2,200 | +| ↪ Replaced | `arbiter-authentication/8` | Aggregate 8; execute its children | 670–1,130 | 1,140–1,740 | +| ↪ Replaced | `arbiter-authentication/9` | Aggregate 9; execute its children | 860–1,370 | 1,240–1,870 | +| ↪ Replaced | `arbiter-authentication/10` | Aggregate 10; execute its children | 760–1,250 | 1,260–1,900 | +| ↪ Replaced | `arbiter-authentication/11` | Aggregate 11; execute its children | 380–670 | 780–1,170 | +| ⏳ Pending | `arbiter-authentication/3.1.1` | Shared bounded carrier and streaming peer | 220–310 | 250–360 | +| ⏳ Pending | `arbiter-authentication/3.1.2` | Strict ordinary server TLS peer | 150–220 | 260–370 | +| ⏳ Pending | `arbiter-authentication/3.1.3` | Verified Go native HTTP connection | 170–240 | 250–350 | +| ⏳ Pending | `arbiter-authentication/3.1.4` | One-request HTTP to ASGI stream | 210–290 | 300–420 | +| ⏳ Pending | `arbiter-authentication/3.2.1` | Live enrollment and receipt denial | 210–310 | 370–510 | +| ⏳ Pending | `arbiter-authentication/3.2.2` | Grant controls and dispatch coordinator | 200–280 | 280–390 | +| ⏳ Pending | `arbiter-authentication/3.3` | Grant-filtered discovery and direct lookup | 150–220 | 270–380 | +| ⏳ Pending | `arbiter-authentication/3.4` | Authorized plugins with closed artifacts | 190–280 | 300–410 | +| ⏳ Pending | `arbiter-authentication/3.6.1` | Cross-connection denial and worker ownership | 160–240 | 300–420 | +| ⏳ Pending | `arbiter-authentication/3.6.2` | Final-write revocation barrier | 130–200 | 280–390 | +| ⏳ Pending | `arbiter-authentication/3.5.1` | Explicit enrollment selection across CLI | 110–170 | 260–360 | +| ⏳ Pending | `arbiter-authentication/3.5.2` | Atomic authenticated API cutover | 100–170 | 310–430 | +| ⏳ Pending | `arbiter-authentication/3.7` | Installed native transport integration | 20–60 | 300–420 | +| ⏳ Pending | `arbiter-authentication/4.1` | Due rotation with a fixed deadline | 250–370 | 280–410 | +| ⏳ Pending | `arbiter-authentication/4.2` | Durable candidate activation and reconciliation | 280–390 | 320–450 | +| ⏳ Pending | `arbiter-authentication/4.3` | Purpose-bound late completion | 230–350 | 280–410 | +| ⏳ Pending | `arbiter-authentication/4.4` | One authenticated predecessor attempt | 140–230 | 210–320 | +| ⏳ Pending | `arbiter-authentication/4.5` | Lifecycle process and clock integration | 30–90 | 270–400 | +| ⏳ Pending | `arbiter-authentication/5.1` | Pairing repair of an existing enrollment | 170–270 | 230–350 | +| ⏳ Pending | `arbiter-authentication/5.2` | Offline owner authorization files | 240–360 | 300–420 | +| ⏳ Pending | `arbiter-authentication/5.3` | Atomic access recovery and exact receipt | 220–330 | 260–390 | +| ⏳ Pending | `arbiter-authentication/5.4` | Portable replacement across enrolled servers | 280–410 | 340–490 | +| ⏳ Pending | `arbiter-authentication/5.5` | Owner issuer and portable certificate renewal | 240–360 | 310–470 | +| ⏳ Pending | `arbiter-authentication/6.1` | Planned server-key transition publication | 190–300 | 230–340 | +| ⏳ Pending | `arbiter-authentication/6.2` | Verified server transition adoption | 170–280 | 240–350 | +| ⏳ Pending | `arbiter-authentication/6.3` | Independent compromise recovery | 190–300 | 260–380 | +| ⏳ Pending | `arbiter-authentication/6.4` | Server authority and leaf certificate renewal | 180–290 | 240–360 | +| ⏳ Pending | `arbiter-authentication/7.1` | Recipient possession and bounded retention | 180–280 | 220–330 | +| ⏳ Pending | `arbiter-authentication/7.2` | Dual-recipient encrypted artifact writing | 220–330 | 260–390 | +| ⏳ Pending | `arbiter-authentication/7.3` | Physical quotas and encrypted-store restart | 200–300 | 240–360 | +| ⏳ Pending | `arbiter-authentication/7.4` | Creator-bound descriptor HEAD and one GET | 190–290 | 260–380 | +| ⏳ Pending | `arbiter-authentication/7.5` | Encrypted plugin adapter activation | 140–240 | 230–340 | +| ⏳ Pending | `arbiter-authentication/7.6` | Encrypted-store contention and packaging | 30–100 | 260–400 | +| ⏳ Pending | `arbiter-authentication/8.1` | Immediate decrypted stdin with explicit stream flag | 170–270 | 220–340 | +| ↪ Replaced | `arbiter-authentication/8.2` | Verified ciphertext staging then stdin | 220–340 | 260–390 | +| ⏳ Pending | `arbiter-authentication/8.2.1` | Verified ciphertext staging then stdin | 220–340 | 260–390 | +| ⏳ Pending | `arbiter-authentication/8.3` | Explicit verified plaintext temporary path | 130–220 | 200–310 | +| ⏳ Pending | `arbiter-authentication/8.4` | Verified persistent plaintext export | 120–210 | 200–310 | +| ⏳ Pending | `arbiter-authentication/8.5` | Four-path installed process integration | 30–90 | 260–390 | +| ⏳ Pending | `arbiter-authentication/9.1` | Coherent saved configuration and actual secrets | 240–360 | 260–390 | +| ⏳ Pending | `arbiter-authentication/9.2` | Fenced SQLite and saved-state snapshot | 180–280 | 230–350 | +| ⏳ Pending | `arbiter-authentication/9.3` | Strict signed recovery stream format | 220–340 | 260–390 | +| ⏳ Pending | `arbiter-authentication/9.4` | Encrypted atomic local export | 200–310 | 240–360 | +| ⏳ Pending | `arbiter-authentication/9.5` | External backup job and snapshot integration | 20–80 | 250–380 | +| ⏳ Pending | `arbiter-authentication/10.1` | Strict offline decrypt and validation | 200–310 | 260–390 | +| ⏳ Pending | `arbiter-authentication/10.2` | Exclusive restore staging and cleanup | 180–280 | 230–350 | +| ⏳ Pending | `arbiter-authentication/10.3` | Atomic active and immutable undo publication | 190–300 | 260–390 | +| ⏳ Pending | `arbiter-authentication/10.4` | Repeatable latest undo and explicit discard | 160–260 | 230–350 | +| ⏳ Pending | `arbiter-authentication/10.5` | Native restore crash and client integration | 30–100 | 280–420 | +| ⏳ Pending | `arbiter-authentication/11.1` | Maintenance drain and cooperative migration | 170–280 | 240–360 | +| ⏳ Pending | `arbiter-authentication/11.2` | Authenticated fixed URL handoff | 180–290 | 240–370 | +| ⏳ Pending | `arbiter-authentication/11.3` | Multi-client migration and whole-auth integration | 30–100 | 300–440 | +| | **Project total** | Current slices; replaced parents excluded. | **8,460–13,280** | **13,390–19,630** | + diff --git a/docs/authentication/slices.json b/docs/authentication/slices.json new file mode 100644 index 0000000..a02e2f6 --- /dev/null +++ b/docs/authentication/slices.json @@ -0,0 +1,3106 @@ +{ + "schema_version": 2, + "slices": [ + { + "id": "arbiter-authentication/2", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2] Pairing and durable enrollment", + "responsibility": "Retain the original milestone-2 aggregate acceptance and immutable merged 2.1-2.9 delivery history; only its unimplemented 2.10 correction is admitted here.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "client/go-cli/internal/identity/enrollment_test.go", + "client/go-cli/internal/identity/pairing_peer_test.go", + "client/go-cli/internal/identity/portable.go", + "client/go-cli/internal/identity/portable_test.go", + "client/go-cli/internal/identity/prepared.go", + "client/go-cli/internal/identity/prepared_test.go", + "client/go-cli/internal/identity/provisional.go", + "client/go-cli/internal/identity/provisional_store.go", + "client/go-cli/internal/identity/provisional_test.go", + "client/go-cli/internal/identity/registration_peer_test.go", + "docs/enrollment.md", + "server/news/+portable-enrollment-activation.feature.md", + "server/news/+portable-enrollment.feature.md", + "server/news/+portable-identity-codecs.feature.md", + "server/news/+portable-issuer-controls.feature.md", + "server/src/arbiter_server/authority.py", + "server/src/arbiter_server/enrollment.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/issuer_admin.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_issuers.py", + "server/src/arbiter_server/prepared.py", + "server/tests/integration/enrollment_terminal_driver.py", + "server/tests/integration/test_enrollment_cli_peer.py", + "server/tests/integration/test_enrollment_receipt_peer.py", + "server/tests/integration/test_installed_enrollment.py", + "server/tests/integration/test_provisional_peer.py", + "server/tests/unit/test_authority.py", + "server/tests/unit/test_enrollment_activation.py", + "server/tests/unit/test_enrollment_requests.py", + "server/tests/unit/test_local_control.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_owner_issuers.py", + "server/tests/unit/test_prepared.py", + "server/tests/unit/test_windows_control.py" + ], + "dependencies": [], + "acceptance": [ + "Preserve merged fresh pairing and receipt behavior; ordinary milestone-3 API remains unchanged." + ] + }, + "display": { + "summary": "Already merged: Pairing and durable enrollment", + "production": [ + 0, + 0 + ], + "tests": [ + 0, + 0 + ] + } + }, + { + "id": "arbiter-authentication/2.10", + "parent": "arbiter-authentication/2", + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10] Existing portable identity enrollment", + "responsibility": "Close only portable LLD P01-P10 through the four already reviewed cuts; preserve original 22 spent attempts and all historical delivery identities.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "client/go-cli/internal/identity/enrollment_test.go", + "client/go-cli/internal/identity/pairing_peer_test.go", + "client/go-cli/internal/identity/portable.go", + "client/go-cli/internal/identity/portable_test.go", + "client/go-cli/internal/identity/prepared.go", + "client/go-cli/internal/identity/prepared_test.go", + "client/go-cli/internal/identity/provisional.go", + "client/go-cli/internal/identity/provisional_store.go", + "client/go-cli/internal/identity/provisional_test.go", + "client/go-cli/internal/identity/registration_peer_test.go", + "docs/enrollment.md", + "server/news/+portable-enrollment-activation.feature.md", + "server/news/+portable-enrollment.feature.md", + "server/news/+portable-identity-codecs.feature.md", + "server/news/+portable-issuer-controls.feature.md", + "server/src/arbiter_server/authority.py", + "server/src/arbiter_server/enrollment.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/issuer_admin.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_issuers.py", + "server/src/arbiter_server/prepared.py", + "server/tests/integration/enrollment_terminal_driver.py", + "server/tests/integration/test_enrollment_cli_peer.py", + "server/tests/integration/test_enrollment_receipt_peer.py", + "server/tests/integration/test_installed_enrollment.py", + "server/tests/integration/test_provisional_peer.py", + "server/tests/unit/test_authority.py", + "server/tests/unit/test_enrollment_activation.py", + "server/tests/unit/test_enrollment_requests.py", + "server/tests/unit/test_local_control.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_owner_issuers.py", + "server/tests/unit/test_prepared.py", + "server/tests/unit/test_windows_control.py" + ], + "dependencies": [], + "acceptance": [ + "Real A/B/Go journey preserves agent ID/portable key/certificate and fresh independent B access/grants." + ] + }, + "display": { + "summary": "Already merged: Existing portable identity enrollment", + "production": [ + 0, + 0 + ], + "tests": [ + 0, + 0 + ] + } + }, + { + "id": "arbiter-authentication/2.10.1", + "parent": "arbiter-authentication/2.10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10.1] Local issuer trust and unique agent bindings", + "responsibility": "Implement the portable LLD first cut: OS-local issuer controls, exact certificate fingerprint trust, atomic schema/backfill and binding maintenance in every fresh-v1 activation/replay. Requires the merged 25a8cf2 fresh-enrollment baseline. No public reuse or milestone-3 work.", + "paths": [ + "server/src/arbiter_server/authority.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/owner_issuers.py", + "server/src/arbiter_server/issuer_admin.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/tests/unit/test_owner_issuers.py", + "server/tests/unit/test_authority.py", + "server/tests/unit/test_local_control.py", + "server/tests/unit/test_windows_control.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_enrollment_activation.py", + "server/news/+portable-issuer-controls.feature.md", + "docs/enrollment.md" + ], + "dependencies": [], + "acceptance": [ + "P02/P06/P09: exact issuer registration, removal/reactivation and revision; invalid profile rejected and local control remains OS authenticated.", + "Atomic migration preserves real old results/denial and rejects duplicate or malformed bindings.", + "Real post-upgrade fresh-v1 activation/replay/rollback maintains one agent/enrollment mapping, including later denied or inactive enrollments.", + "Retain 610-865 changed handwritten code/test/CI estimate and <=1000 hard cap." + ] + }, + "display": { + "summary": "Already merged: Local issuer trust and unique agent bindings", + "production": [ + 0, + 0 + ], + "tests": [ + 0, + 0 + ] + } + }, + { + "id": "arbiter-authentication/2.10.2", + "parent": "arbiter-authentication/2.10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10.2] Portable source custody and versioned codecs", + "responsibility": "Implement the portable LLD second cut: strict enrolled-source loading and v2 private/public codecs consumed by executable Python/Go peers; reuse the native publisher and shared decoder with purpose-specific checks. Public reuse remains unreachable.", + "paths": [ + "client/go-cli/internal/identity/provisional.go", + "client/go-cli/internal/identity/provisional_store.go", + "client/go-cli/internal/identity/prepared.go", + "client/go-cli/internal/identity/portable.go", + "client/go-cli/internal/identity/provisional_test.go", + "client/go-cli/internal/identity/prepared_test.go", + "client/go-cli/internal/identity/portable_test.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "server/src/arbiter_server/enrollment.py", + "server/tests/unit/test_enrollment_requests.py", + "server/tests/integration/test_provisional_peer.py", + "server/news/+portable-identity-codecs.feature.md", + "docs/enrollment.md", + "client/go-cli/internal/identity/pairing_peer_test.go", + "client/go-cli/internal/identity/registration_peer_test.go" + ], + "dependencies": [ + "arbiter-authentication/2.10.1" + ], + "acceptance": [ + "P03/P08: reject altered source ID/key/certificate/hash, unsafe custody and prepared-only source; source bytes stay unchanged.", + "Source loading accepts a currently valid portable identity without A online or an A access-lifetime requirement.", + "Preserve old v1 stored-record/result receipt decoding and its historical portable validation; never relax ordinary TLS or new-enrollment validity.", + "Retain 490-695 changed handwritten code/test/CI estimate and <=1000 hard cap." + ] + }, + "display": { + "summary": "Already merged: Portable source custody and versioned codecs", + "production": [ + 0, + 0 + ], + "tests": [ + 0, + 0 + ] + } + }, + { + "id": "arbiter-authentication/2.10.3", + "parent": "arbiter-authentication/2.10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10.3] Prepared reuse and single activation", + "responsibility": "Implement the portable LLD third cut through existing preparation/proofs and atomic activation, extending the same binding writer. Exercise real A/B/Go peers with fresh B access, explicit issuer trust/approval and exact receipt recovery. Public v2 remains closed.", + "paths": [ + "server/src/arbiter_server/prepared.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/enrollment.py", + "server/src/arbiter_server/owner_issuers.py", + "server/tests/unit/test_prepared.py", + "server/tests/unit/test_enrollment_activation.py", + "server/tests/integration/test_enrollment_cli_peer.py", + "server/tests/integration/test_enrollment_receipt_peer.py", + "client/go-cli/internal/identity/prepared.go", + "client/go-cli/internal/identity/prepared_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_test.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "server/news/+portable-enrollment-activation.feature.md", + "docs/enrollment.md", + "client/go-cli/internal/identity/pairing_peer_test.go", + "client/go-cli/internal/identity/registration_peer_test.go" + ], + "dependencies": [ + "arbiter-authentication/2.10.2" + ], + "acceptance": [ + "P01/P03/P05/P06/P07: preserve original agent/portable identity, generate independent B access/enrollment/recipient state; A may be offline.", + "Existing active/denied/inactive B binding rejects reuse, including real fresh-v1 enrollments created on both earlier upgraded prefixes.", + "Trust-revision removal/ready/commit races fail or reconcile once; lost final reply/restart/expiry returns the exact committed result.", + "Retain 550-745 changed handwritten code/test/CI estimate and <=1000 hard cap." + ] + }, + "display": { + "summary": "Already merged: Prepared reuse and single activation", + "production": [ + 0, + 0 + ], + "tests": [ + 0, + 0 + ] + } + }, + { + "id": "arbiter-authentication/2.10.4", + "parent": "arbiter-authentication/2.10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10.4] Public CLI reuse and installed acceptance", + "responsibility": "Implement the portable LLD fourth cut: explicit identity source selection, atomic v2-only public registration switch, installed A/B and fresh regression journeys, final migration/help/news and complete P01-P10 acceptance. Preserve all platforms and existing test harnesses.", + "paths": [ + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/provisional_session.go", + "client/go-cli/internal/identity/registration_peer_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_test.go", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/enrollment.py", + "server/tests/unit/test_enrollment_requests.py", + "server/tests/unit/test_enrollment_admin.py", + "server/tests/unit/test_main.py", + "server/tests/integration/enrollment_terminal_driver.py", + "server/tests/integration/test_installed_enrollment.py", + ".github/workflows/ci.yml", + "server/news/+portable-enrollment.feature.md", + "docs/enrollment.md" + ], + "dependencies": [ + "arbiter-authentication/2.10.3" + ], + "acceptance": [ + "P04/P08/P10 and all P01-P10: installed CLI completes fresh/reused enrollment and recovery on native CI; existing admission/time/attempt limits remain.", + "Reject identity plus resume, same-server reuse, unknown/invalid source and old public wire with actionable diagnostics and no saved identity deletion.", + "Confirm public server/client switch together, v1 saved receipt recovery survives, no live accounts and no milestone-3 API changes.", + "Retain 500-710 changed handwritten code/test/CI estimate and <=1000 hard cap." + ] + }, + "display": { + "summary": "Already merged: Public CLI reuse and installed acceptance", + "production": [ + 0, + 0 + ], + "tests": [ + 0, + 0 + ] + } + }, + { + "id": "arbiter-authentication/3", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3] Milestone 3 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/arbiterhttp/client.go", + "client/go-cli/internal/arbiterhttp/client_test.go", + "client/go-cli/internal/arbiterhttp/timeouts.go", + "client/go-cli/internal/arbiterhttp/timeouts_test.go", + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-1-1.feature.md", + "server/news/+auth-3-1-2.feature.md", + "server/news/+auth-3-1-3.feature.md", + "server/news/+auth-3-1-4.feature.md", + "server/news/+auth-3-2-1.feature.md", + "server/news/+auth-3-2-2.feature.md", + "server/news/+auth-3-3.feature.md", + "server/news/+auth-3-4.feature.md", + "server/news/+auth-3-5-1.feature.md", + "server/news/+auth-3-5-2.feature.md", + "server/news/+auth-3-6-1.feature.md", + "server/news/+auth-3-6-2.feature.md", + "server/news/+auth-3-7.feature.md", + "server/pyproject.toml", + "server/src/arbiter_server/artifacts.py", + "server/src/arbiter_server/control_tls.py", + "server/src/arbiter_server/credentials.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/enrollment_receipt.py", + "server/src/arbiter_server/http_work.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/native_http.py", + "server/src/arbiter_server/native_stream.py", + "server/src/arbiter_server/pairing_carrier.py", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/integration/test_installed_authentication.py", + "server/tests/unit/test_artifact_http_admission.py", + "server/tests/unit/test_artifacts.py", + "server/tests/unit/test_control_tls.py", + "server/tests/unit/test_credentials.py", + "server/tests/unit/test_enrollment_live.py", + "server/tests/unit/test_enrollment_receipt.py", + "server/tests/unit/test_live_authority.py", + "server/tests/unit/test_local_control.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_native_http_protocol.py", + "server/tests/unit/test_native_stream.py", + "server/tests/unit/test_pairing_carrier.py", + "skill/SKILL.md" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 3; execute its children", + "production": [ + 2020, + 2990 + ], + "tests": [ + 3730, + 5210 + ] + } + }, + { + "id": "arbiter-authentication/3.1", + "parent": "arbiter-authentication/3", + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.1] Milestone 3.1 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/arbiterhttp/client.go", + "client/go-cli/internal/arbiterhttp/client_test.go", + "client/go-cli/internal/arbiterhttp/timeouts.go", + "client/go-cli/internal/arbiterhttp/timeouts_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-1-1.feature.md", + "server/news/+auth-3-1-2.feature.md", + "server/news/+auth-3-1-3.feature.md", + "server/news/+auth-3-1-4.feature.md", + "server/pyproject.toml", + "server/src/arbiter_server/control_tls.py", + "server/src/arbiter_server/credentials.py", + "server/src/arbiter_server/http_work.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/native_http.py", + "server/src/arbiter_server/native_stream.py", + "server/src/arbiter_server/pairing_carrier.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_artifact_http_admission.py", + "server/tests/unit/test_control_tls.py", + "server/tests/unit/test_credentials.py", + "server/tests/unit/test_native_http_protocol.py", + "server/tests/unit/test_native_stream.py", + "server/tests/unit/test_pairing_carrier.py" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 3.1; execute its children", + "production": [ + 750, + 1060 + ], + "tests": [ + 1060, + 1500 + ] + } + }, + { + "id": "arbiter-authentication/3.2", + "parent": "arbiter-authentication/3", + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.2] Milestone 3.2 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-2-1.feature.md", + "server/news/+auth-3-2-2.feature.md", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/enrollment_receipt.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_enrollment_live.py", + "server/tests/unit/test_enrollment_receipt.py", + "server/tests/unit/test_local_control.py" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 3.2; execute its children", + "production": [ + 410, + 590 + ], + "tests": [ + 650, + 900 + ] + } + }, + { + "id": "arbiter-authentication/3.5", + "parent": "arbiter-authentication/3", + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.5] Milestone 3.5 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + "client/go-cli/internal/arbiterhttp/client.go", + "client/go-cli/internal/arbiterhttp/client_test.go", + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-5-1.feature.md", + "server/news/+auth-3-5-2.feature.md", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_native_http_protocol.py", + "skill/SKILL.md" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 3.5; execute its children", + "production": [ + 210, + 340 + ], + "tests": [ + 570, + 790 + ] + } + }, + { + "id": "arbiter-authentication/3.6", + "parent": "arbiter-authentication/3", + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.6] Milestone 3.6 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-6-1.feature.md", + "server/news/+auth-3-6-2.feature.md", + "server/src/arbiter_server/http_work.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/native_http.py", + "server/src/arbiter_server/native_stream.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_live_authority.py", + "server/tests/unit/test_native_http_protocol.py", + "server/tests/unit/test_native_stream.py" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 3.6; execute its children", + "production": [ + 290, + 440 + ], + "tests": [ + 580, + 810 + ] + } + }, + { + "id": "arbiter-authentication/4", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/4] Milestone 4 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + "client/go-cli/internal/arbiterhttp/client.go", + "client/go-cli/internal/arbiterhttp/client_test.go", + "client/go-cli/internal/arbiterhttp/timeouts.go", + "client/go-cli/internal/arbiterhttp/timeouts_test.go", + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "client/go-cli/internal/identity/lifecycle.go", + "client/go-cli/internal/identity/lifecycle_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "docs/authentication-cli.md", + "server/news/+auth-4-1.feature.md", + "server/news/+auth-4-2.feature.md", + "server/news/+auth-4-3.feature.md", + "server/news/+auth-4-4.feature.md", + "server/news/+auth-4-5.feature.md", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/lifecycle.py", + "server/src/arbiter_server/lifecycle_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/native_http.py", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/integration/test_installed_authentication.py", + "server/tests/unit/test_lifecycle.py", + "server/tests/unit/test_lifecycle_control.py", + "server/tests/unit/test_native_http_protocol.py" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 4; execute its children", + "production": [ + 930, + 1430 + ], + "tests": [ + 1360, + 1990 + ] + } + }, + { + "id": "arbiter-authentication/5", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/5] Milestone 5 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/credentials.go", + "client/go-cli/internal/identity/credentials_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_test.go", + "client/go-cli/internal/identity/lifecycle.go", + "client/go-cli/internal/identity/lifecycle_test.go", + "client/go-cli/internal/identity/portable.go", + "client/go-cli/internal/identity/portable_test.go", + "client/go-cli/internal/identity/recovery.go", + "client/go-cli/internal/identity/recovery_test.go", + "docs/authentication-cli.md", + "server/news/+auth-5-1.feature.md", + "server/news/+auth-5-2.feature.md", + "server/news/+auth-5-3.feature.md", + "server/news/+auth-5-4.feature.md", + "server/news/+auth-5-5.feature.md", + "server/src/arbiter_server/credentials.py", + "server/src/arbiter_server/enrollment.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/lifecycle.py", + "server/src/arbiter_server/lifecycle_control.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_issuers.py", + "server/src/arbiter_server/owner_recovery.py", + "server/src/arbiter_server/prepared.py", + "server/src/arbiter_server/recovery.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_credentials.py", + "server/tests/unit/test_enrollment_activation.py", + "server/tests/unit/test_owner_issuers.py", + "server/tests/unit/test_owner_recovery.py", + "server/tests/unit/test_recovery.py", + "skill/SKILL.md" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 5; execute its children", + "production": [ + 1150, + 1730 + ], + "tests": [ + 1440, + 2120 + ] + } + }, + { + "id": "arbiter-authentication/6", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/6] Milestone 6 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "client/go-cli/internal/identity/server_transition.go", + "client/go-cli/internal/identity/server_transition_test.go", + "docs/authentication-cli.md", + "server/news/+auth-6-1.feature.md", + "server/news/+auth-6-2.feature.md", + "server/news/+auth-6-3.feature.md", + "server/news/+auth-6-4.feature.md", + "server/src/arbiter_server/credentials.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/lifecycle_control.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_recovery.py", + "server/src/arbiter_server/recovery.py", + "server/src/arbiter_server/server_transition.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_credentials.py", + "server/tests/unit/test_generations.py", + "server/tests/unit/test_owner_recovery.py", + "server/tests/unit/test_server_transition.py", + "skill/SKILL.md" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 6; execute its children", + "production": [ + 730, + 1170 + ], + "tests": [ + 970, + 1430 + ] + } + }, + { + "id": "arbiter-authentication/7", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/7] Milestone 7 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/recipient.go", + "client/go-cli/internal/identity/recipient_test.go", + "docs/authentication-cli.md", + "server/news/+auth-7-1.feature.md", + "server/news/+auth-7-2.feature.md", + "server/news/+auth-7-3.feature.md", + "server/news/+auth-7-4.feature.md", + "server/news/+auth-7-5.feature.md", + "server/news/+auth-7-6.feature.md", + "server/pyproject.toml", + "server/src/arbiter_server/artifact_crypto.py", + "server/src/arbiter_server/artifacts.py", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/http_work.py", + "server/src/arbiter_server/lifecycle_control.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/integration/test_installed_authentication.py", + "server/tests/unit/test_artifact_crypto.py", + "server/tests/unit/test_artifact_http_admission.py", + "server/tests/unit/test_artifacts.py", + "server/tests/unit/test_native_http_protocol.py" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 7; execute its children", + "production": [ + 960, + 1540 + ], + "tests": [ + 1470, + 2200 + ] + } + }, + { + "id": "arbiter-authentication/8", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/8] Milestone 8 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/cli/artifact_crypto.go", + "client/go-cli/internal/cli/artifact_crypto_test.go", + "client/go-cli/internal/cli/artifact_temp.go", + "client/go-cli/internal/cli/artifact_temp_test.go", + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-8-1.feature.md", + "server/news/+auth-8-2.feature.md", + "server/news/+auth-8-3.feature.md", + "server/news/+auth-8-4.feature.md", + "server/news/+auth-8-5.feature.md", + "server/pyproject.toml", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/integration/test_installed_authentication.py", + "skill/SKILL.md" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 8; execute its children", + "production": [ + 670, + 1130 + ], + "tests": [ + 1140, + 1740 + ] + } + }, + { + "id": "arbiter-authentication/9", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/9] Milestone 9 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-9-1.feature.md", + "server/news/+auth-9-2.feature.md", + "server/news/+auth-9-3.feature.md", + "server/news/+auth-9-4.feature.md", + "server/news/+auth-9-5.feature.md", + "server/pyproject.toml", + "server/src/arbiter_server/backup_format.py", + "server/src/arbiter_server/backups.py", + "server/src/arbiter_server/config.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/integration/test_installed_authentication.py", + "server/tests/unit/test_backup_format.py", + "server/tests/unit/test_backups.py", + "server/tests/unit/test_config.py", + "server/tests/unit/test_generations.py", + "server/tests/unit/test_local_control.py", + "skill/SKILL.md" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 9; execute its children", + "production": [ + 860, + 1370 + ], + "tests": [ + 1240, + 1870 + ] + } + }, + { + "id": "arbiter-authentication/10", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/10] Milestone 10 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-10-1.feature.md", + "server/news/+auth-10-2.feature.md", + "server/news/+auth-10-3.feature.md", + "server/news/+auth-10-4.feature.md", + "server/news/+auth-10-5.feature.md", + "server/pyproject.toml", + "server/src/arbiter_server/authority.py", + "server/src/arbiter_server/backup_format.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/recovery.py", + "server/src/arbiter_server/restore.py", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/integration/test_installed_authentication.py", + "server/tests/unit/test_backup_format.py", + "server/tests/unit/test_generations.py", + "server/tests/unit/test_restore.py", + "skill/SKILL.md" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 10; execute its children", + "production": [ + 760, + 1250 + ], + "tests": [ + 1260, + 1900 + ] + } + }, + { + "id": "arbiter-authentication/11", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/11] Milestone 11 aggregate acceptance", + "responsibility": "Retain this existing parent identity and the complete aggregate approved behavior; execution responsibility belongs to its ordered children, not another implementation reservation.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "client/go-cli/internal/identity/server_transition.go", + "client/go-cli/internal/identity/server_transition_test.go", + "docs/authentication-cli.md", + "server/news/+auth-11-1.feature.md", + "server/news/+auth-11-2.feature.md", + "server/news/+auth-11-3.feature.md", + "server/pyproject.toml", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/maintenance.py", + "server/src/arbiter_server/server_transition.py", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/integration/test_installed_authentication.py", + "server/tests/unit/test_local_control.py", + "server/tests/unit/test_maintenance.py", + "server/tests/unit/test_server_transition.py", + "skill/SKILL.md" + ], + "dependencies": [], + "acceptance": [ + "All descendant behavior, parent prose and integrated acceptance in implementation-plan.md pass on current final child heads." + ] + }, + "display": { + "summary": "Aggregate 11; execute its children", + "production": [ + 380, + 670 + ], + "tests": [ + 780, + 1170 + ] + } + }, + { + "id": "arbiter-authentication/3.1.1", + "parent": "arbiter-authentication/3.1", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.1.1] Shared bounded carrier and streaming peer", + "responsibility": "Extract the existing carrier lease, credit ledger and serialized BIO pump once, consumed by unchanged pairing/control and a private real streaming peer. Own the shared streaming harness. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-1-1.feature.md", + "server/pyproject.toml", + "server/src/arbiter_server/control_tls.py", + "server/src/arbiter_server/native_stream.py", + "server/src/arbiter_server/pairing_carrier.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_control_tls.py", + "server/tests/unit/test_native_stream.py", + "server/tests/unit/test_pairing_carrier.py" + ], + "dependencies": [ + "arbiter-authentication/2.10.4" + ], + "acceptance": [ + "Fragment/coalesce WS/TLS in both directions, force WantRead/WantWrite and cancellation; actual crypto owners retain credits and leases; no public ordinary route." + ] + }, + "display": { + "summary": "Shared bounded carrier and streaming peer", + "production": [ + 220, + 310 + ], + "tests": [ + 250, + 360 + ] + } + }, + { + "id": "arbiter-authentication/3.1.2", + "parent": "arbiter-authentication/3.1", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.1.2] Strict ordinary server TLS peer", + "responsibility": "Add strict ordinary mutual TLS and immutable candidate identity on the shared pump, still private until live admission and public cutover. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-1-2.feature.md", + "server/src/arbiter_server/credentials.py", + "server/src/arbiter_server/native_stream.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_credentials.py", + "server/tests/unit/test_native_stream.py" + ], + "dependencies": [ + "arbiter-authentication/3.1.1" + ], + "acceptance": [ + "Reject wrong role/server/issuer/key/time/ALPN, portable and prepared-only identity; execute a real Go/Python peer and bounded handshake failures." + ] + }, + "display": { + "summary": "Strict ordinary server TLS peer", + "production": [ + 150, + 220 + ], + "tests": [ + 260, + 370 + ] + } + }, + { + "id": "arbiter-authentication/3.1.3", + "parent": "arbiter-authentication/3.1", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.1.3] Verified Go native HTTP connection", + "responsibility": "Reuse the Go WebSocket adapter and http.Transport/TimeoutTransport with selected expected-server identity and strict access credentials. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/arbiterhttp/client.go", + "client/go-cli/internal/arbiterhttp/client_test.go", + "client/go-cli/internal/arbiterhttp/timeouts.go", + "client/go-cli/internal/arbiterhttp/timeouts_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-1-3.feature.md", + "server/tests/integration/test_authentication_peer.py" + ], + "dependencies": [ + "arbiter-authentication/3.1.2" + ], + "acceptance": [ + "Untrusted outer relay sees no native credentials or plaintext; wrong server fails before client certificate; redirects and uncertain operation replay are absent." + ] + }, + "display": { + "summary": "Verified Go native HTTP connection", + "production": [ + 170, + 240 + ], + "tests": [ + 250, + 350 + ] + } + }, + { + "id": "arbiter-authentication/3.1.4", + "parent": "arbiter-authentication/3.1", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.1.4] One-request HTTP to ASGI stream", + "responsibility": "Consume the strict stream through h11 into the real ASGI application with immutable candidate scope, header/body limits and existing worker/body admission. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-1-4.feature.md", + "server/src/arbiter_server/http_work.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/native_http.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_artifact_http_admission.py", + "server/tests/unit/test_native_http_protocol.py" + ], + "dependencies": [ + "arbiter-authentication/3.1.3" + ], + "acceptance": [ + "Real chunked/coalesced bodies, Expect, ambiguous framing, second request, drip/silent body and response backpressure stay bounded without public cutover." + ] + }, + "display": { + "summary": "One-request HTTP to ASGI stream", + "production": [ + 210, + 290 + ], + "tests": [ + 300, + 420 + ] + } + }, + { + "id": "arbiter-authentication/3.2.1", + "parent": "arbiter-authentication/3.2", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.2.1] Live enrollment and receipt denial", + "responsibility": "Upgrade live enrollment rows and grants atomically, retain sole agent_enrollments mapping and exact prepared history; introduce one coordinator consumed by local deny and fixed receipt output. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-2-1.feature.md", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/enrollment_receipt.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_enrollment_live.py", + "server/tests/unit/test_enrollment_receipt.py", + "server/tests/unit/test_local_control.py" + ], + "dependencies": [ + "arbiter-authentication/3.1.4" + ], + "acceptance": [ + "Old/fresh/replay/corrupt rows, deny-versus-receipt snapshot/token/final-write races, rollback and actual cleanup use the same denial/cutoff authority." + ] + }, + "display": { + "summary": "Live enrollment and receipt denial", + "production": [ + 210, + 310 + ], + "tests": [ + 370, + 510 + ] + } + }, + { + "id": "arbiter-authentication/3.2.2", + "parent": "arbiter-authentication/3.2", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.2.2] Grant controls and dispatch coordinator", + "responsibility": "Extend that coordinator to ordinary body/dispatch tokens and OS-local grant add/remove, reusing existing admin and plugin workers. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-2-2.feature.md", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/enrollment_receipt.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_enrollment_live.py", + "server/tests/unit/test_enrollment_receipt.py", + "server/tests/unit/test_local_control.py" + ], + "dependencies": [ + "arbiter-authentication/3.2.1" + ], + "acceptance": [ + "Wrong/removed accounts never dispatch; writer busy/rollback/unrelated changes and final plugin-entry handoff preserve live authority and worker ownership." + ] + }, + "display": { + "summary": "Grant controls and dispatch coordinator", + "production": [ + 200, + 280 + ], + "tests": [ + 280, + 390 + ] + } + }, + { + "id": "arbiter-authentication/3.3", + "parent": "arbiter-authentication/3", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.3] Grant-filtered discovery and direct lookup", + "responsibility": "Apply one grant projection to overview/catalog/schema/policy/preview/direct-account paths without a new policy engine. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-3.feature.md", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_native_http_protocol.py" + ], + "dependencies": [ + "arbiter-authentication/3.2.2" + ], + "acceptance": [ + "Names, counts, guidance and errors leak no hidden accounts; password change and deliberate name repoint preserve grants; policy behavior remains existing." + ] + }, + "display": { + "summary": "Grant-filtered discovery and direct lookup", + "production": [ + 150, + 220 + ], + "tests": [ + 270, + 380 + ] + } + }, + { + "id": "arbiter-authentication/3.4", + "parent": "arbiter-authentication/3", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.4] Authorized plugins with closed artifacts", + "responsibility": "Set immutable caller/account context in actual plugin workers; install the closed concrete artifact adapter and close descriptor/inline paths before legacy access. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-4.feature.md", + "server/src/arbiter_server/artifacts.py", + "server/src/arbiter_server/http_work.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_artifacts.py", + "server/tests/unit/test_native_http_protocol.py" + ], + "dependencies": [ + "arbiter-authentication/3.3" + ], + "acceptance": [ + "Spy plus actual managed files show no legacy create/open/nonce/descriptor publication; startup cleanup is confined, repeatable and fail-closed." + ] + }, + "display": { + "summary": "Authorized plugins with closed artifacts", + "production": [ + 190, + 280 + ], + "tests": [ + 300, + 410 + ] + } + }, + { + "id": "arbiter-authentication/3.6.1", + "parent": "arbiter-authentication/3.6", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.6.1] Cross-connection denial and worker ownership", + "responsibility": "Complete body and dispatch cancellation on all affected sockets while real blocking upstream owners retain their worker/carrier slots. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-6-1.feature.md", + "server/src/arbiter_server/http_work.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/native_http.py", + "server/src/arbiter_server/native_stream.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_live_authority.py", + "server/tests/unit/test_native_http_protocol.py", + "server/tests/unit/test_native_stream.py" + ], + "dependencies": [ + "arbiter-authentication/3.4" + ], + "acceptance": [ + "Barrier races before/after plugin handoff, all-eight blocked workers, rollback, shutdown and unrelated grants preserve admin/health responsiveness and honest prior effects." + ] + }, + "display": { + "summary": "Cross-connection denial and worker ownership", + "production": [ + 160, + 240 + ], + "tests": [ + 300, + 420 + ] + } + }, + { + "id": "arbiter-authentication/3.6.2", + "parent": "arbiter-authentication/3.6", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.6.2] Final-write revocation barrier", + "responsibility": "Check permissions after every output wait and immediately before final synchronous ciphertext write; discard unsent revoked bytes without flushing. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-6-2.feature.md", + "server/src/arbiter_server/http_work.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/native_http.py", + "server/src/arbiter_server/native_stream.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_live_authority.py", + "server/tests/unit/test_native_http_protocol.py", + "server/tests/unit/test_native_stream.py" + ], + "dependencies": [ + "arbiter-authentication/3.6.1" + ], + "acceptance": [ + "Slow readers, queued TLS/WS output, late worker results and denial on another connection cannot release ownership early or send post-barrier unsent data." + ] + }, + "display": { + "summary": "Final-write revocation barrier", + "production": [ + 130, + 200 + ], + "tests": [ + 280, + 390 + ] + } + }, + { + "id": "arbiter-authentication/3.5.1", + "parent": "arbiter-authentication/3.5", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.5.1] Explicit enrollment selection across CLI", + "responsibility": "Add config/override selection and exercise every discovery/schema/error/op/tool/artifact constructor against private complete native peers; retain working production route until cutover. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-5-1.feature.md", + "server/tests/integration/test_authentication_peer.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/3.6.2" + ], + "acceptance": [ + "No first-record/URL identity inference; override wins for one invocation; every constructor uses the selected factory; no general outer trust bypass." + ] + }, + "display": { + "summary": "Explicit enrollment selection across CLI", + "production": [ + 110, + 170 + ], + "tests": [ + 260, + 360 + ] + } + }, + { + "id": "arbiter-authentication/3.5.2", + "parent": "arbiter-authentication/3.5", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.5.2] Atomic authenticated API cutover", + "responsibility": "Switch production CLI factory, enable complete ordinary native route and close anonymous API/legacy artifacts in one cut; keep minimal bootstrap/health. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/arbiterhttp/client.go", + "client/go-cli/internal/arbiterhttp/client_test.go", + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-5-2.feature.md", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_native_http_protocol.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/3.5.1" + ], + "acceptance": [ + "First installed authenticated prefix runs grants, live denial, body deadlines and closed-artifact cases; missing authority fails closed with no anonymous fallback." + ] + }, + "display": { + "summary": "Atomic authenticated API cutover", + "production": [ + 100, + 170 + ], + "tests": [ + 310, + 430 + ] + } + }, + { + "id": "arbiter-authentication/3.7", + "parent": "arbiter-authentication/3", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/3.7] Installed native transport integration", + "responsibility": "Extend the same installed driver for relay/certificate/passthrough/timeouts/native packaging and parent N01\u2013N12 composition. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-3-7.feature.md", + "server/pyproject.toml", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_installed_authentication.py" + ], + "dependencies": [ + "arbiter-authentication/3.5.2" + ], + "acceptance": [ + "Required native jobs actually execute, not skip; active long calls and progressing downloads keep original budgets; no deferred transport mechanism is introduced." + ] + }, + "display": { + "summary": "Installed native transport integration", + "production": [ + 20, + 60 + ], + "tests": [ + 300, + 420 + ] + } + }, + { + "id": "arbiter-authentication/4.1", + "parent": "arbiter-authentication/4", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/4.1] Due rotation with a fixed deadline", + "responsibility": "Implement bounded strict ordinary prepare/bind/confirm/result rotation handlers, stable pending state and unchanged grace with real private peers before client activation. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-4-1.feature.md", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/lifecycle.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/native_http.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_lifecycle.py", + "server/tests/unit/test_native_http_protocol.py" + ], + "dependencies": [ + "arbiter-authentication/3.7" + ], + "acceptance": [ + "Separate one-request connections, not-due/due/resumed prepare, one candidate and stale grant snapshot preserve exact pending ID/deadline; denial and lost replies never slide grace." + ] + }, + "display": { + "summary": "Due rotation with a fixed deadline", + "production": [ + 250, + 370 + ], + "tests": [ + 280, + 410 + ] + } + }, + { + "id": "arbiter-authentication/4.2", + "parent": "arbiter-authentication/4", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/4.2] Durable candidate activation and reconciliation", + "responsibility": "Integrate one shared pre-operation lifecycle preflight into every CLI constructor, private candidate save/bind/confirm/result and atomic current/predecessor promotion with one unchanged logical budget. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/arbiterhttp/client.go", + "client/go-cli/internal/arbiterhttp/client_test.go", + "client/go-cli/internal/arbiterhttp/timeouts.go", + "client/go-cli/internal/arbiterhttp/timeouts_test.go", + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "client/go-cli/internal/identity/lifecycle.go", + "client/go-cli/internal/identity/lifecycle_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "docs/authentication-cli.md", + "server/news/+auth-4-2.feature.md", + "server/src/arbiter_server/lifecycle.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_lifecycle.py" + ], + "dependencies": [ + "arbiter-authentication/4.1" + ], + "acceptance": [ + "No user body or consuming nonce precedes preflight; lost confirm reconciles candidate first; save failure, concurrent clients, busy/stale writer and budget exhaustion never replay work or reset a deadline." + ] + }, + "display": { + "summary": "Durable candidate activation and reconciliation", + "production": [ + 280, + 390 + ], + "tests": [ + 320, + 450 + ] + } + }, + { + "id": "arbiter-authentication/4.3", + "parent": "arbiter-authentication/4", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/4.3] Purpose-bound late completion", + "responsibility": "Extend fixed server-authenticated controls for exact pending old-plus-candidate exporter proofs and same-key certificate reissue after expiry. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/lifecycle.go", + "client/go-cli/internal/identity/lifecycle_test.go", + "docs/authentication-cli.md", + "server/news/+auth-4-3.feature.md", + "server/src/arbiter_server/lifecycle.py", + "server/src/arbiter_server/lifecycle_control.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_lifecycle_control.py" + ], + "dependencies": [ + "arbiter-authentication/4.2" + ], + "acceptance": [ + "Cross-channel/purpose/revision replay, wrong stored certificate, inactivity and denial fail; ordinary TLS stays strict and incomplete controls never refresh contact." + ] + }, + "display": { + "summary": "Purpose-bound late completion", + "production": [ + 230, + 350 + ], + "tests": [ + 280, + 410 + ] + } + }, + { + "id": "arbiter-authentication/4.4", + "parent": "arbiter-authentication/4", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/4.4] One authenticated predecessor attempt", + "responsibility": "Add authenticated credential status and one auth-only predecessor attempt before any operation submission, preserving existing strict deadlines and trust. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "client/go-cli/internal/identity/lifecycle.go", + "client/go-cli/internal/identity/lifecycle_test.go", + "docs/authentication-cli.md", + "server/news/+auth-4-4.feature.md", + "server/src/arbiter_server/lifecycle.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_lifecycle.py" + ], + "dependencies": [ + "arbiter-authentication/4.3" + ], + "acceptance": [ + "No fallback after timeout/denial/unverified peer or submitted request; expiry/recovery/unenrollment discards predecessor; stale restore either works safely or gives repair guidance." + ] + }, + "display": { + "summary": "One authenticated predecessor attempt", + "production": [ + 140, + 230 + ], + "tests": [ + 210, + 320 + ] + } + }, + { + "id": "arbiter-authentication/4.5", + "parent": "arbiter-authentication/4", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/4.5] Lifecycle process and clock integration", + "responsibility": "Extend shared restart/clock peers through due contact, late completion and retained result cleanup with current help and errors. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-4-5.feature.md", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_installed_authentication.py" + ], + "dependencies": [ + "arbiter-authentication/4.4" + ], + "acceptance": [ + "Full pending/current/predecessor chain survives lost results and actual restarts; denial and incomplete exchanges preserve inactivity semantics." + ] + }, + "display": { + "summary": "Lifecycle process and clock integration", + "production": [ + 30, + 90 + ], + "tests": [ + 270, + 400 + ] + } + }, + { + "id": "arbiter-authentication/5.1", + "parent": "arbiter-authentication/5", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/5.1] Pairing repair of an existing enrollment", + "responsibility": "Reuse exact approved pairing for an explicit existing enrollment; replace access credentials without assigning a new durable agent or regranting. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_test.go", + "docs/authentication-cli.md", + "server/news/+auth-5-1.feature.md", + "server/src/arbiter_server/enrollment.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_recovery.py", + "server/src/arbiter_server/prepared.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_enrollment_activation.py", + "server/tests/unit/test_owner_recovery.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/4.5" + ], + "acceptance": [ + "Fresh enrollment cannot select existing identity; existing deny and grants survive; old pending/current sessions lose authority atomically." + ] + }, + "display": { + "summary": "Pairing repair of an existing enrollment", + "production": [ + 170, + 270 + ], + "tests": [ + 230, + 350 + ] + } + }, + { + "id": "arbiter-authentication/5.2", + "parent": "arbiter-authentication/5", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/5.2] Offline owner authorization files", + "responsibility": "Issue bounded stateless purpose-separated origin-signed recovery cookies and offline owner JWS through existing public commands; no unauthenticated per-enrollment reservation. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/recovery.go", + "client/go-cli/internal/identity/recovery_test.go", + "docs/authentication-cli.md", + "server/news/+auth-5-2.feature.md", + "server/src/arbiter_server/lifecycle_control.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_recovery.py", + "server/src/arbiter_server/recovery.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_owner_recovery.py", + "server/tests/unit/test_recovery.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/5.1" + ], + "acceptance": [ + "Continuously submitted attacker new-key proofs cannot occupy a legitimate recovery slot; unknown/expired/stale/wrong signer/algorithm/purpose/server/revision/duplicate fields fail generically, and private owner material stays offline." + ] + }, + "display": { + "summary": "Offline owner authorization files", + "production": [ + 240, + 360 + ], + "tests": [ + 300, + 420 + ] + } + }, + { + "id": "arbiter-authentication/5.3", + "parent": "arbiter-authentication/5", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/5.3] Atomic access recovery and exact receipt", + "responsibility": "Verify stateless cookie, independent owner JWS and new-key exporter proof before one guarded durable access replacement/consumed operation/result; first valid owner completion wins. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/recovery.go", + "client/go-cli/internal/identity/recovery_test.go", + "docs/authentication-cli.md", + "server/news/+auth-5-3.feature.md", + "server/src/arbiter_server/lifecycle_control.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_recovery.py", + "server/src/arbiter_server/recovery.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_owner_recovery.py", + "server/tests/unit/test_recovery.py" + ], + "dependencies": [ + "arbiter-authentication/5.2" + ], + "acceptance": [ + "Competing valid cookies, rotation/denial/recovery races and lost replies consume once, preserve suspension/grants and return exact receipt without another approval." + ] + }, + "display": { + "summary": "Atomic access recovery and exact receipt", + "production": [ + 220, + 330 + ], + "tests": [ + 260, + 390 + ] + } + }, + { + "id": "arbiter-authentication/5.4", + "parent": "arbiter-authentication/5", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/5.4] Portable replacement across enrolled servers", + "responsibility": "Use the existing request/authorize/complete journey for owner-authorized original-local-issuer portable signing plus atomic access/result commit and crash-safe shared portable publication across separately recovered servers. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/lifecycle.go", + "client/go-cli/internal/identity/lifecycle_test.go", + "client/go-cli/internal/identity/portable.go", + "client/go-cli/internal/identity/portable_test.go", + "client/go-cli/internal/identity/recovery.go", + "client/go-cli/internal/identity/recovery_test.go", + "docs/authentication-cli.md", + "server/news/+auth-5-4.feature.md", + "server/src/arbiter_server/credentials.py", + "server/src/arbiter_server/lifecycle_control.py", + "server/src/arbiter_server/owner_issuers.py", + "server/src/arbiter_server/owner_recovery.py", + "server/src/arbiter_server/recovery.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_owner_issuers.py", + "server/tests/unit/test_owner_recovery.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/5.3" + ], + "acceptance": [ + "Two actual servers preserve independent grants/denial; remote public trust/access alone cannot sign; wrong owner/key/issuer, denied issue, commit/save/lost-result races and missing issuer leave honest portable-pending state without another enrollment approval." + ] + }, + "display": { + "summary": "Portable replacement across enrolled servers", + "production": [ + 280, + 410 + ], + "tests": [ + 340, + 490 + ] + } + }, + { + "id": "arbiter-authentication/5.5", + "parent": "arbiter-authentication/5", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/5.5] Owner issuer and portable certificate renewal", + "responsibility": "Renew the same local owner key/certificate, retain signed old-to-new root continuity and exact-fingerprint aliases only through still-valid active registered trust, then renew the same portable leaf with both live access and portable possession. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/credentials.go", + "client/go-cli/internal/identity/credentials_test.go", + "client/go-cli/internal/identity/lifecycle.go", + "client/go-cli/internal/identity/lifecycle_test.go", + "client/go-cli/internal/identity/portable.go", + "client/go-cli/internal/identity/portable_test.go", + "docs/authentication-cli.md", + "server/news/+auth-5-5.feature.md", + "server/src/arbiter_server/credentials.py", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/lifecycle.py", + "server/src/arbiter_server/lifecycle_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_issuers.py", + "server/src/arbiter_server/owner_recovery.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_credentials.py", + "server/tests/unit/test_owner_issuers.py" + ], + "dependencies": [ + "arbiter-authentication/5.4" + ], + "acceptance": [ + "Two-server old-to-new root forwarding, removal/expiry/races, wrong owner/key/profile, leaf renewal and every lost-result/save boundary preserve trust and grants; inactive/expired or unknown old roots cannot self-register." + ] + }, + "display": { + "summary": "Owner issuer and portable certificate renewal", + "production": [ + 240, + 360 + ], + "tests": [ + 310, + 470 + ] + } + }, + { + "id": "arbiter-authentication/6.1", + "parent": "arbiter-authentication/6", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/6.1] Planned server-key transition publication", + "responsibility": "Use the stopped/live exclusive owner to stage a successor, bind old endorsement plus new possession and publish one stable-ID transition and active key atomically. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-6-1.feature.md", + "server/src/arbiter_server/credentials.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/server_transition.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_credentials.py", + "server/tests/unit/test_generations.py", + "server/tests/unit/test_server_transition.py" + ], + "dependencies": [ + "arbiter-authentication/5.5" + ], + "acceptance": [ + "Wrong ID/key, incomplete staging, repeated operation and restart retain only complete authoritative history without losing current enrollment/grants/denial." + ] + }, + "display": { + "summary": "Planned server-key transition publication", + "production": [ + 190, + 300 + ], + "tests": [ + 230, + 340 + ] + } + }, + { + "id": "arbiter-authentication/6.2", + "parent": "arbiter-authentication/6", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/6.2] Verified server transition adoption", + "responsibility": "Retrieve bounded transition records before credentials, verify continuity to the current channel key and atomically store client trust. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "client/go-cli/internal/identity/server_transition.go", + "client/go-cli/internal/identity/server_transition_test.go", + "docs/authentication-cli.md", + "server/news/+auth-6-2.feature.md", + "server/src/arbiter_server/lifecycle_control.py", + "server/src/arbiter_server/server_transition.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_server_transition.py" + ], + "dependencies": [ + "arbiter-authentication/6.1" + ], + "acceptance": [ + "Offline clients, missing/forked/interleaved history, failed save and replay never silently accept another identity or send credentials before verified adoption." + ] + }, + "display": { + "summary": "Verified server transition adoption", + "production": [ + 170, + 280 + ], + "tests": [ + 240, + 350 + ] + } + }, + { + "id": "arbiter-authentication/6.3", + "parent": "arbiter-authentication/6", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/6.3] Independent compromise recovery", + "responsibility": "Bind owner recovery signer, fresh challenge and new authority possession for compromise replacement; invalidate superseded transition authority and sessions. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/server_transition.go", + "client/go-cli/internal/identity/server_transition_test.go", + "docs/authentication-cli.md", + "server/news/+auth-6-3.feature.md", + "server/src/arbiter_server/owner_recovery.py", + "server/src/arbiter_server/recovery.py", + "server/src/arbiter_server/server_transition.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_owner_recovery.py", + "server/tests/unit/test_server_transition.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/6.2" + ], + "acceptance": [ + "Old compromised key alone cannot complete this recovery; retained owner proof reaches enrolled clients and never clears denial, changes durable server ID or replays operations." + ] + }, + "display": { + "summary": "Independent compromise recovery", + "production": [ + 190, + 300 + ], + "tests": [ + 260, + 380 + ] + } + }, + { + "id": "arbiter-authentication/6.4", + "parent": "arbiter-authentication/6", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/6.4] Server authority and leaf certificate renewal", + "responsibility": "Renew same-key authority/leaf before selected validity windows; missed trust validity requires independent owner recovery or explicit pairing. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-6-4.feature.md", + "server/src/arbiter_server/credentials.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/server_transition.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_credentials.py", + "server/tests/unit/test_generations.py", + "server/tests/unit/test_server_transition.py" + ], + "dependencies": [ + "arbiter-authentication/6.3" + ], + "acceptance": [ + "Strict time/role/ID verification, failed publication and restart preserve trust; HTTPS/URL change triggers no native identity-key replacement." + ] + }, + "display": { + "summary": "Server authority and leaf certificate renewal", + "production": [ + 180, + 290 + ], + "tests": [ + 240, + 360 + ] + } + }, + { + "id": "arbiter-authentication/7.1", + "parent": "arbiter-authentication/7", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/7.1] Recipient possession and bounded retention", + "responsibility": "Register recipient version through live access and a decrypt/possession challenge; retain client/server keys required by unexpired artifacts separately from access rotation. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/recipient.go", + "client/go-cli/internal/identity/recipient_test.go", + "docs/authentication-cli.md", + "server/news/+auth-7-1.feature.md", + "server/src/arbiter_server/artifact_crypto.py", + "server/src/arbiter_server/enrollment_live.py", + "server/src/arbiter_server/lifecycle_control.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_artifact_crypto.py" + ], + "dependencies": [ + "arbiter-authentication/6.4" + ], + "acceptance": [ + "Proxy replacement, wrong creator/version/challenge fails; revocation blocks registration and access rotation cannot delete an active artifact key." + ] + }, + "display": { + "summary": "Recipient possession and bounded retention", + "production": [ + 180, + 280 + ], + "tests": [ + 220, + 330 + ] + } + }, + { + "id": "arbiter-authentication/7.2", + "parent": "arbiter-authentication/7", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/7.2] Dual-recipient encrypted artifact writing", + "responsibility": "Install bounded binary age streaming and encrypted metadata behind the still-closed public adapter; retain server inspection with caller-owned sticky I/O failure checks. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-7-2.feature.md", + "server/pyproject.toml", + "server/src/arbiter_server/artifact_crypto.py", + "server/src/arbiter_server/artifacts.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_artifact_crypto.py", + "server/tests/unit/test_artifacts.py" + ], + "dependencies": [ + "arbiter-authentication/7.1" + ], + "acceptance": [ + "Both recipients decrypt; wrong key/tamper/truncation and swallowed final-writer failure prevent publication; no persistent plaintext payload staging or custom cipher format." + ] + }, + "display": { + "summary": "Dual-recipient encrypted artifact writing", + "production": [ + 220, + 330 + ], + "tests": [ + 260, + 390 + ] + } + }, + { + "id": "arbiter-authentication/7.3", + "parent": "arbiter-authentication/7", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/7.3] Physical quotas and encrypted-store restart", + "responsibility": "Reserve plaintext limit plus exact bounded crypto/metadata overhead, count staging and actual owners, and reconcile private encrypted files on restart. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-7-3.feature.md", + "server/src/arbiter_server/artifacts.py", + "server/src/arbiter_server/http_work.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_artifact_http_admission.py", + "server/tests/unit/test_artifacts.py" + ], + "dependencies": [ + "arbiter-authentication/7.2" + ], + "acceptance": [ + "Near-1GiB/full disk/2000 slots/concurrent writers/slow readers preserve 50MiB cap and reservations until actual deletion; no stale orphan becomes accessible." + ] + }, + "display": { + "summary": "Physical quotas and encrypted-store restart", + "production": [ + 200, + 300 + ], + "tests": [ + 240, + 360 + ] + } + }, + { + "id": "arbiter-authentication/7.4", + "parent": "arbiter-authentication/7", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/7.4] Creator-bound descriptor HEAD and one GET", + "responsibility": "Authorize metadata/HEAD/GET by creator, originating account grant and nonce, with durable consume-before-open and native authenticated origin descriptor. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-7-4.feature.md", + "server/src/arbiter_server/artifacts.py", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_artifact_http_admission.py", + "server/tests/unit/test_artifacts.py" + ], + "dependencies": [ + "arbiter-authentication/7.3" + ], + "acceptance": [ + "Shared account/copied nonce/wrong creator/revocation fails; HEAD is non-consuming and failed GET stays consumed across restart and snapshot policy." + ] + }, + "display": { + "summary": "Creator-bound descriptor HEAD and one GET", + "production": [ + 190, + 290 + ], + "tests": [ + 260, + 380 + ] + } + }, + { + "id": "arbiter-authentication/7.5", + "parent": "arbiter-authentication/7", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/7.5] Encrypted plugin adapter activation", + "responsibility": "Replace the closed adapter through the same trusted caller context for all plugin/inline paths; keep legacy routes permanently closed. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-7-5.feature.md", + "server/src/arbiter_server/artifacts.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_artifacts.py", + "server/tests/unit/test_native_http_protocol.py" + ], + "dependencies": [ + "arbiter-authentication/7.4" + ], + "acceptance": [ + "Mock SMTP/IMAP actual dispatch cannot choose creator or return legacy plaintext descriptors; live denial terminates further encrypted delivery." + ] + }, + "display": { + "summary": "Encrypted plugin adapter activation", + "production": [ + 140, + 240 + ], + "tests": [ + 230, + 340 + ] + } + }, + { + "id": "arbiter-authentication/7.6", + "parent": "arbiter-authentication/7", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/7.6] Encrypted-store contention and packaging", + "responsibility": "Extend installed driver for age backend/platform packaging and real consume/quota/revoke/cleanup composition; charge no duplicate encryption foundation. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-7-6.feature.md", + "server/pyproject.toml", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_installed_authentication.py" + ], + "dependencies": [ + "arbiter-authentication/7.5" + ], + "acceptance": [ + "Health remains responsive, actual file/crypto owners survive waiter cancellation, near-limit artifacts complete and no GET replay is introduced." + ] + }, + "display": { + "summary": "Encrypted-store contention and packaging", + "production": [ + 30, + 100 + ], + "tests": [ + 260, + 400 + ] + } + }, + { + "id": "arbiter-authentication/8.1", + "parent": "arbiter-authentication/8", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/8.1] Immediate decrypted stdin with explicit stream flag", + "responsibility": "Parse required --stream true|false without default and add true mode to existing bounded child stdin pipeline using the authenticated descriptor. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/artifact_crypto.go", + "client/go-cli/internal/cli/artifact_crypto_test.go", + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-8-1.feature.md", + "server/tests/integration/test_authentication_peer.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/7.6" + ], + "acceptance": [ + "Valid partial input and irreversible child effects remain possible; wrong final digest/EOF reports failure, no automatic retry or plaintext input file." + ] + }, + "display": { + "summary": "Immediate decrypted stdin with explicit stream flag", + "production": [ + 170, + 270 + ], + "tests": [ + 220, + 340 + ] + } + }, + { + "id": "arbiter-authentication/8.2", + "parent": "arbiter-authentication/8", + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/8.2] Verified ciphertext staging then stdin", + "responsibility": "Implement false mode: consume one GET into reserved private ciphertext, verify to discard, freeze exact bytes, then decrypt into the child. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/artifact_crypto.go", + "client/go-cli/internal/cli/artifact_crypto_test.go", + "client/go-cli/internal/cli/artifact_temp.go", + "client/go-cli/internal/cli/artifact_temp_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-8-2.feature.md", + "server/tests/integration/test_authentication_peer.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/8.1" + ], + "acceptance": [ + "Native POSIX/Windows immutable handles or bounded snapshot resist writable aliases/path replacement; failed preverification starts no child and four transfers bound memory/disk." + ] + }, + "display": { + "summary": "Verified ciphertext staging then stdin", + "production": [ + 220, + 340 + ], + "tests": [ + 260, + 390 + ] + } + }, + { + "id": "arbiter-authentication/8.2.1", + "parent": "arbiter-authentication/8.2", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/8.2.1] Verified ciphertext staging then stdin", + "responsibility": "Implement false mode: consume one GET into reserved private ciphertext, freeze or snapshot the exact bytes, fully verify that immutable source to discard, then decrypt the same source into the child. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/artifact_crypto.go", + "client/go-cli/internal/cli/artifact_crypto_test.go", + "client/go-cli/internal/cli/artifact_temp.go", + "client/go-cli/internal/cli/artifact_temp_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-8-2.feature.md", + "server/tests/integration/test_authentication_peer.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/8.1" + ], + "acceptance": [ + "Native POSIX/Windows immutable handles or bounded snapshot resist writable aliases/path replacement; failed preverification starts no child and four transfers bound memory/disk." + ] + }, + "display": { + "summary": "Verified ciphertext staging then stdin", + "production": [ + 220, + 340 + ], + "tests": [ + 260, + 390 + ] + } + }, + { + "id": "arbiter-authentication/8.3", + "parent": "arbiter-authentication/8", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/8.3] Explicit verified plaintext temporary path", + "responsibility": "Require --allow-plaintext-temp and fully verify private plaintext before handing the existing argv placeholder path to a child. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/artifact_crypto.go", + "client/go-cli/internal/cli/artifact_crypto_test.go", + "client/go-cli/internal/cli/artifact_temp.go", + "client/go-cli/internal/cli/artifact_temp_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-8-3.feature.md", + "server/tests/integration/test_authentication_peer.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/8.2.1" + ], + "acceptance": [ + "Origin/finalization failure exposes no path; signals/full disk/child failure exercise actual cleanup with honest crash and same-user limits." + ] + }, + "display": { + "summary": "Explicit verified plaintext temporary path", + "production": [ + 130, + 220 + ], + "tests": [ + 200, + 310 + ] + } + }, + { + "id": "arbiter-authentication/8.4", + "parent": "arbiter-authentication/8", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/8.4] Verified persistent plaintext export", + "responsibility": "Replace ambiguous save with save-decrypted, stage privately, verify and atomically publish without overwriting an existing destination. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/artifact_crypto.go", + "client/go-cli/internal/cli/artifact_crypto_test.go", + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-8-4.feature.md", + "server/tests/integration/test_authentication_peer.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/8.3" + ], + "acceptance": [ + "Tamper/full disk/cancellation/no-clobber races cannot leave partial final plaintext or follow attacker-controlled links; old alias is absent." + ] + }, + "display": { + "summary": "Verified persistent plaintext export", + "production": [ + 120, + 210 + ], + "tests": [ + 200, + 310 + ] + } + }, + { + "id": "arbiter-authentication/8.5", + "parent": "arbiter-authentication/8", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/8.5] Four-path installed process integration", + "responsibility": "Extend existing installed real-child driver for all four paths, lifecycle/revocation, cleanup and guidance; reconcile help/skill examples. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-8-5.feature.md", + "server/pyproject.toml", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_installed_authentication.py" + ], + "dependencies": [ + "arbiter-authentication/8.4" + ], + "acceptance": [ + "Both stream values, explicit plaintext paths, all platform process/custody limits and orphan non-resumption execute without a hidden default." + ] + }, + "display": { + "summary": "Four-path installed process integration", + "production": [ + 30, + 90 + ], + "tests": [ + 260, + 390 + ] + } + }, + { + "id": "arbiter-authentication/9.1", + "parent": "arbiter-authentication/9", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/9.1] Coherent saved configuration and actual secrets", + "responsibility": "Extend current generation capture/reload to canonical selected configuration/policies and actual configured resolver values/private files; fail before publication on changed sources. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-9-1.feature.md", + "server/src/arbiter_server/config.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_config.py", + "server/tests/unit/test_generations.py" + ], + "dependencies": [ + "arbiter-authentication/8.5" + ], + "acceptance": [ + "Environment/file secret resolution is bounded and repeatable; arbitrary environment/host files stay absent; failed reload retains old complete saved generation." + ] + }, + "display": { + "summary": "Coherent saved configuration and actual secrets", + "production": [ + 240, + 360 + ], + "tests": [ + 260, + 390 + ] + } + }, + { + "id": "arbiter-authentication/9.2", + "parent": "arbiter-authentication/9", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/9.2] Fenced SQLite and saved-state snapshot", + "responsibility": "Use the existing writer barrier to pair SQLite backup with immutable saved configuration/key references, then release before signed encrypted streaming. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-9-2.feature.md", + "server/src/arbiter_server/backups.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/live_authority.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_backups.py", + "server/tests/unit/test_generations.py" + ], + "dependencies": [ + "arbiter-authentication/9.1" + ], + "acceptance": [ + "Concurrent enrollment/grant/rotation/reload yields one coherent snapshot; busy writer, cancellation and shutdown retain/release the actual admin owner correctly." + ] + }, + "display": { + "summary": "Fenced SQLite and saved-state snapshot", + "production": [ + 180, + 280 + ], + "tests": [ + 230, + 350 + ] + } + }, + { + "id": "arbiter-authentication/9.3", + "parent": "arbiter-authentication/9", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/9.3] Strict signed recovery stream format", + "responsibility": "Implement one bounded length-prefixed uncompressed record grammar and exact-byte ES256 manifest, shared by exporter self-validation and offline restore. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-9-3.feature.md", + "server/src/arbiter_server/backup_format.py", + "server/src/arbiter_server/backups.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_backup_format.py", + "server/tests/unit/test_backups.py" + ], + "dependencies": [ + "arbiter-authentication/9.2" + ], + "acceptance": [ + "Duplicate/traversing/link/device paths, unsupported fields, oversize counts/records and incoming nominated verifier fail; finalization binds every file hash." + ] + }, + "display": { + "summary": "Strict signed recovery stream format", + "production": [ + 220, + 340 + ], + "tests": [ + 260, + 390 + ] + } + }, + { + "id": "arbiter-authentication/9.4", + "parent": "arbiter-authentication/9", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/9.4] Encrypted atomic local export", + "responsibility": "Expose backup export through OS-local/verified SSH control, one actual job, public recipient only, bounded age writer and atomic designated output replacement. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-9-4.feature.md", + "server/src/arbiter_server/backups.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_backups.py", + "server/tests/unit/test_local_control.py" + ], + "dependencies": [ + "arbiter-authentication/9.3" + ], + "acceptance": [ + "Full-disk/final-write/cancellation/disconnect preserve the last complete bundle; private owner signer/decryptor never enters server/job/bundle." + ] + }, + "display": { + "summary": "Encrypted atomic local export", + "production": [ + 200, + 310 + ], + "tests": [ + 240, + 360 + ] + } + }, + { + "id": "arbiter-authentication/9.5", + "parent": "arbiter-authentication/9", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/9.5] External backup job and snapshot integration", + "responsibility": "Provide external startup/periodic job guidance and extend installed driver through verification/restore-reader round trip and snapshot contention. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-9-5.feature.md", + "server/pyproject.toml", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_installed_authentication.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/9.4" + ], + "acceptance": [ + "Jobs report failure and retain off-host data; bundle omissions are explicit and all durable credentials/configured secrets are restorable; no internal scheduler or live accounts." + ] + }, + "display": { + "summary": "External backup job and snapshot integration", + "production": [ + 20, + 80 + ], + "tests": [ + 250, + 380 + ] + } + }, + { + "id": "arbiter-authentication/10.1", + "parent": "arbiter-authentication/10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/10.1] Strict offline decrypt and validation", + "responsibility": "Consume backup grammar under external recovery trust with target stopped; verify age EOF, exact origin/signature, hashes, certificates, keys and configuration. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-10-1.feature.md", + "server/src/arbiter_server/backup_format.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/recovery.py", + "server/src/arbiter_server/restore.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_backup_format.py", + "server/tests/unit/test_restore.py" + ], + "dependencies": [ + "arbiter-authentication/9.5" + ], + "acceptance": [ + "Wrong verifier/malformed/truncated/oversized streams never expose active state; private staged output is bounded and discarded on failure." + ] + }, + "display": { + "summary": "Strict offline decrypt and validation", + "production": [ + 200, + 310 + ], + "tests": [ + 260, + 390 + ] + } + }, + { + "id": "arbiter-authentication/10.2", + "parent": "arbiter-authentication/10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/10.2] Exclusive restore staging and cleanup", + "responsibility": "Extend the existing instance lock and private generation primitives for stopped same-filesystem staging, disk reservation and startup cleanup. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-10-2.feature.md", + "server/src/arbiter_server/authority.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/restore.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_generations.py", + "server/tests/unit/test_restore.py" + ], + "dependencies": [ + "arbiter-authentication/10.1" + ], + "acceptance": [ + "Concurrent server start/restore, process kill, symlink/ACL error and disk exhaustion leave active generation and prior undo intact." + ] + }, + "display": { + "summary": "Exclusive restore staging and cleanup", + "production": [ + 180, + 280 + ], + "tests": [ + 230, + 350 + ] + } + }, + { + "id": "arbiter-authentication/10.3", + "parent": "arbiter-authentication/10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/10.3] Atomic active and immutable undo publication", + "responsibility": "Replace the active-only selector with one durable active/undo control record, reusing platform publication; preserve old generation as immutable undo. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-10-3.feature.md", + "server/src/arbiter_server/authority.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/restore.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_generations.py", + "server/tests/unit/test_restore.py" + ], + "dependencies": [ + "arbiter-authentication/10.2" + ], + "acceptance": [ + "Faults before/after each flush and selector publication choose complete old/new state, never a mixed active/undo pair, silent settings merge or reset deadline." + ] + }, + "display": { + "summary": "Atomic active and immutable undo publication", + "production": [ + 190, + 300 + ], + "tests": [ + 260, + 390 + ] + } + }, + { + "id": "arbiter-authentication/10.4", + "parent": "arbiter-authentication/10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/10.4] Repeatable latest undo and explicit discard", + "responsibility": "Undo clones the retained immutable pre-restore point into a fresh active generation, keeps that undo point after use, and supports explicit offline discard. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-10-4.feature.md", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/restore.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_generations.py", + "server/tests/unit/test_restore.py" + ], + "dependencies": [ + "arbiter-authentication/10.3" + ], + "acceptance": [ + "Repeated undo after further writes restores the same point; failed restore preserves it; next successful restore replaces it; no redo or upstream rollback claim." + ] + }, + "display": { + "summary": "Repeatable latest undo and explicit discard", + "production": [ + 160, + 260 + ], + "tests": [ + 230, + 350 + ] + } + }, + { + "id": "arbiter-authentication/10.5", + "parent": "arbiter-authentication/10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/10.5] Native restore crash and client integration", + "responsibility": "Extend process/native durability driver with empty/existing host restore, stale client/current/predecessor repair and warning/runbook checks. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-10-5.feature.md", + "server/pyproject.toml", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_installed_authentication.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/10.4" + ], + "acceptance": [ + "Actual platform termination boundaries, post-use undo and snapshot denial/deadlines are tested; unseen client history is never guessed." + ] + }, + "display": { + "summary": "Native restore crash and client integration", + "production": [ + 30, + 100 + ], + "tests": [ + 280, + 420 + ] + } + }, + { + "id": "arbiter-authentication/11.1", + "parent": "arbiter-authentication/11", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/11.1] Maintenance drain and cooperative migration", + "responsibility": "Commit local maintenance inhibition, drain/cancel real work, capture final bundle and guide stopped destination restore while source remains disabled. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-11-1.feature.md", + "server/src/arbiter_server/live_authority.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/maintenance.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_local_control.py", + "server/tests/unit/test_maintenance.py" + ], + "dependencies": [ + "arbiter-authentication/10.5" + ], + "acceptance": [ + "Failure/shutdown cannot re-enable source; read-only export remains possible; no hidden epoch/fencing/takeover or automatic old-host restart." + ] + }, + "display": { + "summary": "Maintenance drain and cooperative migration", + "production": [ + 170, + 280 + ], + "tests": [ + 240, + 360 + ] + } + }, + { + "id": "arbiter-authentication/11.2", + "parent": "arbiter-authentication/11", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/11.2] Authenticated fixed URL handoff", + "responsibility": "Serve fixed destination URL only from disabled source, verify remembered source and destination identity/transition, then durably adopt client URL before submission. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + "client/go-cli/internal/cli/cli.go", + "client/go-cli/internal/cli/cli_test.go", + "client/go-cli/internal/identity/authentication_peer_test.go", + "client/go-cli/internal/identity/native_transport.go", + "client/go-cli/internal/identity/native_transport_test.go", + "client/go-cli/internal/identity/server_transition.go", + "client/go-cli/internal/identity/server_transition_test.go", + "docs/authentication-cli.md", + "server/news/+auth-11-2.feature.md", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/maintenance.py", + "server/src/arbiter_server/server_transition.py", + "server/tests/integration/test_authentication_peer.py", + "server/tests/unit/test_maintenance.py", + "server/tests/unit/test_server_transition.py" + ], + "dependencies": [ + "arbiter-authentication/11.1" + ], + "acceptance": [ + "Wrong destination, later key rotation, stale old URL and lost reply cannot expose credentials/capabilities or replay operations; handoff has no mutation handlers." + ] + }, + "display": { + "summary": "Authenticated fixed URL handoff", + "production": [ + 180, + 290 + ], + "tests": [ + 240, + 370 + ] + } + }, + { + "id": "arbiter-authentication/11.3", + "parent": "arbiter-authentication/11", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/11.3] Multi-client migration and whole-auth integration", + "responsibility": "Extend shared installed/migration harness and isolated staging runbook across complete R01\u2013R25 journey, package/help/skill and native matrices. Scope excludes later behavior and all product authority beyond the approved HLD. Each cut owns its relevant negative/platform/failure tests, help and package fragment.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/go.mod", + "client/go-cli/go.sum", + "client/go-cli/internal/identity/authentication_peer_test.go", + "docs/authentication-cli.md", + "server/news/+auth-11-3.feature.md", + "server/pyproject.toml", + "server/tests/integration/authentication_terminal_driver.py", + "server/tests/integration/test_installed_authentication.py", + "skill/SKILL.md" + ], + "dependencies": [ + "arbiter-authentication/11.2" + ], + "acceptance": [ + "Multiple clients/grants/pending rotations, backup/restore/undo and handoff compose; every required check executes or stays explicitly unverified and blocks release." + ] + }, + "display": { + "summary": "Multi-client migration and whole-auth integration", + "production": [ + 30, + 100 + ], + "tests": [ + 300, + 440 + ] + } + } + ] +} diff --git a/docs/authentication/supporting/high-level-design/historical-feasibility.md b/docs/authentication/supporting/high-level-design/historical-feasibility.md new file mode 100644 index 0000000..10942d7 --- /dev/null +++ b/docs/authentication/supporting/high-level-design/historical-feasibility.md @@ -0,0 +1,22 @@ +# Historical authentication feasibility evidence + +This preserves the original HLD probe record. It is context, not a current +implementation, packaging, dependency-security or release claim. The source HLD +was SHA-256 `b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57`. + +Local evidence, 2026-10-20: fourteen synthetic checks passed on Linux amd64, +CPython 3.13.12 and Go 1.26.8, using pyOpenSSL 25.3.0, cryptography 46.0.7, +pyrage 1.3.0, websockets 15.0.1, Go age 1.2.1 and coder/websocket 1.8.14. +Results JSON SHA-256: +`34071a913ba400e79242ebe0b4481214a953f14fb78815e0f62ab82b180e789b`. +Checks covered TLS-over-WebSocket/exporter agreement, ordinary expired-certificate +rejection, separate expired-key control proofs and cross-channel replay rejection; +age both directions, second recipient, wrong key, tamper/truncation, immutable +snapshot/path replacement and 50 MiB plaintext; ES256 fixed-width JWS signing-byte +compatibility and changed-byte rejection. `go vet` passed and the peer compiled +with Go 1.24.13 (execution used 1.26.8). These fixtures are not complete profile, +JWS schema, recovery, overload or crash implementations. pyOpenSSL 26.3.0 was +rejected for this design's compatibility assessment because it requires +cryptography 49 outside Arbiter's current `<49` range. The compatible probe pair +is a tested candidate, not permission to freeze old versions indefinitely; resolve +production versions/advisories and platform builds in the implementation plan. diff --git a/docs/authentication/supporting/implementation-plan/.review/backend-evidence.md b/docs/authentication/supporting/implementation-plan/.review/backend-evidence.md new file mode 100644 index 0000000..9866634 --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/.review/backend-evidence.md @@ -0,0 +1,30 @@ +--- +artifact: swe-design-review-attestation +schema_version: 6 +scope_key: c2ebaf06c49668e199e08bccef68303c5cd0925e79b8f635860bb8fa8494d61b +scope: {"kind": "path", "primary_target": "docs/authentication/implementation-plan.md", "repository": ".", "selector": "docs/authentication/implementation-plan.md"} +review_content_identity_sha256: 5893064257f1b8afd405898058d9b7fc9e9b957c95a40e9acd6fc018982f0869 +target_content_identity_sha256: 8a3289d4d765221e818ae1babfe09bbd0c1801a6eb9510d09761e7f87e1a9315 +baseline_content_identity_sha256: 36c6b33068c1ca88278d21f6e92eb299e77be6e00dce5ec2e8e7a4c2da85bc62 +target_documents: [{"executable": false, "path": "docs/authentication/README.md", "repository": ".", "sha256": "714a197db6b067167bf224c0fa45263b4e89b9caa605131ce58f6267b3b76224"}, {"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "7bf550552c24f8d66e7032ed1b25379ecd062dfc5e3e9db4de3b197ee66fc0f2"}, {"executable": false, "path": "docs/authentication/overview.md", "repository": ".", "sha256": "f0e95b138f566067c735898d2fdff3d02fad8d1c4369204266fe26ef89b8e212"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/slices.json", "repository": ".", "sha256": "995e7ed8c99dd2133188ba4ee5f8d9d5feaa1d175772f9dbba336755dedc533c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/backend-evidence.md", "repository": ".", "sha256": "fa1cd32632dbab696648369015c5c4ebd0762f27b81455548cf3bcb1545a9fa4"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-basis.md", "repository": ".", "sha256": "176283b0aa31cdfe3070508dd89c68e84457731d774bebd771f3718f01d0e46f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-comparison.md", "repository": ".", "sha256": "b64b26f9337c6be505f11319ef321dd647519d20527d45cf962b446835df84ba"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-after.json", "repository": ".", "sha256": "39393c7f902f9907415acbed0a861d5014997053ad2199f82215853ae94c1e80"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-before.json", "repository": ".", "sha256": "0570a8902bf55c255289cbb5ff3d48df17779b9e4fb66e352fca34446531545c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-native-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-plan.txt", "repository": ".", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a"}] +baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +design_dependency_documents: [] +plan_binding: {"base_revision": "4f6db43d72bd59705cdefd0851f6c25c63a699cf", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "26189fa66fc3804040b98edfd72ba346567c0280c5ebbca4f12ab5ebcaa421fe"}]} +security_review: {"actual": "dbb", "binding_identity_sha256": "477b0e2b315f79ce92dc2819d4046ea1e61fc6a9557cea8bb5462beca8044e62", "requested": "dbb", "reviewer": "/root/pr83_current_combined_dbb", "schema_version": 1} +document_repository: "." +document_path: "docs/authentication/supporting/implementation-plan/backend-evidence.md" +document_revision_provenance: "4f6db43d72bd59705cdefd0851f6c25c63a699cf" +document_sha256: fa1cd32632dbab696648369015c5c4ebd0762f27b81455548cf3bcb1545a9fa4 +verdict: clean +attested_at: 2026-11-04T15:50:04Z +--- + + +# SWE design-review attestation + +Review freshness binds target and baseline document bytes and executable state +listed in the version-6 header. Revisions are provenance only. + +## Durable review state + +No standing rejected or deferred decisions. diff --git a/docs/authentication/supporting/implementation-plan/.review/estimate-basis.md b/docs/authentication/supporting/implementation-plan/.review/estimate-basis.md new file mode 100644 index 0000000..7b58e25 --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/.review/estimate-basis.md @@ -0,0 +1,30 @@ +--- +artifact: swe-design-review-attestation +schema_version: 6 +scope_key: c2ebaf06c49668e199e08bccef68303c5cd0925e79b8f635860bb8fa8494d61b +scope: {"kind": "path", "primary_target": "docs/authentication/implementation-plan.md", "repository": ".", "selector": "docs/authentication/implementation-plan.md"} +review_content_identity_sha256: 5893064257f1b8afd405898058d9b7fc9e9b957c95a40e9acd6fc018982f0869 +target_content_identity_sha256: 8a3289d4d765221e818ae1babfe09bbd0c1801a6eb9510d09761e7f87e1a9315 +baseline_content_identity_sha256: 36c6b33068c1ca88278d21f6e92eb299e77be6e00dce5ec2e8e7a4c2da85bc62 +target_documents: [{"executable": false, "path": "docs/authentication/README.md", "repository": ".", "sha256": "714a197db6b067167bf224c0fa45263b4e89b9caa605131ce58f6267b3b76224"}, {"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "7bf550552c24f8d66e7032ed1b25379ecd062dfc5e3e9db4de3b197ee66fc0f2"}, {"executable": false, "path": "docs/authentication/overview.md", "repository": ".", "sha256": "f0e95b138f566067c735898d2fdff3d02fad8d1c4369204266fe26ef89b8e212"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/slices.json", "repository": ".", "sha256": "995e7ed8c99dd2133188ba4ee5f8d9d5feaa1d175772f9dbba336755dedc533c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/backend-evidence.md", "repository": ".", "sha256": "fa1cd32632dbab696648369015c5c4ebd0762f27b81455548cf3bcb1545a9fa4"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-basis.md", "repository": ".", "sha256": "176283b0aa31cdfe3070508dd89c68e84457731d774bebd771f3718f01d0e46f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-comparison.md", "repository": ".", "sha256": "b64b26f9337c6be505f11319ef321dd647519d20527d45cf962b446835df84ba"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-after.json", "repository": ".", "sha256": "39393c7f902f9907415acbed0a861d5014997053ad2199f82215853ae94c1e80"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-before.json", "repository": ".", "sha256": "0570a8902bf55c255289cbb5ff3d48df17779b9e4fb66e352fca34446531545c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-native-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-plan.txt", "repository": ".", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a"}] +baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +design_dependency_documents: [] +plan_binding: {"base_revision": "4f6db43d72bd59705cdefd0851f6c25c63a699cf", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "26189fa66fc3804040b98edfd72ba346567c0280c5ebbca4f12ab5ebcaa421fe"}]} +security_review: {"actual": "dbb", "binding_identity_sha256": "477b0e2b315f79ce92dc2819d4046ea1e61fc6a9557cea8bb5462beca8044e62", "requested": "dbb", "reviewer": "/root/pr83_current_combined_dbb", "schema_version": 1} +document_repository: "." +document_path: "docs/authentication/supporting/implementation-plan/estimate-basis.md" +document_revision_provenance: "4f6db43d72bd59705cdefd0851f6c25c63a699cf" +document_sha256: 176283b0aa31cdfe3070508dd89c68e84457731d774bebd771f3718f01d0e46f +verdict: clean +attested_at: 2026-11-04T15:50:04Z +--- + + +# SWE design-review attestation + +Review freshness binds target and baseline document bytes and executable state +listed in the version-6 header. Revisions are provenance only. + +## Durable review state + +No standing rejected or deferred decisions. diff --git a/docs/authentication/supporting/implementation-plan/.review/estimate-comparison.md b/docs/authentication/supporting/implementation-plan/.review/estimate-comparison.md new file mode 100644 index 0000000..4629827 --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/.review/estimate-comparison.md @@ -0,0 +1,30 @@ +--- +artifact: swe-design-review-attestation +schema_version: 6 +scope_key: c2ebaf06c49668e199e08bccef68303c5cd0925e79b8f635860bb8fa8494d61b +scope: {"kind": "path", "primary_target": "docs/authentication/implementation-plan.md", "repository": ".", "selector": "docs/authentication/implementation-plan.md"} +review_content_identity_sha256: 5893064257f1b8afd405898058d9b7fc9e9b957c95a40e9acd6fc018982f0869 +target_content_identity_sha256: 8a3289d4d765221e818ae1babfe09bbd0c1801a6eb9510d09761e7f87e1a9315 +baseline_content_identity_sha256: 36c6b33068c1ca88278d21f6e92eb299e77be6e00dce5ec2e8e7a4c2da85bc62 +target_documents: [{"executable": false, "path": "docs/authentication/README.md", "repository": ".", "sha256": "714a197db6b067167bf224c0fa45263b4e89b9caa605131ce58f6267b3b76224"}, {"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "7bf550552c24f8d66e7032ed1b25379ecd062dfc5e3e9db4de3b197ee66fc0f2"}, {"executable": false, "path": "docs/authentication/overview.md", "repository": ".", "sha256": "f0e95b138f566067c735898d2fdff3d02fad8d1c4369204266fe26ef89b8e212"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/slices.json", "repository": ".", "sha256": "995e7ed8c99dd2133188ba4ee5f8d9d5feaa1d175772f9dbba336755dedc533c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/backend-evidence.md", "repository": ".", "sha256": "fa1cd32632dbab696648369015c5c4ebd0762f27b81455548cf3bcb1545a9fa4"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-basis.md", "repository": ".", "sha256": "176283b0aa31cdfe3070508dd89c68e84457731d774bebd771f3718f01d0e46f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-comparison.md", "repository": ".", "sha256": "b64b26f9337c6be505f11319ef321dd647519d20527d45cf962b446835df84ba"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-after.json", "repository": ".", "sha256": "39393c7f902f9907415acbed0a861d5014997053ad2199f82215853ae94c1e80"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-before.json", "repository": ".", "sha256": "0570a8902bf55c255289cbb5ff3d48df17779b9e4fb66e352fca34446531545c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-native-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-plan.txt", "repository": ".", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a"}] +baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +design_dependency_documents: [] +plan_binding: {"base_revision": "4f6db43d72bd59705cdefd0851f6c25c63a699cf", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "26189fa66fc3804040b98edfd72ba346567c0280c5ebbca4f12ab5ebcaa421fe"}]} +security_review: {"actual": "dbb", "binding_identity_sha256": "477b0e2b315f79ce92dc2819d4046ea1e61fc6a9557cea8bb5462beca8044e62", "requested": "dbb", "reviewer": "/root/pr83_current_combined_dbb", "schema_version": 1} +document_repository: "." +document_path: "docs/authentication/supporting/implementation-plan/estimate-comparison.md" +document_revision_provenance: "4f6db43d72bd59705cdefd0851f6c25c63a699cf" +document_sha256: b64b26f9337c6be505f11319ef321dd647519d20527d45cf962b446835df84ba +verdict: clean +attested_at: 2026-11-04T15:50:04Z +--- + + +# SWE design-review attestation + +Review freshness binds target and baseline document bytes and executable state +listed in the version-6 header. Revisions are provenance only. + +## Durable review state + +No standing rejected or deferred decisions. diff --git a/docs/authentication/supporting/implementation-plan/.review/historical-native-lld.md b/docs/authentication/supporting/implementation-plan/.review/historical-native-lld.md new file mode 100644 index 0000000..cf246d9 --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/.review/historical-native-lld.md @@ -0,0 +1,30 @@ +--- +artifact: swe-design-review-attestation +schema_version: 6 +scope_key: c2ebaf06c49668e199e08bccef68303c5cd0925e79b8f635860bb8fa8494d61b +scope: {"kind": "path", "primary_target": "docs/authentication/implementation-plan.md", "repository": ".", "selector": "docs/authentication/implementation-plan.md"} +review_content_identity_sha256: 5893064257f1b8afd405898058d9b7fc9e9b957c95a40e9acd6fc018982f0869 +target_content_identity_sha256: 8a3289d4d765221e818ae1babfe09bbd0c1801a6eb9510d09761e7f87e1a9315 +baseline_content_identity_sha256: 36c6b33068c1ca88278d21f6e92eb299e77be6e00dce5ec2e8e7a4c2da85bc62 +target_documents: [{"executable": false, "path": "docs/authentication/README.md", "repository": ".", "sha256": "714a197db6b067167bf224c0fa45263b4e89b9caa605131ce58f6267b3b76224"}, {"executable": false, "path": "docs/authentication/implementation-plan.md", "repository": ".", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36"}, {"executable": false, "path": "docs/authentication/milestone-3-lld.md", "repository": ".", "sha256": "7bf550552c24f8d66e7032ed1b25379ecd062dfc5e3e9db4de3b197ee66fc0f2"}, {"executable": false, "path": "docs/authentication/overview.md", "repository": ".", "sha256": "f0e95b138f566067c735898d2fdff3d02fad8d1c4369204266fe26ef89b8e212"}, {"executable": false, "path": "docs/authentication/portable-enrollment-lld.md", "repository": ".", "sha256": "7cbad8803d0ade4090289d22a681a01026782ade9785c731ac7a2d8a33b9c0e1"}, {"executable": false, "path": "docs/authentication/slices.json", "repository": ".", "sha256": "995e7ed8c99dd2133188ba4ee5f8d9d5feaa1d175772f9dbba336755dedc533c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/backend-evidence.md", "repository": ".", "sha256": "fa1cd32632dbab696648369015c5c4ebd0762f27b81455548cf3bcb1545a9fa4"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-basis.md", "repository": ".", "sha256": "176283b0aa31cdfe3070508dd89c68e84457731d774bebd771f3718f01d0e46f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimate-comparison.md", "repository": ".", "sha256": "b64b26f9337c6be505f11319ef321dd647519d20527d45cf962b446835df84ba"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-after.json", "repository": ".", "sha256": "39393c7f902f9907415acbed0a861d5014997053ad2199f82215853ae94c1e80"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/estimates-before.json", "repository": ".", "sha256": "0570a8902bf55c255289cbb5ff3d48df17779b9e4fb66e352fca34446531545c"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-native-lld.md", "repository": ".", "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f"}, {"executable": false, "path": "docs/authentication/supporting/implementation-plan/historical-plan.txt", "repository": ".", "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a"}] +baseline_documents: [{"executable": false, "path": "docs/authentication/high-level-design.md", "repository": ".", "sha256": "5c0c6c2115b3129b7534cc924dcc9bf1f7f3a9be5175440e8e551f09361f6fbe"}, {"executable": false, "path": "docs/authentication/requirements.md", "repository": ".", "sha256": "d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929"}] +design_dependency_documents: [] +plan_binding: {"base_revision": "4f6db43d72bd59705cdefd0851f6c25c63a699cf", "documents": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "plan_key": "arbiter-authentication", "sha256": "cd60b69fdf51ec7ff367f4fba9b5c8d0edab2f4590158652d9b4a27deec98d36", "slice_convention": "hierarchical-v1"}], "predecessors": [{"executable": false, "path": "docs/authentication/implementation-plan.md", "sha256": "26189fa66fc3804040b98edfd72ba346567c0280c5ebbca4f12ab5ebcaa421fe"}]} +security_review: {"actual": "dbb", "binding_identity_sha256": "477b0e2b315f79ce92dc2819d4046ea1e61fc6a9557cea8bb5462beca8044e62", "requested": "dbb", "reviewer": "/root/pr83_current_combined_dbb", "schema_version": 1} +document_repository: "." +document_path: "docs/authentication/supporting/implementation-plan/historical-native-lld.md" +document_revision_provenance: "4f6db43d72bd59705cdefd0851f6c25c63a699cf" +document_sha256: 566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f +verdict: clean +attested_at: 2026-11-04T15:50:04Z +--- + + +# SWE design-review attestation + +Review freshness binds target and baseline document bytes and executable state +listed in the version-6 header. Revisions are provenance only. + +## Durable review state + +No standing rejected or deferred decisions. diff --git a/docs/authentication/supporting/implementation-plan/backend-evidence.md b/docs/authentication/supporting/implementation-plan/backend-evidence.md new file mode 100644 index 0000000..1465e72 --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/backend-evidence.md @@ -0,0 +1,40 @@ +# Backend feasibility and limits + +This is planning evidence, not product validation or dependency-security approval. +The source baseline is `d52f8bc0acadc1de0dcb53fb1a96eb3e822e174a`. +Existing server dependencies are pyOpenSSL26.2.0/cryptography>=42,<49; the current +Go client uses Gorilla WebSocket1.5.3 and Go1.24. No dependency was installed or +changed for this design. + +The existing historical synthetic probe establishes binary age interoperability, +not bounded product I/O or platform approval. For this revision, a small isolated +probe used the already-existing pyrage1.3.0 probe environment with synthetic keys +and a writer that raises on every write. `encrypt_io` returned normally despite +the failing final write; a caller-owned sticky failure recorded the error. +`decrypt_io` propagated OSError in the exercised case. Both paths therefore +require sticky I/O state and measured integrity/finalization checks; do not infer +successful publication from return status. No source or live service was changed. + +The probe source and JSON result are retained in the redesign evidence under +`lld-probes/age_io_failure.py` and `lld-probes/age_io_failure.json`. Their immutable +content digests are recorded below by the authoring validator. This check does +not measure all-platform GIL scheduling, cancellation, disk durability, package +installation or release advisories. Those remain the concrete first-use/native +acceptance checks assigned to 7.2/7.6 and the backup consumers. + +Primary source inspection supports the selected engineering boundary: + +- [pyrage1.3.0 streaming source](https://github.com/woodruffw/pyrage/blob/v1.3.0/src/lib.rs): use file-like streaming callbacks, not whole-buffer convenience APIs. +- [pyrage1.3.0 package requirements](https://github.com/woodruffw/pyrage/blob/v1.3.0/pyproject.toml): Python>=3.9 is compatible with the project floor; this alone proves no wheel/OS matrix. +- [age1.2.1 module](https://github.com/FiloSottile/age/blob/v1.2.1/go.mod): Go1.19 minimum; evaluate with this project's newer transitive dependencies. +- [age1.3.2 module](https://github.com/FiloSottile/age/blob/v1.3.2/go.mod): Go1.25 minimum, so it is not selected under the current Go1.24 floor. + +The plan keeps binary age/X25519, bounded headers and callback-owned work. It adds +no custom format to fix library I/O and does not claim old versions are indefinitely +safe. A failed current advisory/install/native check blocks the affected first-use +cut and requires supported dependency/design correction, not a platform reduction. + +Retained probe identities: + +- `age_io_failure.json` SHA256 `92504539724dd6fde9b267519ddfcd4887c2add9f6947fb0f533107d59af0b1c`. +- `age_io_failure.py` SHA256 `bbc9bb6db11270ecb98933e0bcb00d648897c642f1839d15fb55f148d74b4d3c`. diff --git a/docs/authentication/supporting/implementation-plan/estimate-basis.md b/docs/authentication/supporting/implementation-plan/estimate-basis.md new file mode 100644 index 0000000..db9dfee --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/estimate-basis.md @@ -0,0 +1,60 @@ +# Estimate basis and ownership + +These are low-confidence engineering ranges, not future measured diffs or a +statistical confidence interval. They were assigned to the complete consumed +changes after inspecting the merged source, not by applying a percentage to +old counts. Display values are incremental final nonblank physical code/test +content; comment-only lines are excluded and docstrings count physically. + +The separate authored-churn envelope allows 180 lines of replacement/motion/ +comments for3.1.1; 100 for3.2.1/9.1; and80 for other cuts, in addition to upper +final-content and CI estimates. This is a conservative **forecast**, not proof +of the cap or a standing correction allowance. Source-dependent headroom can be +wrong. Recheck it against the actual predecessor and return to design if a cut +cannot fit the unchanged1,000-line authored change maximum. No test deletion, +code compression, fixture relabeling or extra review budget is authorized. + +## Current inspected foundations + +Physical source lines below are inspection context, not the estimate unit. + +| Source at merged baseline | Physical lines | Reuse and missing change | +| --- | ---: | --- | +| authority.py / credentials.py | 498 / 550 | Private SQLite/instance/certificate roles exist; live lifecycle, recovery and renewal writers remain work. | +| generations.py / recovery.py | 224 / 274 | Initial-only generation and external key custody exist; full config/secret capture, active+undo transaction and backup codec are new. | +| enrollment_activation.py / enrollment_receipt.py | 165 / 129 | Exact prepared and durable completion exist; live row/coordinator guards extend them without copying identity authority. | +| artifacts.py / http_work.py / blocking.py | 570 / 170 / 102 | Store/quota/HTTP bridge/actual worker retention exist; encryption, creator/account and live permission are new. | +| local_control.py | 463 | OS-authenticated owner boundary exists; commands extend this owner rather than introducing remote admin. | +| Go credentials.go / control_tls.go | 428 / 271 | Strict roles and bounded carrier exist; ordinary HTTP stream and lifecycle are not implemented. | +| Go provisional_store.go / enrollment_receipt.go | 251 / 141 | Private immutable custody/publication exists; atomic mutable lifecycle records reuse native adapters. | +| Go HTTP client.go / timeouts.go / CLI cli.go | 212 / 306 / 2,309 | Existing HTTP/phase timers/process helpers are reused; only selected constructors and command paths change. | + +## Per-area sizing rationale + +Each slice's exact responsibility, ownership files, dependency and completion +check are in the canonical inventory. These component groups explain its range. +They are overlapping read surfaces, not independent code packages counted again. + +| Cuts | Production components charged once | Test work included in those cuts | +| --- | --- | --- | +|3.1.1–3.1.4|Shared carrier extraction/credit pump; strict TLS candidate; Go dial/HTTP factory; h11-ASGI body/response adapter. No second HTTP client or timer stack.|One real cross-language stream harness at3.1.1, extended for roles/relay/partial BIO/framing/body admission and failure peers.| +|3.2.1–3.2.2|One live schema/backfill, one coordinator/writer barrier, fixed-receipt permission and local denial first; ordinary tokens/grant controls extend it.|Existing activation/receipt tests plus corruption/backfill, deterministic revoke/snapshot/final-write and worker-handoff barriers.| +|3.3–3.4|Grant projections through existing schema/policy paths; actual worker caller context; small closed concrete artifact adapter/legacy descriptor closure.|Existing native/admission/store fixtures with hidden-information and real spy/filesystem assertions. No new copy of every discovery fixture.| +|3.6.1–3.7|Cross-connection cancel/final-write ownership, explicit CLI selection, atomic public cutover and installed packaging/timeout composition.|Shared sockets/installed driver extended at first consumer; race cases owned before public cutover, closure adds integrated scenarios only.| +|4.1–4.5|Pending-state plus four bounded ordinary rotation handlers in4.1; shared all-constructor HTTP/CLI preflight and private lifecycle publication in4.2; strict late controls/result/fallback follow.|Real one-request-per-connection peers, every prepare/bind/confirm/result loss and save boundary, shared absolute budgets, concurrent clients, then controlled-clock expiry/denial/replay/native restart.| +|5.1–5.5|Reuse pairing; stateless purpose-separated origin cookie/offline owner JWS in5.2; first-valid-owner atomic access receipt in5.3; actual original-issuer private signing and shared portable publication in5.4; same-key root continuity/registry forwarding plus leaf renewal in5.5. Existing public issuer controls do not sign.|Exact negative schemas and sustained attacker-candidate requests, competing valid owner completions, two real original/remote-public issuer peers, all result/save boundaries, missing issuer/denial/removal/expiry and renewal/recovery races.| +|6.1–6.4|Bounded transition publication and history, verified client adoption, independent compromise proof and same-key renewal.|Reuse recovery/custody fixtures; online/offline/fork/failed-save/expiry tests, exact retained access and no preverification credentials.| +|7.1–7.6|Recipient registration, one binary-age streaming adapter, sticky I/O wrapper, existing store/quota extension, authenticated descriptor/consume and real plugin activation.|One backend fixture set at7.2, existing store/contention fixtures extended for both recipients, limits, fault-finalization and live denial. Native closure adds packaging/composition only.| +|8.1–8.5|Existing child pipeline plus explicit stream parser; immutable ciphertext staging; plaintext temp; no-clobber export and exact help paths.|Reuse real child/stdout/timeout tests; add origin/EOF, writable-alias/native fallback, signal/disk/denial and orphan cases. No duplicate transfer pool.| +|9.1–9.5|Resolve/save selected config/secrets, coherent SQLite snapshot, one strict signed record codec/verifier, public-recipient export and atomic output.|Current generation/config tests plus source-race/snapshot barriers, malicious record corpus, sticky disk failures and one job round-trip driver. No scheduler/cloud client.| +|10.1–10.5|Reuse backup verifier and generation/lock/custody primitives; private offline staging, one active+undo control switch, immutable repeatable undo and discard.|Shared native kill-at-boundary driver with empty/existing host, prior undo preservation, ACL/disk/start races and stale-client lifecycle. Decoder tests are reused, not recopied.| +|11.1–11.3|Persistent inhibition/drain, fixed source handoff and client URL adoption; existing restore/export/transition components reused.|Extend installed drivers to several clients, later destination replacement and whole-parent journey; isolated staging and required native execution. No new migration/fencing framework.| + +Every range includes its own negative/failure tests, integration additions and +applicable platform scenarios. Static fixture bytes/generated outputs, dependency +locks and development documents remain separate unquantified review burden; +unknown is not zero. Handwritten CI is separately quantified. Required shipped +help/config/instructions and packaging edits count as production when applicable. +No test suite was rerun merely to produce these design estimates. + +The review corrections increased only six cuts:4.1/4.2/5.2–5.5, with their actual source owners and focused native scenarios. Maximum forecast authored churn is now980 at5.4, leaving only20 lines below the hard cap; this is a tight low-confidence cut, not permission to squeeze work. Validate its consumed implementation and tests before admission and revise the design openly if the envelope does not fit. The original51 IDs and historical before snapshot remain exact. diff --git a/docs/authentication/supporting/implementation-plan/estimate-comparison.md b/docs/authentication/supporting/implementation-plan/estimate-comparison.md new file mode 100644 index 0000000..90d951c --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/estimate-comparison.md @@ -0,0 +1,85 @@ +# Predicted lines before and after redesign + +Before is the exact forecast frozen before this redesign: added-plus-deleted edit churn. +After is incremental final delivered nonblank physical content, excluding comment-only lines and counting docstrings physically. +These are **different units**. Lower after values do not establish percentage savings or smaller implementation effort. +The original1,000 authored-changed-line cap remains a separate constraint. CI shown as unknown before is not zero. +All51 cut IDs and nine milestone obligations are preserved; no split/merge mapping is needed. +Completed1–2, including2.10, are excluded from remaining estimates. +Current estimates include the accepted normal rotation wire/preflight and portable issuer/recovery-availability corrections. + +## Milestone rollups + +| Milestone | Cuts before / after | Before production churn | Before tests churn | Before CI churn | Before combined churn | After production final | After tests final | After CI final | After combined final | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | +| 3 | 13 / 13 | 2,350–3,360 | 4,440–5,980 | 0–70 | 6,790–9,410 | 2,020–2,990 | 3,730–5,210 | 0–15 | 5,750–8,215 | +| 4 | 5 / 5 | 960–1,640 | 1,420–2,440 | unknown | 2,380–4,080 | 930–1,430 | 1,360–1,990 | 0–10 | 2,290–3,430 | +| 5 | 5 / 5 | 960–1,650 | 1,320–2,280 | unknown | 2,280–3,930 | 1,150–1,730 | 1,440–2,120 | 0–0 | 2,590–3,850 | +| 6 | 4 / 4 | 840–1,430 | 1,080–1,880 | unknown | 1,920–3,310 | 730–1,170 | 970–1,430 | 0–0 | 1,700–2,600 | +| 7 | 6 / 6 | 1,160–2,000 | 1,680–2,920 | unknown | 2,840–4,920 | 960–1,540 | 1,470–2,200 | 0–15 | 2,430–3,755 | +| 8 | 5 / 5 | 810–1,430 | 1,300–2,290 | unknown | 2,110–3,720 | 670–1,130 | 1,140–1,740 | 0–10 | 1,810–2,880 | +| 9 | 5 / 5 | 990–1,700 | 1,420–2,450 | unknown | 2,410–4,150 | 860–1,370 | 1,240–1,870 | 0–10 | 2,100–3,250 | +| 10 | 5 / 5 | 920–1,580 | 1,460–2,520 | unknown | 2,380–4,100 | 760–1,250 | 1,260–1,900 | 0–10 | 2,020–3,160 | +| 11 | 3 / 3 | 480–860 | 860–1,500 | unknown | 1,340–2,360 | 380–670 | 780–1,170 | 0–10 | 1,160–1,850 | + +After project totals: production **8,460–13,280**, tests **13,390–19,630**, ci **0–80**, combined **21,850–32,990**. +Before combined is24,450–39,980 churn, with unquantified CI outside milestone3. +Production+tests final-content total: 21,850–32,910. CI is separately added to combined. + +## Every preserved cut + +| Slice | Before production / tests / CI / combined churn | After production / tests / CI / combined final | Predicted authored churn upper | +| --- | --- | --- | ---: | +| `arbiter-authentication/3.1.1` — Shared bounded carrier and streaming peer | 320–440 / 300–420 / 0–5 / 620–865 | 220–310 / 250–360 / 0–5 / 470–675 | 855 | +| `arbiter-authentication/3.1.2` — Strict ordinary server TLS peer | 170–240 / 310–420 / 0–5 / 480–665 | 150–220 / 260–370 / 0–0 / 410–590 | 670 | +| `arbiter-authentication/3.1.3` — Verified Go native HTTP connection | 190–260 / 300–410 / 0–5 / 490–675 | 170–240 / 250–350 / 0–0 / 420–590 | 670 | +| `arbiter-authentication/3.1.4` — One-request HTTP to ASGI stream | 230–320 / 350–470 / 0–5 / 580–795 | 210–290 / 300–420 / 0–0 / 510–710 | 790 | +| `arbiter-authentication/3.2.1` — Live enrollment and receipt denial | 230–330 / 420–610 / 0–5 / 650–945 | 210–310 / 370–510 / 0–0 / 580–820 | 920 | +| `arbiter-authentication/3.2.2` — Grant controls and dispatch coordinator | 220–300 / 330–430 / 0–5 / 550–735 | 200–280 / 280–390 / 0–0 / 480–670 | 750 | +| `arbiter-authentication/3.3` — Grant-filtered discovery and direct lookup | 160–230 / 320–440 / 0–5 / 480–675 | 150–220 / 270–380 / 0–0 / 420–600 | 680 | +| `arbiter-authentication/3.4` — Authorized plugins with closed artifacts | 230–320 / 350–460 / 0–5 / 580–785 | 190–280 / 300–410 / 0–0 / 490–690 | 770 | +| `arbiter-authentication/3.6.1` — Cross-connection denial and worker ownership | 190–270 / 350–470 / 0–5 / 540–745 | 160–240 / 300–420 / 0–0 / 460–660 | 740 | +| `arbiter-authentication/3.6.2` — Final-write revocation barrier | 150–220 / 330–450 / 0–5 / 480–675 | 130–200 / 280–390 / 0–0 / 410–590 | 670 | +| `arbiter-authentication/3.5.1` — Explicit enrollment selection across CLI | 130–180 / 320–410 / 0–5 / 450–595 | 110–170 / 260–360 / 0–0 / 370–530 | 610 | +| `arbiter-authentication/3.5.2` — Atomic authenticated API cutover | 110–190 / 380–510 / 0–5 / 490–705 | 100–170 / 310–430 / 0–0 / 410–600 | 680 | +| `arbiter-authentication/3.7` — Installed native transport integration | 20–60 / 380–480 / 0–10 / 400–550 | 20–60 / 300–420 / 0–10 / 320–490 | 570 | +| `arbiter-authentication/4.1` — Due rotation with a fixed deadline | 220–360 / 260–450 / unknown / 480–810 | 250–370 / 280–410 / 0–0 / 530–780 | 860 | +| `arbiter-authentication/4.2` — Durable candidate activation and reconciliation | 240–400 / 300–500 / unknown / 540–900 | 280–390 / 320–450 / 0–0 / 600–840 | 920 | +| `arbiter-authentication/4.3` — Purpose-bound late completion | 260–420 / 300–520 / unknown / 560–940 | 230–350 / 280–410 / 0–0 / 510–760 | 840 | +| `arbiter-authentication/4.4` — One authenticated predecessor attempt | 160–280 / 240–420 / unknown / 400–700 | 140–230 / 210–320 / 0–0 / 350–550 | 630 | +| `arbiter-authentication/4.5` — Lifecycle process and clock integration | 80–180 / 320–550 / unknown / 400–730 | 30–90 / 270–400 / 0–10 / 300–500 | 580 | +| `arbiter-authentication/5.1` — Pairing repair of an existing enrollment | 180–300 / 240–420 / unknown / 420–720 | 170–270 / 230–350 / 0–0 / 400–620 | 700 | +| `arbiter-authentication/5.2` — Offline owner authorization files | 220–370 / 280–480 / unknown / 500–850 | 240–360 / 300–420 / 0–0 / 540–780 | 860 | +| `arbiter-authentication/5.3` — Atomic access recovery and exact receipt | 200–330 / 260–450 / unknown / 460–780 | 220–330 / 260–390 / 0–0 / 480–720 | 800 | +| `arbiter-authentication/5.4` — Portable replacement across enrolled servers | 180–320 / 280–480 / unknown / 460–800 | 280–410 / 340–490 / 0–0 / 620–900 | 980 | +| `arbiter-authentication/5.5` — Owner issuer and portable certificate renewal | 180–330 / 260–450 / unknown / 440–780 | 240–360 / 310–470 / 0–0 / 550–830 | 910 | +| `arbiter-authentication/6.1` — Planned server-key transition publication | 200–340 / 260–450 / unknown / 460–790 | 190–300 / 230–340 / 0–0 / 420–640 | 720 | +| `arbiter-authentication/6.2` — Verified server transition adoption | 200–340 / 260–450 / unknown / 460–790 | 170–280 / 240–350 / 0–0 / 410–630 | 710 | +| `arbiter-authentication/6.3` — Independent compromise recovery | 220–370 / 280–480 / unknown / 500–850 | 190–300 / 260–380 / 0–0 / 450–680 | 760 | +| `arbiter-authentication/6.4` — Server authority and leaf certificate renewal | 220–380 / 280–500 / unknown / 500–880 | 180–290 / 240–360 / 0–0 / 420–650 | 730 | +| `arbiter-authentication/7.1` — Recipient possession and bounded retention | 220–370 / 260–450 / unknown / 480–820 | 180–280 / 220–330 / 0–0 / 400–610 | 690 | +| `arbiter-authentication/7.2` — Dual-recipient encrypted artifact writing | 240–400 / 280–480 / unknown / 520–880 | 220–330 / 260–390 / 0–5 / 480–725 | 805 | +| `arbiter-authentication/7.3` — Physical quotas and encrypted-store restart | 220–360 / 280–480 / unknown / 500–840 | 200–300 / 240–360 / 0–0 / 440–660 | 740 | +| `arbiter-authentication/7.4` — Creator-bound descriptor HEAD and one GET | 220–370 / 300–500 / unknown / 520–870 | 190–290 / 260–380 / 0–0 / 450–670 | 750 | +| `arbiter-authentication/7.5` — Encrypted plugin adapter activation | 180–320 / 260–460 / unknown / 440–780 | 140–240 / 230–340 / 0–0 / 370–580 | 660 | +| `arbiter-authentication/7.6` — Encrypted-store contention and packaging | 80–180 / 300–550 / unknown / 380–730 | 30–100 / 260–400 / 0–10 / 290–510 | 590 | +| `arbiter-authentication/8.1` — Immediate decrypted stdin with explicit stream flag | 180–320 / 260–450 / unknown / 440–770 | 170–270 / 220–340 / 0–0 / 390–610 | 690 | +| `arbiter-authentication/8.2` — Verified ciphertext staging then stdin | 260–420 / 300–520 / unknown / 560–940 | 220–340 / 260–390 / 0–0 / 480–730 | 810 | +| `arbiter-authentication/8.3` — Explicit verified plaintext temporary path | 150–260 / 220–400 / unknown / 370–660 | 130–220 / 200–310 / 0–0 / 330–530 | 610 | +| `arbiter-authentication/8.4` — Verified persistent plaintext export | 140–250 / 220–400 / unknown / 360–650 | 120–210 / 200–310 / 0–0 / 320–520 | 600 | +| `arbiter-authentication/8.5` — Four-path installed process integration | 80–180 / 300–520 / unknown / 380–700 | 30–90 / 260–390 / 0–10 / 290–490 | 570 | +| `arbiter-authentication/9.1` — Coherent saved configuration and actual secrets | 240–400 / 280–480 / unknown / 520–880 | 240–360 / 260–390 / 0–0 / 500–750 | 850 | +| `arbiter-authentication/9.2` — Fenced SQLite and saved-state snapshot | 200–340 / 280–470 / unknown / 480–810 | 180–280 / 230–350 / 0–0 / 410–630 | 710 | +| `arbiter-authentication/9.3` — Strict signed recovery stream format | 250–420 / 300–520 / unknown / 550–940 | 220–340 / 260–390 / 0–0 / 480–730 | 810 | +| `arbiter-authentication/9.4` — Encrypted atomic local export | 220–360 / 280–480 / unknown / 500–840 | 200–310 / 240–360 / 0–0 / 440–670 | 750 | +| `arbiter-authentication/9.5` — External backup job and snapshot integration | 80–180 / 280–500 / unknown / 360–680 | 20–80 / 250–380 / 0–10 / 270–470 | 550 | +| `arbiter-authentication/10.1` — Strict offline decrypt and validation | 240–400 / 300–520 / unknown / 540–920 | 200–310 / 260–390 / 0–0 / 460–700 | 780 | +| `arbiter-authentication/10.2` — Exclusive restore staging and cleanup | 200–340 / 280–480 / unknown / 480–820 | 180–280 / 230–350 / 0–0 / 410–630 | 710 | +| `arbiter-authentication/10.3` — Atomic active and immutable undo publication | 220–360 / 300–520 / unknown / 520–880 | 190–300 / 260–390 / 0–0 / 450–690 | 770 | +| `arbiter-authentication/10.4` — Repeatable latest undo and explicit discard | 180–300 / 260–450 / unknown / 440–750 | 160–260 / 230–350 / 0–0 / 390–610 | 690 | +| `arbiter-authentication/10.5` — Native restore crash and client integration | 80–180 / 320–550 / unknown / 400–730 | 30–100 / 280–420 / 0–10 / 310–530 | 610 | +| `arbiter-authentication/11.1` — Maintenance drain and cooperative migration | 180–300 / 260–450 / unknown / 440–750 | 170–280 / 240–360 / 0–0 / 410–640 | 720 | +| `arbiter-authentication/11.2` — Authenticated fixed URL handoff | 220–380 / 280–500 / unknown / 500–880 | 180–290 / 240–370 / 0–0 / 420–660 | 740 | +| `arbiter-authentication/11.3` — Multi-client migration and whole-auth integration | 80–180 / 320–550 / unknown / 400–730 | 30–100 / 300–440 / 0–10 / 330–550 | 630 | + +Ranges are low-confidence forecasts from the consumed mechanisms and native test obligations, not measured bounds. Static fixture data/generated outputs and development docs remain additional unquantified burden. Recheck actual authored additions plus deletions before each cut; do not compress code or remove tests to fit. diff --git a/docs/authentication/supporting/implementation-plan/estimates-after.json b/docs/authentication/supporting/implementation-plan/estimates-after.json new file mode 100644 index 0000000..fc53cdd --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/estimates-after.json @@ -0,0 +1,1489 @@ +{ + "schema_version": 1, + "source_head": "d52f8bc0acadc1de0dcb53fb1a96eb3e822e174a", + "unit": "Incremental final delivered nonblank physical production/test/CI lines; exclude comment-only lines, count docstrings physically", + "slices": [ + { + "slice_id": "arbiter-authentication/3.1.1", + "title": "Shared bounded carrier and streaming peer", + "production": [ + 220, + 310 + ], + "tests": [ + 250, + 360 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 470, + 675 + ], + "predicted_authored_churn_upper": 855, + "churn_headroom": 180, + "basis": "pump", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.1.2", + "title": "Strict ordinary server TLS peer", + "production": [ + 150, + 220 + ], + "tests": [ + 260, + 370 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 410, + 590 + ], + "predicted_authored_churn_upper": 670, + "churn_headroom": 80, + "basis": "tls", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.1.3", + "title": "Verified Go native HTTP connection", + "production": [ + 170, + 240 + ], + "tests": [ + 250, + 350 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 420, + 590 + ], + "predicted_authored_churn_upper": 670, + "churn_headroom": 80, + "basis": "dial", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.1.4", + "title": "One-request HTTP to ASGI stream", + "production": [ + 210, + 290 + ], + "tests": [ + 300, + 420 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 510, + 710 + ], + "predicted_authored_churn_upper": 790, + "churn_headroom": 80, + "basis": "http", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.2.1", + "title": "Live enrollment and receipt denial", + "production": [ + 210, + 310 + ], + "tests": [ + 370, + 510 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 580, + 820 + ], + "predicted_authored_churn_upper": 920, + "churn_headroom": 100, + "basis": "live", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.2.2", + "title": "Grant controls and dispatch coordinator", + "production": [ + 200, + 280 + ], + "tests": [ + 280, + 390 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 480, + 670 + ], + "predicted_authored_churn_upper": 750, + "churn_headroom": 80, + "basis": "live", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.3", + "title": "Grant-filtered discovery and direct lookup", + "production": [ + 150, + 220 + ], + "tests": [ + 270, + 380 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 420, + 600 + ], + "predicted_authored_churn_upper": 680, + "churn_headroom": 80, + "basis": "projection", + "confidence": "medium", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.4", + "title": "Authorized plugins with closed artifacts", + "production": [ + 190, + 280 + ], + "tests": [ + 300, + 410 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 490, + 690 + ], + "predicted_authored_churn_upper": 770, + "churn_headroom": 80, + "basis": "dispatch", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.6.1", + "title": "Cross-connection denial and worker ownership", + "production": [ + 160, + 240 + ], + "tests": [ + 300, + 420 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 460, + 660 + ], + "predicted_authored_churn_upper": 740, + "churn_headroom": 80, + "basis": "denial", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.6.2", + "title": "Final-write revocation barrier", + "production": [ + 130, + 200 + ], + "tests": [ + 280, + 390 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 410, + 590 + ], + "predicted_authored_churn_upper": 670, + "churn_headroom": 80, + "basis": "denial", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.5.1", + "title": "Explicit enrollment selection across CLI", + "production": [ + 110, + 170 + ], + "tests": [ + 260, + 360 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 370, + 530 + ], + "predicted_authored_churn_upper": 610, + "churn_headroom": 80, + "basis": "cli", + "confidence": "medium", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.5.2", + "title": "Atomic authenticated API cutover", + "production": [ + 100, + 170 + ], + "tests": [ + 310, + 430 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 410, + 600 + ], + "predicted_authored_churn_upper": 680, + "churn_headroom": 80, + "basis": "cutover", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/3.7", + "title": "Installed native transport integration", + "production": [ + 20, + 60 + ], + "tests": [ + 300, + 420 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 320, + 490 + ], + "predicted_authored_churn_upper": 570, + "churn_headroom": 80, + "basis": "installed", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/4.1", + "title": "Due rotation with a fixed deadline", + "production": [ + 250, + 370 + ], + "tests": [ + 280, + 410 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 530, + 780 + ], + "predicted_authored_churn_upper": 860, + "churn_headroom": 80, + "basis": "rotation", + "confidence": "low", + "source_inspection": "estimate-basis.md", + "review_correction_basis": "R4-1: actual server wire and bounded route ownership" + }, + { + "slice_id": "arbiter-authentication/4.2", + "title": "Durable candidate activation and reconciliation", + "production": [ + 280, + 390 + ], + "tests": [ + 320, + 450 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 600, + 840 + ], + "predicted_authored_churn_upper": 920, + "churn_headroom": 80, + "basis": "rotationclient", + "confidence": "low", + "source_inspection": "estimate-basis.md", + "review_correction_basis": "R4-1: shared CLI/HTTP lifecycle preflight, every loss/save/deadline path" + }, + { + "slice_id": "arbiter-authentication/4.3", + "title": "Purpose-bound late completion", + "production": [ + 230, + 350 + ], + "tests": [ + 280, + 410 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 510, + 760 + ], + "predicted_authored_churn_upper": 840, + "churn_headroom": 80, + "basis": "rotationcontrol", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/4.4", + "title": "One authenticated predecessor attempt", + "production": [ + 140, + 230 + ], + "tests": [ + 210, + 320 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 350, + 550 + ], + "predicted_authored_churn_upper": 630, + "churn_headroom": 80, + "basis": "rotationclient", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/4.5", + "title": "Lifecycle process and clock integration", + "production": [ + 30, + 90 + ], + "tests": [ + 270, + 400 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 300, + 500 + ], + "predicted_authored_churn_upper": 580, + "churn_headroom": 80, + "basis": "lifecycleinstalled", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/5.1", + "title": "Pairing repair of an existing enrollment", + "production": [ + 170, + 270 + ], + "tests": [ + 230, + 350 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 400, + 620 + ], + "predicted_authored_churn_upper": 700, + "churn_headroom": 80, + "basis": "repair", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/5.2", + "title": "Offline owner authorization files", + "production": [ + 240, + 360 + ], + "tests": [ + 300, + 420 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 540, + 780 + ], + "predicted_authored_churn_upper": 860, + "churn_headroom": 80, + "basis": "recovery", + "confidence": "low", + "source_inspection": "estimate-basis.md", + "review_correction_basis": "R4-3: stateless origin cookie and request-flood availability tests" + }, + { + "slice_id": "arbiter-authentication/5.3", + "title": "Atomic access recovery and exact receipt", + "production": [ + 220, + 330 + ], + "tests": [ + 260, + 390 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 480, + 720 + ], + "predicted_authored_churn_upper": 800, + "churn_headroom": 80, + "basis": "recovery", + "confidence": "low", + "source_inspection": "estimate-basis.md", + "review_correction_basis": "R4-3: authorized first-wins compare-and-swap and consumed operation" + }, + { + "slice_id": "arbiter-authentication/5.4", + "title": "Portable replacement across enrolled servers", + "production": [ + 280, + 410 + ], + "tests": [ + 340, + 490 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 620, + 900 + ], + "predicted_authored_churn_upper": 980, + "churn_headroom": 80, + "basis": "portable", + "confidence": "low", + "source_inspection": "estimate-basis.md", + "review_correction_basis": "R4-2: actual original issuer signing handler and atomic two-server custody" + }, + { + "slice_id": "arbiter-authentication/5.5", + "title": "Owner issuer and portable certificate renewal", + "production": [ + 240, + 360 + ], + "tests": [ + 310, + 470 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 550, + 830 + ], + "predicted_authored_churn_upper": 910, + "churn_headroom": 80, + "basis": "renewowner", + "confidence": "low", + "source_inspection": "estimate-basis.md", + "review_correction_basis": "R4-2: exact same-key root continuity/registry forwarding plus leaf renewal" + }, + { + "slice_id": "arbiter-authentication/6.1", + "title": "Planned server-key transition publication", + "production": [ + 190, + 300 + ], + "tests": [ + 230, + 340 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 420, + 640 + ], + "predicted_authored_churn_upper": 720, + "churn_headroom": 80, + "basis": "transition", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/6.2", + "title": "Verified server transition adoption", + "production": [ + 170, + 280 + ], + "tests": [ + 240, + 350 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 410, + 630 + ], + "predicted_authored_churn_upper": 710, + "churn_headroom": 80, + "basis": "transitionclient", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/6.3", + "title": "Independent compromise recovery", + "production": [ + 190, + 300 + ], + "tests": [ + 260, + 380 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 450, + 680 + ], + "predicted_authored_churn_upper": 760, + "churn_headroom": 80, + "basis": "compromise", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/6.4", + "title": "Server authority and leaf certificate renewal", + "production": [ + 180, + 290 + ], + "tests": [ + 240, + 360 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 420, + 650 + ], + "predicted_authored_churn_upper": 730, + "churn_headroom": 80, + "basis": "transition", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/7.1", + "title": "Recipient possession and bounded retention", + "production": [ + 180, + 280 + ], + "tests": [ + 220, + 330 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 400, + 610 + ], + "predicted_authored_churn_upper": 690, + "churn_headroom": 80, + "basis": "recipient", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/7.2", + "title": "Dual-recipient encrypted artifact writing", + "production": [ + 220, + 330 + ], + "tests": [ + 260, + 390 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 480, + 725 + ], + "predicted_authored_churn_upper": 805, + "churn_headroom": 80, + "basis": "artifactcrypto", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/7.3", + "title": "Physical quotas and encrypted-store restart", + "production": [ + 200, + 300 + ], + "tests": [ + 240, + 360 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 440, + 660 + ], + "predicted_authored_churn_upper": 740, + "churn_headroom": 80, + "basis": "artifactquota", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/7.4", + "title": "Creator-bound descriptor HEAD and one GET", + "production": [ + 190, + 290 + ], + "tests": [ + 260, + 380 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 450, + 670 + ], + "predicted_authored_churn_upper": 750, + "churn_headroom": 80, + "basis": "artifactaccess", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/7.5", + "title": "Encrypted plugin adapter activation", + "production": [ + 140, + 240 + ], + "tests": [ + 230, + 340 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 370, + 580 + ], + "predicted_authored_churn_upper": 660, + "churn_headroom": 80, + "basis": "artifactplugin", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/7.6", + "title": "Encrypted-store contention and packaging", + "production": [ + 30, + 100 + ], + "tests": [ + 260, + 400 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 290, + 510 + ], + "predicted_authored_churn_upper": 590, + "churn_headroom": 80, + "basis": "artifactinstalled", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/8.1", + "title": "Immediate decrypted stdin with explicit stream flag", + "production": [ + 170, + 270 + ], + "tests": [ + 220, + 340 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 390, + 610 + ], + "predicted_authored_churn_upper": 690, + "churn_headroom": 80, + "basis": "artifactcli", + "confidence": "medium", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/8.2", + "title": "Verified ciphertext staging then stdin", + "production": [ + 220, + 340 + ], + "tests": [ + 260, + 390 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 480, + 730 + ], + "predicted_authored_churn_upper": 810, + "churn_headroom": 80, + "basis": "artifacttemp", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/8.3", + "title": "Explicit verified plaintext temporary path", + "production": [ + 130, + 220 + ], + "tests": [ + 200, + 310 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 330, + 530 + ], + "predicted_authored_churn_upper": 610, + "churn_headroom": 80, + "basis": "artifacttemp", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/8.4", + "title": "Verified persistent plaintext export", + "production": [ + 120, + 210 + ], + "tests": [ + 200, + 310 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 320, + 520 + ], + "predicted_authored_churn_upper": 600, + "churn_headroom": 80, + "basis": "artifactcli", + "confidence": "medium", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/8.5", + "title": "Four-path installed process integration", + "production": [ + 30, + 90 + ], + "tests": [ + 260, + 390 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 290, + 490 + ], + "predicted_authored_churn_upper": 570, + "churn_headroom": 80, + "basis": "artifactinstalled", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/9.1", + "title": "Coherent saved configuration and actual secrets", + "production": [ + 240, + 360 + ], + "tests": [ + 260, + 390 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 500, + 750 + ], + "predicted_authored_churn_upper": 850, + "churn_headroom": 100, + "basis": "savedconfig", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/9.2", + "title": "Fenced SQLite and saved-state snapshot", + "production": [ + 180, + 280 + ], + "tests": [ + 230, + 350 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 410, + 630 + ], + "predicted_authored_churn_upper": 710, + "churn_headroom": 80, + "basis": "snapshot", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/9.3", + "title": "Strict signed recovery stream format", + "production": [ + 220, + 340 + ], + "tests": [ + 260, + 390 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 480, + 730 + ], + "predicted_authored_churn_upper": 810, + "churn_headroom": 80, + "basis": "backupformat", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/9.4", + "title": "Encrypted atomic local export", + "production": [ + 200, + 310 + ], + "tests": [ + 240, + 360 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 440, + 670 + ], + "predicted_authored_churn_upper": 750, + "churn_headroom": 80, + "basis": "export", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/9.5", + "title": "External backup job and snapshot integration", + "production": [ + 20, + 80 + ], + "tests": [ + 250, + 380 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 270, + 470 + ], + "predicted_authored_churn_upper": 550, + "churn_headroom": 80, + "basis": "backupinstalled", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/10.1", + "title": "Strict offline decrypt and validation", + "production": [ + 200, + 310 + ], + "tests": [ + 260, + 390 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 460, + 700 + ], + "predicted_authored_churn_upper": 780, + "churn_headroom": 80, + "basis": "restore", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/10.2", + "title": "Exclusive restore staging and cleanup", + "production": [ + 180, + 280 + ], + "tests": [ + 230, + 350 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 410, + 630 + ], + "predicted_authored_churn_upper": 710, + "churn_headroom": 80, + "basis": "restorestage", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/10.3", + "title": "Atomic active and immutable undo publication", + "production": [ + 190, + 300 + ], + "tests": [ + 260, + 390 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 450, + 690 + ], + "predicted_authored_churn_upper": 770, + "churn_headroom": 80, + "basis": "activate", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/10.4", + "title": "Repeatable latest undo and explicit discard", + "production": [ + 160, + 260 + ], + "tests": [ + 230, + 350 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 390, + 610 + ], + "predicted_authored_churn_upper": 690, + "churn_headroom": 80, + "basis": "undo", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/10.5", + "title": "Native restore crash and client integration", + "production": [ + 30, + 100 + ], + "tests": [ + 280, + 420 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 310, + 530 + ], + "predicted_authored_churn_upper": 610, + "churn_headroom": 80, + "basis": "restoreinstalled", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/11.1", + "title": "Maintenance drain and cooperative migration", + "production": [ + 170, + 280 + ], + "tests": [ + 240, + 360 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 410, + 640 + ], + "predicted_authored_churn_upper": 720, + "churn_headroom": 80, + "basis": "maintenance", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/11.2", + "title": "Authenticated fixed URL handoff", + "production": [ + 180, + 290 + ], + "tests": [ + 240, + 370 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 420, + 660 + ], + "predicted_authored_churn_upper": 740, + "churn_headroom": 80, + "basis": "handoff", + "confidence": "low", + "source_inspection": "estimate-basis.md" + }, + { + "slice_id": "arbiter-authentication/11.3", + "title": "Multi-client migration and whole-auth integration", + "production": [ + 30, + 100 + ], + "tests": [ + 300, + 440 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 330, + 550 + ], + "predicted_authored_churn_upper": 630, + "churn_headroom": 80, + "basis": "combined", + "confidence": "low", + "source_inspection": "estimate-basis.md" + } + ], + "range_basis": "Bottom-up complete consumed boundary, current source/harness reuse, concrete state/schema/negative/failure/platform obligations. No mechanical scaling of old estimates. Separate conservative authored-churn envelope includes bounded replacement/code-motion/comment headroom and must be rechecked before delivery.", + "milestone_rollups": [ + { + "milestone": "3", + "cuts": 13, + "production": [ + 2020, + 2990 + ], + "tests": [ + 3730, + 5210 + ], + "ci": [ + 0, + 15 + ], + "combined": [ + 5750, + 8215 + ] + }, + { + "milestone": "4", + "cuts": 5, + "production": [ + 930, + 1430 + ], + "tests": [ + 1360, + 1990 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 2290, + 3430 + ] + }, + { + "milestone": "5", + "cuts": 5, + "production": [ + 1150, + 1730 + ], + "tests": [ + 1440, + 2120 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 2590, + 3850 + ] + }, + { + "milestone": "6", + "cuts": 4, + "production": [ + 730, + 1170 + ], + "tests": [ + 970, + 1430 + ], + "ci": [ + 0, + 0 + ], + "combined": [ + 1700, + 2600 + ] + }, + { + "milestone": "7", + "cuts": 6, + "production": [ + 960, + 1540 + ], + "tests": [ + 1470, + 2200 + ], + "ci": [ + 0, + 15 + ], + "combined": [ + 2430, + 3755 + ] + }, + { + "milestone": "8", + "cuts": 5, + "production": [ + 670, + 1130 + ], + "tests": [ + 1140, + 1740 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 1810, + 2880 + ] + }, + { + "milestone": "9", + "cuts": 5, + "production": [ + 860, + 1370 + ], + "tests": [ + 1240, + 1870 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 2100, + 3250 + ] + }, + { + "milestone": "10", + "cuts": 5, + "production": [ + 760, + 1250 + ], + "tests": [ + 1260, + 1900 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 2020, + 3160 + ] + }, + { + "milestone": "11", + "cuts": 3, + "production": [ + 380, + 670 + ], + "tests": [ + 780, + 1170 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 1160, + 1850 + ] + } + ], + "project_totals": { + "production": [ + 8460, + 13280 + ], + "tests": [ + 13390, + 19630 + ], + "ci": [ + 0, + 80 + ], + "combined": [ + 21850, + 32990 + ] + } +} diff --git a/docs/authentication/supporting/implementation-plan/estimates-before.json b/docs/authentication/supporting/implementation-plan/estimates-before.json new file mode 100644 index 0000000..8e8447e --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/estimates-before.json @@ -0,0 +1,1188 @@ +{ + "schema_version": 1, + "source_head": "d52f8bc0acadc1de0dcb53fb1a96eb3e822e174a", + "scope": "milestones3\u201311", + "unit": "added-plus-deleted edit churn, excluding unquantified work as noted", + "counting_note": "Original estimates are added-plus-deleted handwritten edit churn. They do not establish final nonblank code size. Historical CI unknown is not zero.", + "source_documents": [ + { + "path": "docs/authentication/implementation-plan.md", + "sha256": "3c0fada6a105777ecd5546b3f3898b0b2dea71f1032176e6ccd7c3fd51386a6a", + "executable": false + }, + { + "path": "docs/authentication/milestone-3-lld.md", + "sha256": "566601529e5dabfa25cb575a9fc890ab625f358115ab0b836a53174a025bd25f", + "executable": false + } + ], + "slices": [ + { + "slice_id": "arbiter-authentication/4.1", + "title": "Server pending rotation and fixed grace", + "production": [ + 220, + 360 + ], + "tests": [ + 260, + 450 + ], + "combined": [ + 480, + 810 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/4.2", + "title": "Durable candidate confirmation", + "production": [ + 240, + 400 + ], + "tests": [ + 300, + 500 + ], + "combined": [ + 540, + 900 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/4.3", + "title": "Expired-key restricted completion", + "production": [ + 260, + 420 + ], + "tests": [ + 300, + 520 + ], + "combined": [ + 560, + 940 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/4.4", + "title": "Authenticated predecessor assistance", + "production": [ + 160, + 280 + ], + "tests": [ + 240, + 420 + ], + "combined": [ + 400, + 700 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/4.5", + "title": "Lifecycle race and clock closure", + "production": [ + 80, + 180 + ], + "tests": [ + 320, + 550 + ], + "combined": [ + 400, + 730 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/5.1", + "title": "Owner-approved pairing repair", + "production": [ + 180, + 300 + ], + "tests": [ + 240, + 420 + ], + "combined": [ + 420, + 720 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/5.2", + "title": "External owner challenge proofs", + "production": [ + 220, + 370 + ], + "tests": [ + 280, + 480 + ], + "combined": [ + 500, + 850 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/5.3", + "title": "Atomic access-key recovery", + "production": [ + 200, + 330 + ], + "tests": [ + 260, + 450 + ], + "combined": [ + 460, + 780 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/5.4", + "title": "Portable identity repair across servers", + "production": [ + 180, + 320 + ], + "tests": [ + 280, + 480 + ], + "combined": [ + 460, + 800 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/5.5", + "title": "Owner and portable certificate renewal", + "production": [ + 180, + 330 + ], + "tests": [ + 260, + 450 + ], + "combined": [ + 440, + 780 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/6.1", + "title": "Planned server transition publication", + "production": [ + 200, + 340 + ], + "tests": [ + 260, + 450 + ], + "combined": [ + 460, + 790 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/6.2", + "title": "Client transition adoption", + "production": [ + 200, + 340 + ], + "tests": [ + 260, + 450 + ], + "combined": [ + 460, + 790 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/6.3", + "title": "Independent compromise recovery", + "production": [ + 220, + 370 + ], + "tests": [ + 280, + 480 + ], + "combined": [ + 500, + 850 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/6.4", + "title": "Server authority and leaf renewal", + "production": [ + 220, + 380 + ], + "tests": [ + 280, + 500 + ], + "combined": [ + 500, + 880 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/7.1", + "title": "Artifact recipient registration and retention", + "production": [ + 220, + 370 + ], + "tests": [ + 260, + 450 + ], + "combined": [ + 480, + 820 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/7.2", + "title": "Encrypted payload and metadata writing", + "production": [ + 240, + 400 + ], + "tests": [ + 280, + 480 + ], + "combined": [ + 520, + 880 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/7.3", + "title": "Physical quota and encrypted-store recovery", + "production": [ + 220, + 360 + ], + "tests": [ + 280, + 480 + ], + "combined": [ + 500, + 840 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/7.4", + "title": "Creator-bound HEAD and consuming GET", + "production": [ + 220, + 370 + ], + "tests": [ + 300, + 500 + ], + "combined": [ + 520, + 870 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/7.5", + "title": "Plugin adapter and descriptor activation", + "production": [ + 180, + 320 + ], + "tests": [ + 260, + 460 + ], + "combined": [ + 440, + 780 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/7.6", + "title": "Artifact contention and packaging closure", + "production": [ + 80, + 180 + ], + "tests": [ + 300, + 550 + ], + "combined": [ + 380, + 730 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/8.1", + "title": "Immediate authenticated plaintext stdin", + "production": [ + 180, + 320 + ], + "tests": [ + 260, + 450 + ], + "combined": [ + 440, + 770 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/8.2", + "title": "Verified encrypted-temp stdin", + "production": [ + 260, + 420 + ], + "tests": [ + 300, + 520 + ], + "combined": [ + 560, + 940 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/8.3", + "title": "Explicit plaintext-temp path", + "production": [ + 150, + 260 + ], + "tests": [ + 220, + 400 + ], + "combined": [ + 370, + 660 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/8.4", + "title": "Deliberate save-decrypted export", + "production": [ + 140, + 250 + ], + "tests": [ + 220, + 400 + ], + "combined": [ + 360, + 650 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/8.5", + "title": "Four-mode process and platform closure", + "production": [ + 80, + 180 + ], + "tests": [ + 300, + 520 + ], + "combined": [ + 380, + 700 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/9.1", + "title": "Saved configuration and real secret capture", + "production": [ + 240, + 400 + ], + "tests": [ + 280, + 480 + ], + "combined": [ + 520, + 880 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/9.2", + "title": "Coherent authority snapshot", + "production": [ + 200, + 340 + ], + "tests": [ + 280, + 470 + ], + "combined": [ + 480, + 810 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/9.3", + "title": "Signed bounded recovery records", + "production": [ + 250, + 420 + ], + "tests": [ + 300, + 520 + ], + "combined": [ + 550, + 940 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/9.4", + "title": "Encrypted local and SSH export", + "production": [ + 220, + 360 + ], + "tests": [ + 280, + 480 + ], + "combined": [ + 500, + 840 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/9.5", + "title": "External job and concurrent-export closure", + "production": [ + 80, + 180 + ], + "tests": [ + 280, + 500 + ], + "combined": [ + 360, + 680 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/10.1", + "title": "Strict offline bundle validation", + "production": [ + 240, + 400 + ], + "tests": [ + 300, + 520 + ], + "combined": [ + 540, + 920 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/10.2", + "title": "Stopped-instance private restore staging", + "production": [ + 200, + 340 + ], + "tests": [ + 280, + 480 + ], + "combined": [ + 480, + 820 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/10.3", + "title": "Atomic full restore activation", + "production": [ + 220, + 360 + ], + "tests": [ + 300, + 520 + ], + "combined": [ + 520, + 880 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/10.4", + "title": "Latest undo and explicit discard", + "production": [ + 180, + 300 + ], + "tests": [ + 260, + 450 + ], + "combined": [ + 440, + 750 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/10.5", + "title": "Restore-client and native crash closure", + "production": [ + 80, + 180 + ], + "tests": [ + 320, + 550 + ], + "combined": [ + 400, + 730 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/11.1", + "title": "Cooperative maintenance and migration", + "production": [ + 180, + 300 + ], + "tests": [ + 260, + 450 + ], + "combined": [ + 440, + 750 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/11.2", + "title": "Verified source URL handoff", + "production": [ + 220, + 380 + ], + "tests": [ + 280, + 500 + ], + "combined": [ + 500, + 880 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/11.3", + "title": "Migration and combined release evidence", + "production": [ + 80, + 180 + ], + "tests": [ + 320, + 550 + ], + "combined": [ + 400, + 730 + ], + "ci": null, + "unit": "historical handwritten added-plus-deleted edit churn", + "basis": "implementation-plan.md historical child tables; CI not separately quantified" + }, + { + "slice_id": "arbiter-authentication/3.1.1", + "title": "Shared bounded carrier/lease/TLS pump extracted and consumed by existing pairing/control and real streaming Python/Go peers. Own shared streaming harness. N03/N04; no ordinary public route.", + "production": [ + 320, + 440 + ], + "tests": [ + 300, + 420 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 620, + 865 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.1.2", + "title": "Strict Python ordinary mTLS and immutable candidate identity consumed by real peer; live admission still private. N01 and handshake limits.", + "production": [ + 170, + 240 + ], + "tests": [ + 310, + 420 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 480, + 665 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.1.3", + "title": "Go strict native identity/dial plus standard HTTP transport, exercised against real Python; reuse stored decoder and existing timeout wrapper. N01/N02/N11.", + "production": [ + 190, + 260 + ], + "tests": [ + 300, + 410 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 490, + 675 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.1.4", + "title": "One-request bounded HTTP/ASGI stream with immutable scope, real body/response peers and no public cutover. N03/N04, parser/body admission.", + "production": [ + 230, + 320 + ], + "tests": [ + 350, + 470 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 580, + 795 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.2.1", + "title": "Live row extension/atomic backfill and OS enrollment-deny control with minimal shared coordinator consumed by the real fixed receipt. Guard receipt admission and final output, retain actual owners and test N07 receipt races/rollback/cleanup. Use the existing agent binding without a row copy; validate old/fresh/replay and corrupt relations. Extend activation once; preserve original receipt. N05.", + "production": [ + 230, + 330 + ], + "tests": [ + 420, + 610 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 650, + 945 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.2.2", + "title": "Extend the same coordinator/writer reservation to ordinary authority and actual-worker callbacks, consumed by private real ASGI peer. Own OS grant add/remove controls. N04/N05/N06/N07 dispatch, busy/rollback and no stale snapshot authorization.", + "production": [ + 220, + 300 + ], + "tests": [ + 330, + 430 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 550, + 735 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.3", + "title": "All discovery/direct-account/policy projections use exact live grants with current schemas and private peer. N06 including negative information leaks.", + "production": [ + 160, + 230 + ], + "tests": [ + 320, + 440 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 480, + 675 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.4", + "title": "Real authorized plugin dispatch with caller context, closed concrete artifact dependency, descriptor/inline closure and confined startup invalidation. N09 with spy plus filesystem; reuse shared harness.", + "production": [ + 230, + 320 + ], + "tests": [ + 350, + 460 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 580, + 785 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.6.1", + "title": "Denial closes all affected body/dispatch paths across actual sockets; actual blocked work retains slots/carriers. N07/N08, cutoff/rollback and admin responsiveness.", + "production": [ + 190, + 270 + ], + "tests": [ + 350, + 470 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 540, + 745 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.6.2", + "title": "Permission after backpressure and final ciphertext-write boundary, abort without flushing revoked output. N03/N07/N08 streaming/late-worker cases.", + "production": [ + 150, + 220 + ], + "tests": [ + 330, + 450 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 480, + 675 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.5.1", + "title": "Explicit selector/config/help and every CLI constructor exercises the verified native factory through complete private real peers; production selection stays on the existing working route. N10/N11.", + "production": [ + 130, + 180 + ], + "tests": [ + 320, + 410 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 450, + 595 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.5.2", + "title": "Atomic production CLI constructor switch, public ordinary enablement and anonymous API/artifact closure, with no fallback; first installed authenticated prefix executes denial and closed-artifact journey. N01/N04/N07/N09/N10/N12.", + "production": [ + 110, + 190 + ], + "tests": [ + 380, + 510 + ], + "ci": [ + 0, + 5 + ], + "combined": [ + 490, + 705 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + }, + { + "slice_id": "arbiter-authentication/3.7", + "title": "Focused installed relay/outer-cert/passthrough and timeout composition, native prefix/packaging closure; add no deferred core mechanism. N02/N11/N12 and all parent N01\u2013N12.", + "production": [ + 20, + 60 + ], + "tests": [ + 380, + 480 + ], + "ci": [ + 0, + 10 + ], + "combined": [ + 400, + 550 + ], + "unit": "handwritten added-plus-deleted edit churn", + "basis": "milestone-3-lld.md newly sized 13-cut table" + } + ], + "milestone_rollups": { + "4": { + "cuts": 5, + "production": [ + 960, + 1640 + ], + "tests": [ + 1420, + 2440 + ], + "combined": [ + 2380, + 4080 + ], + "ci": null, + "ci_quantified": false + }, + "5": { + "cuts": 5, + "production": [ + 960, + 1650 + ], + "tests": [ + 1320, + 2280 + ], + "combined": [ + 2280, + 3930 + ], + "ci": null, + "ci_quantified": false + }, + "6": { + "cuts": 4, + "production": [ + 840, + 1430 + ], + "tests": [ + 1080, + 1880 + ], + "combined": [ + 1920, + 3310 + ], + "ci": null, + "ci_quantified": false + }, + "7": { + "cuts": 6, + "production": [ + 1160, + 2000 + ], + "tests": [ + 1680, + 2920 + ], + "combined": [ + 2840, + 4920 + ], + "ci": null, + "ci_quantified": false + }, + "8": { + "cuts": 5, + "production": [ + 810, + 1430 + ], + "tests": [ + 1300, + 2290 + ], + "combined": [ + 2110, + 3720 + ], + "ci": null, + "ci_quantified": false + }, + "9": { + "cuts": 5, + "production": [ + 990, + 1700 + ], + "tests": [ + 1420, + 2450 + ], + "combined": [ + 2410, + 4150 + ], + "ci": null, + "ci_quantified": false + }, + "10": { + "cuts": 5, + "production": [ + 920, + 1580 + ], + "tests": [ + 1460, + 2520 + ], + "combined": [ + 2380, + 4100 + ], + "ci": null, + "ci_quantified": false + }, + "11": { + "cuts": 3, + "production": [ + 480, + 860 + ], + "tests": [ + 860, + 1500 + ], + "combined": [ + 1340, + 2360 + ], + "ci": null, + "ci_quantified": false + }, + "3": { + "cuts": 13, + "production": [ + 2350, + 3360 + ], + "tests": [ + 4440, + 5980 + ], + "combined": [ + 6790, + 9410 + ], + "ci": [ + 0, + 70 + ], + "ci_quantified": true + } + }, + "comparison_rule": "Retain original units. Raw before/after numbers are not a like-for-like savings claim. Preserve parent rollups when cuts change; historical CI unknown is not zero." +} diff --git a/docs/authentication/supporting/implementation-plan/historical-native-lld.md b/docs/authentication/supporting/implementation-plan/historical-native-lld.md new file mode 100644 index 0000000..e4732b8 --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/historical-native-lld.md @@ -0,0 +1,436 @@ +# Native API, grants and live denial: low-level design + +Status: design candidate; no product implementation or delivery authorization. +This refines [requirements](requirements.md) R10–R14 and [HLD](high-level-design.md) +B2/B3. It consumes the reviewed [portable enrollment LLD](portable-enrollment-lld.md). +Those three documents are its explicit design dependencies. Requirements/HLD bytes +remain unchanged. The original milestone-3 seven-PR forecast is historical; the +already sized proposal below replaces its cuts, not its approved product scope. + +Source basis: merged main `25a8cf2196f36499ff92ce890f313901b51b4f2b` plus the +unimplemented portable-enrollment contract. Current `ControlTLS` is a fixed +64-KiB exchange, not an ordinary stream. `PairingProtocol` owns carrier bounds; +`BlockingOperationPool` already retains actual threads after waiter cancellation; +`HTTPWork` supplies a worker/loop bridge. `main.py` still exposes anonymous API +and legacy artifact routes. Go `configuredHTTPClient` still constructs ordinary +HTTP clients. This document specifies changes to those paths, not a second API, +transport daemon, policy engine or authorization cache. + +## One ordinary channel and one selected enrollment + +The outer carrier is a binary WebSocket at `/api/v1/native/api`. Ordinary inner +TLS is exactly TLS 1.3 with ALPN `arbiter-native-v1`; the existing fixed control +endpoint keeps `arbiter-control-v1` and never reaches ASGI. Pairing remains Noise. +Disable compression, TLS tickets/resumption, early data, HTTP/2, pipelining and +redirects. Use one HTTP/1.1 request per inner connection, then close. This is a +simple subset of the HLD's one-in-flight rule and needs no connection pool or +operation replay protocol. + +Add the public selector setting `arbiter.enrollment` to existing client YAML and +the `enrollment=SELECTOR` override. It uses the existing canonical 22-character +selector, not a filename, key, URL or display name. Explicit override wins over +the config value. Missing selection gives enrollment/configuration guidance before +dial; never scan for a first identity or derive authority from URL. Enrollment +prints its final selector and this configuration guidance after durable promotion. +Changing `url=...` changes location only. Loading the selected record fixes the +expected server ID, remembered server authority and exact access key for this +logical request. Another server's record cannot authenticate a redirected URL. + +Reuse the strict stored-record decoder from portable enrollment with a distinct +`LoadNativeIdentity` validator. Accept only final `enrolled/` native-owned state, +validate current server authority, exact access profile/IDs/key correspondence and +complete receipt/promotion. The portable leaf is historical enrollment evidence; +its later expiry is not ordinary access authority. Never accept portable proof, +prepared-only state or a lifecycle time exception as ordinary authentication. +Owner recovery and current/predecessor rotation remain milestones 4/5, not an +authentication retry added here. + +Go's existing WebSocket `net.Conn` adapter carries `crypto/tls`. Verify the exact +remembered server authority, server-role SAN/ID, validity, key usage, EKU and +critical extensions before returning the stream. `GetClientCertificate` requires +the per-connection expected-server-verified marker before it supplies access +credentials. Do not put enrollment IDs, account names, application headers, +cookies, proxy authorization or nonces in the outer request. The dedicated native +outer dial may tolerate unverified carrier HTTPS; general/browser constructors +do not inherit that exception. Reject outer redirects and inherited proxy auth. + +Return the verified inner connection from standard `http.Transport.DialTLSContext`. +Set `DisableKeepAlives`, disable HTTP/2 and proxy use, and reject all redirects in +the owning `http.Client`. Retain existing `TimeoutTransport` around that standard +transport; do not build a custom HTTP RoundTripper or duplicate phase timers. +The original connect budget covers outer TCP/HTTPS, upgrade and inner handshake. +`GotConn` means inner verification completed. API response time, plugin overrides +and download header/idle-progress time keep their current semantics. No phase, +reconnect, ping or wrapper restarts a logical deadline. No automatic retry after +request submission, uncertain result or consuming artifact GET. + +## Shared bounded carrier and TLS stream + +Extract only the common private carrier ownership/pump from `pairing_carrier.py` +and `control_tls.py`. Existing pairing/control behavior remains consumed by real +regression peers after extraction; fixed control framing is not generalized into +HTTP. Ordinary TLS adds a stream consumer on that same owner. Serialize every +memory-BIO operation in the existing bounded crypto pool, including handshake, +read, write, outgoing BIO drain and teardown. Handle partial writes, `WantRead` +and `WantWrite`; do not assume one send consumes one buffer. No OpenSSL private +API, TLS-record parser or new cryptographic dependency is needed. + +Python ordinary TLS requires a client certificate. Verify its exact server-issued +access profile and remembered server IDs in the crypto worker. The resulting +immutable candidate identity is not yet an authorized caller: live enrollment, +accepted key, denial, inactivity and grants are checked through the coordinator +before ASGI admission. Portable and cross-server certificates fail even with a +generic valid clientAuth chain. No caller is reconstructed from HTTP headers, +outer TLS or WebSocket metadata. Expose only the server's selected ordinary leaf; +keep owner issuer and lifecycle-control trust selection separate. + +The existing `arbiter.limits.native_transport` bounds remain: + +| Owner/resource | Limit and release condition | +| --- | --- | +| Native carrier | 16 shared by pairing, fixed control and ordinary; reserve before upgrade, no wait queue. Release after stream cleanup and every actual crypto/plugin owner ends. | +| Handshake/crypto | Four concurrent bounded crypto workers; ordinary handshake uses the same gate, 10-second handshake deadline, 256-KiB cumulative ciphertext each direction, 32-KiB chain cap. | +| Pending native data | 256 KiB in each direction, including owned adapter, WebSocket, inner TLS and transport-pending copies. Reserve before a copy or feed; release only when its owner drains/discards. | +| WebSocket | Binary only, no compression, at most 64 KiB per message including fragmentation; existing byte/time control-frame limiter. | +| HTTP | 32-KiB header section, one request, 1-MiB configured operation-body ceiling; reserve actual operation work before pulling body data. | +| Request receipt | Server-owned absolute 30-second default from inner TLS completion through complete headers/body; configurable positive `arbiter.limits.native_transport.request_receive_timeout`. Fragments/pings never restart it. | +| Operation work | Existing configured eight actual blocking workers. A canceled waiter does not release a running worker or its carrier. | +| Client transfer | Existing four-per-process admission before GET/temp reservation; closed artifact paths do not create another transfer pool. | + +Handshake totals and ordinary pending-data credits are different counters. Do not +retain the fixed control's lifetime `_control_tls_fed` counter for a long HTTP +stream or reset a cumulative counter and claim that buffers are bounded. Use one +moving credit ledger per direction, on the existing carrier owner. It accounts +for simultaneous parser fragments, queued WS chunks, BIO input/output, decrypted +pending data, header assembly and transient copies. One held WS message and one +active BIO call per carrier suffice; no background read-ahead queue is needed. + +Feed/return TLS application chunks of at most 16 KiB. Drain outgoing BIO data +before offering more input or another application write. Because `pending()` +reports decrypted bytes rather than encrypted BIO occupancy, retain credits for +all fed ciphertext until the worker reaches `WantRead` with no pending plaintext; +then, only after the initial handshake completes, retain conservative space for +one incomplete TLS 1.3 record and its copy +(36 KiB total), in addition to still-owned adapter data. Disable post-handshake +client authentication and renegotiation; control/pairing keep their existing +cumulative limits. Never discount that +reserve while a partial record remains. If credits cannot be proved available, +pause input and drain; if the peer overruns the finite pending budget, abort +before another copy. An actual worker retains its input/output credit until its +completion callback, even after cancellation. + +Use public `asyncio.Protocol`, `pause_reading`, `pause_writing` and transport +write-buffer APIs. Do not require `BufferedProtocol` at the Python 3.10 floor: +its outer SSL implementation still calls application `data_received`. Handle a +borrowed callback in bounded slices without retaining the full callback or feeding +wsproto past available credit. Reject over-budget delivery before copying it; +OS/kernel buffers and allocator capacity are not a claimed total-process heap +limit. The implementation must test actual pending-copy accounting under plain +and outer-TLS callbacks, fragmentation, coalescing and both slow directions. + +The five-minute authenticated idle timer runs only with no admitted application +work or transfer progress. A long operation remains subject to its existing +operation timeout, not this idle timer. Control pings extend no deadline. Every +timeout/abort wakes blocked readers/writers; nothing retries an operation. +The independent request-receipt timer still runs while a worker waits for a body; +admission does not exempt that wait. Stop it only on complete bounded body receipt +or request termination. One absolute timer, rather than a second sliding idle +mechanism, bounds silent and drip-fed bodies. A smaller client budget may fail +first; raising a client budget does not extend the server's configured deadline. +After body completion this timer does not cut off an admitted long plugin call. + +## HTTP/1.1 to the existing ASGI application + +Reuse the installed HTTP parser (`h11` through the existing Uvicorn dependency) +for framing, not a new HTTP grammar. The private stream adapter builds one ASGI +scope with immutable `arbiter.caller`, verified server/agent/enrollment/key IDs and +the coordinator token. Only the server transport can construct that value. Reject +Upgrade, CONNECT, absolute-form targets, unsupported transfer encodings, ambiguous +Content-Length/Transfer-Encoding, trailers that change routing/authority, and a +second request. Preserve ordinary route paths, JSON envelopes and error codes. +The outer URL's Host and identity headers have no authorization role. + +Parse a bounded complete header before choosing a route. Reserve the existing +worker and a provisional coordinator token before ASGI `receive` can supply body +data. A coalesced early body stays within pending carrier credit; excess closes +without invoking the plugin. Enforce both declared Content-Length and cumulative +decoded/chunked bytes; a missing length does not bypass the 1-MiB ceiling. Do not +emit `100 Continue` before reservation. Streaming responses use the same bounded +send/backpressure path; never concatenate an unbounded response. +If the receipt timer expires, stop ASGI body delivery, wake the existing bridge +with timeout and abort the carrier. The underlying worker remains reserved until +its actual completion callback. It must not reach schema/plugin dispatch after +timeout, even if a delayed final body fragment arrives. Missing body bytes never +receive a fresh deadline through another request or connection wrapper. + +An operation ID selects a plugin before the body identifies its account. Before +body admission require a live enrollment with at least one grant for that plugin; +after bounded JSON decode require an explicit string `account`, check that exact +configured `(plugin, account)` grant, then use the existing schema validation and +account policy. There is no default first account or new operation allowlist. +Do not call plugin validation, account lookup or upstream work for a hidden +account. The existing IMAP/SMTP operations use this account argument; a synthetic +test plugin must use the same contract. Catalog-only requests use bounded work +with a token scoped to their returned visible accounts. + +## Live authority and local administration + +Keep exact `enrollments.prepared` bytes as immutable receipt history. Extend that +existing enrollment row, not a second denial/contact table, with `server_id`, +exact accepted access DER/SPKI fingerprint, `last_contact` and a +positive monotonic integer `live_revision`. Retain existing `denied` and +`inactive_after` as the single authoritative fields read by both ordinary access +and the fixed enrollment-receipt path. Existing opaque `revision` is immutable +approval provenance bound in the prepared result; never reinterpret it as a +monotonic live revision. Below, live token/revision checks mean `live_revision`. +Grant rows have unique `(enrollment_id, plugin, account)` and reference that same +enrollment. Do not add independently authoritative caches, mirror denial/cutoff +columns or mutate grants inside historical results. +Use portable enrollment's existing indexed `agent_enrollments` relation as the +sole agent-to-enrollment mapping; do not copy `agent_id` into `enrollments`. +Admission resolves the certificate's exact agent/enrollment pair through that +relation and the same enrollment row. Missing, conflicting or corrupt bindings +fail closed before ASGI admission. Migration validates the already backfilled +relation; fresh activation and exact replay retain its existing atomic writer. +No future key-version/rotation framework is implemented in this milestone. + +One atomic startup schema upgrade backfills current key/grants and preserves each +existing denial, deadline and exact prepared/result. Initial `last_contact` is +derived from that enrollment's recorded activation/inactivity origin, not startup +time. Bound each parsed result, iterate rather than load all enrollments, reject +duplicate/malformed relationships and unknown future versions, and reuse the +existing stopped-instance/publication reconciliation rules. No serving mixed +old/new authority schemas. Fresh portable-enrollment activation populates these +columns and grants in its existing commit transaction; no interim activated row +lacks live authority. Existing receipt reads continue using the same row's exact +prepared result and live denied/inactive_after. Deny atomically blocks both paths; +authenticated ordinary contact refreshes their shared cutoff without changing +historical approval/result bytes. Receipt retrieval itself keeps its existing +contact semantics; incomplete retrieval never advances the cutoff. + +Extend trusted `arbiter-server authority` controls with `grant add`, `grant remove` +and `enrollment deny`. Inputs are one exact enrollment ID and, for grant actions, +one configured plugin/account pair. Use bounded existing local-control messages +and peer credentials/Windows caller token. Add validates configured account and +does not clear enrollment denial/inactivity. Existing add/remove/deny is +idempotent; only an effective change advances live revision. Read summaries use +32-row keyset pages by enrollment ID and never expose private key material. +There is no remote grant endpoint, automatic regrant on password change, or +implicit different account when a configured name is repointed. + +Authenticate contact only after strict mTLS and current accepted-key/live-state +verification. Atomically refresh `last_contact` and the existing 180-day cutoff +for an active enrollment; an already inactive or denied record cannot renew itself. +Malformed unauthenticated traffic or incomplete control exchange cannot refresh +contact. Rotation/grace-specific contact behavior is added by milestone 4. + +## Coordinator, dispatch and denial linearization + +Use one event-loop-owned coordinator with at most one fail-fast authority writer +reservation and live tokens bounded by the carrier/worker caps. Reuse the existing +local-control worker for its SQLite writes and existing crypto worker for +activation. A writer acquires its loop reservation, performs DB work off-loop, +then publishes commit or rollback on the loop. No event-loop SQLite, waiting +thread lock, new executor, unbounded writer queue or per-request global policy +snapshot. All writes that affect ordinary authority use this reservation; busy +writers fail safely rather than wait behind blocked plugin calls. + +Read one bounded enrollment/grant snapshot in an existing worker, carrying the +coordinator's observed write epoch. Before issuing a token or accepting a new +account-specific read, the loop requires that epoch and exact live revision still +match and no writer barrier blocks the token. Stale/busy reads fail retryably +before dispatch, never retry an upstream operation. Already live tokens use the +coordinator's explicit validity/barrier state. On a committed unrelated change, +carry those bounded tokens forward to the new revision without widening their +account scope; affected tokens are invalidated. Do not reject unrelated running +output merely because a global epoch advanced. A read-only snapshot never +independently authorizes a request. + +| Token transition | Owner and required check | +| --- | --- | +| Reserved | Real worker has started; live enrollment and plugin grant permit bounded body reads. It is not yet upstream dispatch. | +| Body complete | Parse only bounded JSON; choose the exact account and live revision, validate input through the existing schema. | +| Dispatched | At the already executing worker's plugin-entry boundary, bridge to the loop for the final exact enrollment/account/revision check. That successful handoff is the dispatch linearization point. The worker's next action calls the existing plugin; no queue, task spawning, await or alternative-account selection follows it. | +| Output | Before every response chunk and final ciphertext write, recheck the token after any wait/backpressure. | +| Canceled/waiter ended | Stop body/output and abort carrier; retain real worker, bridge, token and carrier ownership until actual work ends. | +| Actual worker finished | Existing pool `on_finished` callback retires worker ownership on the loop; release carrier only after all crypto/stream owners also finish. | + +A deny/remove writer first places an affected-token barrier on admission, final +dispatch and output. It then performs the conditional SQLite transaction in the +existing admin worker. On commit, publish revision, invalidate affected tokens +on all connections, wake waiters and abort their carriers before reporting local +success. On rollback, remove the provisional barrier and permit old authority +again without replaying canceled or uncertain operations. A grant removal cancels +that account and catalog tokens whose visible output depends on it; enrollment +denial cancels all enrollment tokens. An unrelated grant does not widen or revoke +another token. Temporarily pausing admission for one authority writer is allowed; +unaffected in-flight plugin work is not canceled merely for a global epoch change. + +The final plugin-entry handoff, not TLS acceptance or early body reservation, +orders dispatch against denial. Denial's barrier first means no later dispatch. +Handoff first means already dispatched work: OS scheduling or upstream completion +may occur after denial and cannot be undone. Report that boundary honestly; never +promise to undo mail effects. Waiting for eight blocked workers is not a condition +of committing denial or suppressing their output. + +At output, drain TLS into bounded unsent buffers, await write readiness, then +check permission immediately before synchronous `transport.write`, with no await +between check and write. Do the same at plaintext/ASGI boundaries. Denial drops +unsent BIO/WS data and aborts raw transport without flushing close-notify or queued +application bytes. Bytes already handed to transport before the barrier cannot +be recalled. A late worker result cannot recreate caller authority or send a new +error after response/cancellation. `HTTPWork` waiter cleanup stops delivery but +does not discard its bridge/token until the pool's actual completion callback. + +Fixed enrollment-receipt control uses this same coordinator. After its existing +proof and exact enrollment/result verification, return the observed write epoch +with the bounded result. Acquire an enrollment-scoped receipt token on the loop +only if the epoch and current denial/inactivity state still permit it. This token +does not grant ordinary account authority or change historical result bytes. +Retain token and carrier ownership through actual crypto/send completion. + +The enrollment-deny barrier blocks new receipt admission and unsent receipt +output. Commit invalidates affected receipt tokens and aborts their carriers +without flushing queued application data. Rollback removes the provisional +barrier; unrelated enrollment or grant changes do not revoke receipt permission. +After every output wait/backpressure, check permission immediately before the +final synchronous raw ciphertext write through the same shared carrier owner, +with no await between check and write. The receipt's database snapshot alone is +not delivery permission. Bytes already handed to transport cannot be recalled. +Inactivity also blocks fresh receipt admission under the shared live state; +existing receipt contact semantics remain unchanged. + +Ship the fixed-receipt guard with the first live enrollment-deny control in +`3.2.1`. That cut introduces the minimal shared coordinator with the real fixed +receipt as its consumer, including its final-write barrier and actual-owner +cleanup. `3.2.2` extends this same coordinator to ordinary grant/body/dispatch +work and owns ordinary grant add/remove controls. Do not expose live denial and +defer receipt output integration to `3.6` or public ordinary cutover. No second +coordinator, authority table, executor, protocol or production bypass is needed. + +## Discovery, policy and artifact closure + +Use the same token/grant projection for overview, plugin/accounts, operation/schema, +policy summaries, previews, test/info routes and direct invocation. Show a plugin +only with visible granted accounts; filter counts/examples/guidance as well as +names. Direct hidden/unknown account and policy lookup returns the same generic +not-found response before account-specific validation or upstream work. A policy +is visible only through a granted account using it; this does not create a policy +grant. Current account policy remains the only operation policy. Preserve grants +for deliberate repointing; password changes require no grant edit. + +Before ordinary public cutover, supply a small closed `ArtifactStore` implementation +through the existing plugin dependency and `for_plugin` wrapper. Current concrete +type checks remain usable. It must not invoke the legacy constructor or any legacy +create/inspect/open/read/nonce method. Keep only inert limit properties needed by +schema responses; creation fails before payload staging with an authenticated +`artifact_unavailable` error. No bypass/config flag and no plaintext fallback. +Caller identity is fixed in ASGI scope and set through a scoped `ContextVar` in +the actual synchronous plugin worker, reset in `finally`; shared runtime context +is never mutated. The later encrypted store consumes this same caller boundary. + +Also close descriptor projection and inline extraction before legacy lookup: +`_operation_artifacts`, `_native_artifact_from_descriptor` and +`_inline_artifact_payload` cannot turn a plugin-supplied old URL/path/nonce into +usable bytes or a descriptor. Close old metadata/HEAD/GET and raw artifact routes, +including guessed paths. A synthetic artifact-producing operation must fail +before any legacy-store entry, payload, metadata or nonce; inspect both a legacy +spy and actual filesystem. Report prior upstream effects without retrying them. + +Under the existing exclusive startup owner, invalidate and incrementally remove +only server-managed ownerless legacy artifact index entries and their validated +files in the configured managed store. Do not instantiate its serving store, +follow links, scan mail or touch client files. Unknown/corrupt managed metadata +fails closed with operator guidance; no guessed ownership. Cleanup is bounded +per entry and repeatable across restart; deletion failure never re-enables serving. + +## Cutover and acceptance + +Private real peers exercise ordinary TLS/ASGI/coordinator paths before public +activation. No public bypass flag or test fixture creates product authority. +Build and exercise every Go discovery/schema/error/invocation/artifact constructor +with the selected native factory through private real peers first. Keep production +constructor selection on the existing path until the same cut switches it to the +native factory, closes ordinary anonymous API and legacy artifact routes, and +enables the complete reviewed ordinary channel. That cut is `3.5.2`; `3.5.1` +does not switch the product to an unavailable server route. After cutover there +is no anonymous fallback or bypass flag. +Only minimal health and bounded enrollment bootstrap remain anonymous. Missing +authority or projection fails closed. Fixed controls stay distinct. The first +installed ordinary prefix includes denial and closed-artifact acceptance; these +are not deferred to a final release checklist. + +| ID | Required real acceptance, assigned to the owning cuts below | +| --- | --- | +| N01 | Python/Go strict mutual TLS; wrong server/ALPN/role/issuer/key/time, portable/cross-server/prepared-only state and forged proxy headers never dispatch. | +| N02 | Real outer relay observes no access identity, account, operation, body or secret; changed outer cert/URL and TCP passthrough preserve expected inner trust; wrong server fails before client credentials. | +| N03 | Exact moving pending-byte accounting, all framing/chain/handshake caps, slow bidirectional peers, fragmented/coalesced WS/TLS/HTTP and valid 1-MiB body; no lifetime-byte cap on ordinary streams. | +| N04 | Pre-body eight-worker admission, Content-Length/chunked limits and Expect behavior. Fill all eight with silent/drip-fed bodies; the absolute server deadline, delayed final fragment, denial and shutdown wake waits, prevent dispatch and recover capacity only on actual worker exit. Fragments/pings/reconnect wrappers do not extend it. Health/admin denial remain responsive. | +| N05 | Existing rows, exact receipts, opaque approval revision, denies, grants and original inactivity survive one-way upgrade/restart. Admission uses the existing canonical agent binding after old-row backfill, fresh activation and exact replay; missing/conflicting/corrupt relations fail closed without a second agent-ID copy. Ordinary access and receipt read one denial/cutoff authority; denial blocks both, and active contact refresh changes their shared cutoff without changing historical bytes. | +| N06 | Discovery/count/schema/policy/error/preview/direct paths reveal only granted accounts and use existing policies; account repoint and password renewal preserve grants. | +| N07 | Controlled real-socket deny/remove races at queued read, body, final dispatch and cross-connection output. Fixed receipts also race snapshot return, token admission, blocked output and final raw write against deny commit; cover rollback, unrelated enrollment/grant changes, disconnect and actual-owner cleanup. No post-barrier dispatch or unsent delivery; already handed-off bytes cannot be recalled. Receipt cases run with the first live deny control in 3.2.1. | +| N08 | Denial/disconnect with blocked upstream calls retains all eight workers and carrier owners until actual exit; no automatic retry or false promise to recall prior effects. | +| N09 | Actual artifact-producing plugin/Go request rejects before legacy store entry or filesystem/nonce/descriptor/inline publication; old routes fail, restart cleanup is confined and failure stays closed. | +| N10 | Every real CLI constructor, including error/tool/artifact paths, uses explicit selected enrollment and verified native factory after atomic client/server cutover; the preceding product prefix keeps its working route while private peers exercise the new factory. No general outer TLS exception, URL identity inference, redirect or uncertain-operation replay. | +| N11 | Existing connect/API/plugin/download idle budgets through real peers: slow connect, no early headers, long active call, ping-only traffic, slow progressing stream and cancellation. | +| N12 | Installed supported Python/Go/native OS/CPU prefix actually executes N01/N04/N07/N09/N10 plus focused relay/timeouts; CI required variables are present and tests do not silently skip. | + +Reuse `test_native_http_protocol`, `test_artifact_http_admission` real-socket +fixtures and the existing Python/Go peer, installed-CLI and terminal drivers. +Own shared harness additions once; add targeted later cases. No live mail account, +full duplicated installed adversarial matrix or production prototype is authorized +by this design. Dependency/source inspection establishes API feasibility only; +native execution is implementation acceptance, not evidence already obtained. + +## Already sized implementation proposal + +Numbers are handwritten added + deleted production, tests/fixtures and CI, +including code motion, shared helper ownership and review-correction headroom. +Docs/news/lock data are separate. These bottom-up ranges replace the historical +3350–5840 code/test forecast; they are estimates for review, not measured future +diffs, approved delivery counts or a dynamic-splitting allowance. Each upper bound +fits the existing 1000-line cap before implementation starts. If source evidence +invalidates a cut, return to design rather than hide a late split in execution. + +| ID | Complete consumed result, scope and focused checks | Production | Tests/fixtures | CI | Total | +| --- | --- | ---: | ---: | ---: | ---: | +| `3.1.1` | Shared bounded carrier/lease/TLS pump extracted and consumed by existing pairing/control and real streaming Python/Go peers. Own shared streaming harness. N03/N04; no ordinary public route. | 320–440 | 300–420 | 0–5 | 620–865 | +| `3.1.2` | Strict Python ordinary mTLS and immutable candidate identity consumed by real peer; live admission still private. N01 and handshake limits. | 170–240 | 310–420 | 0–5 | 480–665 | +| `3.1.3` | Go strict native identity/dial plus standard HTTP transport, exercised against real Python; reuse stored decoder and existing timeout wrapper. N01/N02/N11. | 190–260 | 300–410 | 0–5 | 490–675 | +| `3.1.4` | One-request bounded HTTP/ASGI stream with immutable scope, real body/response peers and no public cutover. N03/N04, parser/body admission. | 230–320 | 350–470 | 0–5 | 580–795 | +| `3.2.1` | Live row extension/atomic backfill and OS enrollment-deny control with minimal shared coordinator consumed by the real fixed receipt. Guard receipt admission and final output, retain actual owners and test N07 receipt races/rollback/cleanup. Use the existing agent binding without a row copy; validate old/fresh/replay and corrupt relations. Extend activation once; preserve original receipt. N05. | 230–330 | 420–610 | 0–5 | 650–945 | +| `3.2.2` | Extend the same coordinator/writer reservation to ordinary authority and actual-worker callbacks, consumed by private real ASGI peer. Own OS grant add/remove controls. N04/N05/N06/N07 dispatch, busy/rollback and no stale snapshot authorization. | 220–300 | 330–430 | 0–5 | 550–735 | +| `3.3` | All discovery/direct-account/policy projections use exact live grants with current schemas and private peer. N06 including negative information leaks. | 160–230 | 320–440 | 0–5 | 480–675 | +| `3.4` | Real authorized plugin dispatch with caller context, closed concrete artifact dependency, descriptor/inline closure and confined startup invalidation. N09 with spy plus filesystem; reuse shared harness. | 230–320 | 350–460 | 0–5 | 580–785 | +| `3.6.1` | Denial closes all affected body/dispatch paths across actual sockets; actual blocked work retains slots/carriers. N07/N08, cutoff/rollback and admin responsiveness. | 190–270 | 350–470 | 0–5 | 540–745 | +| `3.6.2` | Permission after backpressure and final ciphertext-write boundary, abort without flushing revoked output. N03/N07/N08 streaming/late-worker cases. | 150–220 | 330–450 | 0–5 | 480–675 | +| `3.5.1` | Explicit selector/config/help and every CLI constructor exercises the verified native factory through complete private real peers; production selection stays on the existing working route. N10/N11. | 130–180 | 320–410 | 0–5 | 450–595 | +| `3.5.2` | Atomic production CLI constructor switch, public ordinary enablement and anonymous API/artifact closure, with no fallback; first installed authenticated prefix executes denial and closed-artifact journey. N01/N04/N07/N09/N10/N12. | 110–190 | 380–510 | 0–5 | 490–705 | +| `3.7` | Focused installed relay/outer-cert/passthrough and timeout composition, native prefix/packaging closure; add no deferred core mechanism. N02/N11/N12 and all parent N01–N12. | 20–60 | 380–480 | 0–10 | 400–550 | + +Order follows the displayed rows; existing 3.1/3.2/3.5/3.6 parents retain their +identities and acceptance. `2.10.4` precedes `3.1.1`; `3.6.2` precedes public +cutover. Each source/peer foundation has an executable current consumer, not an +empty interface. 3.1.1 owns shared carrier/harness code motion; later cuts own +only incremental scenarios. 3.5.2 owns the first installed ordinary journey; +3.7 extends it, not creates a second harness. The revised cut ranges move +20–40 production and 30–50 focused regression lines from +`3.5.1` into `3.5.2` for their atomic production switch; they are not counted twice. +Receipt/coordinator ownership moves a net 20–30 production and 20–30 test lines +from `3.2.2` into `3.2.1`; ordinary grant controls move the other way. Existing +fixed-control real-socket fixtures support 100–150 additional receipt-race test +lines in `3.2.1`. These are estimates, counted once; later ordinary and installed +coverage extends the shared harness rather than repeating the receipt matrix. +The proposed 13 PRs and aggregate range require separate implementation +authorization. No milestone-2 allowance is +reused and no milestone-3 product work begins as part of this design PR. +Aggregate: 2,350–3,360 production, 4,440–5,980 tests/fixtures and 0–70 handwritten +CI lines, or 6,790–9,410 total. The larger test share includes real streaming, +revocation/worker-lifetime and cross-language composition at their owning cuts. + +Primary API references supporting the adapter choice: +[Python 3.10 protocol API](https://docs.python.org/3.10/library/asyncio-protocol.html), +[Python 3.10 SSL protocol source](https://github.com/python/cpython/blob/v3.10.19/Lib/asyncio/sslproto.py), +[pyOpenSSL memory-BIO API](https://pyopenssl.org/en/stable/api/ssl.html). +The implementation must validate the installed pinned versions and supported Go +floor rather than treat newer local library/source inspection as native proof. diff --git a/docs/authentication/supporting/implementation-plan/historical-plan.txt b/docs/authentication/supporting/implementation-plan/historical-plan.txt new file mode 100644 index 0000000..fd0f895 --- /dev/null +++ b/docs/authentication/supporting/implementation-plan/historical-plan.txt @@ -0,0 +1,1130 @@ +--- +plan_key: arbiter-authentication +slice_convention: hierarchical-v1 +--- + +# Authentication and mutual enrollment: implementation plan + +Stage: design-update candidate after the milestone-2 stack merge, 2026-10-28. +Governing documents are the +[requirements](requirements.md), SHA-256 +`d56e92a7cb01f131ba499650c4a5d7b2c8d17adf2cdc7d612eee7c5f53d07929`, +and [HLD](high-level-design.md), SHA-256 +`b6511414b3a9b485542df83c8f7abfc499dc8d06e522819b48e162a562d21c57`. +Their exact reviewed stamps, the [portable enrollment LLD](portable-enrollment-lld.md) +and the [milestone-3 LLD](milestone-3-lld.md) are explicit design dependencies of +this plan's stamp. The LLDs own their detailed schemas, state transitions, +acceptance cases and already sized cuts. Neither requirements nor HLD changes. +This plan authorizes no +implementation, release, live-account operation or deployment by itself. +DBB must approve the exact final plan before its SWE design stamp. + +## Current delivery state and next design scope + +Source baseline is merged main `25a8cf2196f36499ff92ce890f313901b51b4f2b`. +Milestone 1 authority/setup/local control and the milestone-2 fresh enrollment, +single activation and receipt stack are merged. The latter closed with +[PR74](https://github.com/omry/arbiter/pull/74); its 21 delivered PRs consumed the +22-attempt allowance, including one unshipped parent attempt. Those delivery +identities, approvals and spent allowance remain history, not permission for +additional work. All 13 reported post-merge checks passed in the +[baseline workflow run](https://github.com/omry/arbiter/actions/runs/40579826766). + +Milestone 2 still lacks the approved existing-portable-identity journey. Current +Go provisional creation always generates a new portable key; Python prepare +always assigns a new agent. Fresh-key possession and same-selector receipt +resume do not satisfy reuse of a registered portable identity at a second server. +This is an implementation gap, not an accepted scope deferral. Proposed `2.10` +closes it through the portable LLD before milestone 3 starts. These documents +specify that fix; no product fix is implemented by this design update. + +The original milestone-3 seven-PR estimate lacks the streaming, authority +integration and failure-test detail needed for a credible execution cut. Its approved +behavior is retained, with the LLD's 13 already sized proposed cuts replacing the +old boundaries. Milestones 4–11 retain their ordered scope and historical child +outlines below; their old estimates are not newly validated execution forecasts. +Refine them into source-based, reviewed LLDs with bounded complete cuts before +implementing each milestone. No cumulative remaining-PR or LOC promise follows +from adding those old outline counts to the newly sized work. + +This design and its local/PR review confer no implementation authorization. +Implementing `2.10`, milestone 3 or a later milestone requires separate operator authorization. No old +allowance is reset; no merge, release, deployment or live account work is authorized. +The [original plan at the merged baseline](https://github.com/omry/arbiter/blob/25a8cf2196f36499ff92ce890f313901b51b4f2b/docs/authentication/implementation-plan.md) +preserves the exact earlier text, forecasts and original cuts. + +## Delivery identities and rules + +`arbiter-authentication` owns this plan. Its numbered slices are `1` through `11`; +references below use `arbiter-authentication/1`, for example. Under +`hierarchical-v1`, an approved later split of `4` becomes `4.1`, `4.2`, etc.; never +renumber another slice or reuse a completed identity. The parent retains the +aggregate acceptance obligation. Delivery records bind exact PR URL, revision, +dependencies, checks, reviews and state for each canonical identity. Merged +deliveries are not renumbered or reclassified as unstarted by this plan revision. + +The eleven numbered slices are milestones, not individual PRs. The current LLD +cuts are proposed reviewable PRs with bounded behavior, failure tests and relevant +guidance/fragments. Older child tables are historical outlines as labeled. Work +serially in milestone order and then the listed child order (not numeric sort). Complete local review, checks, +submission and the approved remote review cycle for the current PR before advancing; approval binds +the final PR head, with restacking invalidating affected evidence as appropriate. +This document does not launch those cycles. An LLD must produce already sized +implementable slices; dynamic resizing should be rare. If source evidence shows +a cut is insufficient, revise and review the design before implementing it rather +than treating an execution split as routine capacity. A foundation PR must implement a real consumed boundary +(setup/status, registered pending work or an executable protocol peer), not empty +interfaces, permissive stubs or a throwaway intermediate protocol. A synthetic +peer may exercise a not-yet-public transport; it cannot authorize product traffic. +The historical 2.7/2.8 cuts used synthetic already-activated fixture rows only in +tests before 2.6 enabled real activation; this is not a production trust initializer. +Ordinary public dispatch on the new native boundary remains closed until `3.5.2`. +Both `3.6.1` and `3.6.2` install and test complete live denial first through +private real peers and synthetic accounts. +The eventual cutovers cannot rely on development-only publication policy as their +safety mechanism; the respective runtime routes must actually remain closed. + +Outside the typed portable-correction inventory below, every implementation and +review-fix commit subject, and its PR title, starts with the short slice label in brackets. For example: +`[authentication/1.1] Private authority initialization`. The repository already +identifies Arbiter; do not repeat its name in the title prefix. This display label +maps to canonical ledger identity `arbiter-authentication/1.1`; the plan key and +tracking identities remain unchanged. Use the deeper child ID after an approved +further split, and preserve the label through restacks and corrections. A title or +PR number does not replace the execution-ledger identity. This does not rename +historical commits. + +### Milestone stacks and merge boundary + +Deliver one connected PR stack per milestone. Review and approve its child PRs +serially as described above, retaining the stack until the milestone is complete. +Before merging, require current approval and required checks for every final PR +head, the parent milestone's full acceptance and integration checks, and relevant +integration with completed milestones. Reconcile approval/check evidence after +any correction or restack. Safe intermediate behavior remains mandatory. + +Present the verified milestone stack for operator-authorized merge, bottom-up. +Do not merge automatically. Verify the resulting main-branch state before basing +the next milestone on it; do not carry the previous milestone's unmerged stack +into the next one. A delivery request may stop with the approved stack ready for +the operator to merge. Merging is separate from publishing authentication support: +all eleven milestones and the combined publication gate remain required. No +milestone merge authorizes a package release, deployment or live-account operation. + +Use existing towncrier release surfaces: `server/news/` for core/native-client +integration behavior, `plugins/imap/news/` or `plugins/smtp/news/` for changed plugin +contracts, and `meta/arbiter-suite/news/` only for bundle dependency changes. +Current release tooling associates the native client with the server release +surface; do not invent an unconfigured `client/news/` directory. Internal planning +documents themselves do not need a user-facing release fragment. + +All intermediate revisions are development work, not publishable authentication +support. Use isolated synthetic servers/accounts/state for prefix integration. +Do not add an anonymous compatibility mode, bypass switch, dummy production +identity, second policy layer or temporary protocol that must later be removed. +Product activation of the complete upgrade requires all eleven slices and the +combined gate below. Existing public API exposure is not declared fixed merely +because setup/enrollment exists. Once ordinary native authentication is cut over +in slice 3, anonymous legacy operation/artifact paths stay closed; an incomplete +artifact path must fail safely rather than emit an ownerless/plaintext substitute. +Missing authority state fails closed and directs the operator to trusted setup. + +## Ordered milestone queue + +Dependencies below are direct semantic prerequisites. Serial delivery additionally +requires the preceding PR to finish its review cycle. Final integration covers +cross-milestone interactions, not just each milestone in isolation. The historical +milestone-2 parent order was 2.1–2.5, 2.7, 2.8, 2.6, 2.9. Proposed next work is +`2.10.1 -> 2.10.2 -> 2.10.3 -> 2.10.4`, then the exact displayed milestone-3 +LLD order: `3.1.1–3.1.4`, `3.2.1–3.2.2`, `3.3`, `3.4`, `3.6.1–3.6.2`, +`3.5.1–3.5.2`, `3.7`. Existing parents retain their aggregate obligations. The explicit +child dependencies below are technical prerequisites; serial delivery also +requires the preceding child PR to finish its review cycle. An external dependency +on a milestone means all of that milestone's children, not just its first PR. + +| Slice | Observable result | Direct dependencies | Governing coverage | +| --- | --- | --- | --- | +| 1 | Operator initializes durable authority and uses authenticated local control. | None | R01–R06, R11–R12; HLD shared/B2/B3 | +| 2 | Owner pairs a real Go client with one secret handoff and durable single activation. | 1 | R04–R09, R10–R12; HLD B1/B2/B3 | +| 3 | Enrolled clients discover/invoke only granted accounts; live removal stops affected delivery. | 1, 2 | R10–R14; HLD shared/B2/B3 | +| 4 | Due client keys rotate, reconcile lost replies and complete safely after grace/expiry. | 1, 2, 3 | R15–R17; HLD B2/B3 | +| 5 | Owner repairs client identity/access without losing grants or clearing denials. | 1, 2, 3, 4 | R04–R06, R16–R17; HLD B2 | +| 6 | Planned or independently authorized server-key replacement preserves durable trust. | 1, 2, 4, 5 | R06, R10, R17; HLD B2/B3 | +| 7 | Server retains and delivers encrypted creator-bound artifacts with existing quotas. | 1, 2, 3 | R14, R18, R20; HLD B4 | +| 8 | Client offers all four artifact processing modes with honest verification/cleanup behavior. | 3, 4, 7 | R18–R20; HLD B4 | +| 9 | External local/SSH jobs obtain coherent, signed encrypted application backups. | 1, 3, 4, 5, 6, 7 | R21–R22; HLD B5 | +| 10 | Operator restores offline and can undo the latest restore, including after use. | 4, 5, 6, 9 | R23–R24; HLD B5 | +| 11 | Operator migrates paired clients during maintenance with verified URL handoff. | 3, 4, 6, 9, 10 | R10, R14, R17, R25; HLD B5 | + +## PR sizing and estimation basis + +The original 2026-10-20 breakdown contained **60 planned PRs**; the earlier +30–45 conversation estimate was preliminary. Both are historical, not the +current remaining queue. Only `2.10` and milestone 3 have newly sized LLDs here: + +| Proposed work | Cuts | Production | Tests/fixtures | Handwritten CI | Total | +| --- | ---: | ---: | ---: | ---: | ---: | +| `2.10` portable reuse | 4 | 850–1,220 | 1,300–1,770 | 0–25 | 2,150–3,015 | +| `3` native API/grants/denial | 13 | 2,350–3,360 | 4,440–5,980 | 0–70 | 6,790–9,410 | + +These are engineering estimates for review and later authorization, not approved +delivery allowances or guaranteed future diffs. Each full cut includes code +motion, helpers, fixtures, negative/race/native composition tests and correction +headroom. Shared harness code is charged once. The LLDs own the per-cut tables; +the plan does not maintain a second detailed sizing copy. + +Target **about 600 changed handwritten code lines** per PR. The **hard maximum is +1,000**, counting additions plus deletions in production code, tests and handwritten +fixtures across Python and Go combined. This is not 1,000 per language or per +category. Count moved/reformatted code too; avoid incidental cleanup. Do not drop +negative tests, move a PR's tests into a later PR, compress code, label handwritten +fixtures generated or weaken a boundary to fit. Estimate and report documentation, +generated fixtures/code, lockfiles and tooling output separately in the PR; they +still contribute review burden. Do not introduce new generation tooling merely to +avoid the limit. A large mechanical change should be a separate coherent PR. + +The target is flexible; the maximum is not. Before coding each child, check its +source-based forecast against predecessor changes. Do not begin an overlarge or +underspecified cut expecting to split it later. If actual evidence invalidates +the cut, stop expansion and return to the design boundary before submission. +A rare changed split needs focused review +and updated dependency/acceptance mapping; changes to the stamped plan require +DBB/SWE re-review and replacement stamp before treating that revision as approved. +No additional owner interview is required for a mechanical split that preserves +approved requirements, HLD, size policy and acceptance. + +Historical ranges below estimate handwritten churn, including assertions/helpers and fixture +construction. Production and test ranges are separate; the total is their sum. +They are task-by-task engineering estimates, not statistical confidence intervals +or a guarantee that the implementation will stay within the forecast. `Medium` +means there is a close existing implementation to extend. `Low` means new protocol, +durable state, platform custody or fault behavior dominates. No high-confidence +estimate is claimed. Exact files/modules follow implementation style, not a promise +to create one file for each PR. Existing code/tests are reused rather than copied; +only new/changed lines count. Shared harness work is charged to the first child +that uses it, and later children budget their own scenario additions. + +Historical inspection basis for the original forecast (2026-10-20, +checkout `9d5cfc198bb4`): + +| Existing surface | Measured lines | Consequence for estimates | +| --- | ---: | --- | +| `server/src/arbiter_server/artifacts.py` / `server/tests/unit/test_artifacts.py` | 570 / 810 | Extend the real store and tests; encryption, quota and access cutovers need separate boundaries. | +| `server/src/arbiter_server/http_work.py` / `server/tests/unit/test_artifact_http_admission.py` | 170 / 497 | Reuse bounded streaming owners and real contention barriers; do not budget cancellation as a few happy-path assertions. | +| `server/src/arbiter_server/blocking.py` / `server/tests/unit/test_blocking_pool.py` | 93 / 138 | Preserve the existing worker pool; add authority coordination rather than replace it. | +| `client/go-cli/internal/arbiterhttp/client.go` / `client/go-cli/internal/arbiterhttp/client_test.go` | 212 / 251 | Preserve API construction/error shape while changing the carrier. | +| `client/go-cli/internal/arbiterhttp/timeouts.go` / `client/go-cli/internal/arbiterhttp/timeouts_test.go` | 306 / 368 | Reuse budgets; extend real socket coverage at transport cutover. | +| `client/go-cli/internal/cli/cli.go` / `client/go-cli/internal/cli/artifact_commands_test.go` | 2,306 / 869 | Change relevant command paths; avoid an unrelated whole-file rewrite. | +| `server/tests/unit/test_native_http_protocol.py` / `server/tests/integration/test_cli_entrypoint.py` | 1,394 / 1,245 | Reuse synthetic ASGI and installed Go-wheel fixtures; charge new authenticated/process scenarios separately. | +| `server/src/arbiter_server/storage.py` / `server/src/arbiter_server/config.py` | 57 / 376 | Private generation/authority/ACL recovery is mostly new work, not an existing backup subsystem. | + +Read-through of these paths and the retained HLD probes informed the original +estimates. The two new LLDs use actual merged `25a8cf2` primitives and their named +missing work; old source-line counts above are not measurements of that baseline. +Probe code is not assumed production-ready or copied wholesale. No product code +or product tests were created/run by this design revision. Future streaming, +race/crash and installed-native acceptance remains implementation work, not proof +supplied by design checks or the existing baseline's green CI. + +The per-child tables define scope, a focused minimum acceptance check, code ranges, +confidence and direct dependencies. Every child also owns relevant tests from the +shared contracts and its parent milestone: a parent acceptance requirement is not +postponed until its final closure PR when the behavior already exists. Closure PRs +exercise composition, native builds and additional process-level failure cases; +they are not permission to submit earlier untested behavior. Any new runtime +setting/format is documented and tested where first consumed. Each child includes +its applicable package fragment and command/operator guidance; final documentation +passes only reconcile the complete journey. Documentation effort is not included +in the handwritten-code totals, and must be called out before each PR starts. + +### Historical estimate summary (2026-10-20) + +The following table preserves the original 60-PR forecast for comparison. It is +not a statement that those cuts remain unstarted, an actual delivered-LOC count, +or a newly reviewed forecast for the remaining milestones. In particular, the +old rows for 2 and 3 are superseded for future work by the status and LLDs above. + +| Milestone | Planned PRs | Production churn | Test churn | Combined churn | +| --- | ---: | ---: | ---: | ---: | +| 1 | 6 | 1,340–2,240 | 1,520–2,630 | 2,860–4,870 | +| 2 | 9 | 2,160–3,490 | 2,600–4,380 | 4,760–7,870 | +| 3 | 7 | 1,400–2,410 | 1,950–3,430 | 3,350–5,840 | +| 4 | 5 | 960–1,640 | 1,420–2,440 | 2,380–4,080 | +| 5 | 5 | 960–1,650 | 1,320–2,280 | 2,280–3,930 | +| 6 | 4 | 840–1,430 | 1,080–1,880 | 1,920–3,310 | +| 7 | 6 | 1,160–2,000 | 1,680–2,920 | 2,840–4,920 | +| 8 | 5 | 810–1,430 | 1,300–2,290 | 2,110–3,720 | +| 9 | 5 | 990–1,700 | 1,420–2,450 | 2,410–4,150 | +| 10 | 5 | 920–1,580 | 1,460–2,520 | 2,380–4,100 | +| 11 | 3 | 480–860 | 860–1,500 | 1,340–2,360 | +| **Total** | **60** | **12,020–20,430** | **16,610–28,720** | **28,630–49,150** | + +These totals sum estimated PR churn, including edits to previously introduced code; +they are not final repository size or time estimates. Existing fixtures are reused. +Generated/binary fixtures, dependency locks and documentation have no credible +line forecast yet: quantify them at each child kickoff and separate them in the +review summary. Their absence here is uncertainty, not zero work. No fixed delivery +date or throughput promise follows from these ranges. + +## Shared implementation contracts + +### Code ownership and schemas + +Add cohesive server identity/authority/transport/control modules beneath +`server/src/arbiter_server/`; add Go identity/state/carrier code beneath +`client/go-cli/internal/`. The exact module decomposition follows existing code +style; do not create a plugin/provider framework. `main.py` remains the ASGI +composition point, with immutable verified caller context and shared admission. +Existing `http_work.py`, `blocking.py`, artifact storage and account policies keep +their behavior except for the expressly planned identity/encryption checks. + +Each slice commits its versioned schemas and shared positive/negative Python/Go +fixtures with the implementation that consumes them. Put synthetic protocol +fixtures in a clearly test-only shared location; fixed test keys never initialize +product trust. Schemas reject duplicate identities/JSON fields, unknown critical +fields, invalid lengths/encodings and trailing input. Sign/verify exact bytes; +ES256 is fixed-width `R || S`, not an ASN.1 signature or a reserialized payload. +No unspecified schema field may silently grant authority or select an algorithm. + +Slice 1 fixes X.509/SAN URI/purpose/key-usage profiles, role trust stores, key-file +and recovery-file formats, authority row/revision semantics, and certificate +validity/renewal schedule specifications. Slice 5 owns owner-issuer and portable +certificate renewal; slice 6 owns server-authority and inner server-leaf renewal, +including trust-expiry recovery. Routine certificate renewal preserves the +appropriate key and durable IDs; it is not periodic server identity-key replacement. +Slice 2 fixes +Noise prologue/transcript/messages, pending/receipt state and inner-carrier ALPN. +Slice 4 fixes rotation/control proofs and acceptance state. Slice 5 fixes owner +recovery JWS and fresh challenge consumption. Slice 6 fixes server transition +proofs/history. Slice 7 fixes the authenticated artifact descriptor/age profile. +Slice 9 fixes backup records/manifest/signature and coherent snapshot semantics. +Slice 10 fixes durable active/undo publication and offline lock behavior. +Fixtures are reviewable parts of those PRs, not later unspecified integration work. + +### Dependencies, platforms and defaults + +Keep Python 3.10–3.14 and Go 1.24 as current compatibility floors; preserve the +existing Linux/macOS/Windows x64/arm64 CI matrix. Before adding each dependency, +select an exact tested compatible version set, review advisories/reachable uses, +record wheel/source-build needs and run its affected native matrix. The fourteen +Linux HLD probes are evidence of feasibility, not production dependency approval. +In particular, do not install pyOpenSSL26.3/cryptography49 under the current +`cryptography<49` constraint; evaluate a supported compatible set. Age's Rust +binding and the older Python Noise wrapper require explicit packaging/boundary +tests. Source builds may need build tools but must not create a separately +operated runtime service. Failure blocks the affected slice/release; changing +supported platforms or the HLD mechanism requires alignment, not silent narrowing. + +Use structured named config fields owned by their domain. Carry HLD defaults +unchanged: 16 total carriers, 4 handshakes, 10-second handshake/control budgets, +256 KiB buffers and total handshake bytes per direction, 32 KiB headers/cert +chain, 64 KiB controls/WebSocket messages, no compression, five-minute idle with +active-operation exceptions, four client transfers and one administrative job. +Retain the Noise wire/plaintext limits, twenty pending requests, five authenticated +attempts, ten-minute enrollment lifetime, 30-day rotation, 24-hour fixed grace, +180-day inactivity and 365-day access certificates. Do not turn U53 into a +64-carrier default. Preserve existing worker/body/artifact limits and separate +connect/API/download-idle semantics. Validate types/ranges and expose effective +nonsecret settings through authenticated diagnostics. + +For every public input, enforce aggregate byte/work limits before expensive +decode/crypto or allocation, including fragmentation, age headers, certificate +chains and backup manifests. Library convenience APIs are not admission control. +Reject overload without an unbounded queue; retain ownership until actual cleanup. + +### Test layers and review evidence + +Each PR has focused server/Go unit tests and a real Python-server/Go-client +prefix integration test for its behavior. Include real loopback sockets, a test +TLS-terminating WebSocket relay, restartable temporary directories and deterministic +clock/fault barriers. Isolated mock upstream SMTP/IMAP services supply fixtures; +no personal accounts or external mail effects. Library fixtures alone do not +prove application authorization, resource ownership or crash consistency. + +Run relevant regressions, repository lint/type checks and required CI checks for +that PR. Commands include repo-local pytest targets, `.venv/bin/nox -s lint` +(Black uses one worker), and `go test ./...`/`go vet ./...` in `client/go-cli`. +Use existing supported test runners instead of bypassing their setup. The final +combined gate runs the full Python suite, server/Go integration and complete +supported matrix. Unavailable checks remain unverified and block relevant claims. + +Before each PR is treated as complete, review its final code locally, resolve +findings, run its checks, checkpoint, submit and finish its remote PR review +cycle. Use actual DBB for security-sensitive changes with exact reviewed revision +evidence; if the optional reviewer workflow feature is unavailable, keep explicit +DBB orchestration. Changes after approval need appropriate re-review. No silent +reviewer substitution. This plan does not authorize automatic merging/deployment. + +## Slice 1 — operator authority and local control + +Historical note: the original child table in this section records the design cuts, not an unstarted queue. Authority/setup/local-control implementation is already merged at the source baseline above. + + +Deliver a complete operator setup/status journey: create durable owner/server IDs, +issuer and role-separated keys, external operator recovery file/public trust and +private SQLite authority state; inspect/manage it through authenticated Unix +socket or Windows named-pipe control. Recovery material stays outside running +server/agent/job storage. Status reports setup state without printing private keys. +An ordinary loopback connection cannot administer the instance. Initialize only +through trusted OS/SSH tooling; repeat setup cannot overwrite existing authority. + +Scope includes OS ownership/ACL validation, private atomic file publication, +single-writer instance lock, exact credential profiles and shared Python/Go profile +fixtures. Keys/profile functions are exercised by real initialization and local +control, not a standalone abstraction PR. Register owner public trust before use. +Agent `NEVER SHARE THIS` custody and recovery-file combined powers are documented. + +Acceptance: restart preserves IDs/trust; injected file/DB failures leave either +complete setup or safely recoverable unpublished staging; concurrent init/start +cannot create two writers. Wrong OS user, permissive ACL, unregistered owner, +wrong EKU/issuer/role/SAN, duplicate IDs and generic valid certs fail. Owner/recovery +private material never appears in server state, logs, argv, env or ordinary APIs. +Test native POSIX and Windows control boundaries. Add setup/trust documentation, +operator command help and an `arbiter-server` news fragment. + +### Child PRs + +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `1.1` — Private authority initialization | Create UUID-backed owner/server records and versioned SQLite authority schema through stopped-instance init/status; reject a second initialization. **Check:** Reopen preserves IDs; concurrent init and partial DB writes cannot publish two instances. | 200–340 | 220–380 | 420–720 | Medium | None | +| `1.2` — Role-separated credential profiles | Issue and validate setup credentials with explicit SAN/EKU/issuer profiles, exact certificate bounds and validity/renewal schedules. Publish shared profile fixtures consumed by Python now and Go in 2.1. **Check:** Reject cross-role, duplicate SAN, unregistered issuer, malformed DER and wrong key usage; verify profile time boundaries. | 260–420 | 280–450 | 540–870 | Low | 1.1 | +| `1.3` — External operator recovery file | Extend initialization with external recovery signer/decryptor, backup public configuration and registered public trust; keep private recovery material out of server state. **Check:** No overwrite or secret leakage; interrupted publication never reports successful setup with missing recovery trust. | 200–330 | 230–400 | 430–730 | Low | 1.2 | +| `1.4` — Durable application-state publication | Put initialized authority in a private generation with a durable active selector, instance lock and restart reconciliation; validate native ownership and ACLs. **Check:** Faults around flush/reference changes leave one coherent active state; Windows/POSIX locking prevents concurrent start. | 260–420 | 300–500 | 560–920 | Low | 1.3 | +| `1.5` — POSIX authenticated local control | Serve setup/status and bounded administrative messages over a private Unix socket; verify peer credentials and keep live DB writes server-owned. **Check:** Wrong UID, path replacement, oversized input and disconnect fail without loopback authority or leaked slots. | 190–330 | 230–400 | 420–730 | Medium | 1.4 | +| `1.6` — Windows authenticated local control | Provide the same real setup/status journey via named-pipe ACL and caller-token checks, with platform selection and trusted SSH instructions. **Check:** Native unauthorized caller, permissive ACL and pipe replacement fail; installed local commands work on both OS families. | 230–400 | 260–500 | 490–900 | Low | 1.5 | + +## Slice 2 — pairing a real client and reconciling activation + +Historical note: the original child table below retains parent identities and initial forecasts. The delivered stack used reviewed descendant cuts and is merged; existing-portable reuse remains the explicit `2.10` gap below. + + +Deliver `enrol` from a real Go CLI against a real initialized Python server: +generate provisional per-server/portable/recipient keys and 32-byte secret; closed +server explains opening; trusted operator opens a bounded window, lists/selects +request, supplies protected PSK and approves exact keys/grants once. Existing +portable identity requires registered issuer/fresh possession but no automatic +access. Client receives prepared trust/certs directly and durably saves before +ready proof; one authority transaction activates and returns its recorded receipt. + +Implement production Noise framing and bounded WebSocket adapter together with +the minimal inner server-authenticated TLS receipt/status control required to +recover committed activation without PSK. Python/Go fixtures exercise exact +transcript/key/role/request bindings. This slice includes the real encrypted +transport dependency and platform checks; it does not defer a lost-reply path to +an unspecified future carrier. Ordinary operation dispatch is slice 3. + +Acceptance: one secret handoff/approval, no return bundle or extra fingerprint +step; anonymous/wrong-PSK traffic cannot spend five attempts; identical authenticated +replays share one owner; five distinct failed/abandoned exchanges exhaust without +reset. Enforce original ten-minute deadline and twenty pending records across +reconnect/open/approval races. Fault/crash tests before ready, after client flush, +before/after commit and after lost reply prove one durable identity/grant/result. +Restart invalidates uncommitted PSKs only; denial beats stale completion. Abandoned +client/server state cleans within bounds. Add enrollment/recovery diagnostics, +custody guidance and fragments for server and native client packaging as applicable. + +### Child PRs +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `2.1` — Client provisional identity custody | Add real enrol key generation, private atomic client state and closed-server diagnostics; Go consumes 1.2 profile fixtures. **Check:** Restart, failed save and bad permissions leave recoverable provisional state; keys/PSK never reach argv, env or logs. | 240–380 | 260–430 | 500–810 | Low | 1.6 | +| `2.2` — Pending requests and operator approval | Add bounded public request registration and local open/list/approve/reject; bind immutable proposed keys/grants, protected PSK input and original deadlines. **Check:** Closed enrollment cannot open remotely; twenty pending entries include approved work; reopen/expiry races never reset deadlines. | 240–400 | 280–460 | 520–860 | Low | 2.1 | +| `2.3` — Bounded Python pairing responder | Wire binary WebSocket framing and Noise responder into approved pending requests with carrier/crypto reservations and authenticated first-flight accounting. **Check:** Anonymous failures spend no attempts; authenticated duplicates share one owner; five distinct attempts, byte limits and cancellation retain correct ownership. | 300–450 | 300–500 | 600–950 | Low | 2.2 | +| `2.4` — Go pairing initiator and transcript proof | Connect the real enrol command through the bounded WebSocket/Noise adapter; prove proposed keys and exact role/request transcript to the Python responder. **Check:** Wrong PSK/prologue/selector/key or fragmented oversized input cannot advance; a real Python/Go exchange verifies both peers. | 260–420 | 280–470 | 540–890 | Low | 2.3 | +| `2.5` — Prepared enrollment and durable client ready | Issue the owner-approved prepared result, verify it at the client and flush complete keys/trust/result before emitting ready proof. **Check:** Tampered prepared data, wrong issuer/IDs and save failures prevent ready; prepared certificates alone cannot authorize ordinary work. | 260–430 | 300–500 | 560–930 | Low | 2.4 | +| `2.7` — Server-authenticated inner TLS carrier | Implement bounded Python memory-BIO and Go TLS-over-WebSocket streams for fixed receipt control; verify remembered server and exporter, with no ASGI dispatch. No live activation is reachable yet; activated state exists only in synthetic test fixtures. **Check:** Wrong server/ALPN, overrun, blocked writes and cancellation fail; dedicated outer TLS exception leaks no inherited credentials or redirects. | 300–450 | 300–500 | 600–950 | Low | 2.5 | +| `2.8` — Authenticated receipt reconciliation | Implement exact-result receipt control and client reconciliation against synthetic already-activated fixture rows; no product activation route exists until 2.6. **Check:** Test lost reply, restart, wrong key, replay and denial using exact stored results without PSK; synthetic fixtures cannot become product trust or create another activation. | 200–340 | 260–450 | 460–790 | Low | 2.7 | +| `2.6` — Single activation and receipt | With 2.7/2.8 present, wire the first reachable ready/activation commit: conditionally persist identity, credential, grants and result; promote only from authenticated receipt/retrieval. **Check:** Real Python/Go crash/lost-reply/restart at ready/commit/receipt proves one durable result, authenticated promotion and denial precedence; retries create no second identity or grant. | 280–440 | 320–520 | 600–960 | Low | 2.8 | +| `2.9` — Pairing installation and overload closure | Complete prefix packaging/platform checks and process-level pairing failures, reusing earlier fixtures rather than deferring core assertions here. **Check:** Installed CLI pairs/reconciles; dependency builds, proxy fragmentation and simultaneous expiry/shutdown release real owners and keep health responsive. | 80–180 | 300–550 | 380–730 | Low | 2.6 | + +### Proposed corrective parent `2.10` — existing portable identity enrollment + +The [portable enrollment LLD](portable-enrollment-lld.md) owns the exact source +selection, independently registered issuer, v2 schema, custody/proof, unique +agent binding, migration and receipt contract. Its P01–P10 acceptance and four +complete implementation cuts are normative for this proposed correction: +`2.10.1 -> 2.10.2 -> 2.10.3 -> 2.10.4`, then `3.1.1`. +The first schema/backfill cut also installs binding maintenance in every fresh-v1 +activation transaction; intermediate enrollments cannot evade later uniqueness or +denial. P05/P09 cover active/denied/inactive records created on both intermediate +prefixes. Each cut has its own real consumer and failure tests; `2.10.4` adds +installed fresh/reuse closure to the existing driver. The total is 2,150–3,015 handwritten +production/test/CI lines with all per-cut upper bounds below 1,000. This is no +reset of the exhausted milestone-2 allowance and no implementation authorization. +Existing-enrollment repair stays in milestone 5 and does not substitute for P01. + +## Execution inventory for the portable correction + +This inventory records only the already reviewed `2.10.1–2.10.4` cuts. +The retained `2` and `2.10` entries are aggregate planning parents, not +unstarted replacements for merged work. Original `2.1–2.9` delivery IDs, +findings, approvals and spent counters remain in their immutable history; +they are not re-admitted by this inventory. The two `replaced` states below +mean that executable responsibility is assigned to the four children, not that +completed deliveries were removed. Milestones 3–11 are not selected or admitted. + +The full canonical ID in each inventory title is the exact prefix required by +the current typed-delivery tools for these new cuts. Historical short display +labels stay unchanged. Paths bind the reviewed implementation ownership; a +necessary change outside them returns to reviewed inventory preparation. The +portable LLD remains the authority for behavior, acceptance and estimates. + +```swe-slice-inventory +{ + "schema_version": 1, + "slices": [ + { + "id": "arbiter-authentication/2", + "parent": null, + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2] Pairing and durable enrollment", + "responsibility": "Retain the original milestone-2 aggregate acceptance and immutable merged 2.1-2.9 delivery history; only its unimplemented 2.10 correction is admitted here.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "client/go-cli/internal/identity/enrollment_test.go", + "client/go-cli/internal/identity/pairing_peer_test.go", + "client/go-cli/internal/identity/portable.go", + "client/go-cli/internal/identity/portable_test.go", + "client/go-cli/internal/identity/prepared.go", + "client/go-cli/internal/identity/prepared_test.go", + "client/go-cli/internal/identity/provisional.go", + "client/go-cli/internal/identity/provisional_store.go", + "client/go-cli/internal/identity/provisional_test.go", + "client/go-cli/internal/identity/registration_peer_test.go", + "docs/enrollment.md", + "server/news/+portable-enrollment-activation.feature.md", + "server/news/+portable-enrollment.feature.md", + "server/news/+portable-identity-codecs.feature.md", + "server/news/+portable-issuer-controls.feature.md", + "server/src/arbiter_server/authority.py", + "server/src/arbiter_server/enrollment.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/issuer_admin.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_issuers.py", + "server/src/arbiter_server/prepared.py", + "server/tests/integration/enrollment_terminal_driver.py", + "server/tests/integration/test_enrollment_cli_peer.py", + "server/tests/integration/test_enrollment_receipt_peer.py", + "server/tests/integration/test_installed_enrollment.py", + "server/tests/integration/test_provisional_peer.py", + "server/tests/unit/test_authority.py", + "server/tests/unit/test_enrollment_activation.py", + "server/tests/unit/test_enrollment_requests.py", + "server/tests/unit/test_local_control.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_owner_issuers.py", + "server/tests/unit/test_prepared.py", + "server/tests/unit/test_windows_control.py" + ], + "dependencies": [], + "acceptance": [ + "Preserve merged fresh pairing and receipt behavior; ordinary milestone-3 API remains unchanged." + ] + } + }, + { + "id": "arbiter-authentication/2.10", + "parent": "arbiter-authentication/2", + "state": "replaced", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10] Existing portable identity enrollment", + "responsibility": "Close only portable LLD P01-P10 through the four already reviewed cuts; preserve original 22 spent attempts and all historical delivery identities.", + "paths": [ + ".github/workflows/ci.yml", + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "client/go-cli/internal/identity/enrollment_test.go", + "client/go-cli/internal/identity/pairing_peer_test.go", + "client/go-cli/internal/identity/portable.go", + "client/go-cli/internal/identity/portable_test.go", + "client/go-cli/internal/identity/prepared.go", + "client/go-cli/internal/identity/prepared_test.go", + "client/go-cli/internal/identity/provisional.go", + "client/go-cli/internal/identity/provisional_store.go", + "client/go-cli/internal/identity/provisional_test.go", + "client/go-cli/internal/identity/registration_peer_test.go", + "docs/enrollment.md", + "server/news/+portable-enrollment-activation.feature.md", + "server/news/+portable-enrollment.feature.md", + "server/news/+portable-identity-codecs.feature.md", + "server/news/+portable-issuer-controls.feature.md", + "server/src/arbiter_server/authority.py", + "server/src/arbiter_server/enrollment.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/issuer_admin.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/owner_issuers.py", + "server/src/arbiter_server/prepared.py", + "server/tests/integration/enrollment_terminal_driver.py", + "server/tests/integration/test_enrollment_cli_peer.py", + "server/tests/integration/test_enrollment_receipt_peer.py", + "server/tests/integration/test_installed_enrollment.py", + "server/tests/integration/test_provisional_peer.py", + "server/tests/unit/test_authority.py", + "server/tests/unit/test_enrollment_activation.py", + "server/tests/unit/test_enrollment_requests.py", + "server/tests/unit/test_local_control.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_owner_issuers.py", + "server/tests/unit/test_prepared.py", + "server/tests/unit/test_windows_control.py" + ], + "dependencies": [], + "acceptance": [ + "Real A/B/Go journey preserves agent ID/portable key/certificate and fresh independent B access/grants." + ] + } + }, + { + "id": "arbiter-authentication/2.10.1", + "parent": "arbiter-authentication/2.10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10.1] Local issuer trust and unique agent bindings", + "responsibility": "Implement the portable LLD first cut: OS-local issuer controls, exact certificate fingerprint trust, atomic schema/backfill and binding maintenance in every fresh-v1 activation/replay. Requires the merged 25a8cf2 fresh-enrollment baseline. No public reuse or milestone-3 work.", + "paths": [ + "server/src/arbiter_server/authority.py", + "server/src/arbiter_server/generations.py", + "server/src/arbiter_server/owner_issuers.py", + "server/src/arbiter_server/issuer_admin.py", + "server/src/arbiter_server/local_control.py", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/tests/unit/test_owner_issuers.py", + "server/tests/unit/test_authority.py", + "server/tests/unit/test_local_control.py", + "server/tests/unit/test_windows_control.py", + "server/tests/unit/test_main.py", + "server/tests/unit/test_enrollment_activation.py", + "server/news/+portable-issuer-controls.feature.md", + "docs/enrollment.md" + ], + "dependencies": [], + "acceptance": [ + "P02/P06/P09: exact issuer registration, removal/reactivation and revision; invalid profile rejected and local control remains OS authenticated.", + "Atomic migration preserves real old results/denial and rejects duplicate or malformed bindings.", + "Real post-upgrade fresh-v1 activation/replay/rollback maintains one agent/enrollment mapping, including later denied or inactive enrollments.", + "Retain 610-865 changed handwritten code/test/CI estimate and <=1000 hard cap." + ] + } + }, + { + "id": "arbiter-authentication/2.10.2", + "parent": "arbiter-authentication/2.10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10.2] Portable source custody and versioned codecs", + "responsibility": "Implement the portable LLD second cut: strict enrolled-source loading and v2 private/public codecs consumed by executable Python/Go peers; reuse the native publisher and shared decoder with purpose-specific checks. Public reuse remains unreachable.", + "paths": [ + "client/go-cli/internal/identity/provisional.go", + "client/go-cli/internal/identity/provisional_store.go", + "client/go-cli/internal/identity/prepared.go", + "client/go-cli/internal/identity/portable.go", + "client/go-cli/internal/identity/provisional_test.go", + "client/go-cli/internal/identity/prepared_test.go", + "client/go-cli/internal/identity/portable_test.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "server/src/arbiter_server/enrollment.py", + "server/tests/unit/test_enrollment_requests.py", + "server/tests/integration/test_provisional_peer.py", + "server/news/+portable-identity-codecs.feature.md", + "docs/enrollment.md", + "client/go-cli/internal/identity/pairing_peer_test.go", + "client/go-cli/internal/identity/registration_peer_test.go" + ], + "dependencies": [ + "arbiter-authentication/2.10.1" + ], + "acceptance": [ + "P03/P08: reject altered source ID/key/certificate/hash, unsafe custody and prepared-only source; source bytes stay unchanged.", + "Source loading accepts a currently valid portable identity without A online or an A access-lifetime requirement.", + "Preserve old v1 stored-record/result receipt decoding and its historical portable validation; never relax ordinary TLS or new-enrollment validity.", + "Retain 490-695 changed handwritten code/test/CI estimate and <=1000 hard cap." + ] + } + }, + { + "id": "arbiter-authentication/2.10.3", + "parent": "arbiter-authentication/2.10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10.3] Prepared reuse and single activation", + "responsibility": "Implement the portable LLD third cut through existing preparation/proofs and atomic activation, extending the same binding writer. Exercise real A/B/Go peers with fresh B access, explicit issuer trust/approval and exact receipt recovery. Public v2 remains closed.", + "paths": [ + "server/src/arbiter_server/prepared.py", + "server/src/arbiter_server/enrollment_activation.py", + "server/src/arbiter_server/enrollment.py", + "server/src/arbiter_server/owner_issuers.py", + "server/tests/unit/test_prepared.py", + "server/tests/unit/test_enrollment_activation.py", + "server/tests/integration/test_enrollment_cli_peer.py", + "server/tests/integration/test_enrollment_receipt_peer.py", + "client/go-cli/internal/identity/prepared.go", + "client/go-cli/internal/identity/prepared_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_test.go", + "client/go-cli/internal/identity/enrollment_receipt.go", + "client/go-cli/internal/identity/enrollment_receipt_test.go", + "server/news/+portable-enrollment-activation.feature.md", + "docs/enrollment.md", + "client/go-cli/internal/identity/pairing_peer_test.go", + "client/go-cli/internal/identity/registration_peer_test.go" + ], + "dependencies": [ + "arbiter-authentication/2.10.2" + ], + "acceptance": [ + "P01/P03/P05/P06/P07: preserve original agent/portable identity, generate independent B access/enrollment/recipient state; A may be offline.", + "Existing active/denied/inactive B binding rejects reuse, including real fresh-v1 enrollments created on both earlier upgraded prefixes.", + "Trust-revision removal/ready/commit races fail or reconcile once; lost final reply/restart/expiry returns the exact committed result.", + "Retain 550-745 changed handwritten code/test/CI estimate and <=1000 hard cap." + ] + } + }, + { + "id": "arbiter-authentication/2.10.4", + "parent": "arbiter-authentication/2.10", + "state": "planned", + "role": "implementation", + "intent": { + "title": "[arbiter-authentication/2.10.4] Public CLI reuse and installed acceptance", + "responsibility": "Implement the portable LLD fourth cut: explicit identity source selection, atomic v2-only public registration switch, installed A/B and fresh regression journeys, final migration/help/news and complete P01-P10 acceptance. Preserve all platforms and existing test harnesses.", + "paths": [ + "client/go-cli/internal/cli/enrollment.go", + "client/go-cli/internal/cli/enrollment_test.go", + "client/go-cli/internal/identity/provisional_session.go", + "client/go-cli/internal/identity/registration_peer_test.go", + "client/go-cli/internal/identity/enrollment.go", + "client/go-cli/internal/identity/enrollment_test.go", + "server/src/arbiter_server/main.py", + "server/src/arbiter_server/enrollment.py", + "server/tests/unit/test_enrollment_requests.py", + "server/tests/unit/test_enrollment_admin.py", + "server/tests/unit/test_main.py", + "server/tests/integration/enrollment_terminal_driver.py", + "server/tests/integration/test_installed_enrollment.py", + ".github/workflows/ci.yml", + "server/news/+portable-enrollment.feature.md", + "docs/enrollment.md" + ], + "dependencies": [ + "arbiter-authentication/2.10.3" + ], + "acceptance": [ + "P04/P08/P10 and all P01-P10: installed CLI completes fresh/reused enrollment and recovery on native CI; existing admission/time/attempt limits remain.", + "Reject identity plus resume, same-server reuse, unknown/invalid source and old public wire with actionable diagnostics and no saved identity deletion.", + "Confirm public server/client switch together, v1 saved receipt recovery survives, no live accounts and no milestone-3 API changes.", + "Retain 500-710 changed handwritten code/test/CI estimate and <=1000 hard cap." + ] + } + } + ] +} +``` + +## Slice 3 — native API, account grants and live denial + +Route every ordinary CLI discovery/schema/invocation/download constructor through +the expected-server-verified inner TLS 1.3 transport, including errors and tool +paths. Preserve API shape and existing policies after `(plugin, account)` grants. +Exercise the native factory through private peers in `3.5.1`; keep production +constructor selection on its working route until the atomic client/server switch +in `3.5.2`, with no anonymous fallback after that cut. +Reject anonymous/proxy-header callers and hide ungranted account information from +discovery and direct routes. Provide local grant add/remove and enrollment denial. +Creator/account caller context is mandatory for subsequent artifact work. + +Implement shared coordinator admission and output cancellation across connections; +ordinary TLS checks exact live enrollment/accepted key, certificate and role. +Use `agent_enrollments` as the sole agent-to-enrollment relation; live admission +must not create an independently authoritative `enrollments.agent_id` copy. +Remove anonymous legacy API/artifact routing in the same cutover, invalidate +server-managed ownerless artifacts without guessing ownership or touching mail/ +client files. No artifact storage fallback may bypass caller context. Keep +setup/health/bootstrap separate, and missing authority fails closed. + +Until slice 7 installs the encrypted store, slice 3 must replace the plugin-facing +artifact creation/inspection dependencies with an explicitly closed adapter. +Reject artifact creation before calling the legacy store or creating a payload +file; never delegate to it, return a usable descriptor or expose nonce-only access. +This is an implementation-readiness boundary, not a client policy/allowlist or +operator bypass flag. Errors report any already-completed upstream effect honestly +and never trigger automatic operation replay. Slice 7 replaces this closed adapter +with the encrypted creator-bound adapter through the same caller-context boundary. + +Acceptance: verified enrolled Go client invokes a granted synthetic operation; +portable/cross-server credentials cannot. Denial/grant removal wins races against +queued admission, request bodies, upstream dispatch and ongoing output; retained +blocking work keeps its slot until exit. Password renewal does not require grants; +repointed names keep deliberate grants. Test substituted server, changed outer +cert/proxy, malicious headers/redirects, byte/control limits, slow/chunked bodies +and unchanged timeout budgets; no native secret reaches the relay. Add account +grant/transport/proxy documentation, server/client fragments and skill guidance +where discovery/enrollment instructions change. + +The slice-3 prefix test must also invoke an artifact-producing operation through +the real authenticated Python/Go path before slice 7. Assert the closed adapter +rejects before legacy store entry/payload publication, no plaintext or ownerless +file/metadata/nonce/usable descriptor is created, no legacy route can read one, +and cancellation/repeated failure release bounded staging and worker ownership. +Use a legacy-store spy plus filesystem inspection, including restart cleanup; +the final no-publication gate alone is not this acceptance evidence. + +### Current proposed cuts and dependencies + +The [milestone-3 LLD](milestone-3-lld.md) owns exact N01–N12 acceptance, complete +per-cut scope and production/test/CI ranges. Its 13 cuts replace the historical +seven rows; do not add the two forecasts together. All work remains unimplemented. + +| Cut | Direct implementation prerequisite | Owning result / acceptance | +| --- | --- | --- | +| `3.1.1` | `2.10.4` | Shared carrier/pump with real existing-control and streaming consumers; N03/N04. | +| `3.1.2` | `3.1.1` | Strict Python ordinary mTLS peer; N01. | +| `3.1.3` | `3.1.2` | Go native identity/dial and standard HTTP transport peer; N01/N02/N11. | +| `3.1.4` | `3.1.3` | Bounded single-request HTTP/ASGI, absolute request-receipt timer and pre-body admission; N03/N04. | +| `3.2.1` | `3.1.4` | Existing enrollment-row live fields/grants and migration; first OS enrollment-deny control and minimal shared coordinator guard the real fixed receipt through final output/actual-owner cleanup; N05/N07 receipt races. | +| `3.2.2` | `3.2.1` | Extend the same coordinator, writer/read epochs and actual worker ownership to ordinary authority; OS grant add/remove controls; N04/N05/N06/N07. | +| `3.3` | `3.2.2` | Discovery/direct/policy/error filtering; N06. | +| `3.4` | `3.3` | Real dispatch caller context, closed artifact dependency/inline/legacy cleanup; N09. | +| `3.6.1` | `3.4` | Cross-connection body/dispatch denial and retained actual workers; N07/N08. | +| `3.6.2` | `3.6.1` | Final output permission after backpressure and abort without revoked flush; N03/N07/N08. | +| `3.5.1` | `3.6.2` | Every CLI constructor and explicit enrollment selection through private real peers; production selection retains its working route. N10/N11. | +| `3.5.2` | `3.5.1` | Atomic production CLI/native server switch, anonymous closure and first installed denial/artifact prefix; N01/N04/N07/N09/N10/N12. | +| `3.7` | `3.5.2` | Installed relay/timeouts/native composition and full N01–N12 closure. | + +All `3.1` descendants close parent 3.1, both `3.2` descendants close 3.2, both +`3.6` descendants close 3.6 before cutover, and both `3.5` descendants close 3.5. +Later references to a parent still require all its descendants and aggregate +acceptance. The first public ordinary prefix includes denial and safe artifact +failure; final 3.7 is not a budget for missing earlier mechanisms or tests. + +## Slice 4 — rotation, late completion and bounded fallback + +Milestones 4–11 below retain their approved scope/order and historical outlines. +Their child boundaries and estimates require source-based LLD refinement/review +before implementation. This design revision does not claim those future cuts +are already sized or predictive after milestone-2 implementation changes. + +Deliver on-contact due rotation, fixed grace, durable candidate save/confirmation +and lost-response reconciliation. A pending deadline is recorded before asking +for candidate; withholding/retry/old ordinary use cannot move it. Current, +predecessor and pending candidate form coherent client state. Use the separate +fixed control carrier to finish the exact rotation after grace or cert expiry; +ordinary mTLS stays strict. Control proofs bind both stored keys, fresh challenge, +TLS exporter, identities, purpose and pending revision. Reissue only that same +candidate certificate; no general expired-credential exception. + +Acceptance: test 30-day/24-hour/180-day boundaries, old/candidate expiration, +candidate-withholding, disconnect and restart at every save/commit/receipt point. +Ordinary access remains until grace, then only pending completion is possible; +incomplete controls cannot refresh inactivity. Revocation/owner repair wins every +activation race. Receipt survives needed expiry/reconciliation intervals. One +predecessor authentication attempt requires unambiguous authenticated rejection +by the same verified server; never after denial/timeout/unverified peer or operation +submission, and never replay uncertain mutation/GET. Test across both languages +with real controlled clocks/sockets and malicious control transcripts. Add lifecycle +configuration/help, repair guidance and server/client fragments. + +### Child PRs + +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `4.1` — Server pending rotation and fixed grace | Prepare a due transition on authenticated contact, bind one candidate and preserve current ordinary access until its original deadline. **Check:** Controlled 30-day/24-hour/180-day boundaries, withheld candidates and restart cannot slide grace or inactivity. | 220–360 | 260–450 | 480–810 | Low | 3.7 | +| `4.2` — Durable candidate confirmation | Save candidate state in Go, prove possession and conditionally activate/promote with one retained predecessor and idempotent result. **Check:** Crash/lost reply at save/activate/promote cannot install an unsaved key, clear denial or duplicate transition. | 240–400 | 300–500 | 540–900 | Low | 4.1 | +| `4.3` — Expired-key restricted completion | Add the fixed exporter-bound old-plus-candidate control and reissue only that pending candidate after grace/certificate expiry. **Check:** Ordinary TLS remains strict; wrong pending purpose/revision, replay, inactivity and denial cannot complete or refresh deadlines. | 260–420 | 300–520 | 560–940 | Low | 4.2 | +| `4.4` — Authenticated predecessor assistance | Return authenticated credential status and permit one authentication-only predecessor attempt after the same verified server rejects current credentials. **Check:** Never fallback after timeout, unverified peer, denial or submitted operation/consuming GET; superseding recovery discards history. | 160–280 | 240–420 | 400–700 | Low | 4.3 | +| `4.5` — Lifecycle race and clock closure | Exercise the implemented transitions through process restarts and competing denial/recovery, with final lifecycle diagnostics and retained-receipt cleanup. **Check:** Full Python/Go boundary matrix preserves unattended completion where permitted; incomplete exchanges cannot keep an inactive enrollment alive. | 80–180 | 320–550 | 400–730 | Low | 4.4 | + +## Slice 5 — owner-authorized client recovery + +Deliver trusted owner tooling to authorize a fresh per-server access key or +portable-key repair for an existing durable identity. Consume a server-specific, +fresh challenged ES256 authorization and replacement-key possession proof in one +conditional authority transaction. Signature supplies approval; no second remote +operator approval or grant recreation. Preserve suspensions/revocations. Local +pairing repair of the existing enrollment remains the simple alternative. + +Acceptance: two isolated servers register the same owner trust but distinct access +keys; owner tooling produces per-server proofs and repairs both without sharing +issuer private keys or trusting another server's credential. Portable possession +alone fails. Wrong algorithm/key/purpose/server/revision/expiry, replay, concurrent +recovery/rotation/denial and lost response fail or reconcile exactly once. Revoked +enrollment remains revoked after repair. Owner/recovery file stays outside agent +and server custody; missing proof offers explicit repair, not identity reset. +Add recovery-file theft consequences, CLI journey and server/client fragments. + +This slice also implements owner-issuer and portable-leaf certificate renewal +using slice 1's selected schedules, registered signer and live-state checks while +preserving owner/agent IDs and purpose separation. Controlled-clock tests cover +before-expiry renewal, signer/key mismatch, denial and renewal races, rejection +of portable credentials on ordinary TLS, restart and missed-renewal diagnostics. +Certificate renewal must not become an automatic access-key replacement or grant. + +### Child PRs + +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `5.1` — Owner-approved pairing repair | Extend local pairing for an existing enrollment with explicit owner selection while retaining durable identity, grants and denial. **Check:** New-client enrollment cannot silently select an existing identity; repair invalidates superseded pending/current credentials without regranting. | 180–300 | 240–420 | 420–720 | Low | 4.5 | +| `5.2` — External owner challenge proofs | Implement strict ES256 recovery statements, externally held signer tooling and fresh server-bound challenge with replacement possession proof. **Check:** Shared Python/Go fixtures reject wrong algorithm, purpose, signer, server, expiry, duplicate fields and changed signed bytes. | 220–370 | 280–480 | 500–850 | Low | 5.1 | +| `5.3` — Atomic access-key recovery | Consume the exact challenge and replace access state in one conditional live-authority transaction; reconcile lost response. **Check:** Recovery/rotation/denial races consume once; revoked state stays revoked; no second per-server approval or issuer private-key sharing. | 200–330 | 260–450 | 460–780 | Low | 5.2 | +| `5.4` — Portable identity repair across servers | Apply the owner-authorized portable replacement and orchestrate distinct per-server recovery proofs using the same external owner trust. **Check:** Two real isolated servers keep independent access keys and grants; portable possession alone cannot replace access or trust another server credential. | 180–320 | 280–480 | 460–800 | Low | 5.3 | +| `5.5` — Owner and portable certificate renewal | Implement authorized before-expiry owner-issuer/portable-leaf renewal under 1.2 schedules, keeping purpose and durable IDs. **Check:** Controlled time, wrong signer, denial, concurrent renewal and restart cannot grant native access or masquerade as access-key rotation. | 180–330 | 260–450 | 440–780 | Low | 5.4 | + +## Slice 6 — server identity replacement + +Deliver operator-triggered planned authority replacement with old endorsement, +new-key possession, stable server ID and durable client adoption/transition +history. Separately deliver compromise repair using the independently registered +external owner verifier, never compromised server key alone. URL/HTTPS renewal +does not trigger identity rotation. Private/public-key roles remain distinct. + +Acceptance: online and offline clients recognize legitimate replacement, including +lost transition response/restart and later key changes. Wrong ID, missing history, +expired/untrusted chain or endorsement by compromised key alone cannot install new +trust; missing independent authority gives explicit owner pairing guidance. Client +never sends credentials/capabilities before verifying the expected server or +authorized repair. Neither path clears enrollment denial or duplicates grants. +Test installed-client state and preserved history with real Python/Go peers. +Document planned versus compromised-key procedure and add server/client fragments. + +This slice separately implements server-authority and inner-server-leaf certificate +renewal under slice 1's validity/schedule profiles, without scheduled identity-key +rotation. Test authorized before-expiry renewal with stable server ID/key, +appropriate issuer/live-state checks and clients retaining remembered trust. +Controlled-clock negative tests reject peer-provided renewal of an expired server +trust anchor; missing the trust-validity deadline requires the independently +authorized owner recovery path (or explicit pairing when that trust is missing). +Test expiry/restart/renewal races and ensure HTTPS renewal/URL changes do not replace +native identity or silently extend authority. Keep these tests distinct from +access-key rotation and planned server-key replacement. + +### Child PRs + +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `6.1` — Planned server transition publication | Produce old endorsement plus new possession with stable server ID and durable transition history through operator tooling. **Check:** Wrong identity/key, incomplete publication and restart cannot install unsigned trust or lose the prior complete history. | 200–340 | 260–450 | 460–790 | Low | 5.5 | +| `6.2` — Client transition adoption | Fetch and verify legitimate transition chains, then durably adopt server trust for online and long-offline clients. **Check:** Missing/interleaved history, replay and failed save reject safely; credentials are withheld until destination identity is verified. | 200–340 | 260–450 | 460–790 | Low | 6.1 | +| `6.3` — Independent compromise recovery | Use registered external owner authorization for server-key compromise recovery and propagate explicit client repair diagnostics. **Check:** Stolen old server key alone cannot bless a replacement; owner proof cannot clear client denial, change server ID or duplicate grants. | 220–370 | 280–480 | 500–850 | Low | 6.2 | +| `6.4` — Server authority and leaf renewal | Renew server-authority and inner-server-leaf certificates before expiry without scheduled identity-key replacement; use independent owner recovery after missed trust validity. **Check:** Controlled clocks reject expired peer-driven trust renewal; stable IDs/keys, restart and renewal races work; outer HTTPS renewal changes no native trust. | 220–380 | 280–500 | 500–880 | Low | 6.3 | + +## Slice 7 — encrypted server artifacts and ownership + +Deliver server-side age encryption for the creator's registered recipient and +server storage recipient, authenticated origin descriptors and ciphertext delivery +through the native API. Thread immutable caller/account context into all plugin +artifact creation, including inline native descriptors; a plugin cannot choose +another creator. Keep server-readable inspection possible without adding scanning. +Recipient registration needs authenticated proof/new-key challenge and retained +key history is bounded by active artifact lifetime; auth rotation cannot discard +needed recipient keys. No persistent plaintext staging is introduced as a shortcut. + +Acceptance: creator plus nonce plus live enrollment/account grant is required for +metadata/HEAD/GET; shared account, copied URL or revoked grant fails. HEAD is +non-consuming; GET atomically consumes before open, including failed streams. +Test nonce/consume/revoke/store-lock races, slow writer/disconnect, restart, orphan +cleanup and quota reservations through actual cleanup. Preserve 50 MiB plaintext, +2,000 artifacts, 1 GiB physical, ten-minute idle and 24-hour maximum; count all +crypto/metadata/staging overhead without lowering plaintext cap. Mock IMAP/SMTP +flows exercise real artifact adapters. Legacy cleanup is idempotent and confined +to server-managed ownerless files. Add storage/ownership docs and affected server/ +plugin fragments; server encryption is not whole client-processing completion. + +### Child PRs + +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `7.1` — Artifact recipient registration and retention | Register fresh recipient possession through authenticated identity, persist bounded client/server recipient history and separate it from access-key rotation. **Check:** Wrong origin/key/version or unauthenticated change fails; keys needed by active artifacts survive access rotation until bounded expiry. | 220–370 | 260–450 | 480–820 | Low | 6.4, 3.6 | +| `7.2` — Encrypted payload and metadata writing | Add streaming age dual-recipient creation and encrypted descriptors behind the closed plugin adapter; preserve server inspection capability. **Check:** Python/Go fixtures prove both recipients, wrong-key/tamper/truncation failure and no persistent plaintext staging; disabled delivery cannot publish a usable nonce. | 240–400 | 280–480 | 520–880 | Low | 7.1 | +| `7.3` — Physical quota and encrypted-store recovery | Integrate ciphertext/metadata/staging reservations, 50 MiB plaintext and existing count/storage/retention limits, plus restart orphan cleanup. **Check:** Near-cap overhead, full disk, concurrent writers, cancellation and open readers hold reservation until actual cleanup; no cap is silently lowered. | 220–360 | 280–480 | 500–840 | Low | 7.2 | +| `7.4` — Creator-bound HEAD and consuming GET | Authorize descriptors/HEAD/GET by creator, account grant and nonce, with atomic consume-before-open and authenticated origin. **Check:** Shared account/copied URL/revocation fails; HEAD never consumes; failed/slow GET stays consumed across restart. | 220–370 | 300–500 | 520–870 | Low | 7.3 | +| `7.5` — Plugin adapter and descriptor activation | Replace the closed adapter with creator-bound encrypted creation for all artifact-producing and inline result paths, retaining legacy-route closure. **Check:** Real mock IMAP/SMTP and Python/Go dispatch cannot choose another creator or return a legacy descriptor; ownerless cleanup stays confined. | 180–320 | 260–460 | 440–780 | Low | 7.4 | +| `7.6` — Artifact contention and packaging closure | Complete real storage-lock/consume/revoke/stream races and age dependency/install checks on supported platforms. **Check:** Health stays responsive under valid/invalid nonces; disconnect/shutdown retain file/crypto owners until cleanup; no replay reopens GET. | 80–180 | 300–550 | 380–730 | Low | 7.5 | + +## Slice 8 — four client artifact paths + +Deliver immediate plaintext stdin, fully verified encrypted-temp-to-stdin, +explicit plaintext-temp pathname and deliberate `artifact save-decrypted`. +Authenticated descriptor and key remain private process state; downloaded metadata +cannot nominate origin. Verified modes finish digest/length/age finalization and +source checks before tool launch/publication. Keep stable ciphertext between +passes through proven platform handles or the HLD's bounded immutable snapshot. +Do not select a universal mode/default or preserve an ambiguous `save` alias. + +Acceptance: tamper, truncation, wrong origin/creator/recipient and changed staging +path cannot start a tool in verified modes. Immediate stdin may deliver valid +prefix, but reports final failure honestly. Test POSIX writable-alias removal, +Windows sharing/ACL constraints, fallback reservation, four-transfer saturation, +full disk, child failure, signals/cancellation and crash cleanup. No orphan file +resumes a consumed GET; plaintext temp/export require explicit action and no +partial final export. Access/recipient rotation and grant denial during download +compose with slices 3/4/7. Explain delay/storage/partial-effects/plaintext exposure +in both client reference and operation help, discourage persistent agent exports, +and add native-client fragments and affected skill updates. + +### Child PRs + +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `8.1` — Immediate authenticated plaintext stdin | Decrypt the one native GET directly to child stdin using the authenticated descriptor and bounded process ownership. **Check:** Final digest/EOF failure reports honestly after any valid prefix; no automatic retry, sensitive stdout or default plaintext file. | 180–320 | 260–450 | 440–770 | Medium | 7.6 | +| `8.2` — Verified encrypted-temp stdin | Reserve ciphertext staging, fully verify to a discard sink, then process exact immutable bytes via native handles or bounded memory fallback. **Check:** Path replacement/writable aliases, tamper/truncation and failed verification cannot start tools on POSIX or Windows; four transfers bound fallback memory. | 260–420 | 300–520 | 560–940 | Low | 8.1 | +| `8.3` — Explicit plaintext-temp path | Require explicit selection, privately stage and fully verify plaintext before tool launch, and clean up on exit/cancellation. **Check:** Bad origin, child failure, signals and path abuse cannot expose unverified files or publish a final artifact; document best-effort crash cleanup. | 150–260 | 220–400 | 370–660 | Medium | 8.2 | +| `8.4` — Deliberate save-decrypted export | Rename intentional persistent plaintext export without the ambiguous save alias; verify private staging before atomic final publication. **Check:** No partial output on full disk/tamper/cancellation; overwrite permissions and explicit user-facing warnings are tested. | 140–250 | 220–400 | 360–650 | Medium | 8.3 | +| `8.5` — Four-mode process and platform closure | Finish CLI/skill tradeoff guidance and real child-process, cleanup and rotation/revocation composition checks without adding a universal mode default. **Check:** Installed tools demonstrate all four paths; consumed GET cannot be resumed from an orphan; native platform process/handle limits are enforced. | 80–180 | 300–520 | 380–700 | Low | 8.4 | + +## Slice 9 — useful consistent encrypted export + +Deliver local/SSH export usable by an external startup/periodic job: capture one +saved config/policy/actual-secret/authority generation, briefly fence mutations, +take coherent SQLite snapshot, then stream signed manifest/records through age to +the registered external recipient. Capture configured secret-file values without +arbitrary environment dumps; changed source during capture aborts before publish. +Exclude the HLD omissions, especially sessions, PSKs, client private keys and +transient artifact payloads. Operator file/public metadata and encrypted bundle +are clearly distinct; server/job has no private recovery signer/decryptor. + +Acceptance: enroll/grant/revoke/rotate/config reload during export yields one +coherent snapshot. Secret-source changes, output failure/cancellation/disk full, +oversize/header/manifest abuse and crash preserve the previous complete export; +never expose partial final bundle or plaintext staging. One admin job at a time, +4 GiB total plaintext/10,000 entries/64 MiB per entry/1 MiB manifest and bounded +encrypted header/overhead parsing are enforced before growth. Verify exact signed +manifest/file digests using external trusted metadata in a round-trip harness, +not a signer supplied by the bundle. Include job examples for durable storage and +failure reporting without adding scheduler/cloud integration/first-enrollment +gate. Add backup CLI/docs and an arbiter-server fragment. + +### Child PRs + +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `9.1` — Saved configuration and real secret capture | Extend private generations to active config/policies and materialized configured file-backed secrets on activation/reload. **Check:** Changed-source capture aborts before publication; arbitrary environment/host files never enter saved state; normal reload remains coherent. | 240–400 | 280–480 | 520–880 | Low | 8.5, 1.4 | +| `9.2` — Coherent authority snapshot | Fence live mutations briefly and capture SQLite plus the exact saved config/key/secret generation, releasing the fence before encrypted streaming. **Check:** Concurrent enroll/grant/revoke/rotate/reload yields one coherent snapshot; failure/shutdown releases the real admin owner and preserves service state. | 200–340 | 280–470 | 480–810 | Low | 9.1 | +| `9.3` — Signed bounded recovery records | Write versioned uncompressed records and exact-byte ES256 manifest; provide strict verification primitives consumed by export self-checks and later restore. **Check:** Reject duplicate paths/fields, links, traversal, oversized entries/count/manifest and bundle-supplied verifier substitution in shared synthetic fixtures. | 250–420 | 300–520 | 550–940 | Low | 9.2 | +| `9.4` — Encrypted local and SSH export | Stream the coherent snapshot through age to external recipient with one admin job and safe publication of complete outputs. **Check:** Private recovery signer/decryptor never enters server/job/bundle; 4 GiB limit, disconnect/full disk and cancellation preserve last good bundle. | 220–360 | 280–480 | 500–840 | Low | 9.3 | +| `9.5` — External job and concurrent-export closure | Document startup/periodic external scheduling, durable destination/alerting and round-trip verifier usage; finish process-level snapshot contention tests. **Check:** Real local/verified-SSH jobs produce usable signed encrypted snapshots; excluded transient artifacts/PSKs/client keys remain absent across failures. | 80–180 | 280–500 | 360–680 | Low | 9.4 | + +## Slice 10 — offline restore and latest undo + +Deliver offline restore while the server is broken/stopped, using the external +operator file to decrypt/authenticate a complete bundle privately. Verify strict +records/manifest/origin/hashes/key correspondence/config before publishing a fresh +saved generation. Use exclusive stopped-instance lock and one durable transaction +for active/undo references; failed restore preserves current state and previous +undo point. Preserve saved deadlines, not restore-time authority extensions. + +Deliver offline undo of that latest successful restore, without expiry or a +post-use hard cutoff; explicit discard or next successful restore replaces it. +Warn very prominently about snapshot date, lost post-snapshot/post-restore local +changes, restored grants/revocations and upstream effects that cannot be undone. +No silent merge, restore wizard, redo history, paused-access mode or acceptance +ceremony. Ordinary different-host edits remain available before start. + +Acceptance: real process termination/fault injection before/after flush and each +reference update leaves an old or new coherent generation on native POSIX/Windows. +Reject malformed/duplicate/traversing/link/device/oversized records and wrong +external verifier; no partial activation. Restore to an empty host and over an +existing instance; test old snapshots, client current/predecessor divergence, +pairing repair, revocation preservation within the selected snapshot, repeated +restore failure, undo after use and explicit discard. Show clear repair diagnostics +without claiming to know unseen client history. Add full restore/undo examples, +host-configuration exclusions and arbiter-server fragment. + +### Child PRs + +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `10.1` — Strict offline bundle validation | Decrypt against external trust, validate all record/hash/EOF/certificate/key/config constraints before exposing a restorable generation. **Check:** Malformed/traversing/duplicate/oversized records, wrong verifier and incomplete stream fail with bounded I/O and no active-state changes. | 240–400 | 300–520 | 540–920 | Low | 9.5 | +| `10.2` — Stopped-instance private restore staging | Require exclusive stopped-instance lock, available-disk reservation and same-filesystem private staging; reconcile incomplete restore on restart. **Check:** Concurrent server start/restore, disk failure and real process termination preserve active generation and existing undo. | 200–340 | 280–480 | 480–820 | Low | 10.1 | +| `10.3` — Atomic full restore activation | Publish verified generation with active/undo references in one durable control transaction, retaining saved lifecycle timestamps and host exclusions. **Check:** Empty/existing hosts restore coherently; faults at flush/reference boundaries choose only old or new complete state, never merge or extend authority. | 220–360 | 300–520 | 520–880 | Low | 10.2 | +| `10.4` — Latest undo and explicit discard | Implement offline undo without expiry or post-use hard cutoff; retain the point through ordinary operation and warn prominently before discarding later changes. **Check:** Failed restore preserves undo; next successful restore replaces it; undo after use and discard have no redo/history or upstream rollback promise. | 180–300 | 260–450 | 440–750 | Low | 10.3 | +| `10.5` — Restore-client and native crash closure | Complete controlled process-crash and native durability tests, stale client/predecessor diagnostics and useful full restore/undo examples. **Check:** Multiple paired clients either recover within bounded fallback or require explicit repair; old snapshot denial/deadlines reflect snapshot, not guessed unseen history. | 80–180 | 320–550 | 400–730 | Low | 10.4 | + +## Slice 11 — cooperative migration and handoff + +Deliver maintenance/migration tooling and runbook: disable source ordinary work +and state-changing admin, drain/cancel real owners, export final snapshot, restore +stopped destination, edit host settings, start destination only and keep source +disabled. Optional source handoff is a fixed authenticated URL response using +saved source identity, without ordinary dispatch/enrollment/grant/rotation writes. +Client obtains URL before operation submission, verifies the same durable identity +and legitimate current key-transition chain at destination, then stores the URL. +No HTTP redirect or repair replays uncertain mutation/consuming GET. + +Acceptance: multiple previously paired clients migrate with distinct grants, +pending/completed rotations and receipt state. Test destination identity mismatch, +later destination key replacement without changing old handoff URL, offline/old +URL failure, lost response and explicit URL edits. Clients send no credentials/ +nonces to an unverified destination. Source mode cannot mutate authority. Post-use +undo/fallback warns of stale state and never automatically starts the old host. +The operator, not a new epoch/fencing/cluster mechanism, prevents two writable +copies. Run actual Reploy staging on its separate port using synthetic state; +no live installation migration is authorized by this plan. Add maintenance/handoff +docs, client diagnostics and affected server/client fragments. + +### Child PRs + +| PR | Scope and focused acceptance | Production | Tests | Total | Confidence | Direct prerequisites | +| --- | --- | ---: | ---: | ---: | --- | --- | +| `11.1` — Cooperative maintenance and migration | Disable source ordinary work/admin mutations, drain real owners, export final snapshot and restore stopped destination under documented operator coordination. **Check:** Source stays disabled through failures; no new fencing/epoch/cluster mechanism or automatic old-host restart is introduced. | 180–300 | 260–450 | 440–750 | Low | 10.5 | +| `11.2` — Verified source URL handoff | Serve only a fixed authenticated destination URL from disabled source; client verifies same durable identity/transition chain before adopting and sending any credential. **Check:** Mismatch/unavailable URL/later destination replacement/lost response never replays submitted mutation or GET; handoff cannot mutate authority. | 220–380 | 280–500 | 500–880 | Low | 11.1 | +| `11.3` — Migration and combined release evidence | Finish synthetic multi-client Reploy staging on its separate port and the full combined journey/matrix; reconcile release/help/skill/dependency metadata. **Check:** Migration with grants/pending rotations and post-use undo is honest; all required checks pass or remain explicitly unverified and block publication. | 80–180 | 320–550 | 400–730 | Low | 11.2 | + +## Combined acceptance and publication gate + +Every slice runs prefix integration; do not defer first Python/Go composition, +platform packaging or cancellation testing until this gate. Once all child PRs across the eleven milestones +have approved final heads and required checks, run the complete synthetic journey: + +1. Fresh private setup with no public CA/DNS or external identity account; enroll + first and additional clients with one handoff/approval, restart and reconcile. + Reuse one portable identity at a separately registered second server with + distinct access/grants and no source-server availability requirement (P01–P10). +2. Authenticated discovery/direct invocation of mock SMTP/IMAP accounts with + distinct grants, existing policies, grant change/denial and concurrent output. +3. Due rotation, fixed grace, expired-certificate control completion, inactivity, + predecessor fallback, owner client repair, owner-issuer/portable/server-authority/ + server-leaf certificate renewal and server-key replacement, including refused + expired peer-driven trust renewal and explicit owner recovery after missed validity. +4. Encrypted artifacts through all four modes with origin/recipient checks, + failed consuming GET, full limits, quota contention and real cancellation. +5. Concurrent-state export, offline restore, failed restore preserving undo, + after-use undo/repair, maintenance migration and non-mutating URL handoff. + +Run combined contention/cancellation/deadline/cleanup checks so carrier, crypto, +HTTP/body, plugin worker, file/quota and admin ownership cannot each pass while +their composition leaks work. Run all Python tests and Go tests/vet, lint/type +checks, client/server builds/install smoke, supported Python/OS/CPU matrix and +Reploy staging regressions. Public proxy tests include TLS termination with an +untrusted inspecting relay, changed outer cert, and TCP passthrough; future +browser administration remains unimplemented, with its documented trust boundary. + +Published help/docs/skill, package dependency metadata, release notes and upgrade +guidance must agree with the final implementation. Existing pre-auth clients get +actionable enrollment guidance, not an unauthenticated fallback. Do not require +live accounts to prove safety or mark unavailable checks as passed. Remaining +failures require fixes/re-review or an explicit requirements/HLD decision; no +scope reduction, platform drop or readiness claim is hidden in release wording. + +Approval of this revision attests its design, ordering and verification +obligations. Implemented/merged state is reported explicitly above; the newly +proposed work begins only on separate implementation authorization. Reviews and exact-byte stamp evidence are stored outside this +document so recording its verdict does not invalidate the reviewed plan.