Skip to content

Posthog code/fix prompt session storage - #34

Merged
sagnik11 merged 4 commits into
mainfrom
posthog-code/fix-prompt-session-storage
Jul 5, 2026
Merged

Posthog code/fix prompt session storage#34
sagnik11 merged 4 commits into
mainfrom
posthog-code/fix-prompt-session-storage

Conversation

@sagnik11

@sagnik11 sagnik11 commented Jul 4, 2026

Copy link
Copy Markdown
Member

View code changes stack in Autter

Summary

Summary generated by Autter.
This PR fixes prompt session storage and extends the PostHog telemetry path to correctly handle Claude-based sessions. It introduces a claude_config_registry module that tracks active CLAUDE_CONFIG_DIR directories discovered at hook time, ensures those directories are maintained during install/update cycles, and wires a NotesBackendKind::Http variant (alongside the existing Both mode) through the notes pipeline—fetch, migrate, push, log, and the internal/notes DBs. The telemetry worker's flush loop is refactored to improve batch handling, and a new src/auth/notice.rs module provides structured auth-related notices to surface to the user.

Changes

  • src/mdm/claude_config_registry.rs (new): Registry that records CLAUDE_CONFIG_DIR values seen during live hook execution, persisted per-user so that install/update runs can maintain hooks in non-default config directories.
  • src/auth/notice.rs (new): Structured notice type for surfacing auth-related messages (e.g. token expiry, missing credentials) to the CLI output path.
  • src/config.rs: Adds NotesBackendKind::Http variant and updates NotesBackendKind::from_str/display logic; threads the new variant into notes_backend_kind() resolution.
  • src/mdm/agents/claude_code.rs: Calls claude_config_registry::register_active_config_dir() during hook parsing; extends install/uninstall logic to iterate registered config dirs and maintain hooks within them.
  • src/commands/checkpoint_agent/presets/claude.rs: Calls register_active_config_dir() at parse time so that harnesses using a custom CLAUDE_CONFIG_DIR are automatically tracked.
  • src/daemon/telemetry_worker.rs: Refactors the flush loop—removes stale buffer-drain logic, adds a new flush path for PostHog session data, and improves retry/back-off handling.
  • src/git/notes_api.rs: Extends write_notes_batch, read_note, read_notes_batch, read_authorship, and adds warm_cache_for_remote to support the Http/Both backend modes.
  • src/file_changes/mod.rs / src/file_changes/db.rs: Threads NotesBackendKind::Http into flush_pending_to_cloud and the underlying SQLite schema.
  • src/authorship/internal_db.rs / src/notes/db.rs: Schema additions to support the new storage paths.
  • src/commands/{fetch_notes,notes_migrate,log,push_hooks}.rs, src/git/sync_authorship.rs: Each updated to branch on NotesBackendKind::Http or Both where relevant.
  • src/authorship/cas_bridge.rs: Minor fix to resolve_cas_messages (single-line change, likely an API client context correction).
  • src/main.rs: Wires the auth::notice module into the startup path.
  • tests/integration/main.rs: Reorders/adjusts integration test module registration to reflect renamed or moved test modules.

Acceptance Criteria

  • autter config set prompt_storage http is accepted without error; parse_notes_backend_kind returns NotesBackendKind::Http.
  • autter fetch-notes with notes_backend_kind = Http calls warm_cache_for_remote and exits successfully without attempting a git fetch.
  • autter fetch-notes with notes_backend_kind = Both calls warm_cache_for_remote and then continues with the standard git fetch.
  • A Claude harness that sets a custom CLAUDE_CONFIG_DIR causes that directory to be registered in claude_config_registry after the first hook fires; subsequent autter install-hooks runs install hooks into that directory.
  • The telemetry flush loop drains PostHog session data without regressing existing CAS sync queue behaviour; no items are silently dropped.
  • autter notes migrate and autter log respect the Http backend variant and do not fall through to git-notes paths when Http is configured.

Test Plan

  • task lint && task fmt — confirm no lint/format regressions.
  • task test — full test suite must pass on Ubuntu CI before Mac/Windows.
  • Set prompt_storage = http via autter config set prompt_storage http and run autter fetch-notes; confirm the HTTP warm-cache path is taken and no git fetch is attempted.
  • Set prompt_storage = both and run autter fetch-notes; confirm both warm-cache and git fetch paths execute.
  • Install autter hooks in a repo where CLAUDE_CONFIG_DIR is set to a non-default path; fire a Claude hook; run autter install-hooks and verify hooks appear in the custom config dir.
  • Trigger a commit with an AI checkpoint from Claude Code; verify the telemetry flush loop processes the session record and no panics or silent failures appear in daemon logs (autter daemon tail).
  • Run autter notes migrate with both Http and Both backend kinds configured; confirm it routes correctly and emits no errors.
  • Inspect autter log output for a repo with Http backend; confirm authorship notes are resolved from the HTTP cache rather than git notes.

Rollback Plan

  • Revert the PR branch and redeploy the previous binary via task dev (debug) or the release pipeline.
  • If NotesBackendKind::Http was written to a user's config, reset it: autter config set prompt_storage default (or notes). The new variant is additive—existing default/notes/local users are unaffected.
  • The claude_config_registry is a local per-user file; if it causes spurious installs, delete it manually from ~/.autter/ (exact path determined by dirs::data_dir()). Hook installs in extra config dirs are idempotent and removing them does not affect the primary install.
  • The auth::notice module is read-only at startup; removing the wiring in main.rs is a one-line revert with no data impact.

Related Issues

No linked issue was identified in the branch name (posthog-code/fix-prompt-session-storage), commit messages, or diff context.

Written for commit 83b3321. Summary will update on new commits.

sagnik11 added 4 commits July 4, 2026 22:13
… hook binary paths

Prompt transcripts and authorship notes could silently stop being stored
through two independent failure modes:

1. The daemon's flush loop only ran flush_cas_queue()/flush_notes()/
   flush_pending_to_cloud() when the in-memory telemetry buffer was
   non-empty, so durable queues could sit pending indefinitely on an
   otherwise idle daemon. The loop now flushes every tick; each durable
   drain first does a cheap local pending-count check so an empty queue
   never triggers an auth check (and its potential token-refresh network
   call). When pending work exists but auth is unavailable, a rate-limited
   WARN is logged (previously debug-level, invisible in daemon logs) and a
   5-minute backoff prevents refresh spam.

2. install-hooks persisted std::env::current_exe() into agent hook configs.
   When run from a cargo build directory (e.g. a temporary worktree's
   target/debug binary), the recorded path dies as soon as that directory
   is removed, and every subsequent checkpoint hook fails silently — no
   sessions, no prompts, empty authorship notes. resolve_hook_binary_path()
   now prefers the stable installed binary (~/.autter/bin/autter) whenever
   the current executable is a cargo artifact.

Generated-By: PostHog Code
Task-Id: e5855956-9de8-49a0-836b-8a2c91373bef
…nfig dirs

