Added the recipes page at /recipes: paste a plain-text recipe (a… #9

Merged
cmoriarty merged 3 commits from osf/73-172-comparison-arm-single-small-scale into compare/single-small 2026-10-17 11:43:22 -04:00
Owner

What was done

  • Added the recipes page at /recipes: paste a plain-text recipe (a Serves N line, then one ingredient a line), scale it to the servings entered, and see each line that did not read reported with its line number.
  • The work is split into four small, separately tested modules — reading, scaling and formatting, unit conversion, and the shopping list — so each can be built and tested apart and they meet only in the page.
  • Amounts are shown in Metric or US using a per-kind unit ladder that keeps the number readable (1,500 g as 1.5 kg, a small volume as 1/2 cup), and a positive amount never displays as 0.
  • A recipe can be added to a shopping list of at most five, summing the same ingredient across recipes (matched by name, ignoring case and a plural s, in the same unit) and sorting the list by name; a sixth add is refused.
  • The shopping list travels with the page in hidden form fields rather than in the database or a cookie, so the page stays server-rendered and starts empty again on a fresh visit.
  • Covered the four pieces and the page with six unit suites and a browser spec, and updated the README and CHANGELOG; the unit suites and the project's CI pass, and the page was opened in a real browser as a person would and found to have no remaining defect.
  • Not done: converting between weight and volume (a cup of flour in grams) is out of scope because it needs a density per ingredient.
  • Not done: the shopping list is per-visit only — recipes and lists are not stored anywhere, so it is lost when the page is reopened.

How to review

  1. Get the branch: git fetch origin && git checkout osf/73-172-comparison-arm-single-small-scale; the diff against origin/compare/single-small is the whole change.
  2. Run the unit tests: npm test — it provisions its own Postgres and runs every suite; expect all green, including the new reading, scaling, conversion, shopping-list and recipes-page / recipes-server suites.
  3. Start the app and open the page: point DATABASE_URL at a reachable Postgres (see the README's Run section), npm install and npm start, then open http://localhost:3000/recipes — expect the recipe form (Recipe, Servings, Metric/US, Show recipe, Add to list) and "The shopping list is empty."
  4. Use the page: paste Serves 2, 200 g flour, a pinch of salt, 2 eggs, set Servings to 4 and choose US, press Show recipe — expect 14 oz flour, 4 eggs and a red Line 3: a pinch of salt (no quantity); then press Add to list a few times and expect the list to sum by name and to refuse a sixth.
  5. Read the code first: open src/pages.ts (the form and result markup) and src/server.ts (the /recipes routes); the logic is in src/recipe.ts, src/scale.ts, src/convert.ts and src/shopping.ts.

Code review

Reviewed the whole scale-recipes-and-shopping-list commit: src/recipe.ts (UNITS, parseQuantity, parseIngredientLine, parseRecipe), src/scale.ts (scaleRecipe, formatAmount, formatIngredient), src/convert.ts (System, convertIngredient), src/shopping.ts (MAX_RECIPES, addRecipe, shoppingList), the recipesPage in src/pages.ts, the GET/POST /recipes routes in src/server.ts (sitting before the GET / branch), the six new scenario-tagged test files, the pre-existing test/server.test.ts, e2e/recipes.spec.ts, and the README.md/CHANGELOG.md/tasks.md docs changes. Manually verified the arithmetic (200 g -> 14 oz at x2, 1500 g -> 1.5 kg, 2 l -> 8.454 cup, 120 ml -> 0.507 cup, 9.96 -> "10 oz", 0.05 tsp -> "1/4 tsp", 7/24 tie -> 1/4) and the shopping-list sort (no unit first, then UNITS order). Three edge cases were deliberately judged NOT findings: (a) the hidden-field toFixed(6).replace making "0.000000" into "" at src/server.ts:131 is unreachable because parseQuantity refuses 0, the scale factor is positive, and the hidden fields re-parse through the same reader; (b) scaleRecipe accepting "4.0" as 4 is fine, the spec only pins 0/2.5/two as refused; (c) a recipe with no Serves line and no ingredients is not covered by the spec. The six-decimal round-trip is proven by the e2e test (4 eggs + 2 eggs -> 6 eggs). No generated, cached or secret files in the commit; .gitignore already covers node_modules/, test-results/ and playwright-report/; the .osf/* records are meant to be committed. No code changes were made: every check passed; the only failure in the whole run was a bug in my own runner script (DATABASE_URL sourced without export, so the Playwright webServer never saw it), which was fixed outside the repo and the e2e run then passed 2/2.

It found nothing to fix.

Tests

All 47 scenarios of scale-recipes-and-shopping-list have a tagged test.

The test lint found, in the run's tests on the last check:

Recorded, not decided

  • e2e/recipes.spec.ts:1 B7: no relative import: this file asserts on things it constructed itself, which is the measured 'asserted on my own mock' failure
  • test/recipes-page.test.ts:1 B7: nothing imported here looks like the module under test ('recipes-page')
  • test/recipes-server.test.ts:1 B7: nothing imported here looks like the module under test ('recipes-server')

Braid run

  • Workflow: Braid's OpenSpec flow, change scale-recipes-and-shopping-list (22 steps)
  • Issue: cmoriarty/braid-combined-test#4
  • Model: vLLM · qwen3.8-27b
  • Time: 1 h 49 m from start to this pull request, 1 h 46 m of it in the model
  • Tokens: 10.5M input, 82k output, 201k reasoning, over 362 model calls
  • Pre-flight estimate: fits-flagged, p50 198k / p80 278k tokens against a 86k-token step allowance
  • CI: passed its 6 jobs on 0f280b1257
  • Run: run_01M55284MNP9F2CE8NK5D3D96A

Opened by Braid.

## What was done - Added the recipes page at /recipes: paste a plain-text recipe (a `Serves N` line, then one ingredient a line), scale it to the servings entered, and see each line that did not read reported with its line number. - The work is split into four small, separately tested modules — reading, scaling and formatting, unit conversion, and the shopping list — so each can be built and tested apart and they meet only in the page. - Amounts are shown in Metric or US using a per-kind unit ladder that keeps the number readable (1,500 g as 1.5 kg, a small volume as 1/2 cup), and a positive amount never displays as 0. - A recipe can be added to a shopping list of at most five, summing the same ingredient across recipes (matched by name, ignoring case and a plural s, in the same unit) and sorting the list by name; a sixth add is refused. - The shopping list travels with the page in hidden form fields rather than in the database or a cookie, so the page stays server-rendered and starts empty again on a fresh visit. - Covered the four pieces and the page with six unit suites and a browser spec, and updated the README and CHANGELOG; the unit suites and the project's CI pass, and the page was opened in a real browser as a person would and found to have no remaining defect. - **Not done:** converting between weight and volume (a cup of flour in grams) is out of scope because it needs a density per ingredient. - **Not done:** the shopping list is per-visit only — recipes and lists are not stored anywhere, so it is lost when the page is reopened. ## How to review 1. Get the branch: `git fetch origin && git checkout osf/73-172-comparison-arm-single-small-scale`; the diff against `origin/compare/single-small` is the whole change. 2. Run the unit tests: `npm test` — it provisions its own Postgres and runs every suite; expect all green, including the new reading, scaling, conversion, shopping-list and recipes-page / recipes-server suites. 3. Start the app and open the page: point `DATABASE_URL` at a reachable Postgres (see the README's Run section), `npm install` and `npm start`, then open http://localhost:3000/recipes — expect the recipe form (Recipe, Servings, Metric/US, Show recipe, Add to list) and "The shopping list is empty." 4. Use the page: paste `Serves 2`, `200 g flour`, `a pinch of salt`, `2 eggs`, set Servings to `4` and choose US, press Show recipe — expect `14 oz flour`, `4 eggs` and a red `Line 3: a pinch of salt (no quantity)`; then press Add to list a few times and expect the list to sum by name and to refuse a sixth. 5. Read the code first: open src/pages.ts (the form and result markup) and src/server.ts (the /recipes routes); the logic is in src/recipe.ts, src/scale.ts, src/convert.ts and src/shopping.ts. ## Code review Reviewed the whole scale-recipes-and-shopping-list commit: src/recipe.ts (UNITS, parseQuantity, parseIngredientLine, parseRecipe), src/scale.ts (scaleRecipe, formatAmount, formatIngredient), src/convert.ts (System, convertIngredient), src/shopping.ts (MAX_RECIPES, addRecipe, shoppingList), the recipesPage in src/pages.ts, the GET/POST /recipes routes in src/server.ts (sitting before the GET /<code> branch), the six new scenario-tagged test files, the pre-existing test/server.test.ts, e2e/recipes.spec.ts, and the README.md/CHANGELOG.md/tasks.md docs changes. Manually verified the arithmetic (200 g -> 14 oz at x2, 1500 g -> 1.5 kg, 2 l -> 8.454 cup, 120 ml -> 0.507 cup, 9.96 -> "10 oz", 0.05 tsp -> "1/4 tsp", 7/24 tie -> 1/4) and the shopping-list sort (no unit first, then UNITS order). Three edge cases were deliberately judged NOT findings: (a) the hidden-field toFixed(6).replace making "0.000000" into "" at src/server.ts:131 is unreachable because parseQuantity refuses 0, the scale factor is positive, and the hidden fields re-parse through the same reader; (b) scaleRecipe accepting "4.0" as 4 is fine, the spec only pins 0/2.5/two as refused; (c) a recipe with no Serves line and no ingredients is not covered by the spec. The six-decimal round-trip is proven by the e2e test (4 eggs + 2 eggs -> 6 eggs). No generated, cached or secret files in the commit; .gitignore already covers node_modules/, test-results/ and playwright-report/; the .osf/* records are meant to be committed. No code changes were made: every check passed; the only failure in the whole run was a bug in my own runner script (DATABASE_URL sourced without export, so the Playwright webServer never saw it), which was fixed outside the repo and the e2e run then passed 2/2. It found nothing to fix. ## Tests All 47 scenarios of `scale-recipes-and-shopping-list` have a tagged test. The test lint found, in the run's tests on the last check: **Recorded, not decided** - `e2e/recipes.spec.ts:1` B7: no relative import: this file asserts on things it constructed itself, which is the measured 'asserted on my own mock' failure - `test/recipes-page.test.ts:1` B7: nothing imported here looks like the module under test ('recipes-page') - `test/recipes-server.test.ts:1` B7: nothing imported here looks like the module under test ('recipes-server') ## Braid run - **Workflow:** Braid's OpenSpec flow, change `scale-recipes-and-shopping-list` (22 steps) - **Issue:** cmoriarty/braid-combined-test#4 - **Model:** vLLM · qwen3.8-27b - **Time:** 1 h 49 m from start to this pull request, 1 h 46 m of it in the model - **Tokens:** 10.5M input, 82k output, 201k reasoning, over 362 model calls - **Pre-flight estimate:** fits-flagged, p50 198k / p80 278k tokens against a 86k-token step allowance - **CI:** passed its 6 jobs on `0f280b1257` - **Run:** [run_01M55284MNP9F2CE8NK5D3D96A](http://openspecflow.internal.underthere.xyz/run/run_01M55284MNP9F2CE8NK5D3D96A) _Opened by Braid._
check: the code of fix-loop round 1, for the project's CI
All checks were successful
CI / Release notes (push) Successful in 10s
CI / Unit tests (push) Successful in 48s
CI / Unit tests (pull_request) Successful in 1m5s
CI / Release notes (pull_request) Successful in 9s
CI / Browser tests (pull_request) Successful in 1m9s
CI / Browser tests (push) Successful in 58s
cc8599ab75
cmoriarty force-pushed osf/73-172-comparison-arm-single-small-scale from cc8599ab75
All checks were successful
CI / Release notes (push) Successful in 10s
CI / Unit tests (push) Successful in 48s
CI / Unit tests (pull_request) Successful in 1m5s
CI / Release notes (pull_request) Successful in 9s
CI / Browser tests (pull_request) Successful in 1m9s
CI / Browser tests (push) Successful in 58s
to 0f280b1257
All checks were successful
CI / Browser tests (push) Successful in 1m1s
CI / Release notes (push) Successful in 10s
CI / Unit tests (push) Successful in 49s
CI / Unit tests (pull_request) Successful in 1m19s
CI / Browser tests (pull_request) Successful in 1m7s
CI / Release notes (pull_request) Successful in 8s
2026-10-17 11:20:18 -04:00
Compare
cmoriarty changed title from Scale a recipe, convert its units, and build a shopping list to Added the recipes page at /recipes: paste a plain-text recipe (a… 2026-10-17 11:43:07 -04:00
cmoriarty force-pushed osf/73-172-comparison-arm-single-small-scale from 0f280b1257
All checks were successful
CI / Browser tests (push) Successful in 1m1s
CI / Release notes (push) Successful in 10s
CI / Unit tests (push) Successful in 49s
CI / Unit tests (pull_request) Successful in 1m19s
CI / Browser tests (pull_request) Successful in 1m7s
CI / Release notes (pull_request) Successful in 8s
to add69a60a8
All checks were successful
CI / Browser tests (push) Successful in 1m2s
CI / Unit tests (pull_request) Successful in 1m7s
CI / Release notes (pull_request) Successful in 10s
CI / Browser tests (pull_request) Successful in 1m13s
CI / Release notes (push) Successful in 9s
CI / Unit tests (push) Successful in 48s
2026-10-17 11:43:08 -04:00
Compare
cmoriarty merged commit 1a47518bb7 into compare/single-small 2026-10-17 11:43:22 -04:00
cmoriarty deleted branch osf/73-172-comparison-arm-single-small-scale 2026-10-17 11:43:23 -04:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cmoriarty/braid-combined-test!9
No description provided.