Performs structured code review on a diff or file set, producing inline comments with severity levels and a summary. Checks correctness, error handling, security, and maintainability — in that priority order. Use when reviewing a pull request, when the user asks for a code review, when preparing code for merge, or when a second opinion is needed on a change.
Install with Tessl CLI
npx tessl i github:santosomar/general-secure-coding-agent-skills --skill code-review-assistant100
Quality
100%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Review code as a senior engineer would: find the bug that will page someone at 3am, not the missing semicolon. Every comment should be one the author couldn't have found with a linter.
Stop after any tier that produces a Blocking finding. There is no value in reporting naming nits on code that deletes the wrong rows.
Read in this order:
If the PR description is empty or says "misc fixes" — your first comment is asking for a description. You cannot review intent you don't know.
For every changed function, hold the stated intent (from the PR description) against the implementation. Specific checks:
< vs <=, len-1 vs len, slice end-exclusive vs inclusive. If you see a loop boundary change in the diff, verify against one concrete example.if (!isValid || !isEnabled) — expand De Morgan's in your head and verify the truth table is what the author meant.return in the middle of a function that previously had a single exit → does it skip a close() / unlock() / commit() that used to run?await on a promise-returning call is a silent future bug. Every call to an async function should be awaited, explicitly voided, or collected for Promise.all.For each changed function, walk the inputs:
| Input shape | Ask |
|---|---|
| Collection / array | What if it's empty? What if it has one element? |
| Optional / nullable | Is it checked before first deref? Is there a test for the null path? |
| String | Empty string? Whitespace-only? Longer than the DB column? |
| Number | Zero? Negative? Larger than the downstream type can hold? |
| External call | What if it throws? Times out? Returns a shape you don't expect? |
| Map / dict lookup | What if the key is absent? |
Catch blocks deserve extra scrutiny. A catch that just logs and continues turns a loud failure into a silent data corruption. Ask: is the system in a valid state after this catch runs? If not → Blocking.
Not a full audit — just the things a reviewer spots in a diff:
exec, eval, system, child_process, subprocess, Runtime.execpickle.loads, yaml.load, ObjectInputStream, unserialize)For anything beyond a spot check, defer: "→ run static-vulnerability-detector on this path before merge."
Do not comment on code the PR didn't touch. If a function was already 200 lines and the PR adds 3 lines to it, the 200-line problem is pre-existing tech debt, not this author's responsibility. At most: one summary-level comment suggesting a follow-up, never inline.
On code the PR did introduce:
| Level | Meaning | Author's obligation |
|---|---|---|
| Blocking | Merge will cause a bug, security issue, or data loss | Must fix before merge |
| Should-fix | Will cause pain later; fix is clear and scoped | Fix now or open a follow-up with a link |
| Nit | Preference. Reasonable people disagree. | Author's call. No re-review needed. |
| Question | You don't understand; might be fine, might not | Author answers; you decide severity from the answer |
Do not mark something Blocking to win a style argument. Blocking means "this will break production." If you're not confident it will, it's Should-fix at most.
## Summary
Adds retry-with-backoff to the payment client.
1 blocking (retries non-idempotent POST), 1 should-fix, 2 nits.
Recommend addressing the blocking finding before approval.
## Findings
### src/payments/client.ts:45 [Blocking]
Retry wraps `POST /charges`. That endpoint is not idempotent — a
transient 503 after the charge succeeded server-side will retry and
double-charge the customer.
→ Either: pass an Idempotency-Key header and have the server dedupe,
or only retry on errors that guarantee the request never reached the
server (connection refused, DNS failure).
### src/payments/client.ts:52 [Should-fix]
Backoff is 2^attempt seconds, uncapped. Attempt 10 = 17 minutes.
→ Cap at 30s: `Math.min(2 ** attempt, 30)`.
### src/payments/client.ts:38 [Nit]
`let` could be `const` — `delayMs` is never reassigned.
### test/payments.test.ts:140 [Question]
This test asserts 3 retries, but I don't see where the max is
configured. Is it hardcoded or am I missing a fixture?Diff:
async function deleteUser(userId) {
- const user = await db.users.findById(userId);
- if (!user) throw new NotFoundError();
- await db.users.delete(userId);
+ await db.users.delete(userId);
+ await cache.invalidate(`user:${userId}`);
}Review:
db.users.delete(nonexistentId) — what does it do? If it's a no-op that returns 0 rows affected, fine. If it throws, the error changed from NotFoundError to a DB error — API contract break. → Question.delete succeeds but cache.invalidate throws, the user is gone from the DB but the cache still serves them. Next read is a ghost. → Should-fix: invalidate first, or catch-and-log the cache failure since the DB is source of truth.47d56bb
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.