Claude Code reads hooks from ~/.claude (or $CLAUDE_CONFIG_DIR), but CLIs
built on the Claude Agent SDK run their sessions with CLAUDE_CONFIG_DIR
pointing at their own config directory. Hooks installed there were
invisible to `autter install-hooks` run from a terminal, so a stale hook
in a harness config silently broke checkpointing for every session of
that harness with no repair path.

Each `autter checkpoint claude` invocation runs inside the harness's
environment, so it now records any non-default CLAUDE_CONFIG_DIR in
~/.autter/internal/claude-config-dirs.json. The Claude hook installer
then installs, repairs, and uninstalls hooks across the primary settings
file and every registered harness directory on each install/update run.
Harness entries are best-effort (one malformed harness config can't fail
the whole install) and no vendor paths are hardcoded, so this works for
any current or future Claude-based CLI.

Generated-By: PostHog Code
Task-Id: e5855956-9de8-49a0-836b-8a2c91373bef
…ud sync

Authorship notes previously went to exactly one destination: git
refs/notes/ai (git_notes) or the cloud data plane via notes-db (http).
notes_backend.kind = "both" now writes every note to git refs/notes/ai
AND queues it for cloud upload, so the full record of sessions, prompts,
and tool calls travels with the repository (offline, team-shareable via
the existing notes push/fetch hooks) while the cloud copy powers hosted
features.

Semantics in Both mode:
- Writes: git note first (durable local copy), then best-effort cloud
  enqueue — a cloud failure never loses the git note and can be
  backfilled with `autter notes migrate`.
- Reads: local git notes are authoritative; the notes-db cache and cloud
  API cover commits whose notes only exist remotely (e.g. cloud-only
  teammates). Blob-OID fast paths work again since notes live in git.
- Sync: pre-push pushes refs/notes/ai as in git_notes mode; fetch warms
  the cloud cache in addition to fetching the notes ref; the daemon
  flushes pending notes-db rows as in http mode.

Transcripts already store dual-destination in the default prompt
storage mode (permanent local cas_cache + cloud CAS upload), so notes
were the missing piece for full local+cloud coverage.

Generated-By: PostHog Code
Task-Id: e5855956-9de8-49a0-836b-8a2c91373bef
…ed working

Cloud sync pauses silently when auth breaks — previously the only signal
was a daemon-log warning nobody reads. Interactive autter commands and
git-proxy commands now print a one-line stderr reminder with the pending
queue counts and the fix (`autter login`).

Detection covers both logged-out shapes:
- refresh token past its expiry timestamp, and
- a token that is valid by timestamp but rejected by the server (revoked
  or rotated) — the daemon flush loop persists a sync-auth-blocked stamp
  whenever pending work meets failed auth, and clears it on the first
  successful authenticated sync.

The notice never fires for users who never logged in, is gated on an
interactive stdout so scripts and pipes stay clean, fires at most once
per process, and rate-limits to once per 24h across processes.

Generated-By: PostHog Code
Task-Id: e5855956-9de8-49a0-836b-8a2c91373bef

@autter-dev autter-dev 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.

🔴 Autter review in progress — merge is blocked until the review gate completes. Autter will approve this PR automatically once its checks pass.

@autter-dev autter-dev 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.

Autter found 1 security/observability issue(s) in this PR:

  • 🟡 [heuristic] Batch size limit not detected (risk 48/100) — src/git/notes_api.rs:90

@autter-dev

autter-dev Bot commented Jul 4, 2026

Copy link
Copy Markdown

🚦 Pre-merge checks · ⚠️ 23 warning, ✅ 113 passed

Needs attention

