feat: team deployment — bcli doctor, signed bundles, query discovery, records view#10
Merged
Conversation
…ecords view Phase 1 — `bcli doctor` (diagnostics): Self-rescue command for team installs. 11 independent checks (active profile, tenant, env, company, auth mode, profile-scoped token cache, registry, field coverage, saved queries, team bundle, BC connectivity). --json for monitoring scripts; non-zero exit on any FAIL. Connectivity uses httpx with trust_env=True so corporate proxies are honored. Phase 2 — team bundle infra (`bcli config refresh`/`make-bundle`/etc.): Manifest schema, fetch over HTTPS (file:// gated behind BCLI_DEV=1), per-file content-hash + canonical roll-up verifier, atomic apply with per-profile flock + .previous backup retention, rollback. Hardening: allowlisted file set, no symlinks/devices, bounded compressed/decom- pressed sizes (gzip-bomb defense), traversal-rejecting verifier. field_lists.json is merged into the registry on apply so the prewarm isn't a dead artifact. NOTE: Sha256Verifier is internal-consistency only, not publisher authentication — phase 2 cannot ship to finance without a real cryptographic signer at the Verifier seam OR strict HTTPS+org-auth distribution. Gap is loud in plan + verifier docstring. Phase 3 — saved-query metadata + `bcli q` discovery: Additive YAML keys (aliases, tags, owner, freshness, examples, related). New sub-verbs `bcli q list [tag=...] [owner=...]`, `bcli q search <phrase>`, `bcli q info <name>`, `bcli q run <name>` (escape hatch). Reserved sub-verb names hard-error at bundle load. Substring + alias + tag scoring, no embeddings — codex consult was right that boring metadata wins for a 50-100 query library. Phase 6 — Windows PowerShell wide-table fix: New `records` formatter (vertical, psql-\\x style). Auto-promotion when result is 1-2 rows with >8 columns or wider than the terminal — only when format was auto-detected, never when user passed -f explicitly (auto_format flag threaded through CLIState). Plan: docs/plans/team-deployment.md (drafted earlier; updated to fix schema mismatch and call out the signing ship-blocker explicitly). Tests: 593 passing (+45 new across 4 phases). Includes concurrency test for the apply lock, gzip-bomb rejection, traversal rejection in fetch and verify paths, file://-blocked-without-dev, profile-scoped token cache regression, and explicit-format-disables-auto-records. Codex review (high reasoning) found 2 P1 + 8 P2 issues; all fixed in this commit except the publisher-signing P1 which is correctly deferred to a phase-2-extension and now flagged as a finance-rollout ship-blocker in the plan.
CI runs `ruff check src/ tests/`; my local pre-commit only checked `src/`. Removed `pytest` and `_formatters` imports that became unused after refactoring. No behavioral change.
The team-bundle infra ships in the OSS bcli; how Beautech rolls it out to finance/engine-tech is internal business. Drop "ship-blocker for finance rollout" framing in the plan + verifier docstring — the OSS project doesn't owe Beautech's deployment a publisher-signing implementation, that's tracked separately as a Beautech rollout gate (#11). Sha256Verifier is correctly an integrity check; operators who need authenticity plug Ed25519Verifier into the same Verifier seam when they're ready.
Cross-repo terminology cleanup matching the Beautech bootstrap rename
(bcli-beautech-installer#14): role label changes from "engine-tech" to
"technical" everywhere it referred to the role/team. The OSS bcli tool
itself is unchanged behaviorally — these are pure string renames in
internal-Beautech planning notes, a test fixture, and a diagnostic hint.
- docs/plans/team-deployment.md: 12 occurrences. Plan doc is already
flagged as Beautech-internal (not OSS roadmap) per earlier framing fix.
- tests/test_workflow/test_query_search.py: 2 occurrences in fixtures
("owner": "engine-tech" → "technical"). Tests still pass — the metadata
is opaque strings.
- src/bcli/diagnostics/_checks.py: 1 hint string in check_auth_mode.
593 tests pass.
igor-ctrl
added a commit
that referenced
this pull request
May 12, 2026
The Typer root-callback (introduced in #10) shared the name `main` with the console-script entry point (added in #13), tripping ruff F811 (redefinition) when CI lint runs against the rebased history. The callback's name is arbitrary — Typer wires it via the `@app.callback()` decorator, not by symbol lookup — so renaming to `_root_callback` resolves the redefinition without behavior change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First slice of bcli features for team / multi-role deployments.
bcli doctor: 11 independent checks (profile / tenant / env / company / auth / profile-scoped token cache / registry / field coverage / queries / team bundle / BC connectivity),--jsonmode, non-zero exit on FAIL. Connectivity uses httpx withtrust_env=Trueso corporate proxies are honored.bcli config refresh / rollback / bundle-status / make-bundle. Allowlisted file set, no symlinks/devices, gzip-bomb-bounded fetch (25 MB compressed, 100 MB extracted, 64 members), content-hash + canonical roll-up verifier with traversal rejection, per-profile flock for concurrent refresh, atomic write with.previousbackups + manifest backup, field-lists merged into registry on apply,file://gated behindBCLI_DEV=1.aliases / tags / owner / freshness / examples / related),bcli q list / search / info / runsub-verbs, reserved-name collisions hard-error at bundle load. Substring + alias + tag scoring, no embeddings.recordsformatter (vertical,psql \xstyle). Auto-promote on 1-2 wide rows only when format wasn't user-explicit (-f markdownis honored as a contract).Phases 4 (response caching) and 5 (Redis-for-AI) stay deferred behind explicit telemetry / scale triggers — see
docs/plans/team-deployment.md.Sha256Verifieris an integrity check, not an authenticity check. Operators distributing bundles via a trusted private channel (org-authenticated HTTPS, internal artifact registry) get authenticity from the channel itself; the integrity check then catches in-flight corruption. Operators who want defense-in-depth plug in a strongerVerifierat that seam — design intent, not a gap.Test plan
uv run pytest tests/ -v— 593 passed, 1 skippeduv run ruff check src/— cleanbcli doctorsmoke-tested against active installbcli q list / search / infosmoke-tested against a 60-query saved-query librarybcli config make-bundle+bcli config refresh --dry-runround-trip viafile://works underBCLI_DEV=1apply_bundlefrom two threads serializes via flock; both finish, manifest is consistent-f markdowndisables auto-promotion to records view (contract honored)Files of interest
src/bcli/diagnostics/_checks.py— diagnostic primitivessrc/bcli/bundle/{_manifest,_verify,_fetch,_apply,_publish}.py— bundle pipelinesrc/bcli_cli/commands/{doctor_cmd,refresh_cmd}.py— CLI surfacessrc/bcli/workflow/_query_search.py— query discovery scoringsrc/bcli_cli/output/_formatters.py— records formatter + auto-promote logic