docs: update OpenAPI contract, README branding, and PROJECT_STATE for the correction milestone

- contracts/openapi.yaml: title is now "Fleet Ops API"; documents the new
  status-recommendation preview endpoint and the apply endpoint's request body
  (recommendation_token) and full error-code set; notes the search endpoint's
  code+params response shape.
- README.md: title and intro now say Fleet Ops, with an explicit note on the
  Fleet Ops (visible)/MobilityOps (technical identifier) naming split; refreshed
  stale test counts (151 backend, 108 Playwright).
- PROJECT_STATE.md: full progress record for the in-progress correction milestone,
  including what's done, what bugs were found and fixed, and what's explicitly not
  yet done (i18n test-strengthening 11D/E/F, clean-checkout drill, Unraid deployment,
  merge to master).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
NuklearRabbit
2026-08-03 23:14:34 +02:00
co-authored by Claude Sonnet 5
parent 1e407754e6
commit a7ac5ed9d0
3 changed files with 136 additions and 10 deletions
+75
View File
@@ -872,3 +872,78 @@ scenarios, demo manifest, About page). Gap audit: `docs/demo-release/current-dem
test results, clean-checkout result, deployment evidence for both the feature branch
and master, responsive/accessibility results, known limitations, rollback procedure)
plus 10 screenshots in `artifacts/fleet-ops-release/screenshots/`.
## Fleet Ops correction: safe status-recommendation flow, MO-016, message codes (2026-08-03) — IN PROGRESS on fix/fleet-ops-i18n-status-flow
Branch `fix/fleet-ops-i18n-status-flow`, created from master's post-release head
(`18344bc`). Audit and rationale in `docs/fleet-ops-correction/` (gap audit, i18n
inventory, vehicle-status decision table). Not yet merged to master.
- **Status-recommendation flow redesigned** per the brief: the old single opaque
"calculate and apply recommended status" action is replaced by a single shared, pure
evaluator (`backend/app/services/vehicle_status.py::evaluate_vehicle_status`) used
identically by the scanner, a new non-mutating preview endpoint
(`POST .../status-recommendation`), and a transactional apply endpoint
(`POST .../apply-recommended-status`) that locks the row, recomputes facts, rejects a
stale `recommendation_token` (optimistic concurrency), refuses unsafe/manual-review
recommendations, and re-validates post-write before resolving the issue. Frontend
`DataQualityIssueDetail.tsx` shows "Review recommendation" → a decision panel
(current/recommended status, why, evidence, consequences, localized in all 3
languages) → an exact "Change status to <status>" confirm action → result, with a
distinct "Manual review required" state offering no generic apply button.
- Fixed the real unsafe shortcut this evaluator exists to eliminate: "maintenance +
active booking" no longer auto-recommends "rented" (current status is itself now a
blocking fact), and "maintenance with nothing else wrong" no longer auto-clears to
"available" (no fact proves maintenance is actually finished — that release stays a
manual decision).
- **MO-016 order independence**: order independence does not mean "same final status
regardless of order" — resolving the booking overlap first genuinely removes the
conflict, correctly leaving nothing to apply. What must (and does) hold either way:
the recommendation always reflects real current facts, and nothing unsafe is ever
applied (never "rented"). Verified by both a backend test
(`test_mo_016_status_conflict_recommendation_is_order_independent`, explicitly scoped
to MO-016/DQ-DEMO-STATUS after finding the original version wasn't) and a browser-level
Playwright test in both orders.
- **"Fleet Ops" is a non-localizable brand constant** (`frontend/src/product.ts`,
backend `PRODUCT_NAME`), wired via `{{productName}}` interpolation everywhere the
brand appeared in locale prose; a permanent test fails the build if any locale file
ever defines the brand name or an `appName` key again.
- **Dynamic backend prose converted to message codes + params**: return status reasons,
audit field/actor-type labels, automation `last_error` (new `last_error_code` column,
migration `799d8800e241`), and search results (sections/vehicles/bookings/issues) all
now carry stable codes the frontend localizes; raw technical text is demoted to a
"Technical details" disclosure everywhere.
- **Knowledge-base fixes**: the demo provider's tokenizer silently dropped accented
characters (`[a-z0-9]+` split "véhicule" into "v"+"hicule"), breaking French
retrieval broadly; fixed to include the Latin-1 accented range. Also reweighted
section scoring so a body match (real substance) outranks a heading/title match (a
shallow structural hint) — the old weighting misranked the damage procedure behind
an unrelated document for the brief's exact validation question in all 3 languages.
Removed leftover "MobilityOps"/"PoC" mentions from 9 procedure documents (knowledge
prose is visible content, missed by the earlier rebrand).
- New `frontend/e2e/fleet-ops-correction.spec.ts` (14 tests) covers branding in 3
languages, language persistence, the full status-recommendation flow (non-mutating
preview, exact confirm text, manual review, stale-token rejection), MO-016 order
independence, trilingual knowledge grounding, and localized audit/automation. Writing
it surfaced and fixed two real bugs: the frontend conflated "no conflict" with
"manual review required" (both carry `safe_to_apply: false`), and the original
MO-016 backend test never actually targeted MO-016's own issue.
- Added a keyboard/reduced-motion/no-color-only-status accessibility test for the new
status-decision panel; added `aria-live="polite"` to the panel so the applied
confirmation is announced.
- `contracts/openapi.yaml` and `README.md` updated: title is "Fleet Ops", the new
status-recommendation endpoint documented, apply-recommended-status's request body
and error codes documented, search endpoint's code+params shape documented, README
states the Fleet Ops/MobilityOps naming split explicitly and refreshes stale test
counts (151 backend, 108 Playwright).
- Gates green so far: 151 backend tests, Ruff, mypy, Alembic upgrade/downgrade
verified, frontend `tsc`/build, full 108-test Playwright suite (rebuilt `api`+`web`
containers each time before testing).
- **Not yet done**: sections 11D/E/F of the i18n test-strengthening brief (hardcoded-
JSX lint check, broader dynamic-content localization tests, a 3-language route
matrix), the clean-checkout drill, Unraid deployment + live 3-language validation,
and the final merge to master with `artifacts/fleet-ops-correction/final-summary.md`
evidence. Do not claim PASS on this correction until all of those are done.
- Commits so far on this branch: `6deb955` (status flow + brand constant + message
codes), `e6539d1` (knowledge fixes), `ac4b163` (Playwright spec updates for the new
flow), `1fdd2b3` (new E2E coverage + 2 bug fixes), `1e40775` (accessibility test).
+11 -4
View File
@@ -1,8 +1,15 @@
# MobilityOps
# Fleet Ops
**Connected operations for vehicle rental and service teams.**
MobilityOps is a working proof of concept for a fictitious mobility company. It combines vehicle and booking operations, a controlled vehicle-return workflow, data-quality review, RAGcore-backed internal knowledge, n8n orchestration and read-only tools published through ITWorx MCP Hub.
Fleet Ops is a working proof of concept for a fictitious mobility company. It combines vehicle and booking operations, a controlled vehicle-return workflow, data-quality review, RAGcore-backed internal knowledge, n8n orchestration and read-only tools published through ITWorx MCP Hub.
**Naming:** "Fleet Ops" is the product's visible name everywhere in the UI, the demo
knowledge base, and this documentation. "MobilityOps" remains the technical
identifier only — the repository name, local directory, package/module names, Docker
Compose project, deployment directory, and database names. The UI is fully trilingual
(nl-BE default, en-GB, fr-BE); see `docs/fleet-ops-correction/` for the localization
architecture, the vehicle-status decision table, and the correction evidence.
The web application uses the premium responsive **Control Rail** interface: a compact
operations-first workspace with persisted readiness metrics, evidence-led exceptions,
@@ -114,9 +121,9 @@ All defaults are configurable via `.env` (see `.env.example`).
## Quality gates
```bash
make test # backend: pytest (127 tests)
make test # backend: pytest (151 tests)
make lint # backend: ruff + mypy (strict, zero errors)
make e2e # frontend: Playwright end-to-end (56 tests, live stack required)
make e2e # frontend: Playwright end-to-end (108 tests, live stack required)
```
Frontend build/typecheck: `cd frontend && npm run build` (`tsc -b && vite build`).
+50 -6
View File
@@ -1,8 +1,11 @@
openapi: 3.1.0
info:
title: MobilityOps API
title: Fleet Ops API
version: 0.1.0
description: Contract baseline for the MobilityOps proof of concept.
description: >-
Contract baseline for the Fleet Ops demo. "Fleet Ops" is the visible product name;
"mobilityops" remains the technical identifier for the repository, deployment
directory, database, and internal service/health identifiers only.
servers:
- url: http://localhost:8128
paths:
@@ -181,26 +184,67 @@ paths:
description: Wrong rule type, issue not open, or overlap still present
'422':
description: booking_ref not one of the overlapping bookings
/api/v1/data-quality/issues/{public_ref}/status-recommendation:
post:
operationId: previewVehicleStatusRecommendation
description: >-
vehicle_status_conflict only. Non-mutating: computes the recommendation from
the same shared evaluator the scanner and apply endpoint use
(app.services.vehicle_status.evaluate_vehicle_status), without resolving the
issue, writing an audit event, or queuing automation. Safe to call repeatedly
-- see docs/fleet-ops-correction/vehicle-status-decision-table.md.
parameters:
- $ref: '#/components/parameters/PublicRef'
responses:
'200':
description: >-
Current/recommended status, recommendation code, safe_to_apply,
manual_review_required, the underlying facts, and a recommendation_token
the apply endpoint revalidates against.
'409':
description: Wrong rule type, issue not open, or vehicle not found
/api/v1/data-quality/issues/{public_ref}/apply-recommended-status:
post:
operationId: applyRecommendedVehicleStatus
description: >-
vehicle_status_conflict only. Applies the one authoritative recommendation
function's output and re-validates before resolving.
function's output within one transaction: locks the issue and vehicle,
recomputes the recommendation from fresh facts, rejects the request if the
supplied recommendation_token no longer matches (RECOMMENDATION_STALE), refuses
an unsafe/manual-review recommendation (MANUAL_REVIEW_REQUIRED) or a
recommendation with nothing to apply (NO_CONFLICT_DETECTED), then re-validates
the same evaluator post-write before resolving the issue.
parameters:
- $ref: '#/components/parameters/PublicRef'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [recommendation_token]
properties:
recommendation_token:
type: string
description: The token from the most recent status-recommendation preview call.
responses:
'200':
description: Applied status, reason and the resolved issue
description: Applied status, reason code and the resolved issue
'409':
description: Wrong rule type, issue not open, or no conflict detected
description: >-
Wrong rule type, issue not open, vehicle not found, stale recommendation
token, manual review required, no conflict detected, or the applied status
did not resolve the conflict on re-validation
/api/v1/search:
get:
operationId: search
description: >-
Bounded typed results (vehicle, booking, data_quality_issue, section).
Data-quality and manager-only sections are filtered server-side by role.
Customers are never returned -- no customer detail route exists.
Customers are never returned -- no customer detail route exists. Every result's
`label` is a stable public_ref/section id (never translatable prose); `detail_code`
(+ optional `detail_params` for data values like make/model/location) is what the
frontend localizes -- the backend never emits English/Dutch/French sentences here.
parameters:
- in: query
name: q