Check Status Explanation
Mixed concerns (refactor + behavior change) ⚠️ Warning PR combines multiple refactoring/structural changes (new modules, schema additions) with behavior changes (NotesBackendKind::Http variant, telemetry flush refactor, claude_config_registry registration logic) in a single change set. Split into at least two PRs: (1) Infrastructure/schema PR: add NotesBackendKind::Http va ... [truncated 440 chars]
Migration + app logic + UI combined in one PR ⚠️ Warning PR combines database schema changes (authorship/internal_db.rs, notes/db.rs, file_changes/db.rs) with application logic (NotesBackendKind::Http routing in fetch_notes, notes_migrate, log, push_hooks) and user-facing notice/output changes (src/auth/notice.rs wired to src/main.rs startup path). Split into two PRs: (1) Mi ... [truncated 365 chars]
Missing audit logging ⚠️ Warning 10 potential issue(s) detected (max risk 63/100): src/auth/notice.rs:3, src/auth/notice.rs:26, src/auth/notice.rs:119, src/auth/notice.rs:164, src/commands/git_handlers.rs:277.
Removed observability ⚠️ Warning 1 potential issue(s) detected (max risk 45/100): src/daemon/telemetry_worker.rs:65.
Silent exception swallowing ⚠️ Warning 5 potential issue(s) detected (max risk 25/100): src/auth/notice.rs:54, src/auth/notice.rs:56, src/auth/notice.rs:61, src/auth/notice.rs:96, src/auth/notice.rs:98.
Multi-write without detected transaction ⚠️ Warning 2 potential issue(s) detected (max risk 48/100): src/mdm/agents/claude_code.rs:28, src/mdm/claude_config_registry.rs:15.
Optimistic locking not detected ⚠️ Warning 2 potential issue(s) detected (max risk 40/100): src/mdm/agents/claude_code.rs:24, src/mdm/claude_config_registry.rs:10.
Batch size limit not detected ⚠️ Warning 4 potential issue(s) detected (max risk 48/100): src/git/notes_api.rs:90, src/mdm/agents/claude_code.rs:39, src/mdm/claude_config_registry.rs:56, src/mdm/utils.rs:809.
Pagination not detected ⚠️ Warning 3 potential issue(s) detected (max risk 52/100): src/authorship/internal_db.rs:426, src/file_changes/db.rs:265, src/notes/db.rs:345.
Missing linked tracker issue ⚠️ Warning 1 potential issue(s) detected (max risk 50/100): src/auth/notice.rs:1.
Missing security-team review on sensitive path ⚠️ Warning 2 potential issue(s) detected (max risk 88/100): src/auth/mod.rs:5, src/auth/notice.rs:1.
Multi-write without transaction wrapper ⚠️ Warning 1 potential issue(s) detected (max risk 80/100): src/mdm/agents/claude_code.rs:28.
Overbroad try/catch swallowing all exceptions ⚠️ Warning 2 potential issue(s) detected (max risk 55/100): src/auth/notice.rs:177, src/git/notes_api.rs:915.
Established pattern ignored ⚠️ Warning 1 potential issue(s) detected (max risk 45/100): src/commands/install_hooks.rs:8.
Unhandled edge case (null / empty / zero / boundary) ⚠️ Warning 2 potential issue(s) detected (max risk 40/100): src/auth/notice.rs:79, src/commands/fetch_notes.rs:100.
Doc-copy code with insecure defaults ⚠️ Warning 1 potential issue(s) detected (max risk 70/100): src/git/notes_api.rs:947.
New required field added to request ⚠️ Warning 1 potential issue(s) detected (max risk 88/100): src/file_changes/mod.rs:80.
OAuth callback / redirect handling changed ⚠️ Warning 1 potential issue(s) detected (max risk 85/100): src/auth/notice.rs:6.
Code correctness issue ⚠️ Warning 1 finding(s) on changed lines.
Runtime error risk ⚠️ Warning 1 finding(s) on changed lines.
Data integrity risk ⚠️ Warning 1 finding(s) on changed lines.
Dead export (no callers) ⚠️ Warning 2 finding(s) on changed lines.
Code duplication / DRY violation ⚠️ Warning 2 finding(s) on changed lines.
✅ Passed checks (113)
Check Status Explanation
Too many files changed ✅ Passed Changed 25 file(s), within the limit of 50.
Too many lines changed ✅ Passed Changed 935 line(s), within the limit of 1000.
Too many unrelated chapters ✅ Passed 2 chapter(s) detected, within the limit of 6.
Generated files hiding real changes ✅ Passed Generated-file volume (0 lines) does not obscure the 935 hand-written line(s).
Missing PR context ✅ Passed PR context looks sufficient.
Sensitive data in logs ✅ Passed No sensitive data in logs issues detected.
Log injection ✅ Passed No log injection issues detected.
Unhandled promise rejection ✅ Passed No unhandled promise rejection issues detected.
Circuit breaker not detected ✅ Passed No circuit breaker not detected issues detected.
Stack trace leakage ✅ Passed No stack trace leakage issues detected.
Possible TOCTOU in critical path ✅ Passed No possible toctou in critical path issues detected.
Idempotency key not detected ✅ Passed No idempotency key not detected issues detected.
Possible non-atomic read-modify-write ✅ Passed No possible non-atomic read-modify-write issues detected.
Rate limiting not detected ✅ Passed No rate limiting not detected issues detected.
Rate limiting removed ✅ Passed No rate limiting removed issues detected.
Publicly exposed storage ✅ Passed No publicly exposed storage issues detected.
Over-permissive IAM policy ✅ Passed No over-permissive iam policy issues detected.
Security group open to the internet ✅ Passed No security group open to the internet issues detected.
Unencrypted storage at rest ✅ Passed No unencrypted storage at rest issues detected.
Infrastructure missing access logging ✅ Passed No infrastructure missing access logging issues detected.
Hardcoded secret in IaC ✅ Passed No hardcoded secret in iac issues detected.
Infrastructure misconfiguration ✅ Passed No infrastructure misconfiguration issues detected.
Deprecated Kubernetes API version ✅ Passed No deprecated kubernetes api version issues detected.
Compound IaC attack chain ✅ Passed No compound iac attack chain issues detected.
PII in logs ✅ Passed No pii in logs issues detected.
PII or internals leaked in error response ✅ Passed No pii or internals leaked in error response issues detected.
PII stored without application-level encryption ✅ Passed No pii stored without application-level encryption issues detected.
User data stored without retention controls ✅ Passed No user data stored without retention controls issues detected.
PII sent to external / cross-border destination ✅ Passed No pii sent to external / cross-border destination issues detected.
Lockfile resolution / integrity tampered ✅ Passed No lockfile resolution / integrity tampered issues detected.
Dependency runs install-time lifecycle script ✅ Passed No dependency runs install-time lifecycle script issues detected.
Possible dependency-confusion attack ✅ Passed No possible dependency-confusion attack issues detected.
Lockfile resolves a dependency the manifest does not declare ✅ Passed No lockfile resolves a dependency the manifest does not declare issues detected.
Checked-in build artefact modified without source change ✅ Passed No checked-in build artefact modified without source change issues detected.
Dockerfile build-step is insecure ✅ Passed No dockerfile build-step is insecure issues detected.
External artefact pulled in without integrity pinning ✅ Passed No external artefact pulled in without integrity pinning issues detected.
Changed export, importer not updated ✅ Passed No changed export with an un-updated importer detected.
Missing CODEOWNERS reviewer approval ✅ Passed No missing codeowners reviewer approval issues detected.
Source changes without matching tests ✅ Passed No source changes without matching tests issues detected.
Migration missing rollback / down step ✅ Passed No migration missing rollback / down step issues detected.
Frontend importing database client directly ✅ Passed No frontend importing database client directly issues detected.
Route handler bypassing service layer ✅ Passed No route handler bypassing service layer issues detected.
Backend service importing UI module ✅ Passed No backend service importing ui module issues detected.
Cross-context internals import ✅ Passed No cross-context internals import issues detected.
Workspace package rule violation ✅ Passed No workspace package rule violation issues detected.
Inconsistent logging pattern ✅ Passed No inconsistent logging pattern issues detected.
Inconsistent error handling ✅ Passed No inconsistent error handling issues detected.
Endpoint missing input validation ✅ Passed No endpoint missing input validation issues detected.
New feature shipped without feature flag ✅ Passed No new feature shipped without feature flag issues detected.
Module placed in the wrong workspace package ✅ Passed No module placed in the wrong workspace package issues detected.
Hallucinated import (package not installed) ✅ Passed No hallucinated import (package not installed) issues detected.
Nonexistent package (not found in registry) ✅ Passed No nonexistent package (not found in registry) issues detected.
Call to function that does not exist ✅ Passed No call to function that does not exist issues detected.
Generic placeholder identifier in production logic ✅ Passed No generic placeholder identifier in production logic issues detected.
Repetitive boilerplate (duplicated block) ✅ Passed No repetitive boilerplate (duplicated block) issues detected.
TODO / FIXME on critical path ✅ Passed No todo / fixme on critical path issues detected.
Comment contradicts or fabricates code behaviour ✅ Passed No comment contradicts or fabricates code behaviour issues detected.
Abstraction defined but never used ✅ Passed No abstraction defined but never used issues detected.
Code style differs from rest of codebase ✅ Passed No code style differs from rest of codebase issues detected.
Dead code (defined but never referenced) ✅ Passed No dead code (defined but never referenced) issues detected.
Deprecated API call ✅ Passed No deprecated api call issues detected.
API pattern from wrong library version ✅ Passed No api pattern from wrong library version issues detected.
API endpoint removed ✅ Passed No api endpoint removed issues detected.
HTTP method changed (GET ↔ POST etc.) ✅ Passed No http method changed (get ↔ post etc.) issues detected.
Field removed from response schema ✅ Passed No field removed from response schema issues detected.
Response field type changed ✅ Passed No response field type changed issues detected.
HTTP status code changed ✅ Passed No http status code changed issues detected.
Auth requirement added / removed / changed ✅ Passed No auth requirement added / removed / changed issues detected.
Error response shape changed ✅ Passed No error response shape changed issues detected.
Pagination behaviour changed ✅ Passed No pagination behaviour changed issues detected.
Outbound webhook payload schema changed ✅ Passed No outbound webhook payload schema changed issues detected.
GraphQL field removed without deprecation ✅ Passed No graphql field removed without deprecation issues detected.
GraphQL enum value removed ✅ Passed No graphql enum value removed issues detected.
SQL injection ✅ Passed No sql injection issues detected.
Cross-site scripting (XSS) ✅ Passed No cross-site scripting (xss) issues detected.
Path traversal ✅ Passed No path traversal issues detected.
Command injection ✅ Passed No command injection issues detected.
Insecure deserialization ✅ Passed No insecure deserialization issues detected.
Weak cryptography ✅ Passed No weak cryptography issues detected.
Hardcoded secret ✅ Passed No hardcoded secret issues detected.
Insecure randomness for security material ✅ Passed No insecure randomness for security material issues detected.
Unsafe file upload ✅ Passed No unsafe file upload issues detected.
Missing input validation ✅ Passed No missing input validation issues detected.
Unsafe CORS configuration ✅ Passed No unsafe cors configuration issues detected.
Unsafe / open redirect ✅ Passed No unsafe / open redirect issues detected.
Missing CSRF protection ✅ Passed No missing csrf protection issues detected.
Unsafe cookie / session settings ✅ Passed No unsafe cookie / session settings issues detected.
Sensitive data exposure ✅ Passed No sensitive data exposure issues detected.
API key in source ✅ Passed No api key in source detected.
Access token in source ✅ Passed No access token in source detected.
Private key in source ✅ Passed No private key in source detected.
Database connection URL with embedded credentials ✅ Passed No database connection url with embedded credentials detected.
Cloud credential in source ✅ Passed No cloud credential in source detected.
Webhook signing secret in source ✅ Passed No webhook signing secret in source detected.
OAuth client secret in source ✅ Passed No oauth client secret in source detected.
JWT signing secret in source ✅ Passed No jwt signing secret in source detected.
Auth middleware removed from route ✅ Passed No auth middleware removed from route issues detected.
Route protection changed (protected → public) ✅ Passed No route protection changed (protected → public) issues detected.
Permission / RBAC check removed ✅ Passed No permission / rbac check removed issues detected.
Required role weakened ✅ Passed No required role weakened issues detected.
Admin-only route exposed to lower privilege ✅ Passed No admin-only route exposed to lower privilege issues detected.
Token validation skipped in middleware chain ✅ Passed No token validation skipped in middleware chain issues detected.
JWT verification weakened or changed ✅ Passed No jwt verification weakened or changed issues detected.
Session expiration / TTL changed ✅ Passed No session expiration / ttl changed issues detected.
Password reset flow changed ✅ Passed No password reset flow changed issues detected.
Webhook endpoint missing signature verification ✅ Passed No webhook endpoint missing signature verification issues detected.
Public route touches private/PII data ✅ Passed No public route touches private/pii data issues detected.
Resource leak risk ✅ Passed No additional explanation was reported.
Maintainability issue ✅ Passed No additional explanation was reported.
Redundant alias / duplicate import ✅ Passed No additional explanation was reported.
Redundant type construct ✅ Passed No additional explanation was reported.
Unnecessary type assertion ✅ Passed No additional explanation was reported.
Module smell ✅ Passed No additional explanation was reported.

This comment is updated automatically whenever Autter reviews a new PR revision.

@autter-dev

autter-dev Bot commented Jul 4, 2026

Copy link
Copy Markdown

Autter task list

  • @sagnik11 Verify NotesBackendKind::Http branch coverage in fetch_notes, notes_migrate, and log commands (src/commands/fetch_notes.rs, src/commands/notes_migrate.rs, src/commands/log.rs) - Trace through each command's branch logic to confirm Http and Both variants are handled exhaustively and no fallthrough to git-notes paths occurs when Http is configured.
  • @sagnik11 Audit telemetry_worker flush loop for silent item drops and correct back-off behavior (src/daemon/telemetry_worker.rs) - Review the refactored flush loop in telemetry_worker.rs to confirm no PostHog session records or CAS sync queue items can be silently dropped during retry/back-off, and that the removed buffer-drain logic did not carry state that is now unaccounted for.
  • @sagnik11 Review cas_bridge.rs single-line change for correctness against all agent session types (src/authorship/cas_bridge.rs) - Inspect the single-line fix in resolve_cas_messages to confirm the API client context correction applies correctly for Claude, Gemini, and any other agent platform variants without breaking existing normalization logic.
  • @sagnik11 Validate claude_config_registry persistence path and idempotency of hook install in custom CLAUDE_CONFIG_DIR (src/mdm/claude_config_registry.rs, src/mdm/agents/claude_code.rs, src/commands/install_hooks.rs) - Check that the registry correctly resolves the per-user storage path via dirs::data_dir(), that concurrent writes are safe, and that install/uninstall into registered non-default config dirs is truly idempotent with no duplicate hook entries.
  • @sagnik11 Check warm_cache_for_remote is not called on Http-only path when no remote is configured (src/git/notes_api.rs, src/commands/fetch_notes.rs) - Review notes_api.rs to ensure warm_cache_for_remote gracefully handles missing or misconfigured remotes without panicking or returning a misleading error when the Http backend is active.
  • @sagnik11 Verify SQLite schema additions in internal_db.rs, notes/db.rs, and file_changes/db.rs are migration-safe for existing users (src/authorship/internal_db.rs, src/notes/db.rs, src/file_changes/db.rs) - Confirm each schema addition uses IF NOT EXISTS or an explicit migration guard so that users upgrading from a prior binary version do not hit schema errors on their existing local SQLite databases.
  • @sagnik11 Ensure auth::notice module surfaces notices correctly at startup without blocking the main execution path (src/main.rs, src/auth/notice.rs, src/auth/mod.rs) - Review the wiring in main.rs and auth/notice.rs to confirm that auth notices are displayed non-fatally and that any error in notice resolution does not prevent normal CLI operation.
  • @sagnik11 Confirm integration test module registration in tests/integration/main.rs covers new Http and registry code paths (tests/integration/main.rs) - Review the reordered/adjusted integration test module registrations to ensure the new claude_config_registry and NotesBackendKind::Http paths have corresponding test coverage and no previously covered paths were accidentally dropped.

Generated from PR diff, blast radius, and context.

