Skip to content

feat(v9.1): Onboarding Gate — AC-89..AC-94 - #6

Merged
RCSnyder merged 18 commits into
mainfrom
05_08_2026_features
May 11, 2026
Merged

RCSnyder merged 18 commits into
mainfrom
05_08_2026_features

Conversation

@RCSnyder

Copy link
Copy Markdown
Owner

v9.1 — Onboarding Gate

The smallest set of operator-facing tools that turn a fresh clone into a working install in 15 minutes without reading the source. Shipped via the lights-out-swe pipeline: ITERATE → ANALYZE → BUILD → REVIEW (×3) → RECONCILE → VERIFY → DEPLOY.

Acceptance criteria delivered

  • AC-89 — pcy init: bootstraps .env with 32-byte OsRng secrets, mode 0600, never emits secret bytes on stdout. (commit 88f98c3)
  • AC-90 — pcy doctor: seven ordered self-diagnosis checks (env, DB connectivity, migrations, vault key, sandbox bin, LLM reachability, schema version) with --strict + --format json. (commit 7d4712c; round-3 docstring align 79068d1)
  • AC-91 — pcy backup / pcy restore: tarball with pg_dump --format=custom, manifest with schema-version forward-incompatibility refusal, optional --include-vault-key round-trip, 0o600 recovered-key extraction. (commits 5716003, 2d71a20)
  • AC-92 — docs/onboarding.md: one-page first-run gate, ≤250 lines, every fenced pcy command tied to a real clap verb. (commits 4cdb192, 0e195ee)
  • AC-93 — pcy provider {add|list|use|remove}: first-class per-workspace LLM provider rows with credentialed key resolution; clap rejects raw --key. (commits 17b2b6a, eee48c0)
  • AC-94 — Honesty pass: README "Security Model" table reflects shipped code; aspirational design-vocabulary names that were never code are removed from the live surface.

What's in the change

  • 2 new crates (tar, flate2)
  • 1 new migration (llm_providers)
  • 3 new event types (backup_taken, backup_restored, llm_provider_env_fallback)
  • DELIVERY.md bumped to v9.1 with new Summary + Known Limitations
  • tests/honesty_pass_test.rs asserts v9.1 heading + dual-summary ordering

Declared MLP residual risks (carried in DELIVERY.md → Known Limitations → v9.1)

  1. L-v91-1 — backup audit events emit via tracing + eprintln, not the events table (events table requires agent_id NOT NULL; operator_events table is a v9.2 item).
  2. AC-90b — sandbox-smoke pcy doctor check (8th check) deferred to v9.2; Probe::sandbox_smoke stub preserved as forward-compat.
  3. AC-93c — key-in-process-memory probe deferred to v9.2 (live /proc/self/maps grep).
  4. AC-91 — live pg_dump / pg_restore round-trip exercised in CI only (local dev shell lacks postgresql-client).
  5. T-v91-6 — 15-min hand-walk operator validation pending on the operator side.

Gate status

  • BUILD ✅ — 6 vertical slices (V91-S1..S6) green
  • REVIEW ✅ — round 3 PASS, no Critical / Required
  • RECONCILE ✅ — 7-axis drift sweep clean (auto-repaired env var + flag names)
  • VERIFY ✅ — PASS with residual risks declared above
  • 28/28 no-DB tests pass; DB-bound tests CI-deferred

Provenance

Full audit trail in scaffolding/log.md. scope/design/readiness updated through commit e3ebc64.


Tagging is handled automatically by release-plz from conventional commits — no manual tag in this PR.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7

