Verification ledger: admin guide, files 00 to 03
Scope: every > Not confirmed by code: block in docs-obsidian/user-guide/admin/00-README.md, 01-first-login-and-navigation.md, 02-users-roles-permissions.md, 03-warehouse-structure.md.
Method: static reading only (no build, no database, no server). Paths are relative to crates/ unless stated.
Update 2026-10-11: the fix F-01 (29c0cd6d7) replaced libs/wms-lib-auth/src/authorization/bootstrap.rs by libs/wms-lib-core/src/model/initial_admin.rs. bootstrap-admin now creates the user through UserBmc::create, so rows 2, 14, 22 and the findings F1 and F4 below describe the code before the fix: the first administrator can sign in (the test the_created_administrator_can_sign_in in initial_admin.rs checks the password the way the login does), and must_rotate_password is no longer written by that command.
Result: 21 blocks. 12 CONFIRMED, 7 CORRECTED, 2 UNRESOLVABLE-BY-READING. One new unresolved block was added in 01 (bootstrap sign-in), so 3 blocks remain in the four files.
| # | file | original claim | outcome | evidence | action taken |
|---|---|---|---|---|---|
| 1 | 00-README | Unknown whether anything reads the replenishment policy code. | CONFIRMED (nothing reads it) | libs/wms-lib-core/src/model/sku.rs:206, owners/owner_config.rs:102 only store it. libs/wms-lib-sql/sql/wms-app/migrations/024_*.sql:20-24 ("Reserved identity placeholder"). 001_baseline.sql:2145 (SKU column NOT NULL default 1), :18165 (FK RESTRICT). No other reader found by grep in libs/ and services/. | Block replaced by a plain statement. |
| 2 | 01 (sign-in) | Unknown where the UI forces the password change after must_rotate_password. | CORRECTED | must_rotate_password is written only in libs/wms-lib-auth/src/authorization/bootstrap.rs:122. No Rust, SQL or TS code reads it (grep over crates/ and ui/src). | Text now says nothing enforces it. Block deleted. A new block was added (see row 22). |
| 3 | 01 (password) | Screen says "at least 8 characters" but code checks 6. | CONFIRMED | services/web-ui-server/src/routes/http_params.rs:26 (length(min = 6, message = "...8 characters.")). Called by auth/login.rs:34-41. | Block replaced by a plain statement and advice to use 8 or more. |
| 4 | 01 (switcher) | Position and label of the warehouse switcher unknown. | CONFIRMED | services/web-ui-server/src/components/partials/masthead.rs:60-70 (button #wms-tabs-launcher, shows warehouse code, title Switch warehouse, in .utils group of the top bar). components/partials/application_menu.rs:24-100 (pop-up, search field, Enterprise row only for ADMIN holders, No warehouses assigned). Opens via ui/wms-lib/events.js:190-215. | Steps 1 and 2 rewritten. Block replaced by a plain statement. |
| 5 | 01 (dashboard) | Unknown how the dashboard form opens. | CONFIRMED | wms-meta-ui/migrations/001_baseline.sql:23057 (container main_workspace, default_tab_id = 1), :23066 (tab 1 = dashboard, form 1). services/viewport_service.rs:14-28, auth/session_init.rs:34. Breadcrumb reset: routes/breadcrumb_handler.rs:666-679. | Block replaced: it is the default tab (home page). |
| 6 | 01 (menu to form) | Form codes for several menu items were inferred. | CORRECTED | Traced menu_item -> ui_event -> tab_items -> form_base for all 55 baseline menu items (script over 001_baseline.sql) and for items added in migrations 073, 080, 081, 086, 088, 093, 095, 098, 101, 111, 117, 123. All codes in the table match except Policy > Handling Unit Registry: 080_handling_unit_screens.sql:314,528-570 opens handling_unit_registry_type_list_form, not handling_unit_registry_shell_form. Direct target_form_id count (7 items) confirmed. | Table cell fixed. Block replaced by a description of the real chain. Note on Dashboard item added (see row 23). |
| 7 | 01 (required message) | Exact wording of the "required field" message unknown. | CORRECTED | Live text is <Humanized field> is required: services/web-ui-server/src/extensions/generic/validate_action.rs:228-236 (resolve_required_message), :239-253. Key validation.required_field exists only in wms-meta-ui/migrations/archive_pre_baseline*. | Block replaced by the real wording. |
| 8 | 02 (buttons) | Unknown whether the UI hides a button or only denies the click. | CORRECTED | Sidebar filtered by menu and form rights: components/partials/body.rs:66-90, sidenav::menu_item_usable. Component screens hide buttons: services/component/gate.rs:1-40, components/partials/toolbar.rs:84. Ordinary toolbars: no permission check in components/partials/toolbar.rs. Click denied: extensions/tx_helper.rs (check_action_chain_permissions). | Block replaced by a three-point description. |
| 9 | 02 (role rights) | No complete per-method API list per role. | UNRESOLVABLE-BY-READING | Rights come from code lists, seeder.rs, and many migrations; the merged result exists only in enterprise.role_permission at run time. | Block rewritten with the exact unknown and the steps and SQL to verify. |
| 10 | 02 (password length API) | Minimum password length at the API unknown. | CONFIRMED (no rule) | libs/wms-lib-core/src/model/user.rs:479-515 (create), :675-700 (update_pwd), :596-604 (empty password skipped on update). services/app-server/src/web/rpcs/user_rpc.rs:60-105 has no check. | Block replaced by a plain statement. See finding F2. |
| 11 | 02 (duplicate key text) | Message text for duplicate keys unknown. | CORRECTED | libs/wms-lib-web/src/error.rs:393-398 maps 23505 to Record already exists; :399-407 maps FK refusal to Cannot delete: record is in use. user_warehouse and role creates do not resolve the violation (no resolve_unique_violation in model/user_warehouse.rs, model/role.rs). | Block replaced by the real texts. Table cells still name the constraint (kept as the cause). |
| 12 | 02 (system roles) | Unknown whether is_system roles are protected from deletion. | CONFIRMED (no guard) | is_system appears only in wms-enterprise/migrations/001_baseline.sql:194,811 and web-ui-server/src/components/layout/cortive_role_list.rs:152,194. No trigger on enterprise.role except the RBAC epoch bump (:2046). role_rpc.rs:21,22 delete without a guard. | Block replaced by a plain statement and a warning. |
| 13 | 02 (API key header) | Header name on every endpoint unknown. | CONFIRMED | libs/wms-lib-web/src/middleware/mw_auth.rs:43 (Bearer wms_live_sk_), :215-245. | Block replaced; scope stated as "every route behind this middleware". |
| 14 | 02 (complexity, lock-out, rotate) | No complexity rule, lock-out or enforcement of must_rotate_password found. | CORRECTED | No complexity rule (see row 10). No lock-out, but a throttle exists: libs/wms-lib-auth/src/authentication/login_throttle.rs:10-16,45,51 (10 failures per 60 s, by user name and by client, in memory). Counter column is audit only: libs/wms-lib-core/src/model/user.rs:778-800. must_rotate_password: see row 2. Guide bullet "must change the password" was wrong. | Section 9 rewritten as five plain bullets. Block deleted. |
| 15 | 03 (add warehouse) | No tool found that adds a second warehouse. | UNRESOLVABLE-BY-READING | services/tenant-manager/src/web/rpcs/tenant_rpc.rs:60-122 creates db, runs migrations, no warehouse row. libs/wms-lib-sql/sql/tenant-manager/templates/setup_users_for_tenant_db.sql:11 creates only wh1. Warehouse rows exist only in sql/dev_only/install-db/900-dev-seed.sql:500. libs/wms-lib-auth/src/authorization/bootstrap.rs:88-97 needs the row. Whether a production runbook exists is a product matter. | Block rewritten: facts listed, exact unknown and verification steps. |
| 16 | 03 (seeded locations) | Unknown whether the product needs UNKNOWN, DOCK, QC, RETURN, RTV, STAGE, PICKTO. | CONFIRMED (with corrections) | wms-app/migrations/001_baseline.sql:4178-4181 (zone defaults), :17521-17563 (FK RESTRICT), :2973 (location default zone DOCK), :17255,17297 (owner defaults), :8350-8461 (seed rows). 064_*.sql:19-23 seeds INTRANSIT (the guide said the baseline did). 3D page: services/web-ui-server/src/components/pages/warehouse_3d.rs:141. RTV: libs/wms-inbound/src/service/receipt/damage/move_damage_to_rtv.rs:9. No code reads UNKNOWN, QC, RETURN or RTV by name. | Block replaced by a dependency list. INTRANSIT source corrected. |
| 17 | 03 (location generator) | Unknown if the check digit is computed for generated locations, and what a duplicate does. | CONFIRMED | services/app-server/src/web/rpcs/location_rpc.rs:31-47 (digit only in create_loc), :113-122 (gen_locs does not compute). libs/wms-lib-core/src/model/base/crud_fns.rs:99-140 (one multi-row INSERT). libs/wms-lib-web/src/error.rs:393. Wizard calls gen_locs: extensions/customization/location/wizard_submit_action.rs:62. | Block replaced by two plain statements. |
| 18 | 03 (zone fields) | Replenishment fields do nothing; ADR says zone mixing rules have no reader. | CORRECTED (second half was wrong) | Replenishment fields have no reader (grep: only putawayzone_rpc.rs:45-46 and the form gate). Zone lot mixing IS read: libs/wms-inventory/src/inventory_service.rs:1406-1420,1477-1560, test libs/wms-inventory/tests/move_command_integration.rs:1513. | Block replaced. docs-obsidian/putaway_policy/README.md:53,88 is stale (see F6). |
| 19 | 03 (operator rule) | Exact rule for the operator list unknown. | CONFIRMED | libs/wms-lib-core/src/model/tasks/operator.rs:236-273: rf_login = true, status = 'Active', a user_warehouse row for the warehouse; any role. Loop: services/app-server/src/services/cleanup_tasks.rs:150,991-1020. | Block replaced. Two other lines in 03 and one in 02 (section 8) fixed to add "status Active". |
| 20 | 03 (3D controls) | Controls of the 3D page unknown. | CONFIRMED | services/web-ui-server/src/components/pages/warehouse_3d.rs:12-135. English texts: wms-meta-ui/migrations/118_bespoke_warehouse_topology_words.sql:5-43. | Block replaced by a control list. |
| 21 | 03 (cycle count) | Full count workflow not confirmed. | CONFIRMED (scope note) | It is a scope statement, not a code question. | Block replaced by a plain scope sentence. |
| 22 | 01 (new block) | NEW: can the bootstrap administrator sign in? | UNRESOLVABLE-BY-READING | libs/wms-lib-auth/src/authorization/bootstrap.rs:109-122 stores a bare Argon2 PHC hash with empty pwd_salt. libs/wms-lib-auth/src/pwd/mod.rs:94-104 accepts only #scheme#hash. Reading says sign-in fails; only a run proves it. | Block written with exact unknown and verification steps. |
| 23 | 01 (extra fix) | Enterprise note listed only Warehouses and Owners as dead items. | CORRECTED | Menu item ent_dashboard (id 29) has no target_form_id and no ui_event (001_baseline.sql:21044; script trace). | Note extended to Dashboard. |
Product findings
F1. Bootstrap administrator probably cannot sign in. libs/wms-lib-auth/src/authorization/bootstrap.rs:109-122 writes a raw Argon2 PHC string (no #02# style prefix) and an empty salt. libs/wms-lib-auth/src/pwd/mod.rs:94-104 (PwdParts::from_str) needs ^#(\w+)#(.*). wms-lib-web/src/handlers/handlers_login.rs:112-126 then fails with LoginFailPwdNotMatching. Needs a run to confirm. No test covers hash-then-login for this command (bootstrap.rs tests at :170+ test only config).
F2. No server-side password rule. libs/wms-lib-core/src/model/user.rs:479-515 and :675-700; RPCs create_user / update_user. An empty password is stored on create. The only check is on sign-in (6 characters), so an account made with a short password can never sign in.
F3. Wrong message on sign-in. services/web-ui-server/src/routes/http_params.rs:26: rule is min = 6, text says 8.
F4. must_rotate_password is dead. It is written (bootstrap.rs:122) and in the schema (wms-enterprise/migrations/001_baseline.sql:216), but no reader exists. The CLI message services/app-server/src/cli.rs:82 and the log line bootstrap.rs:148 tell the operator to rotate "on first login", which nothing prompts. failed_login_attempts is audit only (user.rs:778-800).
F5. Duplicate-key and generator errors hide the cause. libs/wms-lib-web/src/error.rs:393-398 returns Record already exists for every unique violation that has no model-level resolver, with no constraint name. Generated locations (gen_locs) fail as a whole when one code exists, and the user is not told which code.
F6. Stale design note: docs-obsidian/putaway_policy/README.md:53,88 says putawayzone_lot_commingle has no reader. It has one since libs/wms-inventory/src/inventory_service.rs:1537-1553.
F7. Inconsistent check digit: create_loc computes it (location_rpc.rs:42-44), gen_locs does not (:113-122), although both are described by the setting CHECK_DIGIT_ENABLED ("new locations", wms-app/migrations/001_baseline.sql:9947).
F8. Dead enterprise menu item Dashboard (ent_dashboard, wms-meta-ui/migrations/001_baseline.sql:21044): no form, no event. Same class as Warehouses and Owners.
F9. Stale comment: services/web-ui-server/src/services/snapshot/impersonation.rs:123-125 (and :1468) says the server logout does not touch the session. routes/login_handler.rs:95-101 does session.flush().
F10. Throttle is per process only (login_throttle.rs header). With several app-server copies the allowed rate multiplies. A stated limit, not a bug.
F11. Other guide files may repeat the wrong registry form code. Not checked here: 04-owners-sku-uom-pack-hierarchy.md (handling_unit_registry_shell_form). Owner of that file should check against 080_handling_unit_screens.sql:314,528-570.