Issues found

  1. Migration + app logic + UI in one PR · risk 65/100 · src/authorship/internal_db.rs:423
  2. PR mixes refactor and behavior change · risk 55/100 · src/config.rs:32
  3. Batch size limit not detected · risk 48/100 · src/git/notes_api.rs:90
  4. Missing linked tracker issue · risk 10/100 · src/auth/notice.rs:1
  5. Established pattern ignored · risk 10/100 · src/commands/install_hooks.rs:8
  6. Code correctness issue · risk 10/100 · src/commands/fetch_notes.rs:99
  7. Data integrity risk · risk 10/100 · src/commands/install_hooks.rs:323
  8. Code duplication / DRY violation · risk 10/100 · src/auth/notice.rs:32
  9. Missing audit logging · risk 5/100 · src/auth/notice.rs:3
  10. Missing audit logging · risk 5/100 · src/auth/notice.rs:119
  11. Missing audit logging · risk 5/100 · src/daemon/telemetry_worker.rs:310
  12. Missing audit logging · risk 5/100 · src/daemon/telemetry_worker.rs:333
  13. Missing audit logging · risk 5/100 · src/daemon/telemetry_worker.rs:372
  14. Multi-write without detected transaction · risk 5/100 · src/mdm/agents/claude_code.rs:28
  15. Silent exception swallowing · risk 5/100 · src/auth/notice.rs:54
  16. Silent exception swallowing · risk 5/100 · src/auth/notice.rs:56
  17. Silent exception swallowing · risk 5/100 · src/auth/notice.rs:96
  18. Silent exception swallowing · risk 5/100 · src/auth/notice.rs:98
  19. Optimistic locking not detected · risk 5/100 · src/mdm/claude_config_registry.rs:10
  20. Missing security-team review on sensitive path · risk 5/100 · src/auth/notice.rs:1
  21. Unhandled edge case (null / empty / zero / boundary) · risk 5/100 · src/auth/notice.rs:79
  22. Unhandled edge case (null / empty / zero / boundary) · risk 5/100 · src/commands/fetch_notes.rs:100
  23. Dead export (no callers) · risk 5/100 · src/auth/notice.rs:51
  24. Dead export (no callers) · risk 5/100 · src/auth/notice.rs:60
  25. Code duplication / DRY violation · risk 5/100 · src/commands/config.rs:1360
  26. Silent exception swallowing · risk 3/100 · src/auth/notice.rs:61
  27. Runtime error risk · risk 3/100 · src/auth/notice.rs:79
  28. Missing audit logging · risk 2/100 · src/commands/git_handlers.rs:277
  29. Missing security-team review on sensitive path · risk 2/100 · src/auth/mod.rs:5
  30. Missing audit logging · risk 1/100 · src/auth/notice.rs:26

And 18 additional finding(s) in the Autter review.

🛠 Fix options (coming soon)

Choose how you would like Autter to package unresolved fixes once automated fix PRs are available.

  • One PR with all unresolved fixes
  • One independent PR per unresolved issue

These checkboxes are currently informational and do not trigger a fix run yet.

@autter-dev

autter-dev Bot commented Jul 4, 2026

Copy link
Copy Markdown

🧭 PR hygiene & process suggestions

Autter has 2 suggestion(s) about the shape of this PR (size, scope, reviewability). These are process guidance — not code defects — so they are consolidated here instead of posted as inline comments on individual files.

🟠 Migration + app logic + UI in one PR — Risk: 65/100

PR combines database schema changes (authorship/internal_db.rs, notes/db.rs, file_changes/db.rs) with application logic (NotesBackendKind::Http routing in fetch_notes, notes_migrate, log, push_hooks) and user-facing notice/output changes (src/auth/notice.rs wired to src/main.rs startup path). The bundle spans src/authorship/internal_db.rs, src/notes/db.rs, src/auth/notice.rs. Split into two PRs: (1) Migration PR: schema-only changes to internal_db.rs, notes/db.rs, and file_changes/db.rs with safe no-op additions. (2) Feature PR: application logic and UI changes—NotesBackendKind::Http handling in commands, auth notice module, claude_config_registry, and telemetry refactor. This allows migration to be deployed and validated independently before behavior changes.

References:

🛠 AI fix prompt (copy & paste into your coding agent)
Split this PR so the schema/database migration lands first, then the application-logic PR consuming it, then the UI PR.
This sequencing de-risks rollback: a bad migration can be reverted before app/UI traffic depends on it.
Concrete next step: extract `src/authorship/internal_db.rs` (or its peer in this PR) into its own follow-up branch and open separate PRs.

References:
https://github.com/advisories/ghsa-jm43-hrq7-r7w6
https://nvd.nist.gov/vuln/detail/CVE-2025-49580

🟠 PR mixes refactor and behavior change — Risk: 55/100

PR combines multiple refactoring/structural changes (new modules, schema additions) with behavior changes (NotesBackendKind::Http variant, telemetry flush refactor, claude_config_registry registration logic) in a single change set. src/config.rs and src/daemon/telemetry_worker.rs are the files contributing most to the mix. Split into at least two PRs: (1) Infrastructure/schema PR: add NotesBackendKind::Http variant to config.rs, schema updates to authorship/internal_db.rs and notes/db.rs, wire Http variant through notes_api.rs and file_changes modules. (2) Feature PR: claude_config_registry registration, telemetry worker flush refactor, auth/notice module, and command-level behavior changes (fetch_notes, notes_migrate, log, push_hooks, etc.). This allows independent review and rollback of the storage mechanism from the behavior that uses it.

References:

🛠 AI fix prompt (copy & paste into your coding agent)
Split this PR so refactors land separately from behavior changes.
Pure-refactor PRs should preserve behavior (no test changes beyond renames). Behavior-change PRs should focus on a single new capability.
Start by extracting `src/config.rs`'s refactor portion (or its behavior portion, whichever is smaller) into its own PR.

References:
https://github.com/advisories/ghsa-jm43-hrq7-r7w6
https://nvd.nist.gov/vuln/detail/CVE-2025-49580

Flagged by Autter PR-hygiene checks.

@autter-dev

autter-dev Bot commented Jul 4, 2026

Copy link
Copy Markdown
🔇 45 finding(s) suppressed as likely false positives by Autter's verification pass

These were flagged by a detector but a second, full-file verification judged them not to be real issues. Listed here for transparency — review if you disagree.

  • Optimistic locking not detectedsrc/mdm/agents/claude_code.rs:24 — This is a local filesystem operation (reading/writing JSON config files) in a CLI tool. There is no shared database row, distributed resource, or concurrent writer scenario that would require optimistic locking. The code uses write_atomic() for safe file writes, and the entire operation is a single-process CLI invocation. The 'optimistic locking' concept (ETags, version columns, affected-row check
  • Optimistic locking not detectedsrc/mdm/claude_config_registry.rs:10 — This is a local JSON file registry on the user's own machine (~/.autter/internal/claude-config-dirs.json). The function is explicitly documented as 'best-effort' with failures ignored so checkpoints are never blocked. It uses write_atomic (which typically writes to a temp file then renames, providing atomicity at the OS level) rather than a read-modify-write without locking. The only concurrency s
  • Multi-write without transaction wrappersrc/mdm/agents/claude_code.rs:28 — This code operates on local filesystem files (settings.json paths), not a database. There is no PostgreSQL transaction context here. The 'multiple writes' are sequential writes to independent JSON config files on disk, each via write_atomic(). The finding conflates filesystem operations with database transactions. No transactional semantics are applicable or expected in this CLI tool's file-writin
  • Multi-write without detected transactionsrc/mdm/agents/claude_code.rs:28 — The code explicitly designates the first path (primary settings file) as fatal and all subsequent paths (registered harness configs) as best-effort with warn-and-continue semantics. This is an intentional design choice: each settings file is an independent configuration file for a different harness, so there is no shared transaction needed. Each write_atomic call is atomic per-file, and partial su
  • Multi-write without detected transactionsrc/mdm/claude_config_registry.rs:15 — There is only one persistence write in register_active_config_dir: a single write_atomic call to one file. The create_dir_all is a prerequisite directory setup, not a separate data-persistence write that needs to be atomic with the JSON write. There is no multi-document or multi-table write that would require a transaction. The function is also explicitly documented as 'best-effort' and errors are
  • Silent exception swallowingsrc/auth/notice.rs:54 — Using let _ to intentionally ignore errors from best-effort filesystem operations is an established pattern throughout this codebase (seen in cas_bridge.rs with let _ = db_lock.set_cas_cache(...), in clear_sync_auth_blocked with let _ = std::fs::remove_file(...), etc.). The module comment explicitly states these are best-effort operations. If create_dir_all fails, the subsequent write will a
  • Silent exception swallowingsrc/auth/notice.rs:56 — Same reasoning as #0. The let _ pattern for fs::write is intentional. If the stamp file cannot be written, the rate-limiting fails open (notices may repeat within 24h), but this is a UI cosmetic issue, not a correctness or security defect. The module doc explicitly describes this as best-effort. The team has also previously dismissed similar silent-swallowing findings on other files.
  • Silent exception swallowingsrc/auth/notice.rs:61 — The let _ on fs::remove_file in clear_sync_auth_blocked() is intentional. The file may not exist (first run, already deleted), so ignoring the error is correct. Even if it fails due to permissions, the 48-hour staleness check in sync_auth_blocked_recently() provides a fallback: a stale stamp ages out naturally. The daemon re-records on every blocked attempt, so a persistent file that can't be de
  • Silent exception swallowingsrc/auth/notice.rs:96 — Same reasoning as #0 and CLI auth (PAT/device) + direct-to-org-database data plane #1. The let _ on create_dir_all in record_notified() is intentional best-effort design. The consequence of failure (repeated notices to stderr) is minor and cosmetic, not a functional or security defect. This is an established pattern in this codebase.
  • Silent exception swallowingsrc/auth/notice.rs:98 — Same reasoning. The fs::write failure in record_notified() would cause repeated notices (spam), but the module explicitly describes once-per-process and per-24h gates — the per-process AtomicBool guard (NOTICE_EMITTED) still prevents within-process repetition even if the file write fails. The cross-process rate limiting degrades gracefully. Intentional best-effort design.
  • Missing audit loggingsrc/auth/notice.rs:3 — _The file is a user-facing UI notification module (displaying a 'you've been logged out' reminder to stderr). It contains no security-sensitive operations requiring audit logging — it reads local credential state and writes a timestamp file to rate-limit notifications. There is no established audit-logging pattern in this codebase for such UI helpers, and the finding is a generic heuristic applied _
  • Missing audit loggingsrc/auth/notice.rs:26 — Line 26 defines the constant SYNC_BLOCKED_FRESH_SECS — a numeric constant. There is no security-sensitive operation here whatsoever. The finding is a false positive from the automated tool flagging proximity to auth-related code.
  • Missing audit loggingsrc/auth/notice.rs:119 — Line 119 is inside maybe_warn_logged_out(), which reads credentials to check expiry status and displays a UI warning to stderr. This is a read-only diagnostic display operation, not a security-sensitive action requiring audit logging. No actual authentication state is changed here.
  • Missing audit loggingsrc/auth/notice.rs:164 — Line 164 is inside maybe_warn_logged_out() — the eprintln! call that prints the logout warning message to stderr. Printing a UI notification to stderr is not a security-sensitive operation that warrants audit logging.
  • Missing audit loggingsrc/commands/git_handlers.rs:277 — The diff adds a UX notification call (maybe_warn_logged_out) in the post-git hook phase — this is a user-facing warning about an expired login session, not a security-sensitive operation that requires audit logging. It is analogous to the already-present maybe_warn_below_min_version call directly above it. The 'missing audit logging' claim is not substantiated: there is no established audit-lo
  • Missing audit loggingsrc/daemon/telemetry_worker.rs:310 — The functions note_durable_sync_unauthenticated and note_durable_sync_authenticated are helper utilities that manage a backoff timer and emit a tracing::warn when auth is missing. They are not security-sensitive operations requiring audit logging — they are telemetry/sync infrastructure. There is no established audit-logging pattern in the codebase for these kinds of internal daemon bookkeeping ca
  • Missing audit loggingsrc/daemon/telemetry_worker.rs:333 — Same reasoning as finding #0. note_durable_sync_authenticated merely clears a backoff flag (stores 0 to an atomic and calls clear_sync_auth_blocked). This is a bookkeeping reset, not a security-sensitive operation. No audit-logging convention in the codebase applies here.
  • Missing audit loggingsrc/daemon/telemetry_worker.rs:372 — The durable_sync_auth_backoff_active() check is a simple read of an AtomicI64 compared against the current time. It is a guard/gating function, not a security-sensitive operation. The surrounding code already logs via tracing::warn when blocked. There is no audit-logging pattern established in the codebase for this type of internal gate check.
  • Removed observabilitysrc/daemon/telemetry_worker.rs:65 — The removed is_empty() method was only used as a guard to skip flushing when no in-memory telemetry was buffered. The diff comment explicitly explains the removal is intentional: the durable queues must be drained on every tick regardless of whether in-memory buffers are empty. No observability was lost; the tracing::warn for auth failures and the tracing::error for panics remain intact. The remov
  • Missing audit loggingsrc/main.rs:98 — The code added is a UX notification call (auth::notice::maybe_warn_logged_out()) that reminds the user when their login has expired. This is a purely informational/display operation, not a security-sensitive action requiring audit logging. The project has no established audit-logging pattern for such notification calls, and there is no evidence in the codebase that this type of check-and-warn pa
  • Missing audit loggingsrc/main.rs:104 — Same reasoning as finding #0 — line 104 is within the same if block that calls auth::notice::maybe_warn_logged_out(). This is a read-only user notification about expired credentials, not a privileged or security-sensitive operation that would warrant audit logging. No audit-logging pattern exists in the provided code for similar notification-only paths.
  • Pagination not detectedsrc/authorship/internal_db.rs:426 — The new function count_pending_cas is a COUNT(*) aggregate query — it returns a single scalar integer, not a list or collection. There is nothing to paginate. The finding incorrectly treats a count query as if it were a list query that could return an unbounded number of rows.
  • Pagination not detectedsrc/file_changes/db.rs:265 — The new method count_pending is a simple COUNT(*) scalar query — it returns a single integer, not a collection or list of rows. There is no unbounded result set to paginate. The pagination concern is a false positive because the method is explicitly documented as a 'cheap gate' to avoid triggering auth checks on an empty queue, and it only returns one row (a count). The existing `dequeue_pendi
  • Batch size limit not detectedsrc/mdm/agents/claude_code.rs:39 — The all_settings_paths() function builds a Vec by iterating over registered_config_dirs(), which is a local registry of harness config directories stored on the user's own machine. This is not an external batch/API input — it's reading from a local registry of installed tool directories. There is no network or user-supplied unbounded input; the number of entries is bounded by the number of Cla
  • Batch size limit not detectedsrc/mdm/claude_config_registry.rs:56 — This is not a handler that accepts external input. The function register_active_config_dir reads a single value from the CLAUDE_CONFIG_DIR environment variable — one directory path — and either adds it to the registry or returns early if it's already present (deduplication check via dirs.iter().any). There is no batch input, no array/list accepted from a caller, and no unbounded loop over ex
  • Batch size limit not detectedsrc/mdm/utils.rs:809 — The flagged code adds utility functions (stable_install_binary_path, is_cargo_build_artifact, resolve_hook_binary_path) plus tests for them. None of these functions accept an array/list/batch input at all — they take a single Path or no arguments and return a single PathBuf. The 'unbounded batch operation' finding is entirely inapplicable to this diff hunk.
  • Pagination not detectedsrc/notes/db.rs:345 — count_pending is a COUNT(*) aggregate query, not a list/collection query. It returns a single i64 scalar — the number of pending rows — not an unbounded collection of rows. Pagination is inapplicable to a count query. The actual row-fetching function dequeue_pending already has a batch_size/LIMIT parameter enforcing pagination.
  • Missing linked tracker issuesrc/auth/notice.rs:1 — The requirement to link a tracker issue is a process/policy convention, not a coding rule enforced by the repository's documented conventions (which specify lint, fmt, coverage, CI order, and architectural discussion — not mandatory issue links). The PR title and description follow the project's auto-generated Autter summary pattern. This is a process preference, not a defect in the code.
  • Missing security-team review on sensitive pathsrc/auth/mod.rs:5 — This is a process/policy finding (missing security-team review), not a code defect. The change itself is trivially adding a new module declaration (pub mod notice;) to an auth mod.rs re-export file — it is not a code vulnerability. The finding is purely about whether a security team approved the PR, which is an organizational process concern external to the code. There is no actual security defe
  • Missing security-team review on sensitive pathsrc/auth/notice.rs:1 — This is a policy/process finding about whether a security-team review was obtained, not a code defect. The file itself is a user-notification helper (displaying a logout warning) with no privileged operations, credential mutation, or sensitive data handling. The code reads credentials read-only via CredentialStore::load() and writes only timestamp files to ~/.autter/internal/. There is no evidence

@autter-dev autter-dev 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.

Autter completed PR review for #34. Generated a PR summary, 8 task(s), and 48 finding(s).

Comment thread tests/integration/main.rs
@@ -16,14 +16,14 @@ mod amp;
mod attribution_tracker_comprehensive;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Captain Autter Patch via Autter

why do we even need to make this change randomly?

@autter-dev autter-dev 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.

Autter found 13 security/observability issue(s) in this PR:

  • 🔴 [ai] No Test Coverage for Both Option in NotesBackendKind (risk 85/100) — src/config.rs:43 — downstream: 1 affected
  • 🔴 [ai] Missing Test for register_active_config_dir Function (risk 80/100) — src/commands/checkpoint_agent/presets/claude.rs:53 — downstream: 1 affected
  • 🟠 [ai] New Durable Sync Auth Backoff Logic Not Tested (risk 75/100) — src/daemon/telemetry_worker.rs:284 — downstream: 1 affected
  • 🟠 [ai] Lack of Test for count_pending_cas Method (risk 70/100) — src/authorship/internal_db.rs:423 — downstream: 1 affected
  • 🟠 [ai] Potential Inefficiency with CAS Queue Handling (risk 60/100) — src/authorship/internal_db.rs:423 — downstream: 1 affected
  • 🟠 [ai] flush_pending_to_cloud silently exits on unauthenticated state without arming the durable-queue backoff (risk 52/100) — src/file_changes/mod.rs:92 — downstream: 2 affected
  • 🟠 [ai] flush_pending_to_cloud does not participate in the durable-queue auth backoff, causing repeated token-refresh attempts every 3 s when only the file-changes queue has pending data (risk 52/100) — src/file_changes/mod.rs:92 — downstream: 3 affected
  • 🟠 [ai] flush_pending_to_cloud silently bypasses auth backoff and blocked-sync notice on unauthenticated failure (risk 52/100) — src/file_changes/mod.rs:92 — downstream: 4 affected
  • 🟡 [ai] TOCTOU lost-update race in register_active_config_dir: concurrent checkpoint hooks corrupt the registry (risk 42/100) — src/mdm/claude_config_registry.rs:62 — downstream: 3 affected
  • 🟡 [ai] Unbounded DB Calls (risk 40/100) — src/notes/db.rs:342 — downstream: 1 affected
  • 🟡 [ai] Redundant Configuration Management Addition (risk 30/100) — src/mdm/claude_config_registry.rs:1 — downstream: 2 affected
  • 🟡 [ai] flush_pending_to_cloud auth failure does not arm the backoff, enabling per-tick token-refresh calls to the auth server (risk 25/100) — src/file_changes/mod.rs:92 — downstream: 3 affected
  • 🟡 [ai] Missing User Feedback on Authentication Failure (risk 20/100) — src/commands/git_handlers.rs:275 — downstream: 3 affected

Comment thread src/config.rs

impl NotesBackendKind {
pub fn as_str(&self) -> &'static str {
match self {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 [ai] No Test Coverage for Both Option in NotesBackendKind — Risk: 85/100

The introduction of the Both option in NotesBackendKind lacks test coverage, posing a risk for missed integration behaviors.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/config.rs
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.


// This process runs inside the agent's environment: when a harness
// built on the Claude Agent SDK routes hooks through its own
// CLAUDE_CONFIG_DIR, record that directory so install/update runs

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 [ai] Missing Test for register_active_config_dir Function — Risk: 80/100

The call to register_active_config_dir within claude.rs lacks testing, which may lead to unverified configuration behavior.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/commands/checkpoint_agent/presets/claude.rs
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

let config = Config::get();
let distinct_id = get_or_create_distinct_id();

// Flush metrics (always processed — uploaded or stored in SQLite)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [ai] New Durable Sync Auth Backoff Logic Not Tested — Risk: 75/100

The implementation of durable sync auth backoff logic lacks tests to verify its effectiveness and correct behavior.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/daemon/telemetry_worker.rs
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

@@ -423,6 +423,18 @@ impl InternalDatabase {
Ok(records)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [ai] Lack of Test for count_pending_cas Method — Risk: 70/100

The newly added count_pending_cas method in InternalDatabase.rs does not have a corresponding test, potentially leading to unverified function behavior.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/authorship/internal_db.rs
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

@@ -423,6 +423,18 @@ impl InternalDatabase {
Ok(records)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [ai] Potential Inefficiency with CAS Queue Handling — Risk: 60/100

Unnecessary queuing and dequeueing without checking if sync is possible might lead to resource exhaustion.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/authorship/internal_db.rs
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

}

let path = registry_path();
let mut dirs: Vec<String> = std::fs::read_to_string(&path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 [ai] TOCTOU lost-update race in register_active_config_dir: concurrent checkpoint hooks corrupt the registry — Risk: 42/100

register_active_config_dir performs an unguarded read-modify-write on the shared JSON registry file (~/.autter/internal/claude-config-dirs.json). The function reads the file (line 62), checks whether the directory is already present (line 68), appends the new entry (line 71), and writes back via write_atomic (line 77). No file lock or advisory lock protects this window. Because autter checkpoint claude is invoked for every pre-edit and post-edit hook event — and Claude agents routinely fire these hooks in rapid succession across parallel editing sessions — two processes can execute this function concurrently with the SAME registry file. Actor A reads ['/dir/harness-a'], sees '/dir/harness-b' is absent, appends, and writes ['harness-a','harness-b']. Actor B, having read the same original snapshot before A's write, also sees 'harness-b' absent, appends only 'harness-b', and its rename atomically overwrites A's write, resulting in ['harness-b'] alone — losing harness-a's registration. An additional hazard exists inside write_atomic itself: the temp file is always named claude-config-dirs.json.tmp (target_path.with_extension('tmp'), src/mdm/utils.rs:459). Two concurrent callers both call File::create on this same fixed path, which truncates the file; whichever writer is slower will overwrite the other's bytes before either rename fires, potentially leaving a zero-byte or interleaved JSON document that future reads will fail to parse (silently falling back to an empty list and erasing all previously registered directories). The consequence is that a harness config directory is silently dropped from the registry, causing autter install-hooks to skip it on the next run, and that harness's sessions will fire hooks against a stale (or missing) binary path — silently dropping all AI attribution checkpoints for those sessions.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/mdm/claude_config_registry.rs, src/commands/checkpoint_agent/presets/claude.rs, src/mdm/utils.rs
🛠 AI fix prompt (copy & paste into your coding agent)
Replace the bare read-modify-write in register_active_config_dir with a lock-protected update. Use a file lock (e.g. fs2::FileExt::lock_exclusive on a companion .lock file, or the same registry file itself opened for write before reading) to serialize concurrent writers. Acquire the lock, read the current contents, check for duplicates, append if needed, write, flush, then release the lock. Alternatively, since the only mutation is appending a new unique string to a list, consider using a dedicated lock file (e.g. claude-config-dirs.lock) held via flock/LockFile for the duration of the read-check-write cycle. Also fix write_atomic to use a per-call unique temp file name (e.g. via tempfile::NamedTempFile in the same directory) rather than the fixed .tmp extension, so concurrent callers to write_atomic on ANY file don't clobber each other's temp files.

Flagged by Autter security & observability checks.

Comment thread src/notes/db.rs
@@ -342,6 +342,18 @@ impl NotesDatabase {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 [ai] Unbounded DB Calls — Risk: 40/100

Lack of boundary checks or limits akin to unbounded read might induce pressure on the database system.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/notes/db.rs
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

@@ -0,0 +1,96 @@
//! Registry of Claude-Code-compatible configuration directories.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 [ai] Redundant Configuration Management Addition — Risk: 30/100

The claude_config_registry introduces directory management that overlaps significantly with existing configurations found in src/config.rs. This duplication could lead to increased complexity and maintenance issues. Consolidation of these configurations is recommended to unify management practices.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/config.rs, src/commands/config.rs
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

Comment thread src/file_changes/mod.rs
let default_client = ApiClient::new(crate::api::client::ApiContext::new(Some(
backend_url.clone(),
)));
if !default_client.is_logged_in() && !default_client.has_api_key() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 [ai] flush_pending_to_cloud auth failure does not arm the backoff, enabling per-tick token-refresh calls to the auth server — Risk: 25/100

This PR introduces a 5-minute auth backoff (DURABLE_SYNC_AUTH_RETRY_AFTER) to prevent hammering the token-refresh endpoint when a durable queue has pending work but authentication is broken. The mechanism works correctly for flush_notes and flush_cas_queue, which call note_durable_sync_unauthenticated() on auth failure. However, flush_pending_to_cloud (file_changes/mod.rs:92-94) silently returns on auth failure without calling note_durable_sync_unauthenticated(). Consequently, when ONLY the file-changes queue has pending rows and auth is broken, the outer durable_sync_auth_backoff_active() guard is never set, and flush_pending_to_cloud runs every daemon tick (~3 s). Each invocation calls ApiClient::new() → try_load_auth_token() which attempts a network token-refresh call (src/api/client.rs:53) when the access token is expired but the refresh token is still nominally valid. This sends a POST to the auth server every 3 seconds until the session finally expires — precisely the abuse pattern the backoff mechanism was designed to prevent. The three co-sibling functions (flush_notes, flush_cas_queue, flush_pending_to_cloud) are documented as a group in telemetry_worker.rs:309-321, making the omission inconsistent with the stated design intent.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/file_changes/mod.rs, src/daemon/telemetry_worker.rs, src/api/client.rs
🛠 AI fix prompt (copy & paste into your coding agent)
In src/file_changes/mod.rs, after the `if !default_client.is_logged_in() && !default_client.has_api_key()` branch that returns early (currently line 92-94), add a call to crate::daemon::telemetry_worker::note_durable_sync_unauthenticated("file_changes", pending_count) before returning, mirroring the pattern in flush_notes (telemetry_worker.rs:651-653) and flush_cas_queue (telemetry_worker.rs:879-881). This requires exposing note_durable_sync_unauthenticated as pub(crate) or moving the auth-backoff logic to a shared module callable from file_changes/mod.rs.

Flagged by Autter security & observability checks.

@@ -273,6 +273,9 @@ fn handle_git_inner(args: &[String]) {
// Warn (loudly, once per process) if this CLI is below the platform's
// minimum required version. Reads the cached releases payload — no network.
crate::commands::upgrade::maybe_warn_below_min_version();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 [ai] Missing User Feedback on Authentication Failure — Risk: 20/100

The proposed changes in PR #34 introduce user prompts for scenarios requiring authentication that previously lacked direct user engagement. While existing functions check authentication, they don't inform users about failures effectively. This enhancement is necessary for user awareness during command execution.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: src/api/client.rs, src/commands/login.rs, src/commands/logout.rs
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

@sagnik11
sagnik11 merged commit 5a67a18 into main Jul 5, 2026
2 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