Apply four low-risk fixes from final code review of the consolidated
add-stock modal: reset newStock on modal close, dedupe stock-item
loading through the existing helper, correct stale empty-state copy
about inventory fallback, and remove a stray blank line left from the
old form deletion.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Editing an inventory-sourced job stock row opened the Edit Stock modal
with the Stock Length dropdown blank instead of showing the row's
current length. EditStock() correctly set newStock.StockItemId from
the row, but then called the fire-and-forget OnStockMaterialChanged(),
which (a) unconditionally reset StockItemId to null, and (b) never
triggered a re-render since its Task wasn't awaited by the event
handler pipeline. Made EditStock async and await a dedicated loader
that populates availableStockItems without touching StockItemId, so
Blazor re-renders once the candidate lengths arrive.
Found during Task 2 manual verification of the unified Add Stock
modal (Step 6).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the three separate surfaces (bulk import modal, inline custom-length
form, inline edit forms) with one "Add Stock" button and modal that handles
both add and edit, for both inventory-sourced and custom-length stock.
Job Edit page's Stock tab currently has three inconsistent entry points
(bulk import modal, inline custom-length form, inline edit forms) for
what should be a single add/edit stock flow.
Three small leftovers from Task 7 / the inventory-quantity-tracking
removal that a final review caught:
- Edit.razor's custom-stock quantity input still had min="1" even
though its own helper text says "Use -1 for unlimited", validation
already accepts -1, and the add-form defaults Quantity to -1 - so
the field rendered pre-populated with a value the browser's native
min validation flagged as invalid. Matches the min="-1" fix already
applied to the catalog-stock input in Task 7.
- optimize_job's MCP tool description still claimed the optimizer
falls back to "available inventory" when no stock is configured -
that auto-discovery fallback was removed in Task 3. An LLM reads
this description as ground truth, so stale wording here actively
misleads tool use. Also tightened add_job_stock's stockItemId/
isCustomLength wording, which still said "inventory" for what is
now just the stock catalog.
- CLAUDE.md's CutListPackingService summary said InStockBins comes
"from inventory", nudging future readers back toward the
auto-discovery mental model this plan removed.
Task 7 extended JobStock.Quantity = -1 (unlimited) to catalog-sourced
rows, but the post-pack classification step in CutListPackingService
only ever treated a catalog-sourced bin as "in stock" when its tracked
quantity was a positive finite number. An unlimited catalog row fell
through to "to be purchased" even though IsInStock=true just means the
bin is catalog-sourced, not a quantity check.
This made the classification effectively unreachable for the most
common path users take to stock a job: the "Import from Inventory"
modal defaults every candidate's quantity to -1, so every resulting
bin was mislabeled "to be purchased" on the Results tab, and the
"everything is available in stock" message could never appear for
jobs stocked that way.
Track unlimited catalog-sourced lengths in a separate set and check it
first; finite catalog quantities keep the existing decrementing-counter
behavior, and custom-length stock (any quantity) is unaffected.
Custom-length job stock already supported -1 (unlimited); catalog-
sourced stock only allowed >= 1. Closes that inconsistency per
docs/superpowers/specs/2026-08-01-remove-inventory-quantity-tracking-design.md.
Also updates the Results tab's unplaced-items message now that
insufficient configured quantity is a normal cause, not an edge case.
Final step of removing inventory quantity tracking - see
docs/superpowers/specs/2026-08-01-remove-inventory-quantity-tracking-design.md.
Destructive to any existing on-hand/transaction data; confirmed
acceptable since nothing read it automatically.
The fallback silently pulled from StockItem.QuantityOnHand and always
added an extra unlimited bin on top when a job had no stock configured
- i.e. it assumed unlimited purchasing. Per
docs/superpowers/specs/2026-08-01-remove-inventory-quantity-tracking-design.md,
a job's available stock must now be exactly what's explicitly entered.
No job workflow ever called these (receive/use/adjust/scrap/recalculate)
- inventory quantity tracking is being removed per
docs/superpowers/specs/2026-08-01-remove-inventory-quantity-tracking-design.md.
First step of removing inventory quantity tracking (see
docs/superpowers/specs/2026-08-01-remove-inventory-quantity-tracking-design.md).
UI no longer shows on-hand counts or offers transaction entry; the
underlying field/service methods are removed in follow-up commits.
Users need to enter parts/stock and get results without a disconnected
inventory system to manage; StockItem.QuantityOnHand and StockTransaction
today aren't read or written by the job workflow anywhere except an
auto-discovery fallback that silently assumes unlimited purchasing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CLAUDE.md still listed GetAverageCostAsync/GetLastPurchasePriceAsync, which
Task 1 of the vendor-data removal already deleted. Also stop tracking the
Playwright MCP browser session logs left behind by Task 10's smoke test.
Ten-task plan ordered so the build stays green at each step: strip
consumers first (StockItemService/DTOs/Controller, Stock/Edit.razor,
Suppliers/Orders pages, Jobs/Edit.razor, CatalogService), delete the
now-unused services, then remove the entities and migrate the schema
last. Closes with CutList.Mcp cleanup and a manual smoke test.
Scopes out Supplier, SupplierOffering, PurchaseItem, and cost tracking
as out-of-scope for a 1D nesting optimizer, while fixing the actual
reported bug (read-only stock length field) and keeping a stripped
quantity-only transaction log.
Adds a Dockerfile and Gitea Actions workflow to build/push the
CutList.Web image to the registry on push to master, enabling
containerized deployment to forge. Also updates CLAUDE.md to reflect
the CutList.Mcp project, REST API surface, and CatalogService, and
tweaks the cut-length badge styling in the job editor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Drop the Stock/Purchase source badge column from the results cut list
table (purchase list card remains). Bump cut length badges to fs-6 for
better readability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Point API client at the deployed service port and clear logging
providers to prevent interference with MCP stdio transport.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Display raw inches in parentheses next to the architectural format
in both Parts and Stock tables for easier reference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap job editor initialization in try/catch to display errors instead of
crashing the circuit. Make LoadSavedResults async. Add a simple Error
page for the production exception handler.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace AddDbContext with AddDbContextFactory for Blazor Server circuit
safety — each service method now creates a short-lived DbContext via the
factory. Configure Windows Service hosting with ContentRootPath and
remove HSTS/HTTPS redirect for reverse-proxy deployment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update all project TFMs to net10.0, EF Core to 10.0.4, add
Microsoft.Extensions.Hosting.WindowsServices, and suppress WFO1000
warning for WinForms project.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the single CatalogMaterialDto + CatalogDimensionsDto (bag of nullable
fields) with per-shape DTOs that have strongly-typed dimension properties.
Catalog JSON now groups materials by shape key instead of a flat array.
Delete the old SeedController/SeedDataDtos (superseded by CatalogService).
Scraper updated to emit the new grouped format, resume by default, and
save items incrementally.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch MaterialDimensions inheritance from TPH (single table with discriminator)
to TPC (table per concrete type) with individual tables per shape. Add Swagger
for dev API exploration, expand SeedController with export/import endpoints and
Alro catalog JSON dataset, and include Python scraper for Alro catalog PDFs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Part form now supports adding multiple parts at once via a table with
add/remove row controls; edit mode stays single-row
- Shape and size dropdowns lock when editing an existing part
- Results tab replaces split in-stock/purchase cards with a unified table
per material showing source badges (Stock/Purchase) for each bar
- New Purchase List card summarizes materials to order with quantities
- Print styles use repeating thead headers per material for multi-page
cut lists; large cards can now break across pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the standalone ExportData console app and hardcoded SeedController
with generic GET /api/catalog/export and POST /api/catalog/import endpoints.
Import uses upsert semantics with per-item error handling, preserving
existing inventory quantities.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Export tool queries all active materials, stock items, suppliers, and
offerings from the database and writes a clean JSON file for version
control. Includes 616 materials and 810 stock items with part numbers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add HTTP client methods for job CRUD, parts, stock, packing, and
cutting tool endpoints. Includes response DTOs for all job-related
API responses.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document new Job entity fields, serialization DTOs, JobService
optimization methods, and merged Results tab in Edit page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>