Skip to content

#706 Show Position Deadlines On Draft Applications - #707

Open
cielbellerose wants to merge 9 commits into
devfrom
706-show-position-deadlines-on-draft-applications
Open

cielbellerose wants to merge 9 commits into
devfrom
706-show-position-deadlines-on-draft-applications

Conversation

@cielbellerose

Copy link
Copy Markdown
Collaborator

Closes #706

Summary

  • Adds a Deadline column (and matching mobile card line) to the My Applications table, and a deadline slot in the dashboard's My Applications widget, so a draft's position deadline is finally visible on the applicant's own surfaces.
  • Introduces getDeadlineInfo (lib/utils.ts) — a pure helper that classifies a position's window into upcoming / distant / soon / urgent / past and derives the countdown text from a single diffMs, so the tier and the displayed text can never disagree.
  • Floats at-risk drafts (closing within 7 days) to the top: client-side in the table (pre-sorted rows, sort-key stays null so a header click still takes over), and query-side in getRecentMyApplications (merges a bounded at-risk query with the existing recency query) — the dashboard widget's take 3 was silently hiding an old draft with an approaching deadline.
  • Adds getClosingSoonDraftCount and a N closing soon segment to the widget's subtitle.

Changes

  • lib/constants.tsDEADLINE_SOON_DAYS (7), DEADLINE_URGENT_HOURS (48): sole owners of the urgency boundaries, shared by the helper and the query.
  • lib/types.tsDeadlineTier, DeadlineInfo.
  • lib/utils.tsgetDeadlineInfo(position, now), placed directly below getPositionDateInfo (deliberately not merged into it — see the "Notes" section).
  • components/features/deadline-indicator.tsx — new; the only place a deadline is styled, full (table/card) and compact (widget) variants.
  • components/features/my-applications-table.tsxDeadline column, now prop, at-risk pre-sort, mobile card line.
  • app/(main)/(auth)/applications/page.tsx — resolves now server-side and passes it down (avoids a hydration mismatch near a tier boundary).
  • prisma/data/applications.tsbuildAtRiskDraftWhere (shared), the at-risk float in getRecentMyApplications, new getClosingSoonDraftCount.
  • components/features/my-applications-widget.tsx — deadline in the trailing slot for drafts, N closing soon subtitle segment, one shared now.
  • tests/unit/utils.test.ts — tier/countdown/boundary coverage for getDeadlineInfo.
  • tests/db/my-applications-deadline-ordering.test.ts — new; float order, dedupe, take cap, exclusions (past-due, not-yet-open, unpublished, soft-deleted), and count parity.
  • docs/WORKFLOWS.md — AP-10 (Deadline column, tiers, at-risk float) and AP-1 (widget trailing slot + N closing soon).

Deliberately not changed: getPositionDateInfo / PositionDateLine. Widening its emphasis union with a "closing soon" tier would repaint every position card and detail page amber/red, which this ticket doesn't ask for. getDeadlineInfo owns applicant urgency instead; both still classify through the shared getPositionAvailability, so they can never disagree about the underlying window state, only about how to present it.

Testing plan

  • /applications shows a Deadline cell for every row: a draft closing in ~12 hours gets a red badge ("Closes in N hours"), one closing in ~3 days gets an amber badge ("Closes in N days"), one closing in ~30 days shows a plain muted "Closes ", one with no closesAt shows "—", one past its close date shows a red "Closed " badge (with Continue still available), and one not yet open shows a muted "Opens " with no badge.
  • A submitted application's deadline always renders as plain muted text/date, never a badge, regardless of how close the date is.
  • At-risk drafts (soon/urgent) sort to the top of the table, nearest deadline first, ahead of more-recently-touched rows; a not-yet-open or past-due draft never floats.
  • Clicking any column header (Position, Status, Applied, Deadline) takes over sorting and the at-risk float does not reassert itself; ?sort=/?dir= round-trips on reload.
  • Narrower than md, the stacked mobile card shows the same deadline/tiering on its own line.
  • Hovering a deadline shows the exact instant and timezone in the tooltip.
  • The dashboard's My Applications widget lists an old-but-at-risk draft ahead of more-recent applications, with a compact "Nh left"/"Nd left" badge, and the subtitle appends N closing soon when at least one at-risk draft exists.
  • Submitting or deleting the last at-risk draft and reloading / drops the count and removes the closing soon segment.
  • An applicant with no applications still gets the table's and widget's existing empty states; an applicant with applications but no at-risk drafts sees the widget's prior ordering/subtitle unchanged.
  • Both the amber (warning) and red (destructive) badges stay legible in light and dark mode.
  • Unit tests cover getDeadlineInfo's tier boundaries (48h inclusive/exclusive, 7d inclusive/exclusive, past, upcoming, null-date) and singular/plural countdown text.
  • DB test covers getRecentMyApplications's float order, dedupe of a row qualifying for both queries, the take cap, and exclusion of past-due/not-yet-open/unpublished/soft-deleted positions from the float, plus getClosingSoonDraftCount parity.

Automated checks

  • npm run prettier:check — pass
  • npm run eslint:check — pass
  • npm run tsc:check — pass
  • npm run test:unit — pass (409 tests)
  • tests/db/my-applications-deadline-ordering.test.ts — added but not executed in this environment: this worktree's Postgres port (5432) was already occupied by an unrelated container and I could not safely provision a second local database to run the db test project. The test logic was traced manually against the implementation (see PR description); please run npm run test (or the db project alone) in CI/review to confirm.

Notes

  • The countdown is only as fresh as the render; both surfaces are per-request dynamic and revalidated after every application mutation, so a long-lived open tab is the only staleness window — the alternative (a client-side ticking timer) would be a useEffect this codebase avoids.
  • formatCountdown in lib/utils.ts (the login OTP mm:ss timer) is unrelated and untouched.

🤖 Generated with Claude Code

@cielbellerose cielbellerose added the claude Will be worked on by Claude label Sep 11, 2026
@cielbellerose cielbellerose self-assigned this Sep 11, 2026
@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
aplio Ready Ready Preview Sep 21, 2026 3:54am UTC

@cielbellerose cielbellerose added ready for review PR ready for review agent reviewing Review agent working (in-flight) and removed ready for review PR ready for review agent labels Sep 11, 2026

@cielbellerose cielbellerose left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 1 · needs revision

4 open — 1 🟠 Medium, 3 🟡 Low (see inline)

Comment thread components/features/deadline-indicator.tsx
Comment thread prisma/data/applications.ts Outdated
Comment thread lib/utils.ts Outdated
Comment thread lib/utils.ts
@cielbellerose cielbellerose added needs revision Review found issues that need fixing revising Revise agent working (in-flight) and removed reviewing Review agent working (in-flight) needs revision Review found issues that need fixing labels Sep 11, 2026
@cielbellerose

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 1

fixed R1-M1, R1-L1, R1-L2, R1-L3 · faf8184

@cielbellerose cielbellerose added ready for review PR ready for review agent reviewing Review agent working (in-flight) and removed revising Revise agent working (in-flight) ready for review PR ready for review agent labels Sep 11, 2026

@cielbellerose cielbellerose left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 2 · approved

0 open

@cielbellerose cielbellerose added approved Review passed, ready to merge and removed reviewing Review agent working (in-flight) labels Sep 11, 2026
@cielbellerose

Copy link
Copy Markdown
Collaborator Author

Revision requested — UX feedback from review of the preview

Three changes, all in components/features/deadline-indicator.tsx and
components/features/my-applications-widget.tsx. Item 3 reverses a decision
from the approved plan — read its note before implementing.

1. Closes vs Closed is not distinguishable enough

On /applications, a future deadline and a past one currently differ by a
single character in identical styling. For any row where emphasizeUrgency is
false (every submitted row), distant and past both fall through to the same
mutedLine🗓 Closes Mar 28 next to 🗓 Closed Mar 02, same icon, same
muted colour, same weight. Scanning the column, they read as the same thing.

Make the past state unmistakable without shouting on rows the user can't act
on. Options worth considering — pick one and say why:

  • a different icon for past (the calendar-clock currently reads "scheduled",
    not "over")
  • clearer wording than a one-letter delta, e.g. Closed Mar 2 vs
    Closes Mar 28Closed · Mar 2 / Due Mar 28, or past-tense phrasing
    that can't be misread at a glance
  • a distinct (still muted) treatment for past — e.g. strikethrough or a
    deliberately dimmer token

