mrp archive: Log 2026-09-11 to 2026-09-28¶
Archived from mrp (Log entries dated 2026-09-11 to 2026-09-28); moved verbatim, nothing summarised. Return to mrp.
- 2026-09-11 19:50: Public URL live — https://erp.embeddedera.com behind Cloudflare Access + Tunnel (
cloudflared-plexuser service). Roles (Owner/Assembler/Purchasing/Read-only) created;erp-backupnightly to R2 with a passing weekly restore test. Phase 1 complete. Angel to do: put the age private key in Vaultwarden; enroll TOTP; walk the first-assembly path. - 2026-09-11: Note created; scout launched; plan skeleton written before the tool is chosen.
- 2026-09-11: Scout back. InvenTree chosen (mrp-tool). Odoo ruled out (quality is paid), ERPNext kept as the fallback. Next: phase 1 stand-up on the box behind a Cloudflare Tunnel + Access.
- 2026-09-11: Phase 1 up — 5 containers (
inventree-db/cache/server/worker/proxy) in the torrentvpn stack, LAN-only aterp.lanvia NPM (publicerp.embeddedera.com+ Cloudflare Access is still a later phase, not done yet). Admin loginangel; creds~/.config/credentials/inventree.txt; API token for scripts in~/.config/inventree/env. Seeded via API: 10 part categories (Assemblies/PCBs/Components+4 children/Mechanical/Consumables/Firmware), 20 stock locations (Shop/Shelf A/Bins 01-10 + 8 process locations). Enabled settings: stock expiry, globally-unique serials, parts trackable by default, test station data, block build-completion/sales-order-allocation on incomplete tests, reports; enabledinventreelabelsheetplugin (label+report plugins otherwise already on by default). Map card: inventree. Next: Angel's first hands-on pass (real product + BOM + build + test + ship, per mrp.md's "first hands-on path"), then the Cloudflare Tunnel/Access subdomain phase. - 2026-09-11: Section G done — role groups created via
/api/user/ruleset/{id}/(not the group endpoint itself; its nestedroles/usersfields are read-only — permissions are set per-ruleset-pk, group membership viaPATCH /api/user/{id}/withgroup_ids, notgroups). Four groups: Owner (all 11 roles, all 4 perms), Assembler (part view; stock+build view/add/change; no purchase/sales/return/admin, no delete), Purchasing (part view; purchase_order view/add/change; stock view/add — InvenTree auto-elevates add→change, so Purchasing's stock role showscan_change:truetoo, that's the model enforcing "can't add what you can't edit," not a scope leak), Read-only (view on all 11 roles, nothing else).angeladded to Owner. MFA: no global "availability" toggle — TOTP is already available to every user via their own Account → Security page; the only global knob isLOGIN_ENFORCE_MFA(makes it mandatory), left off since no user has a TOTP device enrolled yet and flipping it now would lock everyone out. - 2026-09-11: Section "off-site backup" done —
~/.local/bin/erp-backup(backup/verify/list/restore), same house style ashistory-backup. Dumpsinventree-db/listmonk-db/immich-postgresviapg_dump -Fc(credentials read live viadocker exec printenv, not parsed from files, so a rotated password needs no script change), tars InvenTree media+.env,sqlite3 .backups vaultwarden. Encrypted withage(installed user-space from the GitHub release; keypair at~/.config/erp-backup/age.key, public key mirrored to~/.config/credentials/erp-backup.txt, private key still needs a manual copy into Vaultwarden). Local copy:/mnt/storage/EmbeddedEra/backups/erp/<stamp>/, 30-day retention, SnapRAID parity. Off-site: R2 bucketembeddedera-backups(created via API, 90-day lifecycle rule), pushed with the plain Cloudflare account REST API object PUT (.../r2/buckets/{bucket}/objects/{key}, bearer token) — the same mechanismlist-syncalready uses, confirmed working; skipped minting S3 access keys since that needs a token-creation permission this account token doesn't have (and the auto-mode classifier declined the attempt as a sensitive action, which was the right call — this fallback needed no new credential at all). Firstverifyrun restored the newest InvenTree dump into a throwawaypostgres:17container and got exactly the expectedpart_partcategory=10 /stock_stocklocation=20 — PASS. Cron:15 3 * * *backup (before the 03:30 snapraid sync),15 6 * * 0verify. Map: inventree "### Backup", schedules. - 2026-09-11: Single sign-on done — Access (Google) → InvenTree header trust (
INVENTREE_REMOTE_LOGIN), admin renamed toadiaz@embeddedera.com, NPMerp.lanstrips the header so LAN cannot forge it. Team renamed toembeddedera. Details in inventree card. - 2026-09-11: Suppliers seeded via API — DigiKey (1), Mouser (2), LCSC (3), JLCPCB (4), all USD, supplier-only. Manufacturers get added per part when BOMs load.
- 2026-09-11: User yrosado@embeddedera.com (InvenTree pk 3) added to Access policy + group "Sales & Purchasing" (renamed from Purchasing; now view/add/change on purchase_order, sales_order, return_order, stock; view on part, part_category). API gotcha: user membership is written with
group_ids,groupsis read-only. - 2026-09-11: SOPs started — seven drafts in
~/Notes/sops/docs/(part numbers, create part, locations, PO, receiving, build, sales order/invoice), published by~/.local/bin/sop-deploy(MkDocs Material in~/.local/share/mkdocs-venv, Pages projectembeddedera-sop) at https://sop.embeddedera.com behind Cloudflare Access app "EmbeddedEra SOPs" (same Google policy as the ERP). Statusdraftuntil walked through on a real job. Open: one-tile InvenTree dashboard plugin linking to the site (UserInterfaceMixin; no community plugin exists). - 2026-09-11:
soplinkplugin live — dashboard tile to https://sop.embeddedera.com (a navbar item was tried and removed: the 1.x SPA routes nav URLs internally, external links break). Each user adds the tile once: dashboard ⋮ → Add widget → "Standard operating procedures". Source~/torrentvpn/inventree/plugins-src/sop_link/, install steps in the README there.ENABLE_PLUGINS_INTERFACE=Trueset via API. Printing an SOP = browser Print → Save as PDF on the page (Material's print stylesheet). - 2026-09-11: home.embeddedera.com → Cloudflare Access App Launcher (tiles: ERP, SOPs, Vault, website). Card cloudflare-access. The InvenTree
soplinktile stays but is now optional. - 2026-09-11: home.embeddedera.com is now our own static page (
~/embeddedera-home,home-deploy), not a redirect to the App Launcher — the launcher URL in the address bar was the objection. - 2026-09-11: SOP revision control — front-matter version/status/updated rendered on every page (mkdocs-macros), Revision history table in each SOP, rules in SOP-000 Document control. Git history = the audit trail (
git log -- sops/docs/<file>). - 2026-09-11: SOP print stylesheet — dark screen theme was printing light-grey on white.
sops/docs/assets/brand.cssnow has an@media printblock forcing black on white, boxing the document-control banner, hiding nav/search/footer, and keeping steps from splitting across pages. - 2026-09-11: SOP print CSS was correct but browsers served the cached
brand.css. Fix: version the filename (brand.v2.css) on every style change — MkDocs does not hashextra_css. Also forced light backgrounds on code chips and tables for print. - 2026-09-11: Per-user light/dark everywhere — SOP site has Material's 3-state palette toggle (system/light/dark, remembered per browser); home page has its own toggle writing
data-theme+ localStorage; InvenTree already stores a per-user theme (avatar → Settings → Display). embeddedera.com stays dark by design (marketing). Stylesheet renames:brand.v3.css(MkDocs does not hash extra_css). - 2026-09-11: First part created —
EE-K-0001Antistatic bag 8 x 12 cm (Consumables), supplier Amazon (new company, SKU = ASINB077D45R7K). Part-number classes in use: K = consumable. Amazon listings block automated reads, so specs (shield type, mils, pack qty) are flagged in the part notes for Angel to confirm. - 2026-09-11: SOP-002 v1.1 — part image now mandatory (step 11: photograph anything you can hold, distributor photo OK for catalogue components, no customer/brand names in shot). SOP-005 v1.1 — photograph a first-time part at receiving and photograph any shortage/damage onto the PO.
- 2026-09-11: Print templates live — source
~/torrentvpn/inventree/templates-src/, installed/refreshed by~/.local/bin/erp-templates(idempotent: PATCHes by name). Five: Work Order Traveler (build; kit list + operation x P1-P4 sign-off grid + closing counts), Purchase Order, Packing Slip (no prices), Stock Label 62x29, Serial Label 25x25. All test-rendered to PDF and visually checked; temp test records deleted afterwards. Gotchas found: render is async — POST/api/report/print/or/api/label/print/then poll/api/data-output/forcomplete+output; a build must be cancelled (/api/build/<pk>/cancel/) and a part deactivated before either can be deleted; a 25 mm label silently clips overflow, so size the content, don't trust the die-cut; the@bottom-*page footer already prints, so no in-body footer block. Ship-to on the PO and packing slip is 1001 Ridge Dr, Clayton NC 27520 (hard-coded in the two templates with a{# … #}comment; change there if the shop moves — it is our own letterhead, not an InvenTree Address record, becauseorder.addressbelongs to the supplier). Never publish this address on the website. invoices stay withrender-doc/accounting, not duplicated in the ERP. - 2026-09-11: Invoice + Proposal moved INTO the ERP (Angel: "all in erp somehow like the rest of templates"). Seven templates now, all installed by
erp-templates: Work Order Traveler, Purchase Order, Packing Slip, Invoice, Proposal (allreport), Stock Label 62x29, Serial Label 25x25 (label). Invoice and Proposal both print from a sales order — InvenTree has no quote object, so a Pending sales order is the quote and the same order becomes the invoice once shipped.render-docis now the fallback for documents with no ERP record behind them, not the primary path. Invoice payment block is filled in: Net 30, check payable to EmbeddedEra LLC at the Clayton address, or wire/ACH (account name + routing + account number live ONLY inee_invoice.html, deliberately not in this vault, which pushes to a git remote). Bank name is not printed — add it if a customer's bank asks for it on a wire. Template gotchas:{% load markdownify %}is required if you use that filter (the base does not load it); an empty related manager such asextra_linesis truthy in a Django template, so test{% if extra_lines.count %};line.part.full_namealready contains the IPN, do not print both; sales-order lines only accept parts flagged salable. - 2026-09-12: KiCad library integration live (Angel: "do that"). ERP parts appear in the KiCad symbol chooser; install a
.kicad_httplibfile in KiCad → Preferences → Manage Symbol Libraries. Details and the three hidden global settings are in inventree. BOM import back into the ERP needs no plugin: KiCad BOM export with an IPN column → InvenTree's built-in BOM importer matched on IPN. - Open: decide whether the KiCad library should work off-LAN (needs a Cloudflare Access bypass on
/plugin/kicad-library-plugin/*). Open: SOP-008 for the KiCad ↔ ERP workflow once Angel has run it once. - 2026-09-12:
~/.local/bin/erp-part— creates a part with its four KiCad parameters and assigns the next freeEE-<class>-####(never reuses a number). Verified end to end: created a part, read it back through the KiCad endpoint (symbol, value, footprint, reference, IPN all correct), deleted the test parts. API gotchas: parameters are written to/api/parameter/withmodel_type: "part"+model_id(NOT/api/part/parameter/, which does not exist in 1.5), and list endpoints may return either a bare list or a paginated{results: [...]}object, so scripts must handle both. - 2026-09-12: KiCad library repo
EmbeddedEra/KiCad(private, master, 125 MB, Git LFS for STEP models) cloned to~/kicad-lib, git identity set to "EmbeddedEra Server hello@embeddedera.com". Structure:symbols/EmbeddedEra.kicad_sym(147 hand-drawn symbols, properties Manufacturer / Manufacturer Part Number / LCSC / PARTREV / Datasheet / Description, footprints infootprints/EmbeddedEra_Library.pretty), plus AFEX, Molex, digikey and teensy footprint libraries andblocks/,template/,3rdparty/. Ownership rule (decided with Angel): KiCad/git owns the drawing, the ERP owns the number. Symbols are never generated; part numbers are never invented in KiCad.kicad-erp-sync(in progress) audits both sides, creates ERP parts from symbols, and writes theIPNproperty back into the symbol file, then commits and pushes. No token ever goes in the repo; the server pushes with its own credentials and every other machine just pulls. Note:~/.local/bin/part-lookupreferenced in the global CLAUDE.md does NOT exist on this machine, and there are no DigiKey or Mouser credentials yet. Angel has keys for both and offered them (2026-09-12). - 2026-09-12: Distributor APIs wired, quota-safe. Keys (Mouser API key, Digi-Key client id + secret) live in
~/.config/kicad-libsync.envand~/.config/{mouser,digikey}/env, all 0600 — the repo's ownpartlookup.pyreads the first path. That script IS thepart-lookupreferenced in the global rules: it lives in~/kicad-lib/scripting/partlookup.pyand is now symlinked to~/.local/bin/part-lookup. Cache in~/.local/share/part-cache/. Quota design. Both vendors allow ~1000 calls/day. AddedDAILY_BUDGET(default 400/source, overridePART_DAILY_BUDGET) enforced inpartlookup.fetch()— the single place every uncached call passes — plus a matching guard inlifecycle_scan.py. Counter is a per-source, per-day file; a new day is a new filename.BudgetExhaustedis raised before the call, so a background scan can never burn the quota an interactive lookup needs. Scope discipline matters more than pacing:lifecycle_report.csvlists 6814 MPNs but only 72 belong toEmbeddedEra.kicad_sym; the rest are third-party libraries (AFEX, Molex, Digi-Key) that are not ours to track.~/.local/bin/part-refreshwalks tiers — ERP manufacturer parts (refresh 30 d), then EmbeddedEra symbols (90 d), nothing else — and stops at the budget. Cron Mon 05:30. Plan-only by default;--runto act. Verified live with a 3-call budget. Open: add the distributor keys to Vaultwarden (Angel). - 2026-09-12: KiCad ↔ ERP sync done and pushed.
~/.local/bin/kicad-erp-sync(audit / pull / push, dry-run by default,--yesto act,--committo commit+push; README~/kicad-lib/SYNC.md). Ran it for real: 147 symbols → 144 ERP parts (EE-C-0001…EE-C-0146, plus one Mechanical), every symbol now carries a hiddenIPNproperty, committed as2e5a65band pushed toEmbeddedEra/KiCadmaster. Audit is clean: 147 matched, 0 unmatched, 0 orphans, 0 conflicts. Findings worth keeping: three symbol pairs are variants of ONE physical part (YC124-FR-07100KL, YC124-FR-07180RL, TPS55288RPMR) — the tool refused to guess and reported a conflict, the duplicates were deleted, and both variants now share one part number. The reference-designator → category table had to be widened to cover what the library actually uses (RN, RV, LED, DS, JP, TP, BT, F, A, H); before that everything unlisted fell into a generic Components bucket. 13 remaining "field mismatches" are symbols with an empty Description where the ERP has one — the ERP copy is better, leave them. Open: SOP-008 documenting the workflow now that it has been run once. - 2026-09-12: Manufacturer-part descriptions backfilled from the part description (72 of 73; the remaining one has no part description either). Gotcha: a generated curl script inherits only exported shell vars — an unexported $H meant every PATCH ran unauthenticated and
-o /dev/nullhid it. Always echo one record back after a bulk write. - 2026-09-12: SOP-008 "KiCad parts and the ERP" written and published (ownership rule, sync commands, description rules incl. the under-100-character distributor style, conflict handling, BOM import, distributor budget). Repo README added and pushed (
7e939d7). Descriptions: 8 filled from what the part names factually state, 5 still need Angel (ESP32-C6-LCD-1.47, LCD_1.47_Touch, LCD_ST7789VW, Nucleo32, RFX2401C) — Digi-Key and Mouser do not carry the LCSC-only parts, and the repo cache had no usable description data (only 1 of our 72 MPNs had ever been fetched). - 2026-09-12: SOP rules tightened at Angel's request and written into
~/Notes/rules/CLAUDE.md: follow the SOP before touching the ERP (and fix the SOP in the same session if reality disagrees), a repeatable new process gets its own SOP, never restate another SOP (reference it by number), and "Who does this" plusownername a role, never a person. All nine SOPs revised and version-bumped accordingly; description-writing rules moved from SOP-008 to SOP-002 where parts are created. - 2026-09-12: Every SOP page now ends with a What changed block generated at build time by
~/Notes/sops/hooks/history.py— the real git commits for that file, newest first and open, each with the actual diff of the prose. Chosen over a version dropdown (publishing stale procedures) and over linking to GitHub (the notes repo is private, so an employee would hit a login wall). Hidden in print viabrand.v4.css; remember MkDocs does not hashextra_css, so renaming the stylesheet is what busts the cache. - 2026-09-12: Way back out of every internal tool. SOP site: a Home pill in the header on every page (
docs/assets/home-link.js, styled inbrand.v5.css, hidden in print) plusextra.homepageso the logo goes there too. ERP: thesoplinkdashboard tile is now two links, Home and SOPs — InvenTree's own navigation tabs route inside the SPA, so an external URL becomes/web/https:/…and breaks; the tile is the reliable route. - 2026-09-12: SOP-009 "Setting up a new person" written — accounts in dependency order (Google Workspace → Cloudflare Access policy → InvenTree user whose username must be the Google email → vault), the machine, per-department ERP group and reading list, and a reverse-order offboarding section. Draft until walked on a real hire.
- 2026-09-12: Angel asked (not to be built yet) how Sales could use AI the way he does — e.g. "make an invoice for X, qty 10, part Y". Recommended shape: one narrow skill behind the same Google gate, drafting into the ERP and always requiring a human confirm, same guardrail as
quote-drafts. Nothing off the shelf connects to self-hosted InvenTree without moving the data to someone else's cloud. - 2026-09-12: SOP titles standardised to Title Case noun phrases and naming/numbering rules added to SOP-000. A block numbering scheme (100s/200s/…) was tried the same day and rejected by Angel in favour of plain sequential numbers; the set is 000–009 in the order work flows: control, parts, stock, buying, receiving, building, selling, KiCad, people (no separate "how to name SOPs" document — document control already owns numbering, and one procedure has one home). Final set: 000 Document Control, 001 Part Numbering, 002 Part Creation, 003 Stock Locations and Movement, 004 Purchase Orders, 005 Goods Receiving, 006 Assembly Builds, 007 Sales Orders and Invoicing, 008 KiCad Library and ERP Parts, 009 Personnel Onboarding and Offboarding.
- 2026-09-12:
~/.local/bin/onboard— one command for a new person.add(plan by default,--yesto apply) puts the address on every Cloudflare Access policy, creates the InvenTree user with username = full email (what the header SSO matches on) in the group for their department, and for engineering/production creates a personal Samba login and prints the password once;removereverses it Access-first, deactivating rather than deleting the ERP user;listshows who can reach what. Google Workspace and vault accounts stay human steps. Proven end to end on a throwaway account, then reverted byte-for-byte. Two findings from that test: (1) the Samba container had been started outside compose (no compose labels) so it never picked up config changes — stopped, removed and recreated withdocker compose up -d samba; the compose service issamba, the container issamba-nas. (2)/var/lib/sambais a docker volume, so a removed user lingers inpdbedit -Leven after the share config drops them;onboard removenow also runspdbedit -x. Also noticed: a second superuserangelexists in InvenTree, recreated fromINVENTREE_ADMIN_USERininventree/.envat every container start, separate fromadiaz@embeddedera.com. Left alone; worth retiring. - 2026-09-12: NAS mount paths moved off the home page into SOP-009 (per-person logins, no shared credentials); the home page tile now points at the SOP.
- 2026-09-12: Internal assistant live (chat.embeddedera.com), Sales skill only, drafts a sales order + invoice from one sentence and waits for Confirm. Details and threat model in roles-and-skills; memory note
embeddedera-assistant. - 2026-09-12:
erp-sandboxlive (see inventree card, decision sandbox-workflow). Found and fixed an R2 pagination bug inerp-backupthat made "latest backup" stale after ~3 nights; re-check what the Sunday verify actually restored. - 2026-09-13: Quality system rounded out — SOP-014 Returns and Repairs (built on the ERP return orders: RMA number = the order reference, receive into Quarantine, trace the serial to its build and test results, classify the cause, one of six outcomes, and a product-feedback item whenever the cause was ours), SOP-015 Quarterly Review (six timeboxed items, minutes in ~/Notes/meetings/YYYY-QN.md, a decision needs a reason and an action needs an owner and a date), SOP-016 Quality Objectives (a short policy plus eight objectives; on-time, return rate and receiving discrepancies are deliberately measured before they are targeted, and first-pass yield is not measurable until builds record test results per serial). SOP-013 gained product feedback as a fifth source, carrying the part, serial and RMA reference so a repeat fault is visible as a pattern.
- 2026-09-13:
~/.local/bin/quarterly-packassembles the review pack from what already exists (audit trend and failures, ERP orders/builds/returns, feedback by source and state, assistant use and cost, access and guests, backup/restore status, open to-dos per project), writes ~/Notes/meetings/.md, never overwrites an edited pack, and syncs the vault. Objectives table is wired to real numbers. Cron: 07:00 on the first day of each quarter. First pack for 2026-Q3 is in the vault; most rows honestly read "none this quarter" because the ERP has no orders yet. -
2026-09-17: PO PDF template fixed (
~/torrentvpn/inventree/templates-src/ee_purchase_order.html, uploaded witherp-templates). Three bugs, all template-side — the data was right: the Supplier SKU column readline.SKU(it lives on the supplier part,line.part.SKU), MPN read a field that does not exist (line.part.manufacturer_part.MPN), and extra lines printedline.reference/line.noteswhile InvenTree stores the text inline.description, so "Shipping" came out blank. Also added the PO's own Description to the header block. The invoice template had the same extra-line bug and was fixed too. Shipping on a PO is an extra line (SOP-004 v1.5). -
2026-09-19: First Robot Cow 004B run set up. Opening count (SOP-023, Angel's count): 30 panels × 9 = 270 bare EE-P-0002-A, batch
004B, stock item 33 on Shop/Shelf A; 27 (3 panels) transferred to Kitting as stock item 34. Build order BO-0001 (pk 2): 27 × EE-A-0002-A, destination In test, take from Kitting, left Pending. The ERP BOM (29 lines, 57 refs) matches the 004B schematic exactly via kicad-cli export; only the 6 solder jumpers (JP*) are outside the BOM, which is correct. Still to do before issuing: validate the BOM (Engineering), count 23 component lines into stock (0 in ERP; many are loaded on the YY1), confirm stock task #193 (USBLC6 × 3000), pick a serial-number convention (none exists; the ERP's next serial is 1), add part images (181/182 have none; renders in Cow_Robot_Board/hardware/Robot-Cow-004B/Pictures). The YY1 feeder file is set up for the Remote: its 1206 LEDs, STM32G0B1C and E01-ML01SP4 are the wrong parts for the Cow (it needs 0603 LEDs, STM32G0B1KET6 in LQFP-32, E01-ML01DP5 and a horizontal HRO USB-C). -
2026-09-19: Robot Cow 004B components counted in from Angel's estimates (SOP-023): 17 reels on Machine/Neoden YY1, with slot numbers in each item's notes (stock items 35–51), and E01 radios, screw terminals and STM32 on Shop/Shelf A (52–55). Linked substitutes: EE-C-0155 on U7 and EE-C-0165 on 0.1µF. J10 and C15 set Optional pending Engineering. BO-0001 now covers 27 of 29 lines; the two short lines are optional.
-
2026-09-19: Wrong-folder correction. Angel's ordered Robot Cow 004B boards were made from
Cow_Robot_Board/hardware/Robot Cow/(gerbersproduction/COW_ROBOT_004B.zip, 2026-08-11 20:25: 225 F.Paste pads match that PCB exactly;hardware/Robot-Cow-004B/plots 221).hardware/Robot-Cow-004B/is an unreleased edit that was never ordered (adds U7 USBLC6, drops D11/D12/R25/R26). The 09-16 ERP BOM had been rebuilt from the wrong folder. Fixed EE-A-0002-A (pk 181): BAT54S 7→9/board (+D11,D12), 33R 5→7 (+R25,R26), U7 line deleted (its substitute went with it). Now 28 lines/60 refs = the ordered board's fitted parts. Undo record: job tmpbom_before_fix.json. BO-0001 still Pending and fully stocked apart from the optional J10/C15. -
2026-09-19: Robot Cow 004B follows the schematic (Angel): R7/R8 10k, R10 4.7K, R12 220, D13 green (POW), D15 orange (STAT). PCB synced to match on branch
robot-cow-sch-values(a0db5f8), which also clears stale PCB-only DNP/exclude-from-BOM flags on C5, C6, D3, D4, R7, R8, R10, R12. CC1/CC2 checked: R28 on CC1, R23 on CC2, both 5.1K to GND, so no change was needed. C14/C18 (XC6206 in/out 1µF) are on the board butin_bom noin the schematic; they're added to the ERP 1µF line (now 4/board, 62 refs). The YY1 converter gained--rotate(kicad-libcow-yy1-rotate, 8c68604); the Cow feeder slots are in the machine setup TOML; all 7 tests pass, including the Remote 006 proven-file comparison. -
2026-09-19: Proven Robot Cow YY1 values (from Angel's 1×3 job): passives place at 0.2, SOT-23 at 0.0, D1 at -0.3, PTS810 at 2.5 (SW1 head 1, SW2 head 2); RT1 is mode 1 with pick -1.0; J11 slot 58 (head 2, speed 70, pick -0.7, place 1.8, mode 4); U4 slot 55 (head 2, speed 70, place -0.2, mode 4). Its origin sits 2.00/2.35 mm off the board corner. The 3×3 turned job is built from it (PR #9).
-
2026-09-19: C15 = 10µF (Angel), as in the proven run. The schematic and PCB have value, description and manufacturer fields updated (EE-C-0185; the old Murata 4.7µF MPN is cleared). ERC/DRC and parity are unchanged. The ERP C15 line now uses EE-C-0185 and is required. The 3×3 YY1 job places C15 from slot 27. Cow_Robot_Board PR #9 merged (08306cf).
-
2026-09-19: 10µF reel counted in: about 1000 on YY1 slot 27, stock item 56 (EE-C-0185). BO-0001 now has stock for every required line; the only line short is J10, which is optional.
-
2026-09-19: Stencil entered as EE-M-0002 "Cow 004B stencil" (Mechanical, not a component). It's the 1-piece line of JLC order W2026082710026585, which also shipped the 30 panels. Label rendered with the Zebra 2×1.5 in part template (template 11). Serial numbers: SOP-006 v1.5 records the tester's MMYY#### scheme (count per product, per month); the ERP takes serials from the tester and never generates its own.
-
2026-09-19: J10 (PROGRAMER_STM32_1.27) is a programming pad pattern with nothing soldered, so it's never a BOM line (Angel). Removed from EE-A-0002-A (now 27 lines / 61 refs). Gotcha: a placed KiCad symbol keeps its own in_bom/dnp flags, so fixing the library doesn't reach boards drawn before the fix. A sweep of all repos found the flag stale only in Robot Cow, Robot-Cow-004B, Robot Cow 4.0.1 (retired, left as is) and Remote_Universal; the other 27 placements were already correct. Fixes: Cow_Robot_Board PR #10, Remote_Universal PR #1.
-
2026-09-19: Solder paste in the ERP: EE-K-0002 "Solder paste SAC305 T4" (Consumables, counted in grams), MPN GC10SAC305T4 (Henkel Loctite / Multicore). Stock item 57: 500 g, lot A260188, expires 2027-03-17, Shop/Shelf A, about $0.40/g (Angel: about $200 per jar). On the Robot Cow BOM as line PASTE, 0.15 g/board, not consumable, so builds deduct it. That's an estimate: about 0.07 g deposit (174 paste pads, 137 mm², 0.12 mm stencil) plus waste. Now 28 lines; the BOM was never validated, so validation is still Angel's step.
-
2026-09-19: Packing added to the Robot Cow BOM (now 31 lines): BAG = EE-K-0001 antistatic bag 8×12 cm ×1; BAG-LABEL = new EE-K-0003 Zebra 2×1.5 in label ×1 (the tester's bag label, 1.969×1.496 in); SN-LABEL = new EE-K-0004 Brother 18 mm laminated tape, 27 mm per board (the PT-P900 minimum feed per label, from Universal_Tester brother_ptp900.py). All not consumable, so builds deduct them.
-
2026-09-19: Packing stock counted (SOP-023, Angel): EE-K-0004 is Brother TZe-641 (18 mm black on yellow, 8 m); 3 full cassettes = 24,000 mm, stock 58 on Shelf A (no DigiKey/Mouser price). EE-K-0003 Zebra labels: 3 rolls × 950 = 2,850 on Shelf A (stock 59) + about 850 on the roll in the Zebra (stock 60, Shop). BO-0001 now has stock for every line.
-
2026-09-19:
SERIAL_NUMBER_GLOBALLY_UNIQUEset to False (Angel chose it after weighing the tester-prefix option, which would have lengthened the Zebra Code128 barcode and broken the calibrated Brother label). Serials are unique per part, which matches the tester's per-product MMYY####. SOP-006 v1.6 and the inventree map card updated. -
2026-09-19: Robot Cow BOM (EE-A-0002-A, 31 lines) validated on Angel's approval, via the API under adiaz@embeddedera.com. BO-0001 is ready to issue.
-
2026-09-19: Tester bag labels now print the ERP part number (Universal_Tester PR #1, 2cdca41): Robot EE-A-0002-A (H/W 004B), Remote EE-A-0004-A. Tester versions Remote 3.12.1, Robot 2.5.1. Production labels print no barcodes (include_barcodes is off), so the longer part number only changes text. SOP-014 v1.1: returns record part number + serial. Needs a git pull on the tester PC and one test print.
- 2026-09-19: Trackable fixed on production (Angel approved): 177 non-assembly parts untracked,
PART_TRACKABLEdefault off, BO-0001take_fromcleared (reels live on YY1/Shelf A, not Kitting), BO-0001 issued (Production) and auto-allocated: 31/31 lines allocated. Only EE-A-* assemblies stay trackable (SOP-002). -
2026-09-19: Conformal coating added to both BOMs as EE-K-0005 "Conformal coating, acrylic" (MG Chemicals 419D-1L, counted in mL): Robot 1.0 mL/board, Remote 0.7 mL/board, both marked consumable so they don't need allocating on the live BO-0001. Estimate: top side only, board area 40 cm² (Robot) / 30 cm² (Remote) at ~160 µm wet (~40 µm dry) plus ~40% loss, so a 1 L bottle covers roughly 1,000 Robots or 1,400 Remotes; about $0.08 and $0.06 per board at Mouser's price. Both BOMs re-validated on Angel's approval (Robot 32 lines, Remote 31).
-
2026-09-20: Read-only live verification of Robot Cow report discrepancy: EE-A-0002-A has 32/32 validated BOM lines; BO-0001 (27 boards) is Production with 31/31 non-consumable lines fully allocated. COATING is consumable, allocated 0 by design. Live Grafana ee-build-capacity returns Unsupported BOM / null capacities, not a proven stock shortage: its SQL rejects consumable BOMs and does not evaluate substitutes; it also subtracts stock already reserved for builds. No ERP or report changes made.
- 2026-09-20: Capacity report corrected and deployed for all active assemblies. Robot Cow now reports BO-0001 as one fully allocated active build / 27 boards; its zero free-stock capacity means no additional run from unreserved material. Consumables no longer block capacity, declared substitutes are pooled, overlapping pools are withheld, and Dashcam Drive is discovered dynamically.
erp-config421af75;torrentvpndcd6f5d; SOP-028 v1.1. - 2026-09-20: Fixed a remaining stale copy of the capacity query on Grafana's System home. “Buildable from recorded stock” had still treated Robot Cow's consumable coating line as unsupported and rendered a dash. The panel now uses the corrected all-assembly query and labels the two quantities explicitly: Robot Cow has 0 additional from unreserved free stock and 27 ready in its fully allocated active build.
erp-configeb88fbc;torrentvpnfb712e2. - 2026-09-20: Added the combined capacity Angel expected: Total buildable now adds fully allocated active-build quantity to additional unreserved-stock capacity. It appears on System home and the detailed capacity summary for every assembly. Live values: Robot Cow 27, Cow Remote 0, Cow Finger 0; Remote/Finger lack sufficient recorded ERP component stock.
erp-confige3f7b56;torrentvpn445c7fc. - 2026-09-20: Capacity report now directly answers why another board cannot be built. “Parts blocking the next additional board” lists each short BOM line after reservations, with part number, needed, available unreserved and missing quantity. Robot Cow's 28th board is currently blocked by EE-K-0001 antistatic bag (1 needed / 0 unreserved); Remote has 18 recorded blocker lines; Finger is blocked by EE-C-0193 switches and EE-P-0005-A PCB.
erp-configa980439;torrentvpn57cbb14. - 2026-09-20: Reverified and clarified EE-P-0002-A inventory. ERP correctly holds 270 individual bare boards = 30 panels × 9: stock item 33 has 243 unallocated on Shelf A (27 panels) and child stock item 34 has 27 allocated to BO-0001 in Kitting (3 panels). No quantity changed. Set the accepted unit to
pcs, expanded the part description to state board-level counting and nine boards per panel, and set both stock packaging fields to “Panel, 9 boards per panel.” Private before/after receipt:~/.local/state/erp-receipts/2026-09-20-ee-p-0002-a-panel-units.json. - 2026-09-21: Created
Finished goods / Paul Shopand transferred all eligible finished stock requested by Angel: EE-A-0005-A Cow Finger 41, EE-A-0004-A Cow Remote 32, and 21 serialized EE-A-0002-A Robot Cow units (94 total; 23 stock records). Left Robot serials 09260042, 09260046 and 09260059 inIn testbecause they are unfinished BO-0001 outputs; their final tester PASS must consume final-stage material and complete them. Private receipt:~/.local/state/erp-receipts/2026-09-21-paul-shop-transfer.json. - 2026-09-21: Added Grafana Stock table “Assembly quantity by location and part number” because InvenTree's location page reports stock-item rows (23 at Paul Shop) rather than grouped assembly quantity. The live grouped rows correctly show EE-A-0002-A 21, EE-A-0004-A 32 and EE-A-0005-A 41.
erp-config1e63629;torrentvpnc8898e3. - 2026-09-20: Finalized the proposed Production Tools label scope after the copies counter was mistaken for quantity per box: two explicit actions only, Reprint inventory label and Print box labels. Box labels take quantity-on-each-label plus number-of-labels and print directly to the Zebra. No box tracking, numbering, stock split, ERP change, PDF, or added history screen. No live code or ERP data changed. See production-tools-box-labels.
- 2026-09-20: Deployed the approved Production Tools label flow (
assistant259a2d0). Inventory reprints now label their copy count and state the ERP quantity; box labels take quantity-on-each-label plus number-of-labels and send direct ZPL with no ERP write or PDF. Count is renamed Change inventory count with an explicit warning. Double taps are idempotent. Sandbox phone review and all 27 test files passed; no physical test labels were sent. - 2026-09-20: Angel reported one conformal-coating bottle approximately half full. Created assigned, dated Robot Cow finishing tasks #283–289 covering substitute approval, physical YY1 verification, 10 µF reel qualification, STM32 location, coating stock estimate, tester label proof, and completion of BO-0001. The task register now owns these open actions; duplicate project-note to-dos were removed.
- 2026-09-20: Completed Robot Cow task #287 from Angel's confirmed estimate: ERP stock item 85 records 500 mL of EE-K-0005 conformal coating at Shop/Shelf A, with a note identifying it as a visual estimate from one partly used bottle. The BOM remains consumable at 1.0 mL per board. Automated task verification passed and closed the card.
- 2026-09-20: Robot quarantine staged-inventory rollout changed BO-0001's EE-K-0005 BOM line from InvenTree
Consumableto stock-tracked, because InvenTree deliberately skips allocation/consumption for consumable lines. The physical quantity remains 1.0 mL per Robot; exactly 27 mL from stock item 85 is allocated to BO-0001. A sandbox run proved that pretest failure/scrap consumes no coating and only the FINAL pass consumes 1 mL. - 2026-09-20: Failed Robot serials 09260042 and 09260059 returned to PRECHECK as unfinished BO-0001 outputs 87 and 114 in In test/OK. Their installed PRECHECK materials were consumed by exact build allocations and all historical FAIL results were attached. No Quarantine case or final-stage consumption was created; their next physical PRECHECK determines PASS versus Retest/Quarantine.
- 2026-09-28: SOP audit SOP-003.no-location flagged 168 stock records; all were parts consumed by build orders (in_stock false, consumed_by set), which InvenTree leaves without a location. No ERP change: the rule now counts only stock on hand (assistant #62,
scripts/sop-audit). Every in-stock item already has a location. Audit: 46 pass / 15 warn / 0 fail.