feat: add return to service workflow
This commit is contained in:
1 parent
72ad19a071
commit
f2b736b08e
19 files changed
+2883
-46
No files matched your search
+5
-5
@@ -99,11 +99,11 @@ durable asset record. Repairs, maintenance, work orders, parts usage, equipment
|
||||
movement, testing, and return-to-service history become coherent operational
|
||||
records rather than disconnected actions.
|
||||
|
||||
The Begin Repair and read-only Repair Timeline workflows are complete. An
|
||||
authorized actor can open a repair against a durable miner UUID, record
|
||||
sequenced starting events, and move the miner into repair atomically. Authorized
|
||||
readers can inspect the repair and its ordered immutable events. Later repair
|
||||
lifecycle workflows remain planned.
|
||||
The Begin Repair, read-only Repair Timeline, and Return to Service workflows are
|
||||
complete. An authorized actor can open a repair against a durable miner UUID,
|
||||
record sequenced events, and move the miner into or out of repair atomically.
|
||||
Authorized readers can inspect the repair and its ordered immutable events.
|
||||
Later repair lifecycle workflows remain planned.
|
||||
|
||||
Technician experience is a priority. Responsive and QR-assisted workflows may
|
||||
reduce lookup and data-entry effort where they reinforce the same asset record.
|
||||
|
||||
@@ -15,10 +15,10 @@ and immutable history.
|
||||
|
||||
- [x] Begin Repair (`POST /api/repairs`)
|
||||
- [x] Repair detail and timeline read APIs
|
||||
- [x] Return to Service (`POST /api/repairs/{repair_id}/complete`)
|
||||
|
||||
## Planned
|
||||
|
||||
- [ ] Return to Service
|
||||
- [ ] Control Board Replacement
|
||||
- [ ] Repair Parts Tracking
|
||||
|
||||
@@ -41,9 +41,8 @@ not make these workflows complete.
|
||||
|
||||
## Candidate Task Order
|
||||
|
||||
1. `003-return-to-service.md`
|
||||
2. `004-control-board-replacement.md`
|
||||
3. `005-repair-parts-tracking.md`
|
||||
1. `004-control-board-replacement.md`
|
||||
2. `005-repair-parts-tracking.md`
|
||||
|
||||
These are proposed future files under `docs/tasks/`. They do not exist yet and
|
||||
must not be treated as approved specifications until they are created and
|
||||
|
||||
@@ -0,0 +1,814 @@
|
||||
# Task 003: Return to Service
|
||||
|
||||
## Status
|
||||
|
||||
Ready for implementation.
|
||||
|
||||
## Objective
|
||||
|
||||
Complete the MinerOps repair lifecycle by adding an explicit **Return to Service** operation that closes an active repair, records an immutable completion event, and transitions the miner from `in_repair` to an eligible post-repair lifecycle state.
|
||||
|
||||
The operation must be atomic, permission-controlled, auditable, safe under concurrent requests, and compatible with the existing Begin Repair and Repair Timeline implementations.
|
||||
|
||||
## Product Intent
|
||||
|
||||
A repair should not remain open indefinitely after work is complete.
|
||||
|
||||
An authorized operator must be able to:
|
||||
|
||||
1. identify the active repair,
|
||||
2. confirm the miner is ready to leave repair,
|
||||
3. select or confirm the resulting lifecycle state,
|
||||
4. optionally record a concise completion summary,
|
||||
5. close the repair,
|
||||
6. transition the miner out of `in_repair`,
|
||||
7. preserve immutable operational history.
|
||||
|
||||
This is an operational command, not generic repair editing.
|
||||
|
||||
## Background
|
||||
|
||||
Task 001 introduced the Begin Repair workflow.
|
||||
|
||||
Task 002 introduced repair detail and immutable repair timeline read APIs.
|
||||
|
||||
The current repair model supports:
|
||||
|
||||
- creating an active repair,
|
||||
- moving a miner into `in_repair`,
|
||||
- preserving the miner's pre-repair lifecycle in the repair-start event payload,
|
||||
- enforcing one active repair per miner,
|
||||
- reading repair details,
|
||||
- reading ordered repair events.
|
||||
|
||||
Task 003 completes that lifecycle.
|
||||
|
||||
The implementation must inspect the repository and reuse current names, models, exception conventions, migration patterns, event sequencing, and transaction infrastructure rather than inventing parallel abstractions.
|
||||
|
||||
## Scope
|
||||
|
||||
This task includes:
|
||||
|
||||
- a new `repairs.complete` permission,
|
||||
- a new explicit Return to Service API,
|
||||
- request and response models,
|
||||
- service-layer completion workflow,
|
||||
- focused repository methods,
|
||||
- repair completion persistence,
|
||||
- miner lifecycle transition,
|
||||
- immutable completion event,
|
||||
- concurrency protection,
|
||||
- migration and permission assignment,
|
||||
- full authorization, domain, migration, routing, and regression tests,
|
||||
- release-document update after implementation passes.
|
||||
|
||||
## Explicitly Out of Scope
|
||||
|
||||
Do not implement:
|
||||
|
||||
- generic repair update or patch endpoints,
|
||||
- reopening a completed repair,
|
||||
- cancelling a repair,
|
||||
- abandoning a repair,
|
||||
- repair diagnosis fields,
|
||||
- repair photos,
|
||||
- repair parts consumption,
|
||||
- technician assignment,
|
||||
- work orders,
|
||||
- control board replacement,
|
||||
- MAC transfer,
|
||||
- automatic monitoring confirmation,
|
||||
- automated burn-in or test workflows,
|
||||
- bulk Return to Service,
|
||||
- notifications,
|
||||
- UI changes unless the repository already requires generated API client updates,
|
||||
- changes to unrelated legacy repair routes.
|
||||
|
||||
Those belong in later tasks.
|
||||
|
||||
## User and Operator Workflow
|
||||
|
||||
A typical flow is:
|
||||
|
||||
1. A technician opens the active repair.
|
||||
2. The technician completes physical work and any required validation.
|
||||
3. The technician invokes Return to Service.
|
||||
4. The technician chooses the miner's destination lifecycle:
|
||||
- the original pre-repair lifecycle, when eligible,
|
||||
- or another explicitly allowed lifecycle.
|
||||
5. The technician may enter a completion summary.
|
||||
6. MinerOps atomically:
|
||||
- verifies the repair is active,
|
||||
- verifies the miner is still in repair,
|
||||
- validates the destination lifecycle,
|
||||
- closes the repair,
|
||||
- transitions the miner,
|
||||
- appends a completion event.
|
||||
7. The repair becomes read-only historical data.
|
||||
|
||||
## API
|
||||
|
||||
Add one explicit action route.
|
||||
|
||||
```http
|
||||
POST /api/repairs/{repair_id}/complete
|
||||
```
|
||||
|
||||
Use `complete` unless existing route naming conventions make `return-to-service` materially more consistent. Do not add both aliases.
|
||||
|
||||
### Authentication
|
||||
|
||||
Required.
|
||||
|
||||
### Permission
|
||||
|
||||
```text
|
||||
repairs.complete
|
||||
```
|
||||
|
||||
### Path Parameter
|
||||
|
||||
- `repair_id`: UUID
|
||||
|
||||
### Request Body
|
||||
|
||||
The request should contain:
|
||||
|
||||
```json
|
||||
{
|
||||
"target_lifecycle": "active",
|
||||
"completion_summary": "Replaced failed fan and completed load test."
|
||||
}
|
||||
```
|
||||
|
||||
Use repository-established lifecycle values and naming.
|
||||
|
||||
#### `target_lifecycle`
|
||||
|
||||
Required unless the service can unambiguously restore the original lifecycle under existing product rules.
|
||||
|
||||
Preferred design: require an explicit target lifecycle in the request so the operator confirms the resulting operational state.
|
||||
|
||||
Allowed target values must be restricted to valid non-repair lifecycle states.
|
||||
|
||||
At minimum:
|
||||
|
||||
- `active`
|
||||
- `inactive`
|
||||
|
||||
Also allow other existing non-terminal lifecycle states only if they are already legitimate post-repair states in the current domain model.
|
||||
|
||||
Never allow:
|
||||
|
||||
- `in_repair`
|
||||
- unknown values
|
||||
- deprecated values
|
||||
- terminal or destructive states that are not valid Return to Service destinations
|
||||
|
||||
Do not invent new lifecycle states.
|
||||
|
||||
#### `completion_summary`
|
||||
|
||||
Optional.
|
||||
|
||||
Requirements:
|
||||
|
||||
- trim leading and trailing whitespace,
|
||||
- empty after trimming becomes `null`,
|
||||
- enforce a sensible maximum length using current project conventions,
|
||||
- preserve text exactly after normalization,
|
||||
- do not interpret it as structured diagnosis or parts data.
|
||||
|
||||
### Successful Response
|
||||
|
||||
Return the completed repair using the existing repair-detail response model where practical.
|
||||
|
||||
The response must allow the client to determine:
|
||||
|
||||
- repair UUID,
|
||||
- miner UUID,
|
||||
- completed status,
|
||||
- completion timestamp,
|
||||
- completing actor where exposed by current conventions,
|
||||
- resulting miner lifecycle,
|
||||
- timeline or event count only if already part of the established response.
|
||||
|
||||
Do not expand the response with unrelated miner details.
|
||||
|
||||
### Status Codes
|
||||
|
||||
#### `200 OK`
|
||||
|
||||
Preferred when returning the completed repair representation.
|
||||
|
||||
Use `201` only if existing operational-command conventions clearly require it. Do not use `204` if the existing repair response can be returned cleanly.
|
||||
|
||||
#### `401 Unauthorized`
|
||||
|
||||
Unauthenticated request.
|
||||
|
||||
#### `403 Forbidden`
|
||||
|
||||
Authenticated actor lacks `repairs.complete`.
|
||||
|
||||
#### `404 Not Found`
|
||||
|
||||
The repair UUID does not exist.
|
||||
|
||||
Do not reveal authorization-sensitive information beyond existing project behavior.
|
||||
|
||||
#### `409 Conflict`
|
||||
|
||||
Use for valid requests that conflict with current domain state, including:
|
||||
|
||||
- repair is already completed,
|
||||
- repair is otherwise not active,
|
||||
- miner is no longer in `in_repair`,
|
||||
- repair does not match the miner's active repair,
|
||||
- target lifecycle is known but not eligible for Return to Service,
|
||||
- a concurrent request completed the repair first.
|
||||
|
||||
#### `422 Unprocessable Entity`
|
||||
|
||||
Use for malformed UUIDs, invalid JSON, missing required fields, unknown lifecycle values, excessive summary length, or other request-validation errors.
|
||||
|
||||
## Permissions
|
||||
|
||||
Add:
|
||||
|
||||
```text
|
||||
repairs.complete
|
||||
```
|
||||
|
||||
### Intended Role Assignment
|
||||
|
||||
Follow current role conventions and migrations.
|
||||
|
||||
Expected behavior:
|
||||
|
||||
- Administrator: allowed
|
||||
- Technician: allowed
|
||||
- Read Only / Viewer: denied
|
||||
- Auditor: denied unless current policy explicitly grants operational actions
|
||||
- Unauthenticated: denied
|
||||
|
||||
Do not grant the permission to every role by default.
|
||||
|
||||
Do not overload `repairs.create`.
|
||||
|
||||
## Domain Rules
|
||||
|
||||
### Active Repair Requirement
|
||||
|
||||
Only an active repair can be completed.
|
||||
|
||||
A completed repair cannot be completed again.
|
||||
|
||||
### Miner Lifecycle Requirement
|
||||
|
||||
The associated miner must currently be in `in_repair`.
|
||||
|
||||
If it is not, return a domain conflict and do not modify anything.
|
||||
|
||||
### Destination Lifecycle
|
||||
|
||||
The destination must:
|
||||
|
||||
- exist in the current lifecycle domain,
|
||||
- not equal `in_repair`,
|
||||
- be explicitly allowed as a post-repair state,
|
||||
- be applied only after all validation succeeds.
|
||||
|
||||
### Original Lifecycle
|
||||
|
||||
The Begin Repair workflow preserves the previous lifecycle in the `REPAIR_STARTED` event payload.
|
||||
|
||||
The service may use this value for:
|
||||
|
||||
- validation,
|
||||
- response context,
|
||||
- defaulting only if the API contract and existing model conventions support it safely.
|
||||
|
||||
The implementation must not assume every miner should return to `active`.
|
||||
|
||||
If restoration of the previous lifecycle is supported, preserve exact historical meaning. Do not infer or fabricate it when missing.
|
||||
|
||||
### Completion Is Final
|
||||
|
||||
Once completed:
|
||||
|
||||
- the repair is historical,
|
||||
- the completion event is immutable,
|
||||
- the active-repair constraint is released,
|
||||
- a later repair must be a new repair record.
|
||||
|
||||
### No Silent Repair Mutation
|
||||
|
||||
Do not edit prior events.
|
||||
|
||||
Do not replace the start event.
|
||||
|
||||
Do not overwrite historical lifecycle values.
|
||||
|
||||
## Architecture
|
||||
|
||||
Preserve:
|
||||
|
||||
```text
|
||||
Router -> Service -> Repository -> PostgreSQL
|
||||
```
|
||||
|
||||
### Router Responsibilities
|
||||
|
||||
The router should:
|
||||
|
||||
- define the action route,
|
||||
- validate the UUID and request model,
|
||||
- enforce authentication and `repairs.complete`,
|
||||
- call the service,
|
||||
- map established domain exceptions to HTTP responses,
|
||||
- return the established response model.
|
||||
|
||||
The router must not:
|
||||
|
||||
- contain SQL,
|
||||
- manage commits or rollbacks,
|
||||
- choose lifecycle transitions,
|
||||
- construct event sequence values,
|
||||
- read actor UUIDs from the request body.
|
||||
|
||||
### Service Responsibilities
|
||||
|
||||
The service should:
|
||||
|
||||
- load and lock the repair,
|
||||
- verify it exists and is active,
|
||||
- load and lock the associated miner when required,
|
||||
- verify the miner is in repair,
|
||||
- validate target lifecycle,
|
||||
- normalize summary,
|
||||
- close the repair,
|
||||
- update miner lifecycle,
|
||||
- append the completion event,
|
||||
- return the completed domain result,
|
||||
- ensure the operation is atomic.
|
||||
|
||||
### Repository Responsibilities
|
||||
|
||||
Repositories should provide focused methods for:
|
||||
|
||||
- retrieving an active repair for update,
|
||||
- retrieving the associated miner for update,
|
||||
- marking a repair completed,
|
||||
- updating lifecycle,
|
||||
- obtaining or allocating the next repair event sequence,
|
||||
- appending a repair event,
|
||||
- reading the completed repair representation efficiently.
|
||||
|
||||
Do not introduce a broad generic repair-update method.
|
||||
|
||||
## Database and Migration
|
||||
|
||||
A migration is required if the current schema does not already support all required completion data and permission assignment.
|
||||
|
||||
Inspect the existing repair table before adding columns.
|
||||
|
||||
### Preferred Repair Completion Fields
|
||||
|
||||
If not already present, add only the fields needed to represent completion authoritatively:
|
||||
|
||||
- `completed_at`: timezone-aware timestamp, nullable while active
|
||||
- `completed_by_user_id`: UUID foreign key, nullable while active
|
||||
- `completion_summary`: nullable text
|
||||
- `resulting_lifecycle`: constrained lifecycle value, nullable while active
|
||||
|
||||
Use existing naming conventions if equivalent columns already exist.
|
||||
|
||||
### Status Representation
|
||||
|
||||
Do not add redundant mutable status data if active versus completed can be derived safely from established fields.
|
||||
|
||||
If the current repair schema already uses a status column, reuse and constrain it rather than introducing a second status mechanism.
|
||||
|
||||
### Constraints
|
||||
|
||||
Enforce critical invariants in PostgreSQL where practical.
|
||||
|
||||
Examples:
|
||||
|
||||
- active repair has no completion timestamp,
|
||||
- completed repair has a completion timestamp,
|
||||
- completed repair has a completing actor,
|
||||
- resulting lifecycle is null while active and present when completed,
|
||||
- resulting lifecycle cannot equal `in_repair`,
|
||||
- completion summary length is constrained if the project uses database length checks,
|
||||
- one active repair per miner remains enforced.
|
||||
|
||||
Adapt the exact checks to the existing schema.
|
||||
|
||||
### Foreign Keys
|
||||
|
||||
`completed_by_user_id` should reference the established user table.
|
||||
|
||||
Use the project's existing historical-record deletion policy. Operational history should not silently disappear.
|
||||
|
||||
### Indexes
|
||||
|
||||
Add only indexes justified by actual read patterns.
|
||||
|
||||
Likely useful:
|
||||
|
||||
- existing active-repair partial uniqueness,
|
||||
- lookup by miner,
|
||||
- lookup by completion timestamp only if current repair queue/history queries need it.
|
||||
|
||||
Avoid speculative indexes.
|
||||
|
||||
### Migration Data Handling
|
||||
|
||||
Existing active repairs must remain active.
|
||||
|
||||
Existing completed repairs, if legacy data exists, must be handled without inventing actor IDs, summaries, or lifecycle states.
|
||||
|
||||
If new non-null completion invariants cannot be truthfully applied to legacy completed rows:
|
||||
|
||||
- use nullable historical fields with conditional checks,
|
||||
- preserve legacy data,
|
||||
- document the limitation,
|
||||
- do not fabricate values.
|
||||
|
||||
### Downgrade
|
||||
|
||||
The downgrade must restore the previous schema safely.
|
||||
|
||||
Before dropping completion columns or constraints, restore miner lifecycle only if the downgrade actually reverses newly created completion data and there is a truthful historical source.
|
||||
|
||||
Do not map every historical completed repair to `active`.
|
||||
|
||||
Do not invent original lifecycle values.
|
||||
|
||||
If a fully safe downgrade is impossible once real completion records exist, use the project's established explicit-refusal pattern rather than destructive guessing.
|
||||
|
||||
## Events and History
|
||||
|
||||
Append one immutable completion event.
|
||||
|
||||
Use the existing repair event naming conventions. Preferred semantic name:
|
||||
|
||||
```text
|
||||
REPAIR_COMPLETED
|
||||
```
|
||||
|
||||
Reuse an existing equivalent event type if already defined.
|
||||
|
||||
### Event Fields
|
||||
|
||||
The event must include:
|
||||
|
||||
- event UUID,
|
||||
- repair UUID,
|
||||
- next explicit sequence number,
|
||||
- authenticated actor UUID,
|
||||
- server/database timestamp,
|
||||
- structured payload.
|
||||
|
||||
### Payload
|
||||
|
||||
Include only durable, meaningful values.
|
||||
|
||||
Recommended payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"previous_miner_lifecycle": "in_repair",
|
||||
"resulting_miner_lifecycle": "active",
|
||||
"pre_repair_lifecycle": "inactive",
|
||||
"completion_summary": "Replaced failed fan and completed load test."
|
||||
}
|
||||
```
|
||||
|
||||
`pre_repair_lifecycle` may be omitted if the existing event model or service cannot retrieve it reliably without ambiguity.
|
||||
|
||||
Do not duplicate arbitrary repair fields in the payload.
|
||||
|
||||
Do not store display names as authoritative actor identity.
|
||||
|
||||
### Event Ordering
|
||||
|
||||
Use the established explicit sequence mechanism.
|
||||
|
||||
Do not calculate order from timestamps alone.
|
||||
|
||||
Concurrent event insertion must not produce duplicate sequence values.
|
||||
|
||||
## Models and Validation
|
||||
|
||||
Create or extend focused models.
|
||||
|
||||
Suggested names, adapted to current conventions:
|
||||
|
||||
- `RepairCompleteRequest`
|
||||
- `RepairDetailResponse` or existing equivalent
|
||||
- internal completion result model if needed
|
||||
|
||||
### Validation Requirements
|
||||
|
||||
- UUID path validation,
|
||||
- finite lifecycle validation,
|
||||
- summary trimming,
|
||||
- empty summary normalization,
|
||||
- maximum summary length,
|
||||
- no client-supplied actor,
|
||||
- no client-supplied completion timestamp,
|
||||
- no arbitrary event payload supplied by the client.
|
||||
|
||||
## Concurrency and Atomicity
|
||||
|
||||
The entire operation must use one transaction.
|
||||
|
||||
The following must succeed or fail together:
|
||||
|
||||
1. repair validation,
|
||||
2. miner validation,
|
||||
3. repair completion update,
|
||||
4. miner lifecycle transition,
|
||||
5. completion event insertion.
|
||||
|
||||
### Concurrent Completion
|
||||
|
||||
Two simultaneous completion requests must not both succeed.
|
||||
|
||||
Expected result:
|
||||
|
||||
- one request succeeds,
|
||||
- the other receives `409 Conflict`,
|
||||
- one completion event exists,
|
||||
- one final lifecycle transition exists.
|
||||
|
||||
Use row locking, compare-and-update semantics, or another database-backed mechanism consistent with the repository.
|
||||
|
||||
### Concurrent Miner Changes
|
||||
|
||||
A simultaneous lifecycle-changing operation must not leave:
|
||||
|
||||
- a completed repair with miner still in `in_repair`,
|
||||
- an active repair with miner already returned,
|
||||
- conflicting lifecycle history.
|
||||
|
||||
Lock ordering must be consistent with Begin Repair and other miner workflows to reduce deadlock risk.
|
||||
|
||||
Document the chosen lock order in code comments only where it is not obvious.
|
||||
|
||||
## Error and Failure Behaviour
|
||||
|
||||
On any failure after the transaction starts:
|
||||
|
||||
- no partial completion fields persist,
|
||||
- miner lifecycle remains unchanged,
|
||||
- no completion event persists,
|
||||
- repair remains active.
|
||||
|
||||
Unexpected database integrity failures should be translated using established service/repository exception conventions.
|
||||
|
||||
Do not catch broad exceptions merely to convert them into `409`.
|
||||
|
||||
## Tests
|
||||
|
||||
Add focused tests following current test organization.
|
||||
|
||||
### Authorization Tests
|
||||
|
||||
Verify:
|
||||
|
||||
- unauthenticated request is denied,
|
||||
- user without `repairs.complete` is denied,
|
||||
- Read Only / Viewer is denied,
|
||||
- Technician is allowed,
|
||||
- Administrator is allowed,
|
||||
- existing `repairs.read` behavior is unchanged,
|
||||
- existing `repairs.create` behavior is unchanged.
|
||||
|
||||
### Happy Path Tests
|
||||
|
||||
Verify:
|
||||
|
||||
- active repair completes successfully,
|
||||
- miner transitions from `in_repair` to requested eligible lifecycle,
|
||||
- repair is marked completed,
|
||||
- completion timestamp is server-controlled,
|
||||
- completing actor is authenticated user,
|
||||
- optional summary is persisted,
|
||||
- blank summary normalizes to null,
|
||||
- completion event is appended,
|
||||
- event sequence follows existing events,
|
||||
- response represents the completed repair.
|
||||
|
||||
Test at least:
|
||||
|
||||
- return to `active`,
|
||||
- return to `inactive`,
|
||||
- restoration to a valid original lifecycle when relevant.
|
||||
|
||||
### Domain Conflict Tests
|
||||
|
||||
Verify `409` for:
|
||||
|
||||
- already completed repair,
|
||||
- inactive/non-active repair,
|
||||
- miner not in `in_repair`,
|
||||
- mismatched active repair state,
|
||||
- disallowed destination lifecycle,
|
||||
- duplicate concurrent completion.
|
||||
|
||||
### Validation Tests
|
||||
|
||||
Verify `422` for:
|
||||
|
||||
- malformed repair UUID,
|
||||
- missing required lifecycle,
|
||||
- unknown lifecycle,
|
||||
- `in_repair` as destination,
|
||||
- summary over maximum length,
|
||||
- invalid request shape.
|
||||
|
||||
If lifecycle defaulting is intentionally supported, replace the missing-field expectation with tests for documented default behavior.
|
||||
|
||||
### Missing Resource Test
|
||||
|
||||
Verify `404` for unknown repair UUID.
|
||||
|
||||
### Transaction Rollback Tests
|
||||
|
||||
Force failures at meaningful steps, such as:
|
||||
|
||||
- miner update failure,
|
||||
- repair completion update failure,
|
||||
- event insertion failure.
|
||||
|
||||
Verify no partial state persists.
|
||||
|
||||
### Event Tests
|
||||
|
||||
Verify:
|
||||
|
||||
- exactly one completion event,
|
||||
- immutable event behavior remains,
|
||||
- actor is correct,
|
||||
- payload is structured,
|
||||
- ordering is explicit,
|
||||
- prior events remain unchanged.
|
||||
|
||||
### Database Constraint Tests
|
||||
|
||||
Verify applicable constraints directly, including:
|
||||
|
||||
- completed record requirements,
|
||||
- active/completed consistency,
|
||||
- resulting lifecycle restriction,
|
||||
- one-active-repair rule remains valid.
|
||||
|
||||
### Migration Tests
|
||||
|
||||
Verify:
|
||||
|
||||
- previous head upgrades,
|
||||
- new permission exists,
|
||||
- intended roles receive the permission,
|
||||
- unintended roles do not,
|
||||
- schema constraints exist,
|
||||
- downgrade works safely or refuses explicitly according to project convention,
|
||||
- re-upgrade works,
|
||||
- empty database upgrades through head.
|
||||
|
||||
### Routing Tests
|
||||
|
||||
Verify:
|
||||
|
||||
- static repair routes such as `/api/repairs/queue` and `/api/repairs/parts-summary` still resolve,
|
||||
- `/api/repairs/{repair_id}/complete` resolves correctly,
|
||||
- UUID detail and event routes remain unchanged,
|
||||
- malformed static-looking paths are not accidentally consumed by UUID routes,
|
||||
- expected route count increases only by the intended amount.
|
||||
|
||||
### Regression Tests
|
||||
|
||||
Run at minimum:
|
||||
|
||||
- Begin Repair tests,
|
||||
- Repair Timeline tests,
|
||||
- inventory lifecycle tests,
|
||||
- permission tests,
|
||||
- migration lifecycle suite,
|
||||
- relevant legacy repair tests,
|
||||
- complete project suite if practical.
|
||||
|
||||
## Documentation Updates
|
||||
|
||||
After implementation and validation succeed:
|
||||
|
||||
- mark Return to Service complete in `docs/releases/v0.2-repair-workflow.md`,
|
||||
- update `docs/ROADMAP.md` only if the repository uses it as current implementation status,
|
||||
- update API documentation if maintained separately.
|
||||
|
||||
Do not mark Control Board Replacement or Repair Parts Tracking complete.
|
||||
|
||||
Do not perform broad stale-document cleanup in this task unless a directly changed statement would become materially false.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
The task is complete when all of the following are true:
|
||||
|
||||
1. `POST /api/repairs/{repair_id}/complete` exists.
|
||||
2. Authentication and `repairs.complete` are enforced.
|
||||
3. Only an active repair can be completed.
|
||||
4. The associated miner must be in `in_repair`.
|
||||
5. The target lifecycle is explicit and validated.
|
||||
6. Repair completion and miner transition are atomic.
|
||||
7. Exactly one immutable completion event is appended.
|
||||
8. Concurrent completion cannot succeed twice.
|
||||
9. Existing repair static and UUID routes still resolve.
|
||||
10. Existing Begin Repair and Repair Timeline behavior remains unchanged.
|
||||
11. Migration lifecycle validation passes.
|
||||
12. Permission assignments are correct.
|
||||
13. Focused and regression tests pass.
|
||||
14. `git diff --check` passes.
|
||||
15. No unrelated files are changed.
|
||||
16. No commit or push is performed.
|
||||
|
||||
## Validation Commands
|
||||
|
||||
Use repository-native commands where available.
|
||||
|
||||
At minimum run:
|
||||
|
||||
```bash
|
||||
python -m compileall .
|
||||
```
|
||||
|
||||
Run shell syntax checks for changed shell files, if any.
|
||||
|
||||
Run:
|
||||
|
||||
- focused Return to Service tests,
|
||||
- Begin Repair tests,
|
||||
- Repair Timeline tests,
|
||||
- inventory lifecycle tests,
|
||||
- permission tests,
|
||||
- migration tests,
|
||||
- route audits,
|
||||
- architecture audits,
|
||||
- full suite when practical.
|
||||
|
||||
Validate migrations through:
|
||||
|
||||
- previous head to new head,
|
||||
- downgrade,
|
||||
- re-upgrade,
|
||||
- empty database to head,
|
||||
- disposable development baseline.
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
git status --short
|
||||
```
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
Confirm:
|
||||
|
||||
- no SQL in routers,
|
||||
- no database driver imports in routers,
|
||||
- no transaction management in routers,
|
||||
- no FastAPI imports in services or repositories,
|
||||
- no generic repair update repository introduced,
|
||||
- actor identity comes from authentication,
|
||||
- timestamps are server-controlled,
|
||||
- events are append-only,
|
||||
- route ordering is safe.
|
||||
|
||||
## Completion Report
|
||||
|
||||
Return:
|
||||
|
||||
- branch and starting commit,
|
||||
- files created,
|
||||
- files modified,
|
||||
- migration revision and parent,
|
||||
- route added,
|
||||
- permission added and role assignments,
|
||||
- domain behavior,
|
||||
- concurrency strategy,
|
||||
- event type and payload,
|
||||
- tests added,
|
||||
- focused test results,
|
||||
- regression results,
|
||||
- migration validation results,
|
||||
- architecture audit results,
|
||||
- `git diff --check`,
|
||||
- known limitations,
|
||||
- final `git status --short`.
|
||||
|
||||
Do not commit.
|
||||
Do not push.
|
||||
Reference in new issue
Block a user