Whatever you choose has to hold for submitted rows too, which is where the
ambiguity actually bites — those never get the urgency branch.

2. Widget: the deadline belongs to the left of the status badge

In ApplicationList, the row is currently
title (flex-1) · ApplicationStatusBadge · deadline (trailing), so the
deadline sits to the right of the Draft tag. Move the deadline before the
status badge.

The reason is the whole point of the ticket: someone with an unsubmitted draft
needs the closing date to land in the same glance as the word "Draft", not
pushed to the far edge of the row. Reorder for all rows so the column
rhythm stays consistent; urgency styling still applies only to drafts.

Keep the layout resilient — the row is flex flex-wrap, and the title holds
min-w-0 flex-1 truncate, so verify a long position title still truncates
rather than pushing the deadline off-row at narrow widths.

3. The countdown should be text, not a Badge

soon and urgent currently render <Badge variant="warning"> /
<Badge variant="destructive">. Drop the badge. The countdown should read as
emphasised text — red and/or bold — not as a pill. Two filled tags in one row
(status + deadline) competes with the status badge and reads heavier than it
should for what is a piece of metadata.

This reverses the approved plan, and it reopens a real accessibility
constraint — solve it, don't re-discover it.
The badges were chosen precisely
because plain coloured text failed AA:

  • --warning is oklch(0.7 0.15 85); as text on bg-card it measures
    ≈2.7:1 — far below AA. Every existing text-warning use in the repo is
    icon-only for this reason (warning-callout.tsx,
    profile-completeness-banner.tsx, position-date-line.tsx).
  • --destructive is oklch(0.55 0.22 28) and is identical in both themes
    (app/globals.css:75 and :120), while --card inverts from
    oklch(1 0 0) to oklch(0.19 0 0). So text-destructive on a card is
    ≈5.4:1 in light mode but only ≈3.4:1 in dark mode — passing in one
    theme, failing in the other.
  • Bold does not rescue it: WCAG's 3:1 large-text threshold needs ≥18.66px for
    bold, and these surfaces are text-sm (14px) and text-xs (12px).

So the fix is a text-safe colour, most likely a new theme-aware token
(a --destructive/--warning variant that lightens in dark mode, following
the per-theme pattern already in globals.css) rather than reusing a token
that was only ever validated as a fill or an icon. Weight and an icon can carry
additional emphasis, but the colour has to pass on its own at 12px and 14px, in
both themes.

State the computed ratios for whatever you land on, for light and dark, at both
sizes — and add a dark-mode contrast check to the manual test matrix.

Unchanged

Everything else stands: the single-diffMs helper, getDeadlineInfo taking a
PositionWindow and gating urgency on getPositionAvailability, the
server-resolved now, the sort.key-stays-null pre-sort, the two
take-bounded queries plus the separate count, and LocalTime wrapping every
rendered date so the exact instant stays in the tooltip. Do not touch
getPositionDateInfo or PositionDateLine — position cards must not change
appearance.

@cielbellerose cielbellerose added needs revision Review found issues that need fixing revising Revise agent working (in-flight) and removed approved Review passed, ready to merge needs revision Review found issues that need fixing labels Sep 11, 2026
@cielbellerose

Copy link
Copy Markdown
Collaborator Author

Revision — UX feedback follow-up

fixed all 3 items (past-deadline distinctness, deadline-before-badge ordering, Badge → AA-safe text tokens) · 2591a05

New tokens --warning-text / --destructive-text (app/globals.css): light 5.53:1 / 5.43:1, dark 5.66:1 / 5.36:1 against --card at 12px/14px (WCAG AA normal-text threshold, 4.5:1).

@cielbellerose cielbellerose added ready for review PR ready for review agent reviewing Review agent working (in-flight) and removed revising Revise agent working (in-flight) ready for review PR ready for review agent labels Sep 11, 2026
@cielbellerose cielbellerose added revising Revise agent working (in-flight) and removed needs human Pipeline escalation: 3 review cycles without convergence needs revision Review found issues that need fixing labels Sep 18, 2026
cielbellerose and others added 6 commits September 18, 2026 10:45
Adds a Deadline column/mobile line and dashboard-widget trailing slot
with amber/red urgency badges for at-risk drafts, and floats at-risk
drafts ahead of recency order in both the table and
getRecentMyApplications so a stale-but-closing-soon draft can't be
hidden by a take-bounded query.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Distinguish past deadlines (icon + dimmer muted line), move the
deadline before the status badge in the widget, and replace the
soon/urgent/past Badge with AA-safe text tokens (--warning-text /
--destructive-text) instead of the fill-only --warning/--destructive.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Deadline column header already names the field, so drop the redundant
Closes/Closed prefix (upcoming keeps Opens, which is load-bearing);
render soon/urgent as the compact Nd/Nh-left countdown everywhere
instead of a longer table-only form. Removes the now-unused
DeadlineInfo.countdown field and its tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Restore the widget's title-badge-trailing order and add the draft
deadline segment to the application detail page per the addendum.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Closes out three still-open review threads from earlier cycles
(R4-L1, R4-L2, R5-L1) that were never trimmed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@cielbellerose

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 1 (Human Direction)

fixed rebase-authorized action-cell merge, widget row order regression, detail-page deadline segment (scope addendum) · fixed R4-L1, R4-L2, R5-L1 (leftover long comments) · rebase: components/features/my-applications-table.tsx (combined per authorized resolution — kept buildColumns structure, wrapped action cell in TERMINAL_DECISION_STATUSES guard) · 298d505, db005d0

follow-up: no automated render-test coverage added for the detail page's draft/non-draft split — this repo has no component-render test infra (no testing-library dependency), so the split relies on the already-unit-tested getDeadlineInfo/DeadlineIndicator tiering plus the manual testing-plan step; flagging in case a future ticket wants to add that infra.

@cielbellerose cielbellerose added ready for review PR ready for review agent and removed revising Revise agent working (in-flight) labels Sep 18, 2026
@cielbellerose cielbellerose added reviewing Review agent working (in-flight) and removed ready for review PR ready for review agent labels Sep 18, 2026

@cielbellerose cielbellerose left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 6 · approved

0 open

@cielbellerose cielbellerose added approved Review passed, ready to merge and removed reviewing Review agent working (in-flight) labels Sep 18, 2026

@cielbellerose cielbellerose left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Human Direction — Cycle 2

Operator-authored, not a review-agent pass. Two UI corrections, both recorded in the #706 body under "Scope addendum 2". Re-read that issue body before starting.

1. Move the dates to the left of the status tag in the dashboard widget

components/features/my-applications-widget.tsx — the row currently renders:

Link (title) → <ApplicationStatusBadge> → <span> (DeadlineIndicator | LocalTime)

Swap the last two so the trailing date content sits before the badge and the badge is the rightmost element:

Link (title) → <span> (DeadlineIndicator | LocalTime) → <ApplicationStatusBadge>

This applies to all three trailing contents — the urgency countdown (5h left), the plain close date, and the submitted date.

This reverses item 2 of the previous Human Direction, which asked for the badge to sit immediately after the title. That earlier instruction is superseded; the operator has seen it rendered and wants the dates on the left. Update the widget mock in the issue's section 2 and the AP-1 entry in docs/WORKFLOWS.md so neither keeps describing the old order.

2. Remove the orphaned separator dot on the past-deadline line

components/features/deadline-indicator.tsx, in mutedLine:

{isPast && '· '}

Delete this expression. It renders a leading dot with nothing to its left — 🗓 · Mar 2, 2026.

For context, so the fix is made with the right intent: this is a refactor leftover, not a deliberate treatment. The line originally read {info.label}{isPast ? ' · ' : ' '}, where the · separated the word Closed from the date. Commit 2797540 ("drop deadline label, unify countdown to compact form") removed {info.label} as redundant with the column header but left the separator behind.

Keep isPast && 'opacity-70' — the dimming is the intended past-tier treatment. Do not substitute another separator or prefix; the bare icon-plus-date line is what is wanted. upcoming keeps its Opens prefix unchanged, and the emphasized soon/urgent/past lines are untouched.

Note mutedLine is shared by both variants, so this also fixes the table's full variant on non-draft rows with a closed position — verify both surfaces.

Scope

These two changes only. No other behaviour, tiering, ordering or data change. The full acceptance criteria, including the four added ones, are in the #706 body.

Move widget trailing slot before status badge and drop the orphaned
separator dot on the past-deadline muted line.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@cielbellerose

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 2

fixed both Human Direction items · cae2a5f

@cielbellerose cielbellerose left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 7 · approved

0 open

@cielbellerose cielbellerose left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Human Direction — Cycle 3

Operator-authored, not a review-agent pass. One behavioural change, recorded in the #706 body under "Scope addendum 3". Re-read that issue body before starting.

Treat withdrawn exactly like draft for deadline urgency

Every urgency gate in this PR currently tests status === 'draft'. That is too narrow. components/features/my-application-primary-action.tsx renders Edit & resubmit for a withdrawn application while the position is still accepting — its own comment calls draft and withdrawn "the only applicant-editable statuses". The close date is therefore just as actionable on a withdrawn application, and it can expire just as silently.

Widen each gate to draft-or-withdrawn:

  1. components/features/my-applications-widget.tsx — the row branches app.status === 'draft' ? <DeadlineIndicator …/> : <LocalTime date={app.submittedAt} …/>. Withdrawn takes the DeadlineIndicator branch.
  2. components/features/my-applications-table.tsxemphasizeUrgency={a.status === 'draft'} on the deadline column, and the atRiskDeadlineDate helper's if (a.status !== 'draft') return null guard. Both widen. The mobile card inherits the cell, so it needs no separate change — verify that.
  3. app/(main)/(auth)/applications/[id]/page.tsx — the deadline segment is gated on isDraft. Widen only the deadline gate. isDraft also drives the Draft · last saved vs Applied prefix, which must NOT change — a withdrawn application keeps Applied <date>. Introduce a separate boolean for the urgency gate instead of reusing isDraft.
  4. prisma/data/applications.tsbuildAtRiskDraftWhere has status: 'draft'; make it status: { in: ['draft', 'withdrawn'] }. This flows to both getRecentMyApplications's float and getClosingSoonDraftCount.

Ordering and the count are in scope, not just styling. A withdrawn application closing in two days that never floats into the widget's top 3 gets nothing from the display change, and a N closing soon subtitle that omits it contradicts the badge rendered right above it. Same reasoning the original scope gives for the draft float.

Rename the two now-misleading helpers — neither is draft-specific any more: buildAtRiskDraftWherebuildAtRiskWhere, getClosingSoonDraftCountgetClosingSoonCount. Update every call site and tests/db/my-applications-deadline-ordering.test.ts.

Unchanged: submitted, reviewing, accepted, rejected still render the plain muted date with no urgency styling and never float. Tiering, thresholds, copy, row order and the DeadlineIndicator component's internals are all untouched.

Tests and docs

Extend tests/unit/utils.test.ts and tests/db/my-applications-deadline-ordering.test.ts so a withdrawn application is covered at the tier boundaries and in the float ordering — the DB test in particular should prove a withdrawn at-risk row floats and is counted. Update docs/WORKFLOWS.md (AP-1, AP-10, AP-11) wherever they say the urgency treatment is draft-only.

Scope is this change only.

Widens every urgency gate to draft-or-withdrawn (widget, table, mobile
card, detail page, at-risk float, closing-soon count) and renames
buildAtRiskDraftWhere/getClosingSoonDraftCount to drop the now-stale
"draft" qualifier. Also retires the destructive past-deadline badge —
past always renders the plain muted date regardless of status, since
#748 removes Continue from past-deadline drafts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@cielbellerose

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 3

withdrawn treated like draft for urgency (widget/table/mobile card/detail page/float/count), buildAtRiskDraftWhere→buildAtRiskWhere, getClosingSoonDraftCount→getClosingSoonCount; past tier now always renders muted (no destructive badge) regardless of status (issue #706 addendum 3 §8) · 3b92eb3

@cielbellerose cielbellerose left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 8 · approved

1 open — 1 🟡 Low (see inline)

closesAt: new Date(NOW.getTime() + 2 * DAY),
deletedAt: new Date(NOW.getTime() - 1 * HOUR),
});
const posWithdrawnUrgent = await createTestPosition(admin, {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R8-L1 🟡 Low — withdrawn coverage is added only at the urgent and past-due tiers (withdrawnUrgent, withdrawnPastDue); there's no withdrawn fixture at the soon tier analogous to draftSoonOld. buildAtRiskWhere makes draft/withdrawn behave identically so this isn't a correctness risk, but addendum 3 asks for coverage "at each tier." Fix: add a posWithdrawnSoon/withdrawnSoon fixture and include it in the float/count assertions.

@cielbellerose cielbellerose left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Human Direction — Cycle 4

Operator-authored, not a review-agent pass. A styling rework of the deadline column, recorded in the #706 body under Scope addendum 4. Re-read that issue body before starting — addendum 4 supersedes the tier→treatment table in the original UX states section and the contrast table under it.

Why

emphasizeUrgency is consulted only in the soon and urgent branches of DeadlineIndicator, so distant returns mutedLine unconditionally. A draft closing in 10 days renders identically to an accepted application closing in 10 days — the actionable/not-actionable distinction vanishes outside the 7-day window, which defeats the feature.

The changes

1. lib/constants.tsDEADLINE_URGENT_HOURS: 48 → 24. Leave DEADLINE_SOON_DAYS = 7 alone; it still drives the at-risk float and the closing-soon count.

2. components/features/deadline-indicator.tsx — every future deadline on an editable row is red. With emphasizeUrgency true, distant, soon and urgent all render through emphasizedLine in the destructive tone (text-destructive-text, STATE_ICONS.warning, font-semibold). They differ only in content:

  • urgent (≤24h) → {compactCountdown} left, e.g. 9h left
  • soon and distant → the date, via <LocalTime date={info.date} precision="date" />

With emphasizeUrgency false, all three stay mutedLine exactly as today.

upcoming and past are unchanged — both stay muted for every status. upcoming is an opening date, not a deadline, so the red rule does not reach it; past keeps the addendum 3 §8 always-muted treatment and its opacity-70.

3. Remove the amber tone. No tier renders text-warning-text any more. emphasizedLine's tone parameter is now single-valued — collapse it rather than leaving a one-branch conditional.

4. Delete the now-dead token. --warning-text does not exist on origin/dev; this PR introduced it and DeadlineIndicator is its only consumer. Remove --color-warning-text (around app/globals.css:48) and both --warning-text declarations (light ~line 97, dark ~line 144). Keep --destructive-text — still used. Verify with a grep that nothing else references warning-text before deleting.

5. compactCountdown for soon. It is no longer rendered, so getDeadlineInfo should return null for it on the soon tier, matching distant. Drop any unit assertion that expected Nd.

Consequences to encode, not to flag as bugs

  • soon and distant now render identically. Intentional. The only rendering boundary left is 24 hours. soon is retained purely because buildAtRiskWhere and getClosingSoonCount still use the 7-day window for ordering and the subtitle count — do not collapse the tier itself.
  • A draft three months out is the same red as one two hours out. Also intentional; red means "this is yours and the clock is running", not "emergency". This was chosen knowingly over a graduated scale.

Also close R8-L1

The cycle 8 review left one Low open: tests/db/my-applications-deadline-ordering.test.ts covers withdrawn at urgent and past-due but not soon. Add the missing soon withdrawn fixture while you are in that file.

Tests and docs

Update tests/unit/utils.test.ts for the 24h boundary (24h, 23h59m, 25h) and tests/unit/deadline-indicator.test.ts so it asserts distant and soon render red-with-icon when emphasizeUrgency is true and muted when false. Update docs/WORKFLOWS.md (AP-1, AP-10, AP-11) wherever it describes the amber tier, the 48-hour boundary, or a Nd left countdown.

Scope is this rework only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude Will be worked on by Claude revising Revise agent working (in-flight)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show Position Deadlines On Draft Applications

1 participant