Skip to content

Release v1.4.3 - #450

Merged
b-at-neu merged 49 commits into
mainfrom
dev
Aug 15, 2026
Merged

Release v1.4.3#450
b-at-neu merged 49 commits into
mainfrom
dev

Conversation

@b-at-neu

Copy link
Copy Markdown
Collaborator

Release v1.4.3

Changes

Testing plan

  • Browse /positions signed out, reloading ~15 times in a minute → pages keep loading normally; no raw JSON error
  • As a manager, open My Positions → draft positions appear, and long-closed positions with no applications sit under the collapsed archive rather than the active list
  • As an applicant, submit an application, then revisit its apply URL → a read-only "You've already applied" card renders instead of the editable form
  • With a submitted application open in a stale tab, edit a field → refusal toast naming the reason; the answer does not change
  • Start a draft, have an admin add a new required global question, then reopen the draft → it opens with that question shown as an empty required field and blocks submit until answered
  • Answer that new question in /profile instead, return to the draft and submit without touching it → submits successfully
  • As an admin, delete an option an applicant already selected, then open that applicant's answer → the removed value shows in a read-only mismatch notice rather than vanishing
  • Paste 600 characters into a short answer and 6,000 into a long answer → each caps at its limit and saves
  • As a reviewer, open a withdrawn application → the status control is disabled
  • Set a URL-format question and enter google.com (no scheme) → accepted; enter obvious non-URL text → inline error

b-at-neu and others added 30 commits August 13, 2026 22:56
The existing one-liner was too soft to bind and had been ignored: 875
comment lines on dev, 39 of them citing a PR, issue, or ENGINEERING §.
Replaces it with a hard 2-line cap, an explicit no-provenance rule, and
a before/after example, then wires it into the pre-PR self-check so
review-agent scores it. Capped at Low/Nit so comment wording can never
deadlock the review-revise cycle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…very

comment citing an issue, PR, or ENGINEERING § is gone: git blame already
links each line to its PR, and one of these refs pointed at a workflow
file deleted three commits ago.

Comment-only except the ENGINEERING.md clarification that the two-line
cap counts prose, not JSDoc delimiters.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Restore load-bearing facts dropped by condensing: static-path precedence
in the auth webhook route, and formatRelativeTime's bucket contract.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop the ENGINEERING §4 provenance citation from the stale-link guard
comment in position-actions.ts, paraphrasing the reasoning instead —
this PR's own §7 rule forbids doc-section citations in comments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rebases the branch onto the current origin/dev (release bumps + #412/#325/
#383/#358 landed since the last rebase). Reapplies the comment-discipline
sweep at a stricter bar (one line by default, two only where a fact
genuinely can't compress further, terse fragments over narrated sentences)
across the files this cycle covered; ENGINEERING.md/review-agent.md were
not editable from this agent role, so their prose still describes the
prior ≤2-line bar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The docs still described the superseded two-line bar, and the files the
revision agent stopped short of were still written to it. Rewrites §7 and
the review-agent dimension around one line by default, terse fragments
rather than sentences, and sweeps the rest of the codebase to match.

Also clears provenance the earlier passes missed: #356 in lib/auth/guards.ts
and prisma/data/managers.ts, review-finding ids in the question dialogs, and
issue refs across the seed fixtures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Condensed the 3-line isRedirecting comment that merged in from #368
(application-stepper.tsx) down to the established one-line bar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…line

#418 Tighten Comment Discipline Across Code And Docs
Derive read-only state from the shared NON_REVIEWABLE_APPLICATION_STATUSES
constant instead of a hand-written check so the UI cannot drift from the
action's own guard, add explanatory copy, and swap the hardcoded trigger
id for useId() so multiple controls per page stop colliding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Needed for the archived-positions disclosure on /positions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getManagedPositions encoded "still worth attention" as a where OR with
no draft branch, so a manager's drafts never appeared. Invert it: fetch
every non-deleted managed position and decide active vs archived with
a pure predicate, isPositionActive, so the list and (#360) the manager
edit freeze share one source of truth instead of two implementations
that can drift. Archived positions render behind a collapsed disclosure
instead of being dropped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Swap the radix-ui umbrella dependency for the scoped
@radix-ui/react-collapsible package, matching every other primitive
wrapper in components/ui/ and dropping ~40 unnecessary sub-packages
from the lockfile.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
status never auto-flips to 'closed' when closesAt elapses (confirmed:
no cron/trigger does this, and PositionStatusBadge / getRecentlyClosedPositions
already treat status:'open' + past closesAt as closed for display purposes).
isPositionActive checked the raw status column only, so a manager-visible
"Closed" position whose status was still 'open' in the DB stayed in the
active My Positions list forever. It now delegates the closed check to
getPositionAvailability (status:'closed' OR 'closed_by_date'), matching
the rest of the codebase's definition of "closed".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
isPositionActive's _count.applications where clause used
NON_TERMINAL_APPLICATION_STATUSES (includes 'draft'), but that branch is
only reachable once a position is already closed, and submitApplication
refuses a closed position, so a stray draft could never leave 'draft'
and the position could never archive. Switched to
UNRESOLVED_APPLICATION_STATUSES, matching getAdminPositions and the
count shown on the position card.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes stale isPositionActive JSDoc and removes the now-dead
NON_TERMINAL_APPLICATION_STATUSES constant left behind by 90e6e76.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…aft-positions

#340 Managers Cannot See Draft Positions
the client's readiness check now reads snapshot ?? profile (same as the
server), and submitApplication/reopenApplication backfill any missing
snapshot rows from the profile inside a transaction before validating,
so a question added after draft creation surfaces as an empty required
field instead of an unexplained submit failure. Existing drafts also
bypass the profile-completeness gate on the apply page, since that gate
protects creating an application, not resuming one already in progress.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix client/server mismatch for deliberately-cleared global answers:
initialGlobalValues and hasNewRequiredGlobals now branch on snapshot
row presence, not value length, so a cleared (but existing) answer
row no longer falls back to the profile value. Also memoize the
per-render derived values (initialGlobalValues, initialPositionValues,
hasGlobalRow, hasNewRequiredGlobals) since they only depend on props
that don't change after mount.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Condense this PR's comments to the one-line-by-default bar from
ENGINEERING.md §7 and drop the #398 provenance citation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e-after-global-question

#355 Keep In-Progress Drafts Submittable After a Global Question Is Added
reads/writes to APPLICANT_EDITABLE_APPLICATION_STATUSES (draft,
withdrawn) instead of ownership alone, closing the gap where a
submitted application could be silently rewritten and resubmitted.
The apply page renders a read-only "already applied" card for
non-editable statuses, and the stepper/question components surface
the action's exact refusal message via toast instead of a generic one.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Surface the specific refusal message on the "Use profile answers"
revert path, mirroring the onSave/blur path's exact-sentence toast
instead of the generic "Failed to revert some answers" copy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Applies the project-wide comment-discipline rule (ENGINEERING §7) that
landed after most of this PR's comments were written: one line by
default, no provenance refs, no narration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r-writes-and-submission

#345 Gate Application Answer Writes and Submission on Application Status
Prefetches now skip the proxy matcher entirely, the public tier is
sized for a page view plus its RSC payload (10 -> 60/min), and a
rate-limited document navigation gets a real 429 page instead of raw
JSON, while RSC/fetch callers keep the JSON 429.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Git's default core.commentChar of '#' makes every path that re-reads a
message through the editor (rebase, --amend) strip the mandated '#XXX'
subject as a comment, and the commit-msg hook does not run there. Pin it
to ';' in prepare, teach the hook to skip ';' comments, and validate every
commit in a PR by invoking the hook itself so the rules cannot drift.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
b-at-neu and others added 18 commits August 14, 2026 11:19
`git merge -m` writes a message file with no trailing newline, and POSIX
`read` returns non-zero on such a line, so the loop dropped it and found no
subject at all. The hook then exited 1 before the "Merge " exemption could
run, blocking the merge outright.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deleted one comment that only restated its variable's name and
compressed the rest to one line; two genuinely non-obvious
correctness constraints stay as rare two-line exceptions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Redo of a revise-agent cycle whose fixes were lost when its worktree
was deleted before pushing. Collapses the 5/4/3-line comment blocks in
scripts/check-hooks.mjs and commit-message-check.yml down to one line
by default, keeping the two genuinely non-obvious traps (commentChar
pinning, non-fatal config write) as compressed 2-line exceptions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces partitionAnswerValue/isAnswered (lib/utils.ts) so a stored
answer that no longer fits its question's current type/options is
split into the part still renderable ("fitted") and the rest
("orphaned"), instead of one silently overwriting the other on the
next blur. Both applicant editors (ApplicationQuestion, ProfileQuestion)
and the stepper's read-only card now render controls from `fitted` only,
surface `orphaned` via a new read-only AnswerMismatchNotice, and build
every write from `fitted` so a render-time mismatch can never become a
write. "Answered" is redefined via isAnswered everywhere required-answer
checks happen (submitApplication, getProfileCompleteness, the apply-page
gate) so client and server agree on what counts as answered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Consolidating QuestionShape into AnswerQuestion dropped
FORMAT_INPUT_TYPES and the type= prop, so email/phone/url/zip
answers always rendered a plain text input. Relocated the map to
lib/constants.ts alongside the other format constants so
ProfileQuestion can adopt it later.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drops the ENGINEERING §7 citation from the partitionAnswerValue JSDoc
and condenses every other comment this PR introduced (issue refs,
narration, multi-paragraph JSDoc) to the one/two-line terse-fragment
bar, without losing the invariants they document.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Condenses multi-line/duplicated comments this PR introduced to one-line
terse fragments and drops a couple that naming already carried, without
losing the invariants they documented.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes a cross-function reference comment in application-stepper.tsx
and condenses the last two-line comment in profile.ts, completing the
ENGINEERING §7 comment-discipline pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-commit-subjects

#430 Stop Rebases Stripping Commit Subjects and Validate Messages in CI
…s-on-question-shape-change

#354 Preserve Stored Answers When A Question Type Or Options Change
…-throttles-browsing

#404 Public Rate Limit Tier Throttles Normal Browsing And Returns Raw JSON
Adds a shared getAnswerValueError validator (lib/constants.ts) enforcing
choice membership, single-vs-multi value counts, and per-value/array
length caps. Both answer-writing actions call it as the real backstop;
both applicant editors call it inline so the client shows the same
message before round-tripping to the server. Option count/length are
capped via the existing validateOptions refinement so an admin can't
author a choice that's unselectable by the new answer-side limits.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Distinguish a re-thrown { error } from a genuine unexpected throw so
autosave catches never leak an authorization guard's raw message.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Condenses comments added by this PR to the one-line default from
ENGINEERING.md §7 (post #421/#418) and drops issue/section provenance
refs; no behavior change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-against-question-options

#352 Validate Answer Values Against Question Options And Add Length Limits
…-for-withdrawn-applications

#366 Disable Status Control For Withdrawn Applications
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@b-at-neu b-at-neu self-assigned this Aug 15, 2026
@vercel

vercel Bot commented Aug 15, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
aplio Ready Ready Preview Aug 15, 2026 6:04pm

@b-at-neu
b-at-neu merged commit 7299ffb into main Aug 15, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants