PRD-005: Case Workflow — Inquérito Prévio (Preliminary Inquiry)
Author: MLT backend team | Date: 2026-08-19 | Status: Draft | Version: v0.2.0
Revision History
| Version | Date | Author | Description of Change |
|---|---|---|---|
| v0.1.0 | 2026-08-19 | MLT backend team | Initial draft — second phase of the Case Workflow. Backfilled from the rebuild roadmap (which served as the interim PRD) after an independent validation pass; carries that pass's fixes (início diligente + caducidade-suspension ACs, post-inquiry re-check, witness-cap relocation). |
| v0.2.0 | 2026-09-03 | MLT backend team | Reconciled the caducidade model to the verbatim statute (art. 352.º): the inquiry's start interrupts (not "suspends") the art. 329.º clocks, conditional on início diligente + diligence + nota de culpa within 30 days of the inquiry's conclusion (the operative exit rule). Anchor ("suspicion" vs knowledge) + day-kind pending firm confirmation (#186, epic #185). Legal KB: docs/content/legal/codigo-do-trabalho.md. |
1. Context & Business Rationale
The Inquérito Prévio (PRELIMINARY_INQUIRY) is the second, optional phase of a Portuguese
disciplinary process (processo disciplinar, Código do Trabalho). It is reached from Abertura's exit
only when has_preliminary_inquiry = true; otherwise the case goes straight to CHARGES_ISSUED.
Part of the Case Workflow theme (theme: case-workflow, label workflow: inquérito prévio (2/8)).
Unlike Abertura (the "fat" phase that births the engine), this phase reuses what Abertura
established — the guarded-transition engine, the deliverable + checklist mechanisms, and the
holiday-aware deadline calculator — and adds only the inquiry-specific behaviour. Evidence integrity
writes into the shared tamper-evident audit ledger (Platform Infrastructure, #44).
Why this phase is optional
The Inquérito Prévio (art. 352.º) is a preparatory fact-finding step, not part of the procedure's mandatory spine (nota de culpa → defence → reasoned decision). Its job is to let the employer investigate before drafting well-founded charges.
- Facts already clear (
has_preliminary_inquiry = false) → skip it, straight toCHARGES_ISSUED. - Facts murky / complex (
= true) → run it first.
The trade-off is the caducidade clock (art. 329.º — 60 calendar days from knowledge of the infraction): skip it and the 60 days simply run; run it and it must start within 30 days of the suspicion and proceed diligently (the PoC's misread "30-day" figure is this first-diligence deadline, art. 352.º — not caducidade), and doing so interrupts (art. 352.º — interrompe, not "suspends") the art. 329.º caducidade/prescrição count, buying time the bare 60 days wouldn't — provided the nota de culpa is then issued within 30 days of the inquiry's conclusion (art. 352.º condition c). The branch is decided at Abertura's exit (1/8); the clock-interruption logic lives here.
Sourcing: the firm brief (_poc/firm-qa.md) and the 2026-08-11 client meeting
(_poc/meeting-notes-2026-08-11.md). PoC autopsy:
caducidade / 30-day misread,
witness limits,
JSONB legal state,
outcomes & proposal.
2. Problem Statement
When an employer needs to investigate before charging, there is no server-side way to record the investigative work as structured legal data, enforce the início diligente deadline, interrupt and re-check the caducidade clock (art. 352.º), or produce the closing report and proposal that drive the case onward. The PoC stored inquiry state as an untyped JSONB blob, hard-coded a holiday-blind 30-day value against the wrong clock, and let evidence be uploaded outside any chain of custody.
3. Goals, Non-Goals, and Success Metrics
3.1 Goals
- Record inquiry diligências as typed, queryable legal entities (not a JSONB blob).
- Enforce the início diligente deadline (art. 352.º) and the caducidade interruption the inquiry's start triggers (art. 352.º — interrompe, not "suspends"), with a re-check on exit that the nota de culpa issues within 30 days of the inquiry's conclusion (condition c).
- Produce the Relatório de Inquérito and the instructor's proceed/archive proposal that drive the exit transition.
- Keep every evidence file inside a SHA-256 chain of custody that writes into the shared audit ledger.
3.2 Non-Goals
- The Abertura-exit branch decision itself (lives in PRD-004 / #43).
- The tamper-evident ledger substrate (Platform Infrastructure #44 — this phase consumes it).
- The nota de culpa and everything downstream (phase 3/8+).
3.3 Success Metrics
| Metric Type | Metric Definition | Baseline | Target |
|---|---|---|---|
| Primary | Inquiry state captured as typed entities (vs PoC's JSONB) | 0% typed | 100% typed |
| Guard Rail | Caducidade never silently lapses across the inquiry | PoC: not checked | Re-checked on exit, cited test |
| Guard Rail | Evidence outside a custody chain | PoC: possible | Impossible (no orphan uploads) |
4. User Personas & Actors
4.1 Instrutor (Primary)
- Role: the appointed investigator; conducts the diligências, writes the Relatório de Inquérito, and proposes proceed/archive.
- Frustrations: in the PoC, investigative work had no typed home and deadlines were wrong/invisible.
4.2 Case Manager (Secondary)
- Role: oversees the case; relies on the exit guard to prevent an unlawful advance.
5. User Stories
- As an instrutor, I want to record investigative actions (witness hearings, document collection, document analysis, information requests) as typed entities, so the inquiry is queryable and court-defensible — and I want the system to enforce the início diligente deadline and interrupt the caducidade clock (art. 352.º) when the inquiry starts, then produce the Relatório de Inquérito and record my proceed/archive proposal that drives the exit (with caducidade re-checked — nota de culpa within 30 days of conclusion — before advancing). → #49
- As a case manager, I want every piece of evidence hashed on upload and linked to the diligência that produced it (writing a custody entry into the audit ledger), so no file can be swapped or attached outside the chain of custody. → #51
6. System Requirements
6.1 Diligências
- SYS-REQ-101: Each diligência type shall persist its own typed, constrained, queryable fields — no free-form JSON blob.
- SYS-REQ-102: Inquiry actions shall be scoped to the assigned instructor of the case.
6.2 Legal clocks
- SYS-REQ-201: The first material diligence shall be started within 30 days of the suspicion of irregular conduct (art. 352.º início diligente), covered by a cited test. (Whether "suspicion" equals the recorded knowledge date is pending firm confirmation — #186.)
- SYS-REQ-202: Per art. 352.º, the inquiry's start interrupts (interrompe, not "suspends") the
art. 329.º caducidade/prescrição clocks; the
PRELIMINARY_INQUIRY → CHARGES_ISSUEDtransition shall re-check condition (c) — the nota de culpa is issued within 30 calendar days of the inquiry's conclusion — before advancing (the Abertura-exit check alone is insufficient). Exact anchor/day-kind pending firm confirmation (#186).
6.3 Closing the phase
- SYS-REQ-301: The Relatório de Inquérito shall be generated from the phase's diligências via the shared deliverable mechanism.
- SYS-REQ-302: A proposal (
PROCEED_DISCIPLINARY|ARCHIVE) shall be required before the phase can advance.
6.4 Evidence chain of custody
-
SYS-REQ-401: Every evidence item shall store a SHA-256 computed at upload.
-
SYS-REQ-402: An evidence file shall not be attachable without a chain link (no orphan uploads).
-
SYS-REQ-403: Each custody action (upload/access/copy) shall write an entry into the shared audit ledger (#44) carrying the file's SHA-256 — evidence integrity and the audit trail linked, not duplicated.
-
SYS-REQ-404: A stored evidence item shall be retrievable — its metadata (hash, file name, content type, producing diligência) listable for a case, and its bytes downloadable by a caller who may see the case.
Added 2026-09-04, from the #191 review. This requirement was missing, and its absence made two others unsatisfiable rather than merely incomplete: SYS-REQ-403 mandates auditing an access custody action on a read path that was never specified, and SYS-REQ-401's hash is only meaningful if something can re-read the bytes and compare — an integrity record nothing can check is not chain of custody. It also blocks the Dossier (#98/#99), which has to fold the evidence it cites.
7. Workflow
(from Abertura, has_preliminary_inquiry = true)
│
▼
PRELIMINARY_INQUIRY ── início diligente: first diligence within 30 days of suspicion (art. 352.º)
│ caducidade clock INTERRUPTED (art. 352.º) while running
├─ record diligências (typed: witness hearing / doc collection / analysis / info request)
├─ evidence hashed (SHA-256) + custody entry → audit ledger
├─ generate Relatório de Inquérito
▼
Instructor proposal ── ARCHIVE ──────────────► ARCHIVED
│
└─ PROCEED_DISCIPLINARY
│ (exit re-checks: nota de culpa within 30 days of IP conclusion — art. 352.º c)
▼
CHARGES_ISSUED (phase 3/8)
8. Open Questions
- Witness cap here? Art. 356.º/3 sets the cap at 3 per fact and 10 total (both), and it governs
the arguido's witness list in the response/evidence phase (5–6/8) — not the instructor's own
inquiry hearings, which are uncapped here. Do not apply the arguido's cap to the instructor. (See the
legal KB,
../legal/codigo-do-trabalho.md, and witness limits.) - Article numbering. Article numbers (329.º, 352.º, 356.º) are now cross-checked against the verbatim
consolidated Código do Trabalho in the legal KB (
../legal/codigo-do-trabalho.md). The remaining interpretation points (art. 352.º interrupção anchor + day-kind) are pending firm confirmation — #186.
9. Edge Cases & Exception Handling
- Inquiry started late (first diligence after 30 days) — flagged/blocked per the início-diligente guard.
- Caducidade lapses during a long inquiry (nota de culpa not issued within 30 days of conclusion) — caught by the exit re-check (art. 352.º c), not silently advanced.
- Evidence upload with no producing diligência — rejected (no orphan uploads).
10. Given-When-Then Acceptance Criteria
Conduct & conclude the inquiry (#49)
- Each diligência type persists its own typed fields (queryable, constrained) — no free-form JSON blob.
- Actions are scoped to the assigned instructor of this case.
- The first material diligence is started within 30 days of the suspicion (art. 352.º); a cited test covers it.
- Per art. 352.º, the inquiry's start interrupts the art. 329.º clocks; the exit transition
PRELIMINARY_INQUIRY → CHARGES_ISSUEDre-checks that the nota de culpa is issued within 30 calendar days of the inquiry's conclusion (condition c) before advancing. - The Relatório de Inquérito generates from the phase's diligências via the deliverable mechanism.
- A proposal (proceed/archive) is required before the phase can advance.
Evidence chain of custody (#51)
- Every evidence item stores a SHA-256 computed at upload.
- An evidence file cannot be attached without a chain link (no orphan uploads).
- Each custody action (upload/access/copy) writes an entry into the shared audit ledger (#44), carrying the file's SHA-256.
11. Technical Constraints & Dependencies
- Blocked by: the workflow engine (1/8, #40) and the audit-ledger substrate (#44).
- Reuses Abertura's deliverable + checklist mechanisms and the holiday-aware deadline calculator.
- Built on the E15 platform primitives (AggregateRoot + domain events +
Result<T>).