RCSnyder and others added 18 commits May 8, 2026 00:45
Adds AC-89 (pcy init), AC-90 (pcy doctor), AC-91 (pcy backup/restore), AC-92 (onboarding doc), AC-93 (pcy provider), AC-94 (honesty pass). Hard caps: 7.5 dev-days, 2-week wall-clock, 6 ACs, 3 new event types max. Soft cap: ≤2 new crates per slice (named in readiness). Clarifications resolved: tar+flate2 for AC-91 tarball; pcy init prompts with OpenRouter default; pcy doctor --strict ignores kernel-floor WARN on macOS/Windows. ITERATE per .github/copilot-instructions.md.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
Verdict READY. Coverage table maps each AC to a planned test + runtime proof. Build order V91-S1..V91-S6: AC-94 → AC-89 → AC-90 → AC-92 → AC-93 → AC-91. Sanctioned new crates: tar, flate2 (AC-91 only). Six explicit scope-reduction risks documented.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
…LIVERY v9.0

Replaces six-layer aspirational list (Zerobox/OneCLI/Greywall) with a five-row table mapping each shipped layer to its mechanism, status, and AC anchor: process sandbox (AC-53/77/83/85/86), audit log (AC-78), capability gate (AC-80), prompt-injection floor (AC-79), credential vault (AC-38/40/43/71/74). Bumps DELIVERY.md heading to v9.0 and adds a v9.0 Summary lead. Wraps remaining historical Zerobox mentions in HTML-comment historical fences. Adds tests/honesty_pass_test.rs (4 tests). Slice V91-S1 of 6; first AC of the v9.1 Onboarding Gate.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
Adds src/cli/commands/init.rs with rand_core::OsRng-generated 64-char hex bootstrap token and 44-char base64 vault key, hidden rpassword prompt for optional LLM_API_KEY, default LLM_API_BASE_URL prompt (https://openrouter.ai/api/v1 per CR-v91-2), mode 0600 on Unix, refuse-overwrite-without-force, next-steps printer that proves no secret bytes leak to stdout. Adds tests/cli_init_test.rs with 8 tests (all green). Slice V91-S2 of 6. RECONCILE flag: scope.md names the var OPEN_PINCERY_ADMIN_SEED but the binary reads OPEN_PINCERY_BOOTSTRAP_TOKEN; used the real var to keep the generated .env functional; doc rename is RECONCILE's job.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
…n output

Adds src/cli/commands/doctor.rs with a Probe trait test seam, a LiveProbe production impl that wraps the AC-84 kernel floor preflight, runs DB/migration/admin queries through a fresh PgConnection, exec's docker, and HEADs the LLM base URL with a 3s timeout. diagnose() returns a Vec<CheckResult> in a stable 8-row order; exit_code() enforces non-strict (FAIL only) vs --strict (FAIL or non-exempt WARN) with kernel-floor strict-exempt on non-Linux per CR-v91-3. Adds tests/cli_doctor_test.rs with 10 deterministic tests. Slice V91-S3 of 6.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
Adds docs/onboarding.md (~165 lines, well under the 250-line tripwire) with the seven required sections: Prerequisites, Five commands, Doctor check, Add first credential, Send first message, Backup before trust, Where next. Adds tests/onboarding_doc_test.rs (6 tests) that lock the section order, line tripwire, and a critical invariant: every fenced 'pcy <verb>' example must map to a real top-level clap verb, while AC-91/AC-93 verbs (backup/restore/provider) may only be referenced in prose until those slices ship. Slice V91-S4 of 6.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
v9.1 slice S5. New migration creates llm_providers (workspace-scoped, partial-unique default index, app-layer FK to credentials). New model exposes create/list/set_default/delete/resolve_default with admin-friendly error messages. New REST handlers under /workspaces/{id}/providers (admin-gated, emits provider_added/default_set/removed/forbidden audit rows). New CLI noun pcy provider {add|list|use|remove} reuses the credential resolve_workspace_id pattern and has no --key flag. Wake loop now resolves the workspace's default provider at wake start, decrypts the referenced credential via the shared vault, and constructs a per-wake LlmClient override; on any miss it emits llm_provider_env_fallback once and falls back to the env-var-backed client. tests/cli_provider_test.rs covers clap schema (no --key), missing-credential refusal, add/list/use/remove round-trip, and default-with-siblings refusal. Gate: cargo check --tests --offline clean; cargo test --no-run --offline builds all bins; non-DB v9.1 tests (28) still pass.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
Closes the v9.1 onboarding gate. tar + flate2 added (CR-v91-1, both MIT/Apache-2.0). pg_dump/pg_restore shell out; manifest carries schema_version=24 + server_version + taken_at + includes_vault_key; restore validates the manifest before requiring pg_restore so forward-incompatible refusal works on machines without postgresql-client. --include-vault-key is opt-in; default tarball is grep-clean of VAULT_KEY bytes. Audit trail emitted via tracing + stderr — events.agent_id is NOT NULL and v9.1's T-v91-2 budget sanctioned only the llm_providers table, so DB-row persistence is deferred to a future operator_events table. --file flag (not --output) to avoid colliding with the global OutputFormat. cli_backup_restore_test 4/4 pass; lib backup unit tests 2/2 pass; onboarding_doc_test 6/6 pass after moving backup/restore/provider into fenced examples.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
…+ 0o600 modes

Addresses REVIEW Required findings #2 and #4 on the v9.1 AC-91 slice:

(#2) restore now honors a new --write-vault-key-to PATH flag and consumes the bundled vault_key.b64. Without the flag, an include-vault-key tarball is still accepted but stderr warns the operator the bundled key was discarded. Manifest mismatches (--write-vault-key-to on a no-key backup, or includes_vault_key:true with the file missing) refuse with clear diagnostics. Two new tests cover the round-trip and the negative path. AC-91 sub-criterion (c) is now closed by a real test.

(#4) Unix file mode 0o600 is enforced on both the staged vault_key.b64 file and the output tarball when --include-vault-key is passed, matching AC-89's .env standard. Windows inherits the default ACL (best-effort, same caveat as init.rs). The new round-trip test asserts the recovered key file has mode 0o600 under cfg(unix).

Tests: cli_backup_restore_test 6/6 pass (was 4/4). lib + onboarding + doctor + init + honesty tests still green.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
REVIEW round 1 left two Required findings open. v9.1 MLP path:

Required #1 (AC-90 permanent strict_exempt sandbox row): amend scope to
drop check 8 from v9.1 (deferred to v9.2 as AC-90b). A real probe needs
a bootstrapped DB + agent and is out of the 7.5d v9.1 budget. doctor.rs
no longer renders the 8th row; cli_doctor_test asserts 7 checks. The
Probe::sandbox_smoke trait method is preserved as forward-compat stub.

Required #3 (AC-93 wake-loop resolver untested): expose
runtime::wake_loop::resolve_workspace_llm as #[doc(hidden)] pub. New
tests/wake_loop_provider_test.rs covers Some/None paths (default
provider+credential, no providers, revoked credential). AC-71
memory-grep verification deferred to VERIFY live-process inspection.

Gate: post-review re-run pending. cargo build --tests clean;
cli_doctor_test 10/10. Zero new crates, event types, migrations.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
REVIEW round 2 raised one Required finding: docs/onboarding.md said
'eight ordered checks' and showed a 'sandbox smoke' WARN row in the
typical-good-run example, after commit eee48c0 reduced the renderer
to 7 rows. Two-line fix: 'eight' -> 'seven' with v9.2 AC-90b note,
and delete the sandbox-smoke row from the example block.

Also addressed REVIEW Consider items:
- src/cli/commands/doctor.rs module doc updated to 'Seven ordered'
  with AC-90b deferral note.
- Probe::sandbox_smoke trait method annotated as forward-compat stub
  with #[allow(dead_code)] and a comment pointing to scope.md.

Evidence: onboarding_doc_test 6/6, cli_doctor_test 10/10.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
Structural drift auto-fixed (code is ground truth):

1. AC-89 env var: scope said OPEN_PINCERY_ADMIN_SEED; shipped code/.env.example/docker-compose use OPEN_PINCERY_BOOTSTRAP_TOKEN. v9.0 AC-60 rename was never landed; v9.1 normalises scope to shipped name (MLP). 2. AC-91 backup: --out -> --file (collided with global --output formatter). 3. AC-91 restore: --from -> --input, --vault-key-from-env -> --write-vault-key-to (richer 0o600-file recovery contract). 4. AC-91 audit emission: events-table-row deferred to v9.2 operator_events table (T-v91-2 budget); shipped via tracing+eprintln. Recorded as L-v91-1 in new v9.1 Known Limitations subsection.

Also appended # v9.1 Addendum to design.md covering new files (init/doctor/backup/provider/llm_provider/api/providers + 7 tests + migration), interface deltas (llm_providers table, resolve_workspace_llm, Manifest, canonical CLI flags), and the two new sanctioned crates (tar 0.4, flate2 1).

No spec-violating drift. AC-89..AC-94 pass/fail meaning preserved. readiness.md AC coverage rows already match shipped tests. AC-90 7-check amendment landed cleanly across scope/doctor.rs/test/onboarding.md. Pipeline proceeds to VERIFY.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
VERIFY round 1 flagged one cosmetic drift: the Doctor variant's clap
doc-string in src/cli/mod.rs still read 'Runs eight ordered, independent
checks'. The shipping renderer is 7 checks (AC-90b deferred to v9.2).
One-line fix.

VERIFY verdict: PASS (with declared MLP residual risks). All 28
no-DB tests pass; DB tests are PoolTimedOut locally and queued for CI.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
Bump DELIVERY.md heading to v9.1 and prepend v9.1 Summary covering AC-89..AC-94 (pcy init / doctor / backup / restore / provider, docs/onboarding.md, honesty pass). Add v9.1 Known Limitations section with declared MLP residual risks: L-v91-1 (backup events via tracing, not events table), AC-90b (sandbox-smoke doctor check deferred to v9.2), AC-93c (key-in-process-memory probe deferred), AC-91 live pg_dump round-trip CI-only, pg_dump/pg_restore as operator-side tools. Update tests/honesty_pass_test.rs to assert v9.1 heading + dual-summary ordering (v9.1 before v9.0 before What Was Built). Closes v9.1 DEPLOY phase; tests pass 4/4.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
…or pcy init

Two CI failures on v9.1 PR #6:

1. clippy (1.95) flagged tests/cli_backup_restore_test.rs:27 with assertions_on_constants because SCHEMA_VERSION is a const. Wrap the assert in a block with #[allow(clippy::assertions_on_constants)] -- we keep the assert for the diagnostic message rather than collapsing to a const block.

2. tests/cli_credential_test.rs ac40_exactly_one_rpassword_prompt_in_src failed because v9.1 AC-89 (pcy init) introduced a second rpassword::prompt_password call site (src/cli/commands/init.rs). Convert the test from 'exactly one' to an explicit allowlist of two paths (credential.rs + init.rs); any third site must still be allowlisted. The security invariant the test guards (no surprise password prompts in src/) is preserved.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
tests/cli_naming_test.rs::yes_flag_only_on_allowlisted_paths failed because v9.1 AC-93 introduced 'pcy provider remove' with a --yes confirm flag, mirroring 'pcy credential revoke'. Add it to YES_ALLOWLIST. Test invariant preserved: --yes still only permitted on destructive subcommands.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
… AC-91)

tests/env_example_test.rs::ac_29_every_source_env_var_is_in_env_example_or_allowlisted failed because v9.1 AC-91 introduced VAULT_KEY_BASE64 — an operator-side recovery env var read by 'pcy backup --include-vault-key' and 'pcy restore' but never part of the steady-state server config. Add to INTERNAL_ONLY with justification; .env.example unchanged.

Assisted-by: GitHub-Copilot:Claude-Opus-4.7
@RCSnyder
RCSnyder merged commit 32ab41c into main May 11, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant