Skip to content
Back to skills

Language 2026 10 08

ASecurity

**The function throws on every input, including the one case it was written for.** It never returns a number. Measured with Node, not reasoned about: ``` normal [{price:100,qty:2},{price:50,qty:1}] => THREW TypeError: Cannot read properties of undefined (reading 'price') empty [] => THREW TypeError: Cannot read properties of undefined (reading 'price') single [{price:100,qty:1}] => THREW TypeError: Cannot read properties of undefined (re...

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 26, 2026
ai-agentsgonode

Security analysis

A100/100

Pro scans all 19 files and shows the line behind each finding

Scanned October 26, 2026

npx -y skills add Siririn77/i-have-autism --skill language-2026-10-08 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Language 2026 10 08?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Language 2026 10 08
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/siririn77-language-2026-10-08-ff44d514/badge)](https://www.skillsdirectory.com/skills/siririn77-language-2026-10-08-ff44d514)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Review: `total(items)`

**The function throws on every input, including the one case it was written for.** It never returns a number.

Measured with Node, not reasoned about:

```
normal  [{price:100,qty:2},{price:50,qty:1}] => THREW TypeError: Cannot read properties of undefined (reading 'price')
empty   []                                   => THREW TypeError: Cannot read properties of undefined (reading 'price')
single  [{price:100,qty:1}]                   => THREW TypeError: Cannot read properties of undefined (reading 'price')
```

There is no input on which this code works, so everything below the first defect is blocked behind it.

---

## Defects, in order of severity

### 1. Off-by-one in the loop bound — the fatal defect

```js
for (let i = 0; i <= items.length; i++)
```

The last valid index is `items.length - 1`. `i <= items.length` runs one iteration past the end, where
`items[i]` is `undefined`, and reading `undefined.price` throws.

This is the `<=` / `<` defect: the loop was written to include the end index and included one too many.

The function does not work even on its happy path. Fix first:

```js
for (let i = 0; i < items.length; i++)
```

Or remove the index entirely, which also removes the chance of repeating the mistake:

```js
for (const item of items) {
  sum += item.price * item.qty;
}
```

### 2. The function does two jobs, and the name hides the second one

`total` computes a sum **and** writes `items.total = sum`. Two effects, one name.

A caller reading `total(order)` expects a calculation. It cannot see that the argument is mutated. Per the
code's own standard — a name is a label that touches the body — the name is wrong, and the mutation is a
surprise (defect class: mutating an argument).

Split them so each name states one effect:

```js
// Computes the order total in integer kopecks. Does not modify `items`.
function computeTotalKopecks(items) {
  let sum = 0;
  for (const item of items) {
    sum += item.price * item.qty;
  }
  return sum;
}

// Stores the total on the order.
function applyTotal(items) {
  items.total = computeTotalKopecks(items);
}
```

Note the unit in the name. The current name `total` does not say whether it returns rubles or kopecks, and
the body is not consistent about it (see defect 3).

### 3. Unit conversion happens inside the sum; the comment says otherwise

The leading comment is `// Считает суммарную стоимость заказа и сохраняет её.` — "computes the order total and
saves it". But the function returns `sum / 100`, i.e. rubles, while `items.total` is assigned `sum`, i.e.
kopecks. **Two different units leave this one function**, and neither name says which one.

The comment and the code disagree about what is saved. One unit must be chosen and named:

```js
// Integer kopecks on the wire: money is never a float.
function computeTotalKopecks(items) { /* ... */ }
function toRubles(kopecks) { return kopecks / 100; }
```

Rubles as a float is acceptable **only** at the display boundary. Keeping money as an integer (kopecks) inside
the domain avoids the float rounding that loses a kopeck on large orders. This is the one place the review
spends correctness budget fully, because it is money.

### 4. No handling of `null`, `undefined`, or a missing `items`

`total(undefined)` and `total(null)` throw a `TypeError` from `items.length`, which is a worse message than
the caller deserves. State the contract: either guard, or document that `items` must be an array.

### 5. Missing or non-numeric fields are accepted silently

If any item has no `price` and no `qty`, or has them as strings (`"100"`), the multiplication produces `NaN`,
`sum` becomes `NaN`, and the function returns `NaN` with no error. Money silently becomes `NaN`.

Decide the contract and enforce it: reject the item with a message that names the offending index and field,
rather than returning poison.

---

## Suggested rewrite

```js
// Computes the total in integer kopecks, then stores it on the order.
// Returns rubles for display; the stored value stays in kopecks to avoid float rounding.
function total(items) {
  if (!Array.isArray(items)) {
    throw new TypeError('total(items): expected an array, got ' + typeof items);
  }

  let kopecks = 0;
  for (const item of items) {
    if (typeof item.price !== 'number' || typeof item.qty !== 'number') {
      throw new TypeError('total(items): item.price and item.qty must be numbers');
    }
    kopecks += item.price * item.qty;
  }

  items.total = kopecks;
  return kopecks / 100;
}
```

The loop bound is gone (no off-by-one possible). The unit is named in the variable (`kopecks`), not in a
trailing comment. The bad inputs fail with a message that says which value was wrong.

---

## The comment, re-checked

Two comments survive the four-question check:

- `// сохраняем итог в объект` (`// save the total into the object`) — **delete.** The code `items.total = sum`
  already says "assign the total field". The comment restates the line. Per rule 13, delete it and make the
  name do the work.
- The header comment — keep, but it must match the fixed behavior. As written it misdescribes the units.

---

## What I checked

- **Loop bound** → `<=` reads one past the end → throws on every input. Confirmed by running the function.
- **Empty array** → throws (index `0` is `undefined`). Should return `0`.
- **Single item** → throws. Should return that item's line total.
- **Mutation of the argument** → `items.total` is written; the name `total` does not announce it.
- **Units** → returns rubles, stores kopecks; comment and code disagree; names say neither.
- **`null` / non-array `items`** → throws from `items.length`.
- **Non-numeric `price`/`qty`** → silently yields `NaN`, no error.

## Left as is (deliberate)

- The style of the surrounding file (single `function`, no module wrapper) — kept, per "consistency beats
  taste". Rewrite changes behavior and clarity, not the file's conventions.
- Did not add a rounding choice for the ruble return — that is a product decision (round, floor, or throw on
  remainders); the fix keeps the exact division until a rule is chosen.

## Next action

Replace the loop bound `i <= items.length` with `i < items.length`, then re-run the three cases above; all
three should stop throwing.

Files in this skill

  • T1_with-skill.md11.8 KB
  • T1_without-skill.md6.4 KB
  • T2_with-skill.md9.1 KB
  • T2_without-skill.md4.5 KB
  • T3_with-skill.md1.9 KB
  • T3_without-skill.md1.5 KB
  • T4_with-skill.md1.2 KB
  • T4_without-skill.md1.1 KB
  • T5_with-skill.md6.2 KB
  • T5_without-skill.md3.5 KB
  • T6_with-skill.md5.6 KB
  • T6_without-skill.md3.7 KB
  • T7_with-skill.md1.9 KB
  • T7_without-skill.md2.3 KB
  • T8_with-skill.md2.9 KB
  • T8_without-skill.md4.4 KB
  • T9_with-skill.md7.1 KB
  • T9_without-skill.md3.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in ai-agents →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.