diff --git a/README.md b/README.md index 91209c1..ce8db3b 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ checks quickstart handoff evidence for first-run package health, HTTP/team handoff, demo, deploy, support, permissions, preflight, client, dashboard, and artifact inventory coverage. It also checks support/doctor handoff evidence for operator refresh, no-remediation -doctor output, release-manifest binding, and hashed support inventory. It also +doctor output, deploy/preflight evidence, release-manifest binding, and hashed support inventory. It also checks deploy/preflight handoff evidence for templates, placeholders, secret-reference manifests, provider-shaped production refs, and non-local bind defaults. It also checks the @@ -595,11 +595,12 @@ or pass `--release-manifest` so the doctor can confirm the package manifest, package lock, archive checksum, and install receipt hashes still line up. Run `dist/agentk-sidecar/bin/agentk-sidecar-support-bundle --json` when an operator needs one support artifact. It refreshes the operator handoff, runs -the sidecar doctor, inventories package manifest/lock/release manifest, -dashboard, store, trace, and notification evidence with byte counts and -SHA-256 hashes, adds ticket-attachment guidance for operator handoff, doctor, -package, trace, store, approvals, notification drafts, and release manifest -files, then writes +the sidecar doctor, refreshes deploy/preflight handoffs, inventories package +manifest/lock/release manifest, deployment, preflight, dashboard, store, trace, +and notification evidence with byte counts and SHA-256 hashes, adds +ticket-attachment guidance for operator handoff, doctor, deploy handoff, +production preflight, package, trace, store, approvals, notification drafts, +and release manifest files, then writes `sidecar/.agentk/support-bundle/support-bundle.json` and `sidecar/.agentk/support-bundle/support-bundle.md` without uploading anything to a hosted service. @@ -960,7 +961,7 @@ to recreate the package, archive, checksum, and release manifest in a repo-local smoke root, execute the packaged HTTP and team handoff checks, safe-agent demo, dashboard, sidecar check, store export/check/sync, operator handoff artifact, support bundle JSON/Markdown, deploy handoff JSON/Markdown, -release-manifest check, sidecar doctor release-manifest binding, +production preflight JSON/Markdown, release-manifest check, sidecar doctor release-manifest binding, Slack/GitHub/email payload exporters, and Postgres dry-run push launchers, then write one JSON evidence report with SHA-256 and byte counts for the required handoff artifacts before a release branch or tag. Then run diff --git a/docs/mcp-proxy.md b/docs/mcp-proxy.md index 6fc3d21..7c2d025 100644 --- a/docs/mcp-proxy.md +++ b/docs/mcp-proxy.md @@ -307,7 +307,8 @@ install receipt hashes. It is a local/team sidecar alpha support artifact, not a hosted SaaS readiness check. Run `/bin/agentk-sidecar-support-bundle --json` when a reviewer or operator needs one support archive. It refreshes the operator handoff, runs the -sidecar doctor, and writes support-bundle JSON/Markdown with hashed package, +sidecar doctor, deploy handoff, and production preflight, then writes +support-bundle JSON/Markdown with hashed package, deployment, preflight, dashboard, store, trace, notification evidence, and ticket-attachment guidance for local/team handoff. Run `/bin/agentk-sidecar-permissions-handoff --json` when a team wants diff --git a/docs/productization-plan.md b/docs/productization-plan.md index 19e9d9a..39306ed 100644 --- a/docs/productization-plan.md +++ b/docs/productization-plan.md @@ -352,8 +352,8 @@ The safest first productization slice is the local team sidecar path: install receipt hashes into the support report. `sidecar-package-support-bundle` and the packaged `bin/agentk-sidecar-support-bundle` launcher compose the operator handoff, - sidecar doctor, and hashed evidence inventory into one archiveable - support-bundle JSON/Markdown artifact. + sidecar doctor, deploy/preflight handoffs, and hashed evidence inventory + into one archiveable support-bundle JSON/Markdown artifact. 14. The subprocess MCP gateway has an operator-configurable `max_client_messages` cap, exposed on `mcp-proxy-stdio` and generated sidecar bundles, so runaway clients cannot hold one proxy session forever. diff --git a/docs/release-checklist.md b/docs/release-checklist.md index a0d962a..46482af 100644 --- a/docs/release-checklist.md +++ b/docs/release-checklist.md @@ -153,8 +153,9 @@ hardening, redacted probes, and permission-checked review APIs. It also checks quickstart handoff evidence for first-run package health, HTTP/team handoff, demo, deploy, support, permissions, preflight, client, dashboard, owner-specific next actions, and artifact inventory coverage. It checks support/doctor handoff -evidence for operator refresh, no-remediation doctor output, release-manifest -binding, hashed support inventory, and ticket-attachment guidance, plus accepted-limit checks that keep +evidence for operator refresh, no-remediation doctor output, deploy/preflight +evidence, release-manifest binding, hashed support inventory, and +ticket-attachment guidance, plus accepted-limit checks that keep hosted SaaS, live IdP, production secret retrieval, public internet gateway, and similar deferred-scope claims out of the alpha handoff. The same ticket checks deploy/preflight handoff evidence for templates, placeholders, diff --git a/docs/v0.2-alpha-release-notes.md b/docs/v0.2-alpha-release-notes.md index f41677a..ec43b7f 100644 --- a/docs/v0.2-alpha-release-notes.md +++ b/docs/v0.2-alpha-release-notes.md @@ -71,8 +71,9 @@ filesystem-shaped workflows. dashboard, owner-specific next actions, artifact inventory, and local non-hosted scope. The ticket also checks support/doctor handoff evidence for operator handoff - refresh, no-remediation doctor output, release-manifest binding, hashed - support inventory, ticket-attachment guidance, and local non-hosted scope. + refresh, no-remediation doctor output, deploy/preflight evidence, + release-manifest binding, hashed support inventory, ticket-attachment + guidance, and local non-hosted scope. The ticket checks publication handoff evidence for strict finalization, signed tag evidence, package archive hash, final release notes, owner-scoped publication steps, and `release-publication-check` coverage before a @@ -146,8 +147,9 @@ filesystem-shaped workflows. and Markdown remediation output. - Packaged support bundle: `agentk-sidecar-support-bundle` refreshes the operator handoff, runs the - sidecar doctor, and writes one archiveable support-bundle JSON/Markdown report - with hashed package, dashboard, store, trace, and notification evidence. + sidecar doctor, deploy handoff, and production preflight, then writes one + archiveable support-bundle JSON/Markdown report with hashed package, + deployment, preflight, dashboard, store, trace, and notification evidence. - Packaged safe-agent demo handoff: `agentk-sidecar-demo-handoff` refreshes the credential-free GitHub/Postgres/Slack/filesystem demo evidence and writes one archiveable @@ -243,8 +245,9 @@ These limits are explicit alpha scope, not hidden caveats: artifact for the same local proof. The packaged `agentk-sidecar-doctor` command adds one support/remediation report for install or update checks and can bind that report to the package release manifest. The packaged - `agentk-sidecar-support-bundle` command combines the handoff, doctor, and - hashed evidence inventory into one archiveable support artifact. The packaged + `agentk-sidecar-support-bundle` command combines the handoff, doctor, + deploy/preflight handoffs, and hashed evidence inventory into one archiveable + support artifact. The packaged `agentk-sidecar-dashboard-handoff` command refreshes the demo trace, renders the static dashboard, syncs the durable team store, and writes one JSON/Markdown dashboard readiness artifact. The diff --git a/src/lib.rs b/src/lib.rs index 88cf8b6..a0a909e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6794,6 +6794,8 @@ pub struct SidecarPackageSupportBundleReport { pub release_manifest_path: Option, pub operator_handoff_dir: PathBuf, pub doctor_dir: PathBuf, + pub deploy_handoff_dir: PathBuf, + pub production_preflight_dir: PathBuf, pub local_team_sidecar_alpha: bool, pub hosted_saas: bool, pub passed: bool, @@ -6804,6 +6806,8 @@ pub struct SidecarPackageSupportBundleReport { pub package_check: SidecarPackageCheckReport, pub operator_handoff: SidecarPackageOpsHandoffReport, pub doctor: SidecarPackageDoctorReport, + pub deploy_handoff: SidecarPackageDeployHandoffReport, + pub production_preflight: SidecarPackageProductionPreflightReport, } #[derive(Debug, Clone, Serialize)] @@ -8675,22 +8679,31 @@ pub fn write_sidecar_package_support_bundle( let markdown_path = output_dir.join("support-bundle.md"); let operator_handoff_dir = root.join("sidecar/.agentk/operator-handoff"); let doctor_dir = root.join("sidecar/.agentk/doctor"); + let deploy_handoff_dir = root.join("sidecar/.agentk/deploy-handoff"); + let production_preflight_dir = root.join("sidecar/.agentk/production-preflight"); let package_check = check_sidecar_package(root)?; let operator_handoff = write_sidecar_package_ops_handoff(root, &operator_handoff_dir)?; let doctor = write_sidecar_package_doctor(root, &doctor_dir, release_manifest)?; + let deploy_handoff = write_sidecar_package_deploy_handoff(root, &deploy_handoff_dir)?; + let production_preflight = + write_sidecar_package_production_preflight(root, &production_preflight_dir)?; let artifacts = sidecar_package_support_bundle_artifacts( root, release_manifest, &operator_handoff, &doctor, + &deploy_handoff, + &production_preflight, )?; let ticket_attachments = sidecar_package_support_bundle_ticket_attachments( root, release_manifest, &operator_handoff, &doctor, + &deploy_handoff, + &production_preflight, ); let required_artifacts_present = artifacts .iter() @@ -8720,6 +8733,27 @@ pub fn write_sidecar_package_support_bundle( doctor.remediation_steps.len() ), ), + support_bundle_check( + "deploy handoff", + deploy_handoff.passed, + format!( + "{} deploy checks, {} supervisor probes", + deploy_handoff.checks.len(), + deploy_handoff.supervisor_probes.len() + ), + ), + support_bundle_check( + "production preflight", + production_preflight.passed, + format!( + "{} preflight checks, {} production refs, live secret retrieval {}", + production_preflight.checks.len(), + production_preflight + .production_secret_refs + .production_provider_ref_count, + production_preflight.live_secret_retrieval + ), + ), support_bundle_check( "support artifact inventory", required_artifacts_present, @@ -8758,6 +8792,8 @@ pub fn write_sidecar_package_support_bundle( release_manifest_path: release_manifest.map(Path::to_path_buf), operator_handoff_dir, doctor_dir, + deploy_handoff_dir, + production_preflight_dir, local_team_sidecar_alpha: true, hosted_saas: false, passed, @@ -8768,6 +8804,8 @@ pub fn write_sidecar_package_support_bundle( package_check, operator_handoff, doctor, + deploy_handoff, + production_preflight, }; fs::write(&json_path, serde_json::to_string_pretty(&report)?)?; fs::write( @@ -10947,6 +10985,8 @@ fn sidecar_package_support_bundle_artifacts( release_manifest: Option<&Path>, operator_handoff: &SidecarPackageOpsHandoffReport, doctor: &SidecarPackageDoctorReport, + deploy_handoff: &SidecarPackageDeployHandoffReport, + production_preflight: &SidecarPackageProductionPreflightReport, ) -> Result, AgentKError> { let mut artifacts = Vec::new(); sidecar_package_support_bundle_artifact( @@ -10986,6 +11026,26 @@ fn sidecar_package_support_bundle_artifacts( "sidecar doctor markdown", doctor.markdown_path.clone(), )?; + sidecar_package_support_bundle_artifact( + &mut artifacts, + "deploy handoff json", + deploy_handoff.json_path.clone(), + )?; + sidecar_package_support_bundle_artifact( + &mut artifacts, + "deploy handoff markdown", + deploy_handoff.markdown_path.clone(), + )?; + sidecar_package_support_bundle_artifact( + &mut artifacts, + "production preflight json", + production_preflight.json_path.clone(), + )?; + sidecar_package_support_bundle_artifact( + &mut artifacts, + "production preflight markdown", + production_preflight.markdown_path.clone(), + )?; sidecar_package_support_bundle_artifact( &mut artifacts, "safe-agent trace", @@ -11061,6 +11121,8 @@ fn sidecar_package_support_bundle_ticket_attachments( release_manifest: Option<&Path>, operator_handoff: &SidecarPackageOpsHandoffReport, doctor: &SidecarPackageDoctorReport, + deploy_handoff: &SidecarPackageDeployHandoffReport, + production_preflight: &SidecarPackageProductionPreflightReport, ) -> Vec { let mut attachments = vec![ sidecar_package_support_bundle_attachment( @@ -11083,6 +11145,26 @@ fn sidecar_package_support_bundle_ticket_attachments( doctor.json_path.clone(), "Machine-readable support diagnostic with package, gateway, dashboard, and release-manifest checks.", ), + sidecar_package_support_bundle_attachment( + "deploy handoff", + deploy_handoff.markdown_path.clone(), + "Human-readable deployment handoff with service templates, owner steps, and supervisor probes.", + ), + sidecar_package_support_bundle_attachment( + "deploy handoff json", + deploy_handoff.json_path.clone(), + "Machine-readable deployment handoff with hashed deploy artifacts and supervisor probe evidence.", + ), + sidecar_package_support_bundle_attachment( + "production preflight", + production_preflight.markdown_path.clone(), + "Human-readable preflight for supervisor env templates, placeholder coverage, production-shaped refs, and no live secret retrieval.", + ), + sidecar_package_support_bundle_attachment( + "production preflight json", + production_preflight.json_path.clone(), + "Machine-readable preflight with redacted secret-reference provider inventory and local non-hosted scope.", + ), sidecar_package_support_bundle_attachment( "package manifest", root.join("manifest.json"), @@ -11142,7 +11224,7 @@ fn sidecar_package_support_bundle_markdown(report: &SidecarPackageSupportBundleR let verdict = if report.passed { "ready" } else { "blocked" }; let mut out = String::new(); out.push_str("# AgentK Support Bundle\n\n"); - out.push_str("This bundle is an archiveable local/team sidecar alpha support artifact. It combines the package preflight, operator handoff, sidecar doctor report, and hashed evidence inventory without delivery credentials or raw tool payloads.\n\n"); + out.push_str("This bundle is an archiveable local/team sidecar alpha support artifact. It combines the package preflight, operator handoff, sidecar doctor report, deploy handoff, production preflight, and hashed evidence inventory without delivery credentials or raw tool payloads.\n\n"); out.push_str(&format!("- Verdict: `{verdict}`\n")); out.push_str(&format!("- Package root: `{}`\n", report.root.display())); out.push_str(&format!( @@ -11157,6 +11239,14 @@ fn sidecar_package_support_bundle_markdown(report: &SidecarPackageSupportBundleR "- Sidecar doctor: `{}`\n", report.doctor_dir.display() )); + out.push_str(&format!( + "- Deploy handoff: `{}`\n", + report.deploy_handoff_dir.display() + )); + out.push_str(&format!( + "- Production preflight: `{}`\n", + report.production_preflight_dir.display() + )); if let Some(release_manifest) = &report.release_manifest_path { out.push_str(&format!( "- Release manifest: `{}`\n", @@ -13520,7 +13610,7 @@ fn alpha_release_shipped_surfaces(root: &Path) -> Vec { alpha_release_source_surface( root, "support bundle package path", - "packaged support bundle binds operator handoff, sidecar doctor, and hashed evidence inventory", + "packaged support bundle binds operator handoff, sidecar doctor, deploy/preflight handoffs, and hashed evidence inventory", &[ ("src/main.rs", "SidecarPackageSupportBundle"), ("src/lib.rs", "write_sidecar_package_support_bundle"), @@ -26555,9 +26645,10 @@ install receipt still match the handoff. `AGENTK_PACKAGE_RELEASE_MANIFEST` or pass `--release-manifest` to bind the package manifest, package lock, archive checksum, and install receipt hashes. - `bin/agentk-sidecar-support-bundle`: refreshes the operator handoff, runs - the sidecar doctor, and writes one archiveable support-bundle JSON/Markdown - report with hashed package, dashboard, store, trace, and notification - artifact metadata. + the sidecar doctor, deploy handoff, and production preflight, then writes one + archiveable support-bundle JSON/Markdown report with hashed package, + deployment, preflight, dashboard, store, trace, and notification artifact + metadata. - `bin/agentk-sidecar-deploy-handoff`: validates service templates and supervisor env examples, then writes one archiveable deploy-handoff JSON/Markdown report with hashes for local deployment tickets. @@ -26675,9 +26766,10 @@ the IdP or verify live OIDC tokens. `bin/agentk-sidecar-support-bundle` writes `sidecar/.agentk/support-bundle/support-bundle.json` and `sidecar/.agentk/support-bundle/support-bundle.md` by default. -It reruns the package self-check, operator handoff, and sidecar doctor, then -records byte counts and SHA-256s for the package manifest, package lock, -operator handoff, doctor report, safe-agent trace, dashboard, store export, +It reruns the package self-check, operator handoff, sidecar doctor, deploy +handoff, and production preflight, then records byte counts and SHA-256s for +the package manifest, package lock, operator handoff, doctor report, deploy +handoff, production preflight, safe-agent trace, dashboard, store export, durable approvals, and Slack/GitHub/email payload drafts. Set `AGENTK_SUPPORT_BUNDLE_OUT` to choose another output directory and set `AGENTK_PACKAGE_RELEASE_MANIFEST` to bind the support bundle to package release @@ -31375,10 +31467,26 @@ can_deny = ["*"] assert!(support_report.checks.iter().any(|check| { check.name == "support artifact inventory" && check.status == ReadinessStatus::Pass })); + assert!(support_report.checks.iter().any(|check| { + check.name == "deploy handoff" + && check.status == ReadinessStatus::Pass + && check.detail.contains("supervisor probes") + })); + assert!(support_report.checks.iter().any(|check| { + check.name == "production preflight" + && check.status == ReadinessStatus::Pass + && check.detail.contains("live secret retrieval false") + })); + assert!(support_report.deploy_handoff.passed); + assert_eq!(support_report.deploy_handoff.supervisor_probes.len(), 6); + assert!(support_report.production_preflight.passed); + assert!(!support_report.production_preflight.live_secret_retrieval); assert!(support_report.ticket_attachments.len() >= 10); for attachment in [ "operator handoff", "sidecar doctor", + "deploy handoff", + "production preflight", "package manifest", "package lock", "safe-agent trace", @@ -31403,6 +31511,20 @@ can_deny = ["*"] assert!(support_report.artifacts.iter().any(|artifact| { artifact.name == "safe-agent trace" && artifact.present && artifact.bytes.is_some() })); + for artifact in [ + "deploy handoff json", + "deploy handoff markdown", + "production preflight json", + "production preflight markdown", + ] { + assert!( + support_report + .artifacts + .iter() + .any(|item| item.name == artifact && item.present && item.sha256.is_some()), + "missing support artifact {artifact}" + ); + } let support_json = fs::read_to_string(&support_report.json_path).expect("support bundle JSON should read"); let support_value: serde_json::Value = @@ -31413,6 +31535,17 @@ can_deny = ["*"] serde_json::json!(true) ); assert_eq!(support_value["hosted_saas"], serde_json::json!(false)); + assert_eq!( + support_value["deploy_handoff"]["supervisor_probes"] + .as_array() + .expect("nested deploy probes should be an array") + .len(), + 6 + ); + assert_eq!( + support_value["production_preflight"]["live_secret_retrieval"], + serde_json::json!(false) + ); assert!( support_value["ticket_attachments"] .as_array() @@ -31432,6 +31565,8 @@ can_deny = ["*"] assert!(support_markdown.contains("## Ticket Attachments")); assert!(support_markdown.contains("operator handoff")); assert!(support_markdown.contains("sidecar doctor")); + assert!(support_markdown.contains("deploy handoff")); + assert!(support_markdown.contains("production preflight")); assert!(support_markdown.contains("notification payload drafts")); assert!(support_markdown.contains("Hosted SaaS: `false`")); assert!(support_markdown.contains("No remediation required")); diff --git a/src/main.rs b/src/main.rs index 2323625..c40b634 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12741,7 +12741,7 @@ fn release_ticket_support_doctor_handoff_check( Ok(()) => release_ticket_check_item( "support/doctor handoff", ReadinessStatus::Pass, - "support evidence proves operator handoff refresh, sidecar doctor remediation, release-manifest binding, hashed support inventory, ticket attachments, and local non-hosted scope", + "support evidence proves operator handoff refresh, sidecar doctor remediation, deploy/preflight evidence, release-manifest binding, hashed support inventory, ticket attachments, and local non-hosted scope", ), Err(detail) => { release_ticket_check_item("support/doctor handoff", ReadinessStatus::Fail, detail) @@ -12825,6 +12825,10 @@ fn release_ticket_support_doctor_handoff_evidence( "operator handoff json", "sidecar doctor", "sidecar doctor json", + "deploy handoff", + "deploy handoff json", + "production preflight", + "production preflight json", "package manifest", "package lock", "safe-agent trace", @@ -12841,6 +12845,8 @@ fn release_ticket_support_doctor_handoff_evidence( ("package preflight", "package readiness checks"), ("operator handoff refresh", "handoff checks"), ("sidecar doctor", "0 remediation steps"), + ("deploy handoff", "supervisor probes"), + ("production preflight", "live secret retrieval false"), ("support artifact inventory", "support artifacts inspected"), ("alpha scope", "hosted SaaS is false"), ], @@ -12856,6 +12862,10 @@ fn release_ticket_support_doctor_handoff_evidence( "operator handoff markdown", "sidecar doctor json", "sidecar doctor markdown", + "deploy handoff json", + "deploy handoff markdown", + "production preflight json", + "production preflight markdown", "safe-agent trace", "dashboard html", "store export audit", @@ -12877,6 +12887,24 @@ fn release_ticket_support_doctor_handoff_evidence( true, "support bundle json", )?; + release_ticket_require_nested_bool( + &support, + &["deploy_handoff", "passed"], + true, + "support bundle json", + )?; + release_ticket_require_nested_bool( + &support, + &["production_preflight", "passed"], + true, + "support bundle json", + )?; + release_ticket_require_nested_bool( + &support, + &["production_preflight", "live_secret_retrieval"], + false, + "support bundle json", + )?; Ok(()) }