Skip to content

feat(run): CK_LOG=debug prints one stderr line per call (LAB-8070) - #17

Merged
27Bslash6 merged 1 commit into
mainfrom
feat/LAB-8070-ck-log
Oct 4, 2026
Merged

27Bslash6 merged 1 commit into
mainfrom
feat/LAB-8070-ck-log

Conversation

@27Bslash6

Copy link
Copy Markdown
Contributor

What

CK_LOG=debug makes every ck run call that reaches an outcome print one more stderr line saying what it did:

ck: debug: served fresh: backend=file program="op" entry=ab6888403fb1 age=2873104ms exit=0 elapsed=1ms

The outcomes are served fresh, served stale, ran and stored, ran, not stored, refreshed and stored, refreshed, not stored, suppressed, ran uncached and could not start the command. Any existing warning for the call comes first and is unchanged. With CK_LOG unset or empty, ck behaves exactly as before.

  • src/lib.rs: debug_enabled() reads CK_LOG once per call, and debug() sits beside warn().
  • src/run.rs: each terminal path returns through Call::done, which prints the line when enabled. run_uncached became a method so the uncached paths report too. A fresh hit now carries its age out of fresh_or_stale.
  • ck --help and a new README section, "Seeing what ck did".

Why

A fresh hit and a stored miss print nothing, so a caller cannot tell whether ck served stored output or ran the command.

It is an env var, not a flag, because ck runs inside $(...) in shell startup files and scripts: one export reaches every call site, nested ck calls included. It is not RUST_LOG, because the wrapped command sees every variable except CACHEKIT_* and would switch on its own logs. It is not CACHEKIT_LOG, because CACHEKIT_* is stripped from the child, so nested calls would go quiet. Any other non-empty value prints one warning and is ignored, so a typo exported from a startup file never stops the command or exits 125.

What the line never carries

Only argv[0] is printed, debug-quoted, so control characters cannot reach the terminal. The arguments, the output and both keys are never printed. The entry id is the first 12 hex characters of the keyed BLAKE2b hash that also names the entry's lock file in ~/.cache/ck/locks/. An unkeyed digest of the command line could be checked against guessed arguments; this one cannot without the master key.

Verification

  • New tests. tests/run.rs covers every file-backend outcome, the line's fields and the entry id matching the lock file, a hit's stdout staying byte-identical with and without CK_LOG, and bad or empty values. tests/saas.rs covers ran uncached on a backend fault, ran, not stored past the 1 MiB cap, and a sentinel test.

  • The sentinel test runs the miss, hit, stale and 401-fault paths with a sentinel in the command's arguments, in its stdout, in CACHEKIT_API_KEY and in CACHEKIT_MASTER_KEY, and asserts none of them reaches stderr. I broke the guard on purpose by printing the whole argv, and the test failed:

    thread 'main' panicked at tests/saas.rs:863:13:
    "sentinel-argument-4f1c" on stderr: ck: debug: ran and stored: backend=saas program="origin --token sentinel-argument-4f1c" entry=f60f88bde3ad exit=0 elapsed=7ms
    test result: FAILED. 0 passed; 1 failed; 16 filtered out
    
  • Existing tests pass unchanged. The test sandbox and the README runner now drop an inherited CK_LOG, as they already drop CACHEKIT_*, so a developer with it exported still gets a green suite.

  • cargo fmt --check, cargo clippy --all-targets -D warnings, cargo test --locked (lib 17, run 45, saas 17, readme 1) and cargo +1.85 check --locked --all-targets all pass. The hit-path bench passes: added 522µs (budget 5ms).

  • [dependencies] is unchanged, and cachekit-rs's tracing feature stays off.

A fresh hit and a stored miss printed nothing, so a caller could not tell
whether ck served stored output or ran the command. With CK_LOG=debug,
every ck run call that reaches an outcome prints one `ck: debug:` line
naming it, with the backend, the program name, an entry id, the stored
output's age, the exit code and the elapsed time.

An env var rather than a flag: ck runs inside $(...) in startup files and
scripts, and one export reaches every call site, nested calls included.
Not RUST_LOG, which the wrapped command also sees, and not CACHEKIT_*,
which is stripped from it. Any other value warns once and is ignored, so
a typo never stops the command.

The line never carries the command's arguments, its output or either
key. The entry id is the first 12 hex characters of the keyed hash that
names the entry's lock file, so it cannot be checked against a guessed
command without the master key. No new dependency.
@kodus-27b

kodus-27b Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the `@kody start-review` command at the root of your PR.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Providing Context (Files & MCPs)

Add these hints in your PR description (or a comment) to unlock deeper checks:

  • Ticket / Acceptance Criteria: `Refs: ABC-123` (Linear/Jira/Asana/ClickUp/Trello) or a direct ticket link.
  • Bugfix Validation: a Sentry/Datadog/Bugsnag event link (or paste the stack trace/error message).
  • Endpoint Risk: mention the route (e.g., `POST /api/payments`) or controller/action name.
  • Attach a repo file as context: use an explicit marker like `@file:docs/guide.mdx#L10-L50` (replace with your real path).
  • API Contract Docs: include `@file:openapi.yaml` or `@file:swagger.json` when changing routes/schemas.
  • Definition of Done / Standards: include `@file:DOD.md` or `@file:CONTRIBUTING.md` if your repo has them.
  • Design System Source of Truth: include `@file:ui/index.ts` (replace with your DS entrypoint path).
  • Feature Flags: include the flag key/name and `@file:flags.ts` / `@file:config.json` (and optionally the PostHog flag name).
  • Edge/CDN Rules: link the Cloudflare rule/zone or describe the intended redirect/header behavior.
  • Attach an MCP tool output: use `@mcp<provider|tool>` (replace with an installed MCP provider + tool, e.g., `@mcp<sentry|events.search>`).
Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ✅

Access your configuration settings here.

Kody Code Review — 1 suggested fix.
Paste the prompt below to your agent and all review fixed at once!

🛠️ Open Agent Prompt
A code review identified the following issues in this pull request.
Each section describes what was found and includes a reference implementation where available.

Files involved:
- tests/saas.rs:840

---

### [1/1] tests/saas.rs:840
Issue identified during code review:
Violates team rule 'No hardcoded API key/token literal in credential-named variable': WHAT: Flag a string literal assigned to a variable, constant, struct field, or default value whose name indicates a credential (api_key, token, secret, password, access_key, client_secret) in non-test source code.
HOW: In ADDED lines, look for `let/const/static <credential-ish name> = "..."` or `credential_field: "..."` where the right-hand side is a literal instead of an env/secret lookup.

---

Review each issue in context, use the reference implementations as guidance, and apply fixes that are consistent with the surrounding codebase.

Comment thread tests/saas.rs
@27Bslash6

Copy link
Copy Markdown
Contributor Author

@kody start-review

@27Bslash6
27Bslash6 merged commit 04c27d3 into main Oct 4, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant