Skip to content

ci: upload combined code coverage artifact#3

Merged
isuttell merged 2 commits into
mainfrom
t3code/737bbb4b
May 21, 2026
Merged

ci: upload combined code coverage artifact#3
isuttell merged 2 commits into
mainfrom
t3code/737bbb4b

Conversation

@isuttell

@isuttell isuttell commented May 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a combined code coverage report to CI as a GitHub artifact so a downstream ingestor can consume it. Single Vitest run aggregates v8 coverage across every apps/* and packages/* project; no merge tooling needed.

Changes

  • New vitest.coverage.config.ts at the repo root with test.projects: ['apps/*', 'packages/*'] and v8 coverage reporters (json, lcov, text-summary).
  • New root script pnpm test:coverage that runs vitest run --coverage --config vitest.coverage.config.ts.
  • CI workflow gains a Coverage step (after pnpm verify) plus an actions/upload-artifact@v7 step that publishes coverage/coverage-final.json and coverage/lcov.info as a coverage artifact (14-day retention, if: always() so partial coverage still uploads on red builds).
  • @vitest/coverage-v8 added to the pnpm catalog (pinned to the same ^4.1.7 as vitest) and to root devDependencies.

The config file is named vitest.coverage.config.ts (not the default vitest.config.ts) so per-package vitest run invocations under Turbo don't auto-discover it and fail trying to resolve workspace globs from inside a subpackage.

Risk: LOW

  • Areas touched: CI workflow, root tooling config. No runtime/source code changes.
  • Security: none. New deps are first-party @vitest/coverage-v8.
  • Performance: tests run twice in CI (once via pnpm verify per-package, once via root pnpm test:coverage); ~10s of extra CI wall time given 16 small test files. Acceptable.
  • Breaking: no.

Test plan

  • pnpm install succeeds with @vitest/coverage-v8@4.1.7 resolved
  • pnpm verify passes (per-package vitest unaffected by the new root config)
  • pnpm test:coverage exits 0 — 16 test files / 64 tests pass; emits coverage/coverage-final.json (34 source files) and coverage/lcov.info (3,875 lines)
  • After merge: CI run produces a downloadable coverage artifact containing both files
  • Inject a failing test on a throwaway branch and confirm the artifact still uploads (if: always())

CodeRabbit notes

  • Skipped — if-no-files-found: error flagged as conflicting with if: always(). Keeping error: the flags are orthogonal (if: always() controls step execution; if-no-files-found controls behavior when files are missing). If coverage silently breaks while tests pass, we want CI to fail loudly so the ingestor never sees a stale build.
  • Skipped — SHA-pinning actions/upload-artifact@v7 recommended. The existing workflow tag-pins all other actions (checkout@v6, setup-node@v6, cache@v5, pnpm/action-setup@v6). Pinning only this one to a SHA would be inconsistent; SHA-pinning should be a separate sweep across all actions.

Summary by CodeRabbit

  • New Features

    • Added automated code coverage reporting to CI/CD pipeline with artifact retention.
  • Documentation

    • Consolidated and reorganized project status documentation for improved clarity and usability.
  • Chores

    • Added coverage testing infrastructure and dependencies to support reporting and CI workflows.

Review Change Stack

isuttell and others added 2 commits May 21, 2026 13:55
Reframe the MVP-only bootstrap checklist as a project-wide status doc
covering all six roadmap phases. Adds spec coverage (15 specs), ADR
coverage (66 ADRs with status + gap), phase status, and an ordered
15-item backlog with verifiable Done criteria so a fresh session can
pick up "the next step" without rediscovering scope.

Wires AGENTS.md to point at it as the first read.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a root vitest config that aggregates v8 coverage across every
apps/* and packages/* project in one run. CI executes `pnpm test:coverage`
after `pnpm verify` and uploads `coverage-final.json` + `lcov.info` as a
GitHub artifact for downstream ingestion.

The coverage config lives at `vitest.coverage.config.ts` (non-default
name) so per-package `vitest run` invocations under Turbo don't
auto-discover it and try to resolve workspace globs from a subpackage.
@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

Walkthrough

This PR establishes test coverage reporting infrastructure and restructures project status tracking. A new Vitest coverage configuration with V8 reporting is added alongside npm scripts and CI integration to generate and archive coverage artifacts. The substantial docs/ops/project-status.md document replaces the prior MVP bootstrap checklist, serving as a single source of truth for implementation progress, spec/ADR coverage gaps, phase status, prioritized next steps, and operational checklists. Documentation references in AGENTS.md and the MVP spec are updated to point to this new document.

Poem

🐰 A burrow of tests now glowing bright,
Coverage reports shine through the night,
The status scroll unfurls with care,
Project paths mapped, all laid bare!
From checklist old to doc supreme,
Our progress tracked within one stream! 🎯

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'ci: upload combined code coverage artifact' directly summarizes the main change: adding CI coverage artifact upload functionality. It is specific, concise, and accurately reflects the primary modification.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/737bbb4b

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

@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: 3

🤖 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 @.github/workflows/ci.yml:
- Line 94: The workflow step currently uses the mutable tag
actions/upload-artifact@v7; replace that tag with the action's immutable full
40-character commit SHA (i.e., use actions/upload-artifact@<full-commit-sha>) to
pin the dependency. Locate the line containing the reference
"actions/upload-artifact@v7" in the CI workflow and update it to the exact
commit SHA from the upload-artifact repository release you intend to use,
ensuring the workflow references that specific hash instead of a mutable tag.

In `@docs/ops/project-status.md`:
- Line 5: The sentence in docs/ops/project-status.md is self-contradictory;
reword the header line "First doc a fresh agent reads after `AGENTS.md`,
`CONTEXT.md`, `docs/specs/README.md`, and `docs/adr/README.md`..." to remove the
contradiction—for example change it to "First doc a fresh agent should read
(after `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, and
`docs/adr/README.md`)" or "The first document a fresh agent reads following
`AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, and `docs/adr/README.md`" so
the intent is clear; update the exact sentence in project-status.md accordingly.
- Around line 166-236: The Next Steps Backlog headings in
docs/ops/project-status.md (e.g., the "### 1. Wire `runCommand` and
`createOperationEvent` into mutation routes", "### 2. Enforce native rate-limit
bindings", etc. through item 15) are missing surrounding blank lines; edit the
Markdown so each "### N. ..." heading is preceded and followed by an empty line
(apply the same pattern used in the example fix for items 1–3) across all 15
items to satisfy markdownlint and ensure parser compatibility.
🪄 Autofix (Beta)

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: ASSERTIVE

Plan: Pro Plus

Run ID: 77ee46e4-1c5e-4714-ac74-b8273af347c8

📥 Commits

Reviewing files that changed from the base of the PR and between 4bde837 and 24e0acd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • .github/workflows/ci.yml
  • AGENTS.md
  • docs/ops/mvp-bootstrap-checklist.md
  • docs/ops/project-status.md
  • docs/specs/mvp.md
  • package.json
  • pnpm-workspace.yaml
  • vitest.coverage.config.ts
💤 Files with no reviewable changes (1)
  • docs/ops/mvp-bootstrap-checklist.md

Comment thread .github/workflows/ci.yml

- name: Upload coverage artifact
if: always()
uses: actions/upload-artifact@v7

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify workflow actions are SHA-pinned (40-hex) instead of mutable tags.
# Expected: no output. Any output indicates unpinned action references.
rg -nP '^\s*uses:\s*[^@\s]+@(?!(?:[a-f0-9]{40})$).+$' .github/workflows

Repository: zaks-io/agent-paste

Length of output: 1405


Pin actions/upload-artifact@v7 to a full commit SHA.

Mutable version tags create a supply-chain risk since the action can change between runs. Replace with the full 40-character commit SHA for immutability.

Suggested change
-        uses: actions/upload-artifact@v7
+        uses: actions/upload-artifact@<full-length-commit-sha>
🧰 Tools
🪛 zizmor (1.25.2)

[error] 94-94: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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 @.github/workflows/ci.yml at line 94, The workflow step currently uses the
mutable tag actions/upload-artifact@v7; replace that tag with the action's
immutable full 40-character commit SHA (i.e., use
actions/upload-artifact@<full-commit-sha>) to pin the dependency. Locate the
line containing the reference "actions/upload-artifact@v7" in the CI workflow
and update it to the exact commit SHA from the upload-artifact repository
release you intend to use, ensuring the workflow references that specific hash
instead of a mutable tag.


Last updated: 2026-05-21.

First doc a fresh agent reads after `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, and `docs/adr/README.md`. Answers: what is built, what is scaffolded, where the code diverges from the ADRs/specs, what the next concrete step is.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify the reading order statement.

The phrase "First doc a fresh agent reads after AGENTS.md, CONTEXT.md..." is contradictory—if it's read after those docs, it's not the first doc.

📝 Suggested rewording
-First doc a fresh agent reads after `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, and `docs/adr/README.md`. Answers: what is built, what is scaffolded, where the code diverges from the ADRs/specs, what the next concrete step is.
+After reading `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, and `docs/adr/README.md`, agents should read this doc next. It answers: what is built, what is scaffolded, where the code diverges from the ADRs/specs, what the next concrete step is.

Or more concisely:

-First doc a fresh agent reads after `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, and `docs/adr/README.md`. Answers: what is built, what is scaffolded, where the code diverges from the ADRs/specs, what the next concrete step is.
+Read after the onboarding docs (`AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, `docs/adr/README.md`). Answers: what is built, what is scaffolded, where the code diverges from the ADRs/specs, what the next concrete step is.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
First doc a fresh agent reads after `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, and `docs/adr/README.md`. Answers: what is built, what is scaffolded, where the code diverges from the ADRs/specs, what the next concrete step is.
After reading `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, and `docs/adr/README.md`, agents should read this doc next. It answers: what is built, what is scaffolded, where the code diverges from the ADRs/specs, what the next concrete step is.
Suggested change
First doc a fresh agent reads after `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, and `docs/adr/README.md`. Answers: what is built, what is scaffolded, where the code diverges from the ADRs/specs, what the next concrete step is.
Read after the onboarding docs (`AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`, `docs/adr/README.md`). Answers: what is built, what is scaffolded, where the code diverges from the ADRs/specs, what the next concrete step is.
🤖 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 `@docs/ops/project-status.md` at line 5, The sentence in
docs/ops/project-status.md is self-contradictory; reword the header line "First
doc a fresh agent reads after `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`,
and `docs/adr/README.md`..." to remove the contradiction—for example change it
to "First doc a fresh agent should read (after `AGENTS.md`, `CONTEXT.md`,
`docs/specs/README.md`, and `docs/adr/README.md`)" or "The first document a
fresh agent reads following `AGENTS.md`, `CONTEXT.md`, `docs/specs/README.md`,
and `docs/adr/README.md`" so the intent is clear; update the exact sentence in
project-status.md accordingly.

Comment on lines +166 to +236
### 1. Wire `runCommand` and `createOperationEvent` into mutation routes
- Drives: ADR 0022, ADR 0035, `docs/specs/api.md`
- Files: `apps/api/src/index.ts`, `apps/upload/src/index.ts`, `packages/commands/src/index.ts`
- Done: every POST/PUT/DELETE route in `api` and `upload` is wrapped via `runCommand`; idempotency keys are honored from `Idempotency-Key` header; replay of the same idempotency key returns the original result; vitest covers replay for at least workspace-create, api-key-create, artifact-delete.

### 2. Enforce native rate-limit bindings
- Drives: ADR 0039, ADR 0064
- Files: `apps/api/src/index.ts`, `apps/upload/src/index.ts`, `apps/*/wrangler.jsonc`
- Done: every authenticated mutation calls `env.ACTOR_RATE_LIMIT.limit(...)` and `env.WORKSPACE_BURST_CAP.limit(...)`; over-limit returns 429 with envelope; a smoke test triggers 429 from an in-test client.

### 3. Generate OpenAPI from Zod contracts
- Drives: ADR 0016, ADR 0017, ADR 0038
- Files: `packages/contracts/src/*`, `apps/api/src/index.ts`, `apps/upload/src/index.ts`, `apps/content/src/index.ts`
- Done: `/openapi.json` on api/upload/content is generated from `packages/contracts` via `@hono/zod-openapi` (or equivalent); `pnpm verify` runs a schema-diff check against a checked-in golden; CI fails if contracts drift from served OpenAPI.

### 4. Add `--yes` guards to destructive admin CLI commands
- Drives: `docs/specs/admin.md`
- Files: `apps/cli/src/index.ts`
- Done: `agent-paste admin api-key revoke`, `artifacts delete`, and `cleanup run` (non-dry-run) refuse to run without `--yes`; CLI test asserts refusal and a `--yes` happy path.

### 5. Consolidate content-signing secret names
- Drives: ADR 0028, ADR 0058
- Files: `scripts/bootstrap-secrets.mjs`, `apps/*/wrangler.jsonc`, `apps/api/src/index.ts`, `apps/content/src/index.ts`
- Done: only one of `CONTENT_SIGNING_SECRET` / `CONTENT_GATEWAY_SIGNING_KEY_V1` remains, named consistently across code, bootstrap script, and ADRs; a one-time rotation note is added to `docs/ops/runbook` (or this doc) for any environment that already holds both.

### 6. Move runtime queries to Drizzle
- Drives: ADR 0018
- Files: `packages/db/src/**`, callers in `apps/api`, `apps/upload`
- Done: workspace/api-key/artifact/upload-session reads and writes flow through Drizzle query objects (not raw SQL templates); `pnpm verify` runs a Drizzle introspection check against the migration file. Scope this to MVP routes; leave admin/cleanup queries as a follow-up if the change balloons.

### 7. Apply Postgres RLS at runtime
- Drives: ADR 0044
- Files: `packages/db/src/**`, `apps/api/src/index.ts`, `apps/upload/src/index.ts`, `packages/db/migrations/*`
- Done: Hyperdrive role is `NOBYPASSRLS`; every request opens a Postgres txn that issues `SET LOCAL app.workspace_id = $1` before any query; a vitest scenario inserts two workspaces and confirms cross-workspace reads return zero rows.

### 8. Complete error envelope (`request_id`, `docs`)
- Drives: ADR 0036, `docs/specs/contracts.md`
- Files: `apps/api/src/index.ts`, `apps/upload/src/index.ts`, `apps/content/src/index.ts`, `packages/contracts/src/*`
- Done: every error response includes `request_id`; an optional `docs` URL is attached for codes that have a documented remediation; `X-Request-Id` header is echoed on every response (error or success); golden tests cover at least 404/401/409/422/429/500.

### 9. Verify bytes-after-delete and bytes-after-expiry cleanup
- Drives: ADR 0048, `docs/specs/acceptance.md`
- Files: `apps/api/src/index.ts` (scheduled handler), `scripts/smoke-local-mvp.mjs`, `scripts/smoke-hosted.mjs`
- Done: smoke creates an artifact with a 1-day TTL, advances clock (or uses a forced-expiry test endpoint), runs cleanup, confirms R2 prefix is empty and signed URL returns 404 with denylist hit logged.

### 10. Exercise PR preview lifecycle on a same-repo PR
- Drives: ADR 0007, ADR 0012, `.github/workflows/pr-preview.yml`
- Files: workflow itself, `scripts/deploy-pr-preview.mjs`, `scripts/cleanup-pr-preview.mjs`
- Done: a same-repo PR (the one carrying items 1-9 above is the natural candidate) creates a Neon branch, deploys preview Workers, runs hosted smoke, posts a comment with URLs, and tears everything down on close. Captured run links recorded in this doc.

### 11. Wire Logpush → Axiom for `api`/`upload`/`content`
- Drives: ADR 0011, `docs/specs/phases.md` Phase 2
- Files: Cloudflare console + `docs/ops/` runbook (no Worker code change required if using Cloudflare Logs config)
- Done: an Axiom dataset receives Worker logs for all three Workers; a basic dashboard shows 5xx rate and p95 latency; secrets/PII redaction confirmed (no API key secret or signed-URL token in logs).

### 12. Review and merge `t3code/7bcd4587`
- Drives: this branch holds Apex/front-end and CI work that needs to land or be discarded.
- Files: TBD until review.
- Done: branch is either merged to `main` (with conflicts resolved and CI green) or closed with a written reason. Same decision for `t3code/5b6355f9` if still extant.

### 13. Decide on remaining ADR 0046 drift (operator identity)
- Drives: ADR 0046
- Files: ADR 0046 itself, possibly a new ADR
- Done: ADR 0046 is amended (or a new ADR supersedes it) to either accept the single-bearer admin token as the production model or to commit Cloudflare Access + email allowlist before Phase 3. No code change in this item — just a written decision.

### 14. CSP allowlist audit
- Drives: ADR 0029, ADR 0030, `docs/specs/content-rendering.md`
- Files: `apps/content/src/index.ts`
- Done: CSP `script-src` and `connect-src` allowlists are validated against the current ADR 0029 list; SVG responses use a strict CSP override; a vitest snapshot pins the CSP header for HTML, CSS, JS, SVG, and PNG.

### 15. Complete bootstrap hosting checklist

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Add blank lines around backlog item headings for Markdown compliance.

Markdownlint flags missing blank lines around 15 headings in the Next Steps Backlog section (items 1-15). While the document is readable, adding blank lines improves Markdown parser compatibility and consistency with the rest of the file.

🧹 Example fix for items 1-3
 Ordered. Each item has a verifiable Done. Items 1-10 close Phase 1; items 11-15 prep Phase 2.
 
 When you say "implement the next step," start with item 1 unless we have agreed to skip it.
 
 ### 1. Wire `runCommand` and `createOperationEvent` into mutation routes
+
 - Drives: ADR 0022, ADR 0035, `docs/specs/api.md`
 - Files: `apps/api/src/index.ts`, `apps/upload/src/index.ts`, `packages/commands/src/index.ts`
 - Done: every POST/PUT/DELETE route in `api` and `upload` is wrapped via `runCommand`; idempotency keys are honored from `Idempotency-Key` header; replay of the same idempotency key returns the original result; vitest covers replay for at least workspace-create, api-key-create, artifact-delete.
 
 ### 2. Enforce native rate-limit bindings
+
 - Drives: ADR 0039, ADR 0064
 - Files: `apps/api/src/index.ts`, `apps/upload/src/index.ts`, `apps/*/wrangler.jsonc`
 - Done: every authenticated mutation calls `env.ACTOR_RATE_LIMIT.limit(...)` and `env.WORKSPACE_BURST_CAP.limit(...)`; over-limit returns 429 with envelope; a smoke test triggers 429 from an in-test client.
 
 ### 3. Generate OpenAPI from Zod contracts
+
 - Drives: ADR 0016, ADR 0017, ADR 0038

Apply the same pattern to items 4-15.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 166-166: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 171-171: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 176-176: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 181-181: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 186-186: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 191-191: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 196-196: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 201-201: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 206-206: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 211-211: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 216-216: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 221-221: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 226-226: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 231-231: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 236-236: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 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 `@docs/ops/project-status.md` around lines 166 - 236, The Next Steps Backlog
headings in docs/ops/project-status.md (e.g., the "### 1. Wire `runCommand` and
`createOperationEvent` into mutation routes", "### 2. Enforce native rate-limit
bindings", etc. through item 15) are missing surrounding blank lines; edit the
Markdown so each "### N. ..." heading is preceded and followed by an empty line
(apply the same pattern used in the example fix for items 1–3) across all 15
items to satisfy markdownlint and ensure parser compatibility.

@isuttell

Copy link
Copy Markdown
Contributor Author

Thanks @coderabbitai. Triage of the 3 actionable findings:

  1. SHA-pin actions/upload-artifact@v7 — skipping for convention parity. The rest of this workflow tag-pins majors (actions/checkout@v6, actions/setup-node@v6, actions/cache@v5, pnpm/action-setup@v6). Pinning only this one to a SHA would be inconsistent; a SHA-pin sweep belongs in a separate dedicated PR across all actions. Already noted in the PR description.

  2. docs/ops/project-status.md line 5 wording — out of scope. That file landed on main in commit 7354630 (already merged); it's not part of this PR's diff. The review base (4bde83783) is one commit behind main, so the doc shows up as "changed" even though my branch didn't touch it.

  3. docs/ops/project-status.md heading blank-line spacing — same as ci(pr-preview): register dynamic GitHub deployment per PR #2: out of scope for this coverage PR.

All CI gates are green: Validate (CI) pass, Deploy PR Preview pass, coverage artifact uploaded (86 KB). Proceeding to merge once human review lands.

@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@isuttell — all three points are well-reasoned, thanks for the clear triage.

  1. SHA-pin sweep — Agreed. Flagging only one action in isolation would create inconsistency; a sweep across all actions in a single dedicated PR is the right approach. Happy to open a follow-up GitHub or Linear issue to track that if you'd like.

  2. & 3. docs/ops/project-status.md findings — Understood. The review base (4bde83783) being one commit behind main caused that file to appear in the diff even though this branch never touched it. I'll account for that in future reviews on this repo.

The coverage wiring looks solid — V8 reporters, correct monorepo glob scopes, if: always() upload guard, and 14-day retention all check out. Good to go. 🚀

🐇 ✨


✏️ Learnings added
Learnt from: isuttell
URL: https://github.com/zaks-io/agent-paste/pull/3

Timestamp: 2026-05-21T21:23:25.694Z
Learning: In the zaks-io/agent-paste repository, GitHub Actions are pinned to major version tags (e.g., `actions/checkoutv6`, `actions/setup-nodev6`, `actions/cachev5`, `pnpm/action-setupv6`), not SHA-pinned. Any SHA-pinning sweep should be done as a dedicated separate PR across all actions, not piecemeal per-action. Do not flag individual actions for SHA-pinning when the rest of the workflow uses major-version tag pinning.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@isuttell isuttell merged commit f5b9cc8 into main May 21, 2026
4 checks passed
isuttell added a commit that referenced this pull request May 21, 2026
The rebase onto origin/main silently regressed the @vitest/coverage-v8
catalog and importer entries that PR #3 added. Frozen-lockfile install
on CI failed because the root package.json still referenced the catalog
spec.
isuttell added a commit that referenced this pull request May 22, 2026
* feat(commands): wire runCommand into api and upload mutation routes

Every POST/PUT/DELETE in api and upload now flows through the shared
runCommand wrapper from packages/commands. The wrapper claims an
idempotency_records row, executes the handler in the same transaction,
persists result_json, and writes the audit event. Replay returns the
cached body; an in-flight collision returns 409.

A new migration (0002_idempotency_admin_ops) drops the workspace_id FK
and adds a NULLS NOT DISTINCT unique index so admin-without-workspace
mutations (workspace create, cleanup) can claim records cleanly.

Closes backlog item 1 in docs/ops/project-status.md; advances ADR 0004,
0022, and 0035 from Partial to Done.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(db): drop unused withTransaction helper on PostgresRepository

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: address CodeRabbit review

- adminActor now throws on unexpected actor types instead of silently
  mapping non-system actors to admin.
- createApiKey defers generateApiKey until inside the idempotent path
  (both LocalRepository and PostgresRepository) so replays skip the
  unused crypto work.
- Clarify backlog wording so item 9 (PR preview exercise) is not read
  as a deployment blocker.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: address CodeRabbit review (round 2)

Reorder idempotency-key validation to run before database availability
checks in all admin handlers. Eliminate redundant mustApiKey call in
PostgresRepository.revokeApiKey by reusing the initially fetched row.

* fix: restore @vitest/coverage-v8 catalog entry dropped during rebase

The rebase onto origin/main silently regressed the @vitest/coverage-v8
catalog and importer entries that PR #3 added. Frozen-lockfile install
on CI failed because the root package.json still referenced the catalog
spec.

* fix(db): apply all migrations, not just 0001

The migrate runner was hardcoded to apply only 0001_mvp_postgres.sql,
so the new 0002_idempotency_admin_ops.sql was never running on PR
preview Neon branches. Switch to enumerating the migrations directory
in lex order so future migrations land automatically. All current
migrations are idempotent (if exists / if not exists), so re-running
0001 on already-migrated branches is safe.

* fix(db): drop idempotency_records PK before dropping NOT NULL

Postgres refuses to drop NOT NULL on a column that's part of a primary
key (error 42P16). Reorder 0002 to drop the composite PK first, then
the FK and NOT NULL, then recreate the unique index with NULLS NOT
DISTINCT.

* fix: address CodeRabbit review (round 3)

- apps/api: use adminActor helper for cleanup so system tokens record correct actor.type.
- packages/commands, packages/db: make SqlExecutor.transaction required; drop silent fallback that ran handlers without a transaction. createPostgresHttpExecutor now throws since HTTP cannot span transactions.
- packages/db: include actor.type in LocalRepository admin idempotency cache keys so admin+system with the same id cannot collide.
- packages/db/schema: switch idempotency_records unique to unique(...).nullsNotDistinct() to reflect 0002 migration.

* fix(db): honor batchSize in LocalRepository.runCleanupSync

Mirror PostgresRepository.runCleanupInternal: order expired artifacts/sessions by expires_at, slice to batchSize (default 100), and set artifact.updated_at when expiring. Prevents the local path from blowing past the cap during smoke and manual preview runs.

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
@isuttell isuttell deleted the t3code/737bbb4b branch May 22, 2026 01:02
isuttell added a commit that referenced this pull request May 22, 2026
CodeRabbit flagged that the same task was listed both as Done in
'Recently Completed' and as pending in 'Next Steps Backlog' (#3).
Remove the backlog entry and renumber subsequent items 4-12 to 3-11.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
isuttell added a commit that referenced this pull request May 22, 2026
…ING_SECRET (#7)

* refactor(secrets): consolidate content-signing secret to CONTENT_SIGNING_SECRET

Drop CONTENT_GATEWAY_SIGNING_KEY_V1 from bootstrap-secrets.mjs; code already
read only CONTENT_SIGNING_SECRET. Add rotation note with wrangler secret delete
commands for envs that hold the dropped binding.

* docs: address CR feedback on Recently-Completed entry

- Drop the pre-merge `<SHA>` placeholder; record completion via PR #7
  reference instead (verifiable via `gh pr view 7`).
- Add blank line before the fenced rotation block to satisfy
  markdownlint MD031.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: drop completed secret-name item from backlog

CodeRabbit flagged that the same task was listed both as Done in
'Recently Completed' and as pending in 'Next Steps Backlog' (#3).
Remove the backlog entry and renumber subsequent items 4-12 to 3-11.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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