Skip to content

feat(workforce): WR2 P5 — grading store, scorecards, quantified promotion gate (D10)#463

Merged
webdevtodayjason merged 2 commits into
devfrom
feat/workforce-p5-grading
Jul 2, 2026
Merged

feat(workforce): WR2 P5 — grading store, scorecards, quantified promotion gate (D10)#463
webdevtodayjason merged 2 commits into
devfrom
feat/workforce-p5-grading

Conversation

@webdevtodayjason

Copy link
Copy Markdown
Contributor

WR2 P5 — the locked D10 design, implemented

Resumes the Worker Runtime v2 lane where it stopped at P4 (complete + live-verified 2026-06-14). Design source: ops/WORKER_RUNTIME_V2_DESIGN_2026-06-11.md §D10 — numbers and storage locked by Jason 2026-06-11.

Grade store (append-only, PG-native)

  • New job_grade_events table (idempotent DDL in the adapter init + drizzle schema): {run, assignment, template, component, verdict ∈ correct|needs_change|wrong, feedback, grader, created_at}. Assignment/template ids denormalized from the run at write time; no update/delete paths — audit trail first.
  • JobAdapter.recordGrades/listGrades — PG implements, dual delegates, SQLite hard-fails like all workforce paths (PG-canonical policy).

Promotion gate (pure math, exact integers)

  • src/infra/worker-grading.ts: buildScorecard (per-template + per-component rollups) and evaluatePromotionGate≥95% correct over ≥50 graded decisions sustained 2 weeks, computed as correct*100 >= total*95 (no float at the boundary). The sustain clock starts when the passing condition is entered and resets on any dip below the bar.
  • The gate informs; it never auto-promotes. Stage changes remain the operator's existing jobs.runs.review / jobs.assignments.update actions.

Gateway

jobs.grades.record (batch, verdict-validated) · jobs.grades.approveAll (one-click: grades every gradable component correctfeedback only, executes nothing, per D10) · jobs.grades.list · jobs.scorecard (rollup + gate status). All behind the strict-PG workforce guard, audit events emitted.

Workforce Board

  • Run detail: grading panel — ✓/±/✗ per decision component (derived from the run's D9 proposed_action events + report), optional feedback, approve-all, existing grades shown.
  • Template detail: Scorecard section with the gate chip (eligible for next stage / passing — sustaining / not passing) and the gate's own reasons.

Verification

  • 14 gate-math unit tests incl. the exact boundaries (76/80 = 95% passes, 75/80 fails; dip resets the sustain clock; needs_change counts as not-correct).
  • 6 gateway tests (batch record, verdict validation, approve-all derivation, scorecard + gate, param guards); adapter policy suites green.
  • tsc-since 0 net-new (189 baseline); dashboard tsc clean.

Not in this PR (per D10 phasing)

Position-ledger retrieval (D11 read path, P5/P6), knowledge-retrieval grading UI (rides the same store via knowledge:<doc> components), skill self-update proposals (P6). D9 live proof with a write-granting role happens post-deploy.

🤖 Generated with Claude Code

https://claude.ai/code/session_01T3dkQzz2mSrSNtGBE9cmXr

…tion gate (D10)

Implements the locked D10 design (ops/WORKER_RUNTIME_V2_DESIGN_2026-06-11.md):

- Append-only PG grade store: job_grade_events table (idempotent DDL +
  drizzle schema), GradeEvent/GradeEventInput types, JobAdapter
  recordGrades/listGrades (PG-native per the 2026-06-11 storage lock;
  SQLite hard-fails like the rest of workforce, dual delegates to PG).
  Assignment/template ids are denormalized from the run at write time so
  scorecards query without joins. No update/delete paths — audit first.

- Pure gate math (src/infra/worker-grading.ts): buildScorecard rolls up
  per-template and per-component; evaluatePromotionGate implements the
  LOCKED numbers — ≥95% correct over ≥50 graded decisions sustained 2
  weeks — with exact integer math (correct*100 >= total*95) and a
  sustain clock that resets on any dip below the bar. The gate INFORMS
  (eligible/passing/reasons); it never auto-promotes — stage changes
  remain the operator's jobs.runs.review/assignments.update action.

- Gateway: jobs.grades.record (batch, verdict-validated),
  jobs.grades.approveAll (one-click, grades every gradable component
  correct — FEEDBACK ONLY, executes nothing, per D10),
  jobs.grades.list, jobs.scorecard (scorecard + gate status). All behind
  the existing strict-PG workforce guard; audit events emitted.

- Workforce Board: per-run grading panel (✓/±/✗ per decision component,
  optional feedback, approve-all button, existing grades shown) and a
  template Scorecard section with the promotion-gate chip
  (eligible / passing—sustaining / not passing) plus gate reasons.

- Gradable components derive from the run itself (D9 proposed_action
  events by tool + report), so grading plugs straight into the simulate
  evidence trail; knowledge-retrieval grades ride the same store via
  component naming ("knowledge:<doc>").

Verified: 14 gate-math tests (boundaries: 95% exact at 76/80, dip-reset,
sustain window), 6 gateway tests, adapter policy suites green, dashboard
tsc clean, tsc-since 0 net-new (189 baseline).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3dkQzz2mSrSNtGBE9cmXr
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b47ef991-c387-4a22-b67d-e01b6b3f4a4e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/workforce-p5-grading

Comment @coderabbitai help to get the list of available commands.

…rder (review round)

Two confirmed findings from the adversarial review of e2fc392:

- CRITICAL: listGrades defaulted to LIMIT 5000 ascending — once a template
  accrued >5000 grades the scorecard/gate computed over a frozen OLDEST
  window: new wrongs never lowered the rate, dips never reset the sustain
  clock, and a frozen-passing window read "eligible" forever by wall-clock
  alone. listGrades now has NO default limit (the gate's prefix-walk needs
  the full ordered history); the wire-facing jobs.grades.list gets an
  explicit 500 default page instead.

- MAJOR: recordGrades stamped one shared timestamp per batch with a
  random-UUID tiebreak, so whether a mixed-verdict batch transiently
  "dipped below the bar" (resetting the 14-day sustain clock) depended on
  insert-order randomness. Rows now get per-row +1ms offsets so persisted
  order equals the operator's batch order — deterministic gate math.

Also: board's gradable-component mirror now includes metadata.report
(matching gradableComponentsForRun), and the grades-recorded audit event
carries a singular runId so eventLinkValues() links it into run traces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3dkQzz2mSrSNtGBE9cmXr
@webdevtodayjason
webdevtodayjason merged commit d94d5c0 into dev Jul 2, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant