Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
359 changes: 359 additions & 0 deletions casework/common/missing_details.py

Large diffs are not rendered by default.

38 changes: 16 additions & 22 deletions casework/common/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,10 @@ class Stage:
requires_materials=PRESS_TYPES + COURT_TYPES,
requires_stages=("convert",),
),
# provides is ("key_allegations",) ONLY. An earlier draft of the plan also
# listed "missing_details"; that field is real on the case API but this
# enricher never writes it -- the donor has zero references to it anywhere
# in its history, and patches exactly one field
# (enrich_allegations.py:303 `api.patch_field(case_slug, "key_allegations", ...)`).
# `provides` feeds the "already enriched, skip it" idempotency checks, so a
# phantom entry here would make a case look complete that this stage never
# touched -- silently skipping work, the same over-gating shape as the
# tags/entities defects.
# ("key_allegations",) ONLY -- this stage reads the press release, never the
# verdict, so it cannot answer `missing_details`. `provides` feeds the
# "already enriched, skip it" checks: a phantom entry would make a case look
# complete that this stage never touched.
"allegations": Stage(
"allegations", provides=("key_allegations",),
requires_materials=PRESS_TYPES,
Expand All @@ -150,21 +145,20 @@ class Stage:
requires_materials=PRESS_TYPES + COURT_TYPES,
requires_stages=("convert",),
),
# `description` writes the long public narrative. It reads the charge
# sheet, the press release AND the verdict, so it gates on both material
# families -- the same PRESS+COURT pair as `timeline`/`entities`, and for
# the same reason: a court-order-only case is still describable, so
# gating on PRESS_TYPES alone would strand it.
# Gates on both material families, like `timeline`/`entities`: a
# court-order-only case is still describable.
#
# provides is ("description",) ONLY -- deliberately NOT ("description",
# "title"). The donor regenerated `Case.title` as a side effect of this
# pass; this port drops that (see `casework/enrich_description.py`'s
# docstring) and `title` has exactly one owner, `enrich_card`. Naming
# "title" here would be the phantom-`provides` mistake documented on
# `allegations` above: an idempotency check reading `provides` would call
# a case title-complete that this stage never touched.
# `missing_details` is the one CONDITIONAL entry in this table. The stage
# writes it from an extra key in the same generate call, but that field
# needs the COURT ORDER specifically, while this stage runs on either
# family -- so a press-only case gets a description and no missing_details.
# Read the tuple as "can provide": an idempotency check requiring BOTH
# fields would loop forever on those cases.
#
# NOT ("description", "title"). The donor regenerated `Case.title` here;
# `title` now has exactly one owner, `enrich_card`.
"description": Stage(
"description", provides=("description",),
"description", provides=("description", "missing_details"),
requires_materials=PRESS_TYPES + COURT_TYPES,
requires_stages=("convert",),
),
Expand Down
31 changes: 3 additions & 28 deletions casework/enrich_allegations.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,9 @@
through `CaseworkApi.patch_field`, which this project's binding constraint
restricts to loopback (`127.0.0.1:48010`) only.

CONCERN -- phantom `missing_details` field (flagged for the dispatcher, not
silently "fixed"): `STAGES["allegations"]` in `casework/common/pipeline.py`
declares `provides=("key_allegations", "missing_details")`, and the task-14
brief accordingly asked for a `normalise_missing_details(value) -> str | None`
helper. Neither exists anywhere in the donor: `git log --all -p -- casework/
enrich_allegations.py` never mentions `missing_details` in the DB-free script's
history, and the 367-line donor at 0321a85 (read in full) writes exactly ONE
field via `api.patch_field(case_slug, "key_allegations", allegations)`. The
`provides` tuple traces back to `task-11-brief.md` (written before this
donor was ever recovered for a Task-12-14 dispatch), not to any donor
behavior. `missing_details` IS a real `Case` field (see `cases/models.py`,
`cases/services/ciaa_draft_case_service.py`, and the OLD, still-live DB-based
`cases/management/commands/enrich_ciaa_allegations.py`), but this DB-free
enricher never wrote it, before or after deletion. Per this task's explicit
"donor is the source of truth" instruction, this port writes ONLY
`key_allegations` and does NOT invent a `normalise_missing_details` helper.
`STAGES["allegations"].provides` is left uncorrected (out of this task's
Create-file scope -- it is shared Task-11 infrastructure) but should be
revisited: a future idempotency check that requires ALL `provides` fields to
be populated before considering this stage "done" would never see it as
complete.

The donor's own prompt-context construction is also narrower than
`enrich_missing_bigo.py`'s `_source_metadata`: the donor's
`USER_PROMPT_TEMPLATE` only ever includes the case title, the bigo display
string, and the full press-release markdown body -- it never built a
DocumentSource-title/description prompt block the way the bigo donor did, so
there is no analogous metadata-surfacing helper to port here.
Writes exactly ONE field, `key_allegations`. `missing_details` is written by
`casework/enrich_description.py`, which has the verdict in hand; this stage only
ever reads the press release.

Usage:
uv run python -m casework.enrich_allegations --dry-run
Expand Down
Loading
Loading