Skip to content

feat: add downloadable client and atomic production delivery - #12

Merged
avitus merged 6 commits into
mainfrom
codex/simple-api-client
Aug 13, 2026
Merged

feat: add downloadable client and atomic production delivery#12
avitus merged 6 commits into
mainfrom
codex/simple-api-client

Conversation

@avitus

@avitus avitus commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • add a downloadable thin client with interactive chat, SSE progress, cancellation, and sanitized terminal errors
  • add atomic application and nginx deployment flows with CircleCI production delivery coverage
  • preserve stateless OpenAI reasoning items across tool continuations and expose only allowlisted provider diagnostics
  • document the client, deployment model, architectural decisions, and model-error contract

Verification

  • make check
    • 336 static tests passed
    • 136 contract tests passed
    • Ruff formatting and lint passed
    • strict mypy passed
    • application and nginx deployment-script tests passed
    • strict documentation builds and 123 citation checks passed
  • targeted continuation and diagnostic regressions: 50 passed
  • CodeRabbit review: zero remaining findings
  • git diff --check

Notes

  • OpenAI reasoning summaries are replayed as an empty list because summaries are not requested; raw reasoning text is not persisted.
  • Provider failures expose only sanitized HTTP status, code, and parameter fields.
  • No credentialed live-provider call was performed.
  • No milestone status or acceptance criteria were changed.

Summary by CodeRabbit

  • New Features
    • Added a downloadable, dependency-free terminal client with session recovery, streaming responses, approvals, inputs, and reconnection.
    • Added release identity reporting through health checks.
    • Production deployments now use verified, atomic releases with Nginx validation and rollback support.
    • Added HTTPS API routing and improved production model-policy defaults.
  • Bug Fixes
    • Provider errors now include safer, more useful diagnostics while filtering unsafe content.
  • Documentation
    • Added client usage, deployment, security, and operational guidance.
    • Documented automated release packaging and deployment verification.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fb11e684-7760-4394-96b1-8f4a22d230c8

📥 Commits

Reviewing files that changed from the base of the PR and between 8316aa9 and 0668361.

📒 Files selected for processing (1)
  • docs/deployment.md

📝 Walkthrough

Walkthrough

The pull request adds a downloadable API client, atomic CircleCI production delivery, Nginx deployment handling, release identity checks, production model-policy validation, and structured provider diagnostics.

Changes

Downloadable API client

Layer / File(s) Summary
HTTP, SSE, and terminal client
client/veetbot_client/*
Adds authenticated HTTP operations, resumable SSE streaming, interactive chat, retries, approvals, inputs, artifacts, and session commands.
Client packaging and validation
scripts/build_client.py, Makefile, tests/unit/test_downloadable_client.py, .circleci/config.yml
Builds and publishes an executable zipapp. Tests cover transport, replay, sanitization, commands, and dependency-free execution.

Atomic production delivery

Layer / File(s) Summary
Application release promotion
deploy/app/*
Stages and validates releases, runs migrations and checks, promotes the active release, verifies readiness, and retains rollback targets.
Nginx activation
deploy/nginx/*, nginx/veetbot.conf
Installs, validates, reloads, and rolls back Nginx configuration changes.
CircleCI delivery workflow
.circleci/config.yml, tests/unit/test_toolchain.py
Adds release packaging and deployment jobs gated to main, production context, and serialized execution.
Deployment configuration and documentation
deploy/*, docs/deployment.md, docs/security.md
Documents release identity, service environment loading, production configuration, security controls, and manual rollback.

Runtime contracts

Layer / File(s) Summary
Release identity and model policy
src/agent_core/config.py, src/agent_core/api/app.py, src/agent_core/bootstrap.py, src/agent_core/cli/main.py
Validates release IDs, exposes them through health headers, selects production model defaults, and binds the API to localhost.
Provider diagnostics
src/agent_core/domain/messages.py, src/agent_core/adapters/models/*, src/agent_core/runtime/loop.py
Sanitizes provider metadata and propagates safe diagnostics through model errors, events, and run failures.
Contract and gate coverage
tests/contract/*, tests/gates/*, scripts/check_production_deployment.py
Validates provider diagnostics, reasoning replay fields, release identity, model credentials, deployment checks, and secret scanning.

Estimated code review effort: 5 (Critical) | ~120 minutes

Mergeability Score: 🔵 Low · up to 06683

The PR adds atomic production delivery, but the stale-release path does not yet demonstrate that older jobs are ordered correctly and cannot trigger deployment side effects. This is a bounded deployment-safety risk; the change is mergeable with explicit owner awareness and follow-up to strengthen that verification.

Possibly related PRs

  • avitus/veetbot#2: Provides related CircleCI, deployment-check, health API, configuration, and architecture-check foundations.
  • avitus/veetbot#6: Introduces the HTTP/SSE API consumed by the downloadable client.
  • avitus/veetbot#7: Provides related CircleCI sandbox verification and artifact infrastructure.

Poem

A rabbit checks the release gate,
Then hops through streams that reconnect straight.
Nginx turns, the client takes flight,
Safe errors glow in fields of light.
Zipapp packed, the checks all cheer—
“A tidy deployment is here!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two primary changes: the downloadable client and atomic production delivery.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/simple-api-client

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (6)
client/veetbot_client/api.py (2)

245-254: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive the User-Agent version from __version__.

The literal reports 0.1, but the package version is 0.1.0.dev0. The two values will drift on the next release.

♻️ Proposed change
+from . import __version__
+
...
         headers = {
             "Accept": "application/json",
-            "User-Agent": "veetbot-client/0.1",
+            "User-Agent": f"veetbot-client/{__version__}",
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/veetbot_client/api.py` around lines 245 - 254, Update the _headers
method to derive the User-Agent version from the package’s __version__ symbol
instead of the hardcoded “0.1” value, preserving the existing veetbot-client
prefix and header behavior.

314-319: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Silence Ruff S310 explicitly, because make check runs lint.

Ruff reports S310 for the Request construction here and at lines 389-393. The finding is a false positive on behavior: __init__ restricts the scheme to http or https, and _url requires an absolute path. The lint gate still fails.

Add a scoped suppression with the reason, or add a per-file rule exclusion for the client sources.

♻️ Proposed suppression at both call sites
-        request = Request(
+        request = Request(  # noqa: S310 - scheme restricted to http/https in __init__
             self._url(path),
             data=encoded,
             headers=request_headers,
             method=method,
         )
-        request = Request(
+        request = Request(  # noqa: S310 - scheme restricted to http/https in __init__
             self._url(f"/v1/runs/{quote(run_id, safe='')}/events"),
             headers=headers,
             method="GET",
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/veetbot_client/api.py` around lines 314 - 319, Add a scoped Ruff S310
suppression with an explicit false-positive reason to both Request constructions
in the client code, including the shown call site and the one around lines
389-393. Keep the existing Request behavior unchanged and ensure make check no
longer reports these findings.

Source: Linters/SAST tools

client/veetbot_client/chat.py (1)

353-382: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Bound the total reconnect budget, not only the consecutive one.

Line 360 resets reconnect_attempts for every received event. A peer that delivers one event and then closes the stream resets the counter on each cycle, so _max_reconnect_attempts is never reached. The loop then repeats until the run reaches a terminal state, with a 0.25 s floor delay.

The behavior is acceptable for a long non-terminal run. Add a total attempt count or a wall-clock budget to bound the worst case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/veetbot_client/chat.py` around lines 353 - 382, The watch_run
reconnect logic only bounds consecutive failures because reconnect_attempts
resets after every event. Add a separate total reconnect-attempt counter or
wall-clock budget that is not reset by _handle_event processing, enforce it
alongside _max_reconnect_attempts, and preserve the existing terminal-state and
reconnect-delay behavior.
client/veetbot_client/__main__.py (1)

37-69: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Scope the token prompt to the readiness probe.

except ApiError at line 58 wraps the whole _run call. _run also opens a session and runs the interactive shell. A 401 raised after the readiness probe, for example during create_session, therefore restarts _run from the start. The client then creates a second session, and any interactive progress is lost.

Prompt for the token from the probe only, then run the application once.

♻️ Proposed change
-def _run(args: argparse.Namespace, client: ApiClient) -> int:
-    ready = client.health_ready()
+def _check_ready(client: ApiClient) -> None:
+    ready = client.health_ready()
     if ready.get("status") != "ready":
         raise ClientError("API is not ready")
+
+
+def _run(args: argparse.Namespace, client: ApiClient) -> int:
     console = Console(sys.stdout, sys.stderr)
     application = ChatApplication(
         client,
         console,
         agent_id=str(args.agent),
         session_id=str(args.session) if args.session else None,
     )
     return application.run(once=str(args.once) if args.once is not None else None)
 
 
 def main(argv: Sequence[str] | None = None) -> int:
     args = _parser().parse_args(argv)
     token = os.environ.get("VEETBOT_API_TOKEN")
     try:
         client = ApiClient(str(args.api_url), token=token)
         try:
-            return _run(args, client)
+            _check_ready(client)
         except ApiError as exc:
             if exc.status != 401 or client.has_token or not sys.stdin.isatty():
                 raise
             supplied = getpass.getpass("API token: ")
             client.set_token(supplied)
-            return _run(args, client)
+            _check_ready(client)
+        return _run(args, client)
     except KeyboardInterrupt:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/veetbot_client/__main__.py` around lines 37 - 69, Refactor main so the
ApiError retry logic covers only the client.health_ready() probe, not the entire
_run flow. Prompt for a token and retry the readiness check when an
unauthenticated 401 occurs, then invoke _run exactly once with the ready client;
preserve existing handling for authenticated clients and other errors.
.circleci/config.yml (1)

219-229: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Validate the release identifier before remote interpolation.

deploy-app validates release-id against ^[0-9]{8}-[0-9]{6}-[0-9a-f]{7,40}$ at line 146 before it reaches a remote command. deploy-nginx reads the same file and interpolates it into the remote command with no validation. Apply the same check so both jobs enforce one identifier contract.

🛡️ Proposed validation
             expected_release_id="$(cat /tmp/veetbot-release/release-id)"
+            [[ "$expected_release_id" =~ ^[0-9]{8}-[0-9]{6}-[0-9a-f]{7,40}$ ]]
             remote_config="/tmp/veetbot-nginx-$CIRCLE_SHA1.conf"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.circleci/config.yml around lines 219 - 229, Validate expected_release_id in
the deploy-nginx flow before interpolating it into the ssh command, using the
same ^[0-9]{8}-[0-9]{6}-[0-9a-f]{7,40}$ contract already enforced by deploy-app.
Reject invalid values and stop the job before either remote command uses the
identifier.
tests/unit/test_downloadable_client.py (1)

400-414: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Isolate the interpreter so the test proves dependency-free execution.

The test runs the artifact with sys.executable, which is the project interpreter. All project dependencies stay importable, and an inherited PYTHONPATH also stays active. The test therefore passes even if the client imports a third-party package. Add -I to run in isolated mode.

💚 Proposed isolation
     result = subprocess.run(
-        [sys.executable, str(artifact), "--version"],
+        [sys.executable, "-I", str(artifact), "--version"],
         cwd=tmp_path,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/test_downloadable_client.py` around lines 400 - 414, Update
test_client_zipapp_builds_and_runs_without_project_dependencies to invoke the
artifact with Python’s isolated interpreter mode by adding the -I option to the
subprocess command. Preserve the existing version assertion, working directory,
and executable checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.circleci/config.yml:
- Around line 179-196: Update the “Verify public release identity” command to
poll the health endpoint and response headers until the X-Veetbot-Release value
matches VEETBOT_RELEASE_ID, using a bounded retry/time budget. Keep the existing
curl and header validation behavior, but retry transient missing or mismatched
headers and exit nonzero only when the budget expires.
- Line 135: Update both add_ssh_keys steps in the CircleCI configuration to
include the required fingerprints list, replacing the empty mappings at the
referenced deployment-key steps. Use the project’s deployment key fingerprints
consistently in both locations.

In `@client/veetbot_client/api.py`:
- Around line 256-294: Update _api_error so transport exceptions raised while
reading the HTTPError body, including OSError, TimeoutError, and URLError, are
caught and converted to the same sanitized ApiError fallback used for malformed
responses. Keep the existing parsed error response behavior unchanged, and
ensure no raw read exception escapes through _open.

In `@deploy/app/release.sh`:
- Around line 76-80: The stale-release check around RELEASE_PATTERN and
ACTIVE_RELEASE_ID must compare only the YYYYMMDD-HHMMSS timestamp portion, not
the complete release IDs. Extract and compare the timestamp components so
releases sharing a timestamp are not rejected based on revision ordering, and
add a regression case covering equal timestamps with different revisions.

In `@deploy/nginx/deploy.sh`:
- Around line 79-80: Update the deployment flow around the install and symlink
mutations to register an ERR or EXIT trap that invokes rollback after the backup
is established, ensuring failures in either sudo install or sudo ln -sfn restore
the previous configuration. Disable the trap only after the Nginx reload
succeeds, and add tests covering failure of each mutation command.

In `@docs/deployment.md`:
- Around line 37-50: The deployment runbook currently assigns public readiness
verification to the server/application release; update the release workflow
description around the numbered deployment steps and the corresponding
statements near the later verification section to state that CircleCI performs
the public readiness probe after promotion. Keep local readiness header
verification assigned to deploy/app/release.sh and describe public probe
failures as the CircleCI post-promotion boundary.
- Around line 220-230: Update the manual rollback procedure around the commands
that repoint current, retag agent-core-sandbox:production, restart services, and
verify health to acquire and hold /opt/veetbot/shared/deploy.lock with the same
flock mechanism used by deployments. Ensure the lock covers the complete
rollback sequence from before changing the symlink through the service restart
and readiness check.

In `@docs/plan/development-toolchain.md`:
- Around line 278-289: Update the development-toolchain documentation around the
CI job table and `make check` statements to state that deployment validation
(`test-deploy`) and sandbox validation are additional CI gates rather than
claiming the static and contract jobs exactly equal `make check`; preserve the
original verification partition description and clarify the corresponding
`verify` workflow coverage.

In `@src/agent_core/config.py`:
- Around line 530-535: Extract the VEETBOT_RELEASE_ID format check from
load_settings() into a shared release_id validation helper, then invoke that
helper from both load_settings() and validate_settings(). Ensure Settings
instances supplied through build(settings=...) are rejected before create_app()
when release_id is not None and fails RELEASE_ID_PATTERN.

In `@tests/unit/test_downloadable_client.py`:
- Around line 102-106: Add an in-place Ruff S106 suppression to both intentional
bearer-token test fixtures in
test_api_client_refuses_remote_plaintext_bearer_token, covering the failing
constructor calls without changing the test behavior.

---

Nitpick comments:
In @.circleci/config.yml:
- Around line 219-229: Validate expected_release_id in the deploy-nginx flow
before interpolating it into the ssh command, using the same
^[0-9]{8}-[0-9]{6}-[0-9a-f]{7,40}$ contract already enforced by deploy-app.
Reject invalid values and stop the job before either remote command uses the
identifier.

In `@client/veetbot_client/__main__.py`:
- Around line 37-69: Refactor main so the ApiError retry logic covers only the
client.health_ready() probe, not the entire _run flow. Prompt for a token and
retry the readiness check when an unauthenticated 401 occurs, then invoke _run
exactly once with the ready client; preserve existing handling for authenticated
clients and other errors.

In `@client/veetbot_client/api.py`:
- Around line 245-254: Update the _headers method to derive the User-Agent
version from the package’s __version__ symbol instead of the hardcoded “0.1”
value, preserving the existing veetbot-client prefix and header behavior.
- Around line 314-319: Add a scoped Ruff S310 suppression with an explicit
false-positive reason to both Request constructions in the client code,
including the shown call site and the one around lines 389-393. Keep the
existing Request behavior unchanged and ensure make check no longer reports
these findings.

In `@client/veetbot_client/chat.py`:
- Around line 353-382: The watch_run reconnect logic only bounds consecutive
failures because reconnect_attempts resets after every event. Add a separate
total reconnect-attempt counter or wall-clock budget that is not reset by
_handle_event processing, enforce it alongside _max_reconnect_attempts, and
preserve the existing terminal-state and reconnect-delay behavior.

In `@tests/unit/test_downloadable_client.py`:
- Around line 400-414: Update
test_client_zipapp_builds_and_runs_without_project_dependencies to invoke the
artifact with Python’s isolated interpreter mode by adding the -I option to the
subprocess command. Preserve the existing version assertion, working directory,
and executable checks.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3470d292-3c76-47cc-87a1-d97eeb90f7f5

📥 Commits

Reviewing files that changed from the base of the PR and between c45f674 and 245186b.

📒 Files selected for processing (52)
  • .circleci/config.yml
  • .env.example
  • .gitignore
  • Makefile
  • README.md
  • client/__init__.py
  • client/veetbot_client/__init__.py
  • client/veetbot_client/__main__.py
  • client/veetbot_client/api.py
  • client/veetbot_client/chat.py
  • deploy/Caddyfile.example
  • deploy/app/release.sh
  • deploy/app/release.test.sh
  • deploy/nginx/deploy.sh
  • deploy/nginx/deploy.test.sh
  • deploy/systemd/veetbot-api.service
  • deploy/veetbot.env.example
  • docs-manifest.yaml
  • docs/adr/0047-downloadable-thin-client.md
  • docs/adr/0048-atomic-circleci-production-delivery.md
  • docs/adr/index.md
  • docs/changelog.md
  • docs/client.md
  • docs/deployment.md
  • docs/index.md
  • docs/plan/development-toolchain.md
  • docs/plan/model-gateway.md
  • docs/plan/readiness.md
  • docs/security.md
  • docs/status/citation-ledger.yaml
  • mkdocs.yml
  • nginx/veetbot.conf
  • scripts/architecture_checks.py
  • scripts/build_client.py
  • scripts/check_production_deployment.py
  • security/secret-allowlist.yaml
  • src/agent_core/adapters/models/common.py
  • src/agent_core/adapters/models/openai_responses.py
  • src/agent_core/api/app.py
  • src/agent_core/bootstrap.py
  • src/agent_core/cli/main.py
  • src/agent_core/config.py
  • src/agent_core/domain/messages.py
  • src/agent_core/runtime/loop.py
  • tests/contract/test_model_gateway_contract.py
  • tests/gates/test_api_m5.py
  • tests/gates/test_model_profiles_m3.py
  • tests/gates/test_runtime_m1.py
  • tests/gates/test_secret_scanner.py
  • tests/unit/test_config.py
  • tests/unit/test_downloadable_client.py
  • tests/unit/test_toolchain.py
💤 Files with no reviewable changes (1)
  • deploy/Caddyfile.example

Comment thread .circleci/config.yml Outdated
Comment thread .circleci/config.yml Outdated
Comment thread client/veetbot_client/api.py
Comment thread deploy/app/release.sh
Comment thread deploy/nginx/deploy.sh
Comment thread docs/deployment.md
Comment thread docs/deployment.md
Comment thread docs/plan/development-toolchain.md
Comment thread src/agent_core/config.py Outdated
Comment thread tests/unit/test_downloadable_client.py Outdated
@avitus

avitus commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

CodeRabbit auto-fix summary

Addressed all 16 actionable findings from the current review in commit 8316aa9.

  • Added the verified CircleCI deployment-key fingerprint to both delivery jobs, bounded the public readiness probe, and validated the Nginx release ID before SSH interpolation.
  • Made application release ordering timestamp-based and made Nginx file/symlink mutations rollback-safe, with shell regressions for equal timestamps and both mutation failures.
  • Hardened client HTTP error handling, versioned its User-Agent, scoped URL-security suppressions, bounded total SSE reconnects, retried only readiness authentication, and proved the zipapp under isolated Python.
  • Validated prebuilt Settings.release_id values at the composition boundary.
  • Corrected deployment/runbook ownership, rollback locking, and CI partition documentation.
  • Added focused configuration, client, deployment, and CircleCI tests.

Validation:

  • make check: passed (342 static + 136 contract tests, strict Ruff/mypy/docs/citations, deployment tests)
  • focused client/config/toolchain tests: 65 passed
  • local CodeRabbit review: 0 findings

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
deploy/nginx/deploy.test.sh (1)

87-95: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Exercise the documented stale-job direction.

The fixture makes the active application release 20260810-152233-abcdef0 and the expected release 20260810-152244-bcdef01. This models a newer expected release arriving before application promotion, not an older Nginx job arriving after a newer application promotion. It would not catch a stale 20260810-152233-abcdef0 job overwriting an active 20260810-152244-bcdef01 configuration.

Use the reverse ordering, clear LOG_FILE, and assert that the stale run does not call install, nginx -t, or systemctl reload nginx.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/nginx/deploy.test.sh` around lines 87 - 95, Update the
stale-deployment fixture around run_deploy so the active application release is
20260810-152244-bcdef01 while VEETBOT_EXPECTED_RELEASE_ID uses the older
20260810-152233-abcdef0 value. Clear LOG_FILE before the run, then assert the
stale execution skips deployment and does not invoke install, nginx -t, or
systemctl reload nginx, while preserving the existing configuration assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/deployment.md`:
- Around line 229-236: Add fail-fast settings at the start of the manual
rollback shell block with set -euo pipefail, and explicitly handle a nonzero
flock -w 900 9 result by emitting an error to stderr and exiting before any
rollback commands run. Keep the deployment lock held for the entire block.

---

Outside diff comments:
In `@deploy/nginx/deploy.test.sh`:
- Around line 87-95: Update the stale-deployment fixture around run_deploy so
the active application release is 20260810-152244-bcdef01 while
VEETBOT_EXPECTED_RELEASE_ID uses the older 20260810-152233-abcdef0 value. Clear
LOG_FILE before the run, then assert the stale execution skips deployment and
does not invoke install, nginx -t, or systemctl reload nginx, while preserving
the existing configuration assertion.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 72c37b18-f76b-4b09-bc82-59fc7e9cd79b

📥 Commits

Reviewing files that changed from the base of the PR and between 245186b and 8316aa9.

📒 Files selected for processing (15)
  • .circleci/config.yml
  • client/veetbot_client/__main__.py
  • client/veetbot_client/api.py
  • client/veetbot_client/chat.py
  • deploy/app/release.sh
  • deploy/app/release.test.sh
  • deploy/nginx/deploy.sh
  • deploy/nginx/deploy.test.sh
  • docs/deployment.md
  • docs/plan/development-toolchain.md
  • pyproject.toml
  • src/agent_core/config.py
  • tests/unit/test_config.py
  • tests/unit/test_downloadable_client.py
  • tests/unit/test_toolchain.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • tests/unit/test_config.py
  • deploy/app/release.test.sh
  • deploy/app/release.sh
  • tests/unit/test_toolchain.py
  • client/veetbot_client/main.py
  • client/veetbot_client/api.py
  • .circleci/config.yml
  • client/veetbot_client/chat.py

Comment thread docs/deployment.md
@avitus

avitus commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

Addressed the follow-up rollback finding in 0668361: the manual rollback block now enables set -euo pipefail and exits explicitly if the deployment lock cannot be acquired. make citations-fix and make docs-check both pass.

@avitus
avitus merged commit b1238bb into main Aug 13, 2026
6 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