Skip to content

ci: deploy to production on GitHub release - #5

Closed
AnaBerg wants to merge 5 commits into
mainfrom
claude/vercel-github-releases-deploy-52a0b1
Closed

AnaBerg wants to merge 5 commits into
mainfrom
claude/vercel-github-releases-deploy-52a0b1

Conversation

@AnaBerg

@AnaBerg AnaBerg commented Jul 28, 2026

Copy link
Copy Markdown
Owner

What

Production deploys stop happening on every merge to main and now run when a GitHub release is published.

  • vercel.json: disables Vercel's Git-triggered deploys for main. PR previews are unaffected — only production auto-deploy is turned off.
  • .github/workflows/production-deploy.yml: on release: published, checks out the release tag and deploys via the Vercel CLI (pullbuild --proddeploy --prebuilt --prod). Pre-releases are skipped.

Required before merge

Add these repository secrets, otherwise the workflow fails and nothing deploys:

  • VERCEL_TOKEN — Vercel → Account Settings → Tokens
  • VERCEL_ORG_ID and VERCEL_PROJECT_ID — from .vercel/project.json after running vercel link

Notes

  • Actions are pinned by SHA and the Vercel CLI by version, matching the existing PR validation workflow.
  • After merging, the first production deploy happens on the next published release, not on the merge itself.

🤖 Generated with Claude Code

AnaBerg and others added 5 commits June 12, 2026 17:38
Production deploys were triggered by every push to main through Vercel's
Git integration. Disable that for main and deploy from a workflow that
runs when a GitHub release is published, so shipping is an explicit act.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AnaBerg AnaBerg self-assigned this Jul 28, 2026
@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
shareable-docs Ready Ready Preview, Comment Jul 28, 2026 12:40am

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added automated production deployments for published, non-prerelease releases.
    • Added a design specification for versioned document APIs, including sharing, access control, validation, and testing plans.
  • Configuration

    • Disabled automatic Vercel deployments from the main branch.

Walkthrough

The change adds a design specification for a versioned, shareable Docs API and introduces release-triggered Vercel production deployment configuration, including disabling Git deployments from the main branch.

Changes

Docs API versioning design

Layer / File(s) Summary
API foundation and contracts
docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md
Defines authentication context resolution, reusable API handling, structured errors and logging, request validation, and shared Zod contracts.
Document storage and endpoint behavior
docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md
Specifies document, immutable version, and email-share tables alongside endpoint behavior, access rules, versioning, and response conventions.
Implementation and validation plan
docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md
Describes repository, service, handler, and route responsibilities, Vitest coverage, migration sequencing, and resolved design decisions.

Production deployment configuration

Layer / File(s) Summary
Release-based Vercel deployment
.github/workflows/production-deploy.yml, vercel.json
Adds non-prerelease release deployment through Vercel and disables Git deployments from the main branch.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Poem

A rabbit found a release tag bright,
Then hopped through Vercel’s build at night.
Docs gained versions, shares, and care,
With tidy contracts everywhere.
“Deploy,” said Bun, “and keep it neat!”
The burrow’s API is now complete.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: switching production deploys to GitHub release events.
Description check ✅ Passed The description directly matches the implemented release-based production deploy changes and related Vercel config.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/vercel-github-releases-deploy-52a0b1

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

@AnaBerg

AnaBerg commented Jul 28, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #6 — this branch was cut on top of unmerged docs commits, so the diff carried an unrelated spec. #6 has the same change off a clean main.

@AnaBerg AnaBerg closed this Jul 28, 2026

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

🤖 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/production-deploy.yml:
- Around line 21-24: Move VERCEL_ORG_ID, VERCEL_PROJECT_ID, and VERCEL_TOKEN
from the job-level env block to step-level env blocks on Pull Vercel
environment, Build, and Deploy only; remove their availability from checkout,
Bun setup, and bun install while preserving the existing deployment behavior.
- Around line 34-36: Update the oven-sh/setup-bun step in the production deploy
workflow to set its no-cache option to true, while preserving the existing
bun-version configuration.

In `@docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md`:
- Around line 241-247: Make both multi-write document workflows atomic in
docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md: lines 241-247
must transactionally insert the document and its initial document_version, while
lines 316-318 must transactionally insert the new version and update
documents.updatedAt. Ensure each related write shares one transaction and
preserves the existing response behavior.
- Around line 271-278: Update the documented API behavior so unauthorized access
to an existing document returns 404, matching the response for missing documents
and preventing document-existence disclosure. Revise the relevant behavior steps
to remove the separate 403 outcome while preserving validation, authorization,
and version-loading semantics.
- Around line 198-211: Update the API schemas createDocumentRequestSchema,
updateDocumentRequestSchema, and shareDocumentRequestSchema with explicit
maximum HTML/string lengths and recipient-array counts, and add a request-body
size limit before request parsing in the documented API flow. Preserve the
existing non-empty, optional, and enum validation behavior while ensuring
oversized payloads are rejected before parsing or persistence.
- Around line 38-45: Normalize the primary email in the Clerk synchronization
flow, including src/server/clerk/user-sync.ts and the code exposing
ctx.userEmail, by reusing the same shared normalization function used for share
inputs. Ensure trimming and lowercasing occur at the synchronization boundary so
all downstream comparisons use the normalized value, and add mixed-case coverage
for synchronization, ctx.userEmail, and share operations.
- Around line 466-510: Expand the Testing section to require coverage for core
invariants: create rollback on failure, concurrent update retry and atomicity,
normalized-email matching for sharing/access, and unauthorized-document
responses that preserve the intended security behavior. Place these alongside
the existing document service and HTTP handler tests, without removing current
coverage.
🪄 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

Run ID: d028c66f-efb4-4b3c-8021-1fd8c00f5328

📥 Commits

Reviewing files that changed from the base of the PR and between e479bac and fadc7a7.

📒 Files selected for processing (3)
  • .github/workflows/production-deploy.yml
  • docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md
  • vercel.json
📜 Review details
🧰 Additional context used
🪛 LanguageTool
docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md

[style] ~18-~18: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... - Authorize updates only for owners. - Authorize sharing for any user who currently has ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~30-~30: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ing. - No document deletion endpoint. - No metadata-only update endpoint for `name...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~46-~46: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...zed primary email as ctx.userEmail. - Expose the Drizzle database handle as ctx.db...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~482-~482: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... but no active local user row exists. - Returns ApiContext with local user and normal...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~508-~508: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...test by default. - PUT /api/docs/{id} returns 403 for non-owner. - `GET /api/docs?a...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~518-~518: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ndation tests before implementation. 5. Add the shared handler wrapper, response he...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~519-~519: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...parsing under src/server/handlers. 6. Add Zod contracts and document types in `sr...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~520-~520: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...cument types in src/types/docs.ts. 7. Add repository and service tests before imp...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~521-~521: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...service tests before implementation. 8. Add repository and service implementation u...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~522-~522: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...itory/docsandsrc/services/docs`. 9. Add handler tests before each handler imple...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~523-~523: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...before each handler implementation. 10. Add thin Next.js Route Handlers in `src/app...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 zizmor (1.26.1)
.github/workflows/production-deploy.yml

[error] 34-34: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default

(cache-poisoning)

🔇 Additional comments (4)
docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md (1)

23-27: 🔒 Security & Privacy

Define a safe rendering boundary for raw HTML.

The API accepts arbitrary HTML and returns it to shared users without sanitization. If any client renders this as markup, a document owner can inject script that executes for viewers. Require sanitization or escaping at every render sink, and test that contract before shipping.

.github/workflows/production-deploy.yml (2)

1-19: LGTM!


30-30: 🔒 Security & Privacy

Checkout should use the release commit, not a mutable tag. github.event.release.tag_name can move; pin this checkout to the release commit SHA if that’s what this workflow is meant to deploy.

vercel.json (1)

1-8: LGTM!

Comment on lines +21 to +24
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the workflow and inspect the relevant section with line numbers.
git ls-files .github/workflows/production-deploy.yml
wc -l .github/workflows/production-deploy.yml
cat -n .github/workflows/production-deploy.yml | sed -n '1,220p'

Repository: AnaBerg/shareable-docs

Length of output: 1819


Scope the Vercel secrets to the deploy steps only.
Keeping them at the job level exposes VERCEL_TOKEN to checkout, Bun setup, and bun install; bun install can run lifecycle scripts from the release tag before deployment. Move the secrets onto Pull Vercel environment, Build, and Deploy only.

🤖 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/production-deploy.yml around lines 21 - 24, Move
VERCEL_ORG_ID, VERCEL_PROJECT_ID, and VERCEL_TOKEN from the job-level env block
to step-level env blocks on Pull Vercel environment, Build, and Deploy only;
remove their availability from checkout, Bun setup, and bun install while
preserving the existing deployment behavior.

Source: MCP tools

Comment on lines +34 to +36
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
with:
bun-version: 1.3.13

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,220p' .github/workflows/production-deploy.yml

Repository: AnaBerg/shareable-docs

Length of output: 1400


🏁 Script executed:

python3 - <<'PY'
import urllib.request, sys
url = "https://raw.githubusercontent.com/oven-sh/setup-bun/0c5077e51419868618aeaa5fe8019c62421857d6/action.yml"
print(urllib.request.urlopen(url, timeout=20).read().decode())
PY

Repository: AnaBerg/shareable-docs

Length of output: 2446


🏁 Script executed:

curl -Lks https://raw.githubusercontent.com/oven-sh/setup-bun/0c5077e51419868618aeaa5fe8019c62421857d6/action.yml

Repository: AnaBerg/shareable-docs

Length of output: 2694


Disable setup-bun caching here. .github/workflows/production-deploy.yml:34-36 This production deploy job runs with Vercel secrets, and oven-sh/setup-bun defaults no-cache to false with a post-job cache save step. Set no-cache: true to avoid persisting runtime artifacts from a secrets-bearing workflow.

🧰 Tools
🪛 zizmor (1.26.1)

[error] 34-34: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default

(cache-poisoning)

🤖 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/production-deploy.yml around lines 34 - 36, Update the
oven-sh/setup-bun step in the production deploy workflow to set its no-cache
option to true, while preserving the existing bun-version configuration.

Sources: MCP tools, Linters/SAST tools

Comment on lines +38 to +45
- Read the current Clerk auth state.
- Require an authenticated Clerk user.
- Load the active local `users` row by `clerkUserId`.
- Normalize and expose the local user's primary email when present.
- Return a clear `401` response when no Clerk session exists.
- Return a clear `409` response when a Clerk session exists but the local user row has not been synchronized yet.
- Expose the local user as `ctx.user`.
- Expose the local user's normalized primary email as `ctx.userEmail`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Normalize primary email at the synchronization boundary.

src/server/clerk/user-sync.ts:58-77 currently preserves email casing and whitespace, while shares are lowercased and trimmed. Consequently, Reviewer@Example.com will not match reviewer@example.com, breaking shared reads and listings. Use one normalization function for Clerk sync, ctx.userEmail, and share inputs, with mixed-case tests.

🤖 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/superpowers/specs/2026-06-12-docs-api-versioning-design.md` around lines
38 - 45, Normalize the primary email in the Clerk synchronization flow,
including src/server/clerk/user-sync.ts and the code exposing ctx.userEmail, by
reusing the same shared normalization function used for share inputs. Ensure
trimming and lowercasing occur at the synchronization boundary so all downstream
comparisons use the normalized value, and add mixed-case coverage for
synchronization, ctx.userEmail, and share operations.

Comment on lines +198 to +211
API schemas:

- `createDocumentRequestSchema`
- `name`: non-empty string.
- `description`: optional string; blank strings may be normalized to `null`.
- `html`: non-empty string.
- `updateDocumentRequestSchema`
- `html`: non-empty string.
- `getDocumentQuerySchema`
- `version`: optional positive integer parsed from the query string.
- `listDocumentsQuerySchema`
- `access`: optional enum `"all" | "owned" | "shared"`, default `"all"`.
- `shareDocumentRequestSchema`
- `emails`: non-empty array of valid email strings.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Bound document and sharing payload sizes.

These schemas only require non-empty values, so authenticated callers can submit arbitrarily large HTML or recipient arrays. That creates unbounded parsing, database storage, and insert work; immutable versions make oversized content persistent. Add explicit maximum lengths/counts and enforce a request-body limit before parsing.

🤖 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/superpowers/specs/2026-06-12-docs-api-versioning-design.md` around lines
198 - 211, Update the API schemas createDocumentRequestSchema,
updateDocumentRequestSchema, and shareDocumentRequestSchema with explicit
maximum HTML/string lengths and recipient-array counts, and add a request-body
size limit before request parsing in the documented API flow. Preserve the
existing non-empty, optional, and enum validation behavior while ensuring
oversized payloads are rejected before parsing or persistence.

Comment on lines +241 to +247
Behavior:

1. Build `ApiContext`.
2. Validate request body with Zod.
3. Insert `documents` with the current local user as owner.
4. Insert `document_versions` with `versionNumber = 1`.
5. Return `201`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Make every multi-write document workflow atomic.

Both creation and update can leave partially committed state unless all related writes share one transaction.

  • docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md#L241-L247: transactionally insert the document and initial version.
  • docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md#L316-L318: transactionally insert the new version and update documents.updatedAt.
📍 Affects 1 file
  • docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md#L241-L247 (this comment)
  • docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md#L316-L318
🤖 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/superpowers/specs/2026-06-12-docs-api-versioning-design.md` around lines
241 - 247, Make both multi-write document workflows atomic in
docs/superpowers/specs/2026-06-12-docs-api-versioning-design.md: lines 241-247
must transactionally insert the document and its initial document_version, while
lines 316-318 must transactionally insert the new version and update
documents.updatedAt. Ensure each related write shares one transaction and
preserves the existing response behavior.

Comment on lines +271 to +278
Behavior:

1. Build `ApiContext`.
2. Validate route params and query string with Zod.
3. Verify the current user can access the document.
4. Load the requested version or latest version.
5. Return `404` if the document or requested version does not exist.
6. Return `403` if the document exists but the current user cannot access it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Avoid disclosing document existence to unauthorized users.

Returning 403 for existing documents and 404 for missing ones lets authenticated callers probe document IDs; those IDs are returned by the API. Prefer 404 for both inaccessible and missing documents, or explicitly document and mitigate this existence disclosure.

🤖 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/superpowers/specs/2026-06-12-docs-api-versioning-design.md` around lines
271 - 278, Update the documented API behavior so unauthorized access to an
existing document returns 404, matching the response for missing documents and
preventing document-existence disclosure. Revise the relevant behavior steps to
remove the separate 403 outcome while preserving validation, authorization, and
version-loading semantics.

Comment on lines +466 to +510
## Testing

Use Vitest and follow the existing unit-test style.

Test the contract layer:

- Create request accepts valid input.
- Create request rejects missing name and empty HTML.
- Query schema parses positive integer versions.
- Share schema normalizes and deduplicates emails.
- DB insert schemas reject invalid persisted shapes.

Test the API context helper:

- Returns `401` when Clerk has no authenticated user.
- Returns `409` when a Clerk user exists but no active local user row exists.
- Returns `ApiContext` with local user and normalized email when present.

Test the API foundation:

- Handler wrapper catches typed `ApiError` instances and returns the expected status and JSON error envelope.
- Handler wrapper catches unexpected errors, logs them through `src/server/foundation/logs.ts`, and returns a generic `500`.
- Request parser in the handler layer returns `400` for malformed JSON.
- Zod request helpers in the handler layer format validation failures without echoing submitted HTML.
- Completion logs include request id, method, pathname, status, duration, and user id when available.

Test the document service:

- Create inserts metadata and initial version.
- Get latest version defaults correctly.
- Get specific version returns requested HTML.
- Owner can read and update.
- Shared email can read.
- Shared email cannot update.
- Owner and shared user can share.
- List returns owned, shared, or all based on the filter.
- User without primary email gets no shared documents.

Test HTTP handlers with mocked service/context dependencies where useful:

- `POST /api/docs` returns `201`.
- `GET /api/docs/{id}` returns latest by default.
- `PUT /api/docs/{id}` returns `403` for non-owner.
- `GET /api/docs?access=shared` validates the filter.
- `POST /api/docs/share/{id}` validates emails.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Add tests for the core invariants.

The test plan omits create rollback, concurrent update retry/atomicity, normalized email matching, and unauthorized-document response behavior. These should be required coverage because they protect the design’s main data-integrity and authorization contracts.

🧰 Tools
🪛 LanguageTool

[style] ~482-~482: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... but no active local user row exists. - Returns ApiContext with local user and normal...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~508-~508: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...test by default. - PUT /api/docs/{id} returns 403 for non-owner. - `GET /api/docs?a...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🤖 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/superpowers/specs/2026-06-12-docs-api-versioning-design.md` around lines
466 - 510, Expand the Testing section to require coverage for core invariants:
create rollback on failure, concurrent update retry and atomicity,
normalized-email matching for sharing/access, and unauthorized-document
responses that preserve the intended security behavior. Place these alongside
the existing document service and HTTP handler tests, without removing current
coverage.

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