Skip to main content

API guide verification ledger

Scope: every > Not confirmed by code: block in user-guide/api/00-README.md to 08-workflows-by-example.md. Method: static code reading only. No build, no server, no database. Outcomes: CONFIRMED (now plain fact), CORRECTED (docs were wrong or incomplete, text fixed), UNRESOLVABLE (block kept, rewritten with exact steps to verify).

Paths are under crates/ unless noted. 00-README.md:5 is the legend sentence, not a block, and is unchanged.

fileoriginal claimoutcomeevidenceaction taken
01-quickstart.mdResponses are built from code, not a live serverUNRESOLVABLENeeds a running serverBlock kept, added steps to verify with curl -i
02-authentication.mdUser status (Locked/Disabled) does not stop loginCONFIRMEDlibs/wms-lib-core/src/model/user.rs:26-33 ("Descriptive only"); no status read in libs/wms-lib-web/src/handlers/handlers_login.rs; API key check reads only api_access, expiry, revoke (libs/wms-lib-auth/src/authentication/api_key.rs:183,247)Block replaced by fact; added that API keys of Locked/Disabled users also work Superseded: fixed by F-03 (5cb291af1); the page now says Locked and Disabled are refused.
02-authentication.mdDefault of api_access for new users unknownCONFIRMED (default true)libs/wms-lib-sql/sql/wms-enterprise/migrations/001_baseline.sql:224 (DEFAULT true NOT NULL); libs/wms-lib-core/src/model/user.rs:142 (Option<bool> on create)Block replaced by fact
02-authentication.mdWhich methods work in enterprise scopeCORRECTED (answered)libs/wms-lib-web/src/middleware/mw_auth.rs:338-349; libs/wms-lib-core/src/model/store/dbx/mod.rs:240-247,268 (search_path = enterprise only for enterprise scope, <wh>, enterprise for warehouse)Rule written: only enterprise-table methods work in enterprise scope
02-authentication.mdHow tenants map to base URLsCONFIRMED for Kubernetes provisioner onlyservices/tenant-manager/src/provision_k8s.rs:172-173; k8s/base/app-server/templates/ingress.yaml (host {{tenant_name}}.{{base_domain}})Block replaced by fact, with "other deployments: ask admin"
03-request-and-response-format.mdError for a batch arrayCONFIRMEDservices/app-server/src/web/routes_rpc.rs:183-251 (body is Value; Request::try_from); rpc-router-0.1.3 request/request.rs:17-21 (VersionMissing); libs/wms-lib-web/src/error.rs:346-349 (400, RPC_REQUEST_INVALID)Block replaced by fact
03-request-and-response-format.mdHow several objects in filters combineCONFIRMED (OR of AND groups)modql-0.4.1 src/filter/nodes/group.rs:117-150 (Condition::any over groups, Condition::all inside); libs/wms-lib-rpc-core/src/rpc_params.rs:327-332 (Option<OneOrMany<_>>); libs/wms-lib-core/src/model/base/crud_fns.rs:223Block replaced by fact
04-command-types-and-concurrency.mdUndeclared writes may have hidden checksCONFIRMED (general fact)Idempotency is per handler, not global: libs/wms-shared/src/idempotency.rs, pipeline_runner.rs; generic update has no expected-version check (crud_fns.rs:385-425 is the versioned variant only)Block replaced by a plain sentence: "no version check" is not "no rule"
04-command-types-and-concurrency.mdExact current_state fields per commandCORRECTEDlibs/wms-outbound/src/repo/occ.rs:78-109 (order, line); libs/wms-outbound/src/waves/error.rs:111-115 (whole Wave/WavePolicy); libs/wms-outbound/src/packing/commands/carton_close.rs:166; libs/wms-outbound/src/picking/commands/dissolve.rs:797-815; libs/wms-inventory/src/service/inventory_count/mod.rs:182,200; inventory_adjustment/mod.rs:361; inventory_count_policy/save.rs:48; libs/wms-lib-core/src/model/policies/putaway_policy.rs:282 and base/crud_fns.rs:437 (version only); libs/wms-inventory/src/putaway/pipeline/save.rs:244 (conflicts[], no version); libs/wms-tasks/src/error.rs:367-370 (whole task)Table rewritten per domain; block deleted
05-errors.mdMeaning text for serial codes 88-93CORRECTEDEnum libs/wms-shared/src/validation_codes.rs:123-128. 88: libs/wms-serial/src/service/serial/commands/return_serial.rs:70-82 (is_overridable: true). 91: libs/wms-serial/src/service/serial_service.rs:257-273 (is_overridable: true). 92: serial_service.rs:284-297 (false), check at 632-655. 89 and 90: check_two_locations (529) and check_velocity (560) have no caller. 89 and 93: only log warnings in services/app-server/src/services/cleanup_tasks.rs:1097,1176. Override capability is None for all: validation_codes.rs:595-610. "Owner policy" does not exist in codeRows 88-93 rewritten; false "by owner policy" claim removed; block deleted
05-errors.md(found while checking) how serial codes reach the clientCORRECTEDservices/app-server/src/web/rpcs/serial_commands_rpc.rs:37-39 (map_serial_err -> ModelError::Validation(string)); libs/wms-lib-web/src/error.rs:297-300 (HTTP 400 INVALID_DATA); receipt path keeps the code: libs/wms-inbound/src/service/receipt/receive/serial_registration.rs:72Note added under the code table
05-errors.mdLists of context.code strings complete?CORRECTED (not complete)More fn code() / consts in libs/wms-outbound/src/domain/pick_assignment/{aggregate,route,delivery,tare}.rs, picking/infrastructure/holder_change.rs:75-81, cartonization/repair.rs:43-50. Putaway adds none (libs/wms-inventory/src/putaway has no "code": literals)Block replaced by "not complete" note naming the extra sources
05-errors.mdStatus/text for malformed login bodyCONFIRMEDlibs/wms-lib-web/src/handlers/handlers_login.rs:157 (Json<LoginPayload>); axum-0.8.9 extract/rejection.rs (400 syntax, 415 content-type, 422 data)Block replaced by 3-row table and "plain text body"
06-rate-limits-and-limits.mdLimits added by proxy/gatewayUNRESOLVABLEk8s/ has no rate-limit or body-size middleware, but live deployment is unknownBlock kept, narrowed, added a curl loop to verify
06-rate-limits-and-limits.mdMax body sizeCONFIRMEDNo DefaultBodyLimit/RequestBodyLimit anywhere in crates; axum-core-0.5.6 ext_traits/request.rs:319 (2,097,152 bytes), rejection PAYLOAD_TOO_LARGEBlock replaced by fact: 2 MB, HTTP 413
06-rate-limits-and-limits.mdBusiness rules limiting command inputCORRECTED (they exist)libs/wms-outbound/src/waves/policy.rs:44-48,401-410 (max_orders 1..1000, max_lines 1..100000, max_waves_per_run 1..20); wave_rpc.rs:178-186Block replaced by fact
07-webhooks-and-events.mdIs every code in the table published?CORRECTED11 seed codes have no Rust literal (listed in doc). process.order.picked was in the doc but only appears in tests: services/web-ui-server/src/live/outbox_db_tests.rs:133,219Seed-only list added; .picked removed from Order row
07-webhooks-and-events.mdAny API/screen edits event_filter, warehouse_filter, webhook_headersCONFIRMED (none)libs/wms-lib-core/src/model/integration/integration_subscriber.rs:42-61 (no such fields); no match in wms-meta-ui SQL, web-ui-server, ui/srcBlock replaced by fact; seed subscriber ipaas described (wms-enterprise/migrations/001_baseline.sql:1404)
07-webhooks-and-events.mdHTTP client time-out and redirectsCORRECTEDservices/app-server/src/services/webhook_security.rs (30 s production timeout, Policy::none(), validated and pinned DNS answers)Redirect and destination-security behavior updated after B1-03
07-webhooks-and-events.mdStable event id in the webhook bodyCONFIRMED (none)services/app-server/src/services/integration_delivery.rs:597-604 (body fields: event_name, entity_name, key1, warehouse, tenant_id, payload)Block replaced by fact. Also fixed the false mention of key2 (not in body)
07-webhooks-and-events.mdAPI for a poll subscriber to mark readCONFIRMED (none)Reference has only list/get/count for deliveries; integration_delivery.rs:255-257 (poll: debug log only); route string appears only in a SQL comment (archive_pre_baseline/005_integration_event_system.sql:206)Block replaced by fact; added note that poll rows do not hold back event_status (integration_delivery.rs:278,299-304)
07-webhooks-and-events.mdWiring subscriber to integration-platform flowCORRECTEDservices/integration-platform/src/handlers/event_handler.rs:10-24 and server.rs:141,213-215 (POST /api/v1/events/emit, X-Api-Key, tenant from key); seed URL in baseline.sql:1404. Doc said POST /events/emit (wrong path)Path fixed; wiring explained. Which flow runs is platform data, not WMS code (stated)
08-workflows-by-example.mdResponses built from types, not live runUNRESOLVABLENeeds a running serverBlock kept, added steps to verify
08-workflows-by-example.mdDoes putaway run as a Putaway task?CONFIRMED (no)Only TaskDraft creators are picking (libs/wms-outbound/src/picking/infrastructure/tasks.rs) and counting (libs/wms-inventory/src/domain/inventory_count/postgres_repository.rs:573); no create-task RPC in reference/tasks.mdBlock replaced by fact
08-workflows-by-example.mdSteps between closed pallet and shippingCORRECTEDNo dispatch method in any reference group. confirm_shipment and create_picking_task are stubs: services/app-server/src/web/rpcs/wms_task_rpc.rs:10-33. process.shipment.dispatched is never published (only seed, baseline.sql:1057)Block replaced by fact and a "do not use the stubs" warning. Update: both stubs were removed (F-07, 48086a858); the warning is gone from the page.

Counts​

  • Blocks handled: 24 (00-README.md:5 is a legend, not a block).
  • CONFIRMED: 13. Of these, 12 were rewritten as plain fact; the tenant URL fact holds for the Kubernetes provisioner only.
  • CORRECTED: 8 (enterprise scope, current_state fields, serial codes 88-93, context.code lists, business limits, event codes, integration-platform wiring, post-pallet shipping).
  • UNRESOLVABLE (block kept, with steps to verify): 3 (01 quickstart sample responses, 08 sample responses, proxy/gateway limits).
  • Also fixed outside any block: key2 is not in the webhook body; the platform path is /api/v1/events/emit; process.order.picked removed from the event table.

Product findings​

  1. Stub RPCs that look real. confirm_shipment and create_picking_task (services/app-server/src/web/rpcs/wms_task_rpc.rs:10-33) log "STUB" and return fixed fake JSON. They are in the public catalog with roles ADMIN and MANAGER. A client can believe a shipment was confirmed. Remove them, or mark them clearly. Fixed (F-07, commit 48086a858): both methods were removed from the catalog.
  2. Serial commands drop the numeric error code. map_serial_err (services/app-server/src/web/rpcs/serial_commands_rpc.rs:37-39) turns a SerialError::ValidationFailed into a text INVALID_DATA. The return_code (80-95), class and is_overridable are lost. The receipt path keeps them (wms-inbound/.../serial_registration.rs:72). The same code means different wire shapes in two paths. Fixed (F-14): the serial_* methods answer the RF envelope (SerialError::into_model_error) with the code, class and override flag.
  3. Overridable flag with no way to override. Codes 88 and 91 set is_overridable: true (return_serial.rs:75-82, serial_service.rs:257-273), but no serial code has an override capability (wms-shared/src/validation_codes.rs:595-610) and serial_return takes no acknowledgement. The "owner policy" described in the enum comment (validation_codes.rs:472) is not implemented.
  4. Dead anomaly rules. check_two_locations (89) and check_velocity (90) in libs/wms-serial/src/service/serial_service.rs:529,560 have no caller. Code 93 and the 89 scan only write log warnings (services/app-server/src/services/cleanup_tasks.rs:1097,1176). The event process.serial.flagged_anomaly has a payload type but nothing in the anomaly path publishes it. Fixed (P-22): serial_ship runs check_velocity and publishes process.serial.flagged_anomaly; check_two_locations and check_lot_mismatch were removed (89 stays a background log scan).
  5. Locked/Disabled users still authenticate. UserStatus is not checked at login or in API key validation (libs/wms-lib-core/src/model/user.rs:26-33, api_key.rs:247). Only api_access blocks keys. A departed employee marked Disabled keeps access. The code comment already flags it as a missing gate.
  6. api_access flip is delayed up to 30 s (api_key.rs:248-258): no cache invalidation on that change. Revoke does invalidate. Already documented in 02.
  7. Event prefix filter is loose. prefix.* is matched as starts_with(prefix) without the dot (services/app-server/src/services/integration_delivery.rs:440-442). process.* also matches a code like processfoo. A pattern such as process.order.* matches process.order_x... too. Low risk today, but not the documented meaning. Fixed (F-17): prefix.* takes only the codes under the prefix, at a . (event_code_matches).
  8. Resolved B1-03: guarded webhook_url. Create/update still store text, but the worker accepts only HTTP(S), refuses redirects, checks every resolved address, and pins the connection to the validated set. Exact tenant/system-scoped private exceptions require DELIVERY_WEBHOOK_PRIVATE_ALLOWLIST.
  9. Axum rejections bypass the JSON-RPC envelope. rpc_handler takes Json(rpc_body) (routes_rpc.rs:187). Invalid JSON, wrong Content-Type or a body over 2 MB gets a plain-text Axum answer (400/415/413/422), not a JSON-RPC error. Clients must handle both shapes. Fixed (F-16): rpc_handler takes the body as Result<Json<Value>, JsonRejection> and answers RPC_REQUEST_INVALID in the envelope, keeping the HTTP status (wms_lib_web::Error::RpcBodyRejected). /api/login still answers plain text.
  10. Orphan event codes. Eleven seeded codes in event_registry are never published (list in 07). A subscriber that filters on them waits for nothing. Fixed (F-18): is_active now says what is published (enterprise 019: adjusted/moved on, reversal off); wms-lib-core --test event_catalog_census keeps the catalog and the code in step.
  11. Generated reference is silent on stubs. reference/tasks.md lists confirm_shipment without any hint that it is a stub. The generator (scripts/docs-api/generate_reference.py) has no stub marker. Not changed: it needs a source-level marker first.