diff --git a/README.md b/README.md index 72911ed..20d5a76 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ Sports Academy. It helps a guide or coach decide **who to see first, why, and wh adaptive academic software carries practice and adults carry motivation and intervention. The portfolio demo is deliberately narrow: sign in, upload one fixed CSV, validate and commit it, -refresh, inspect the ranked Evidence Desk, review one teacher-friendly evidence list, and see the -report acknowledged. It is not a diagnosis product and makes **no accuracy claim**. +refresh, inspect the ranked Evidence Desk, expand one exact-evidence disclosure, and see the report +acknowledged. It is not a diagnosis product and makes **no accuracy claim**. ## Why this is useful at TSA @@ -140,13 +140,13 @@ walkthrough below; the smoke command does not pretend to replace it. validation stores no activity. 3. **0:40–0:55 — Commit and refresh.** Commit the same bytes, then choose **Refresh board now**. The deterministic engine publishes one immutable ranked run; no model key is needed. -4. **0:55–1:30 — Use the Evidence Desk.** Open the top report. Read the cause-specific opener, compare - it with the student's own baseline, and scan the single deduplicated evidence list. Attempt - outcomes, selected answers, and timing-aware work/session durations remain readable in seconds - without exposing internal record IDs. Severity determines rank; evidence confidence is shown - separately. -5. **1:30–1:45 — Show trust behavior.** Point to “Deterministic fallback · degraded” and the visible - “Seen” acknowledgment. Refresh/back navigation keeps the report and seen state. +4. **0:55–1:30 — Use the Evidence Desk.** Open the top report. Read the cause-specific opener, + compare it with the student's own baseline, then expand **Show exact contributing evidence**. + Exact attempt/session results, selected answers, and timing-aware durations remain readable in + seconds without exposing internal record IDs, additional causes, or rule-quality internals. + Severity determines rank; evidence confidence is shown separately. +5. **1:30–1:45 — Show trust behavior.** Point to the concise “Deterministic fallback” wording cue + and the visible “Seen” acknowledgment. Refresh/back navigation keeps the report and seen state. 6. **1:45–2:00 — Show engineering evidence.** Run `npm run eval:portfolio`: eight fixed cases, hard-fail grounding injections, zero model calls, and an explicit no-accuracy-claim posture. diff --git a/apps/web/app/board/evidence-desk.tsx b/apps/web/app/board/evidence-desk.tsx index 79239ff..423257b 100644 --- a/apps/web/app/board/evidence-desk.tsx +++ b/apps/web/app/board/evidence-desk.tsx @@ -124,8 +124,7 @@ function Rail({

Today’s attention queue

- {board.entries.length} {board.entries.length === 1 ? 'student' : 'students'} · ranked by - deterministic rules + {board.entries.length} {board.entries.length === 1 ? 'student' : 'students'}

    @@ -147,12 +146,6 @@ function Rail({ {entry.scope.kind === 'skill' ? entry.scope.skill.code : 'Across skills'} - {entry.additionalCauseCount > 0 ? ( - - {entry.additionalCauseCount} more{' '} - {entry.additionalCauseCount === 1 ? 'cause' : 'causes'} - - ) : null} {entry.acknowledgedAt ? '✓ Seen' : 'Not yet seen'} @@ -168,42 +161,19 @@ function Rail({ ); } -export function narrationProvenance(entry: BoardEntryView): string { - const mode = - entry.narration.mode === 'deterministic-fallback' - ? 'Deterministic fallback' - : 'Validated generated wording'; - const status = - entry.narration.status === 'degraded' - ? `degraded: ${entry.narration.degradedReason}` - : 'complete'; - return `${mode} · ${status} · catalog ${entry.narration.catalogVersion} · renderer ${entry.narration.renderVersion}`; -} - export function NarrationTrust({ entry }: { entry: BoardEntryView }) { const fallback = entry.narration.mode === 'deterministic-fallback'; - const degraded = entry.narration.status === 'degraded'; - const degradedReason = - entry.narration.degradedReason?.replaceAll('-', ' ') ?? 'generated wording unavailable'; return ( -
+ + ); } @@ -342,20 +322,6 @@ export function ReportContext({

{report.prerequisite}

) : null} - {report.additionalContexts.length ? ( -
-

Also considered

- -
- ) : null} ); } diff --git a/apps/web/app/board/lib/teacher-report-view.ts b/apps/web/app/board/lib/teacher-report-view.ts index 9583ac5..baf4f27 100644 --- a/apps/web/app/board/lib/teacher-report-view.ts +++ b/apps/web/app/board/lib/teacher-report-view.ts @@ -56,29 +56,17 @@ export interface TeacherReportView { evidence: TeacherEvidenceItem[]; sessions: TeacherSessionItem[]; prerequisite: string | null; - additionalContexts: Array<{ - cause: string; - priority: ReturnType; - confidence: string; - }>; } /** - * The report can contain the same activity through several deterministic signals. - * Combine it once at the teacher-facing boundary; internal activity identifiers remain only keys. + * Project only the dominant finding's exact evidence into the teacher-facing disclosure. + * Internal activity identifiers remain rendering keys; additional signals stay in the data contract. */ export function teacherReportView(evidence: EvidenceView): TeacherReportView { const attempts = new Map(); const sessions = new Map(); - const additionalContexts = new Map(); - const attemptSources = [ - evidence.exact.attempts, - ...evidence.comparison.additionalEvidence.map((additional) => additional.attempts), - ]; - const sessionSources = [ - evidence.exact.sessions, - ...evidence.comparison.additionalEvidence.map((additional) => additional.sessions), - ]; + const attemptSources = [evidence.exact.attempts]; + const sessionSources = [evidence.exact.sessions]; for (const source of attemptSources) { for (const attempt of source) attempts.set(attempt.activityId, attempt); @@ -96,17 +84,6 @@ export function teacherReportView(evidence: EvidenceView): TeacherReportView { } } - for (const additional of evidence.comparison.additionalEvidence) { - const cause = humanizeCause(additional.cause); - if (!additionalContexts.has(cause)) { - additionalContexts.set(cause, { - cause, - priority: priorityBand(additional.summary.severity), - confidence: `${confidenceLabel(additional.summary.finalConfidence)} confidence`, - }); - } - } - const prerequisite = evidence.comparison.prerequisiteCheck; return { evidence: Array.from(attempts.entries(), ([key, attempt]) => ({ @@ -139,6 +116,5 @@ export function teacherReportView(evidence: EvidenceView): TeacherReportView { ? `${prerequisite.skillCode} · ${prerequisite.skillName} — mastery not available` : `${prerequisite.skillCode} · ${prerequisite.skillName} — ${Math.round(prerequisite.masteryValue * 100)}% mastery (${prerequisite.verdict})` : null, - additionalContexts: Array.from(additionalContexts.values()), }; } diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css index cc0066d..dee1927 100644 --- a/apps/web/app/globals.css +++ b/apps/web/app/globals.css @@ -681,7 +681,7 @@ blockquote { .provenance { display: grid; - grid-template-columns: auto minmax(0, 1fr) auto; + grid-template-columns: auto minmax(0, 1fr); gap: 10px; align-items: start; padding: 12px 14px; @@ -700,18 +700,6 @@ blockquote { margin-top: 2px; } -.provenance details summary { - padding: 0; - font-size: 0.76rem; - white-space: nowrap; -} - -.provenance details p { - grid-column: 1 / -1; - margin: 8px 0 0; - overflow-wrap: anywhere; -} - .metrics { display: grid; grid-template-columns: repeat(3, 1fr); @@ -728,8 +716,7 @@ blockquote { background: white; } -.metrics dt, -.rule-facts dt { +.metrics dt { color: var(--huddle-muted); font-size: 0.78rem; } @@ -740,13 +727,11 @@ blockquote { font-weight: 800; } -.prerequisite-context, -.additional-context { +.prerequisite-context { margin-top: 18px; } -.prerequisite-context h4, -.additional-context h4 { +.prerequisite-context h4 { margin: 0 0 8px; font-size: 0.9rem; } @@ -756,33 +741,25 @@ blockquote { color: var(--huddle-muted); } -.additional-context ul { - display: flex; - flex-wrap: wrap; - gap: 8px; - margin: 0; - padding: 0; - list-style: none; +.teacher-evidence-disclosure { + overflow: hidden; + border: 1px solid var(--huddle-line); + border-radius: 10px; } -.additional-context li { - display: inline-flex; - flex-wrap: wrap; - gap: 4px; - align-items: baseline; - padding: 6px 8px; - border: 1px solid var(--huddle-line); - border-radius: 8px; - background: var(--huddle-surface); - font-size: 0.78rem; +.teacher-evidence-disclosure > summary { + padding: 14px; + cursor: pointer; + font-weight: 780; } -.additional-context span { - color: var(--huddle-muted); +.teacher-evidence-body { + padding: 0 14px 14px; + border-top: 1px solid var(--huddle-line); } -.teacher-evidence > p { - margin: -2px 0 12px; +.teacher-evidence-body > p { + margin: 12px 0; color: var(--huddle-muted); font-size: 0.86rem; } @@ -990,14 +967,6 @@ blockquote { gap: 4px; } - .provenance { - grid-template-columns: auto minmax(0, 1fr); - } - - .provenance details { - grid-column: 2; - } - .acknowledgment { margin: 14px 14px 0; } diff --git a/apps/web/test/evidence-desk-rendering.test.ts b/apps/web/test/evidence-desk-rendering.test.ts index 7f15971..e5e40ee 100644 --- a/apps/web/test/evidence-desk-rendering.test.ts +++ b/apps/web/test/evidence-desk-rendering.test.ts @@ -10,7 +10,6 @@ import { ReportHeading, StatusCue, TeacherEvidenceList, - narrationProvenance, refreshDescription, } from '../app/board/evidence-desk'; import { teacherReportView } from '../app/board/lib/teacher-report-view'; @@ -61,6 +60,12 @@ const attempt = { hintsUsed: 2, } as const; +const additionalAttempt = { + ...attempt, + activityId: 'activity-hash-additional', + skill: { code: '5.1A', name: 'Additional activity' }, +} as const; + const session = { sessionId: 12, startedAt: '2026-07-29T07:30:00.000Z', @@ -124,20 +129,20 @@ const evidence = { additionalCauses: [ { signalId: 48, - cause: 'hint_farming', + cause: 'decay', severity: 0.45, finalConfidence: 0.7, - ruleId: 'hint.farming', + ruleId: 'decay.previously-mastered', scope: entry.scope, }, ], additionalEvidence: [ { signalId: 48, - cause: 'hint_farming', + cause: 'decay', scope: entry.scope, summary: { - dominantCause: 'hint_farming', + dominantCause: 'decay', severity: 0.45, rawConfidence: 1, finalConfidence: 0.7, @@ -146,7 +151,7 @@ const evidence = { winsorizationMultiplier: 1, conflictMultiplier: 0.7, }, - ruleId: 'hint.farming', + ruleId: 'decay.previously-mastered', ruleVersion: '3', }, computed: { @@ -166,7 +171,7 @@ const evidence = { }, prerequisiteCheck: null, conflicts: [], - attempts: [attempt], + attempts: [additionalAttempt], sessions: [session, emptySession], }, ], @@ -206,6 +211,8 @@ describe('Evidence Desk teacher presentation', () => { expect(html).toContain('Urgent priority'); expect(html).toContain('#1 today'); expect(html).toContain('Medium confidence'); + expect(html).not.toContain('ranked by deterministic rules'); + expect(html).not.toContain('2 more causes'); expect(html).toContain('aria-label="Rank #1 today. Urgent priority. Medium confidence."'); }); @@ -233,7 +240,6 @@ describe('Evidence Desk teacher presentation', () => { expect(report.sessions).toHaveLength(1); expect(html.match(/Work session<\/strong>/g)).toHaveLength(1); expect(report.prerequisite).toBe('4.3E · Fractions — 73% mastery (adequate)'); - expect(report.additionalContexts).toHaveLength(1); expect(html).not.toMatch(/\bms\b/); }); @@ -274,28 +280,25 @@ describe('Evidence Desk teacher presentation', () => { expect(html).not.toContain('conflict'); }); - it('keeps engine and storage jargon out of the normal evidence flow', () => { + it('keeps only exact contributing evidence behind one clear teacher disclosure', () => { + const report = teacherReportView(evidence); const html = renderToStaticMarkup( - createElement(TeacherEvidenceList, { - studentName: 'Avery', - report: teacherReportView(evidence), - }) + createElement(TeacherEvidenceList, { studentName: 'Avery', report }) ); - for (const jargon of [ - 'Attempt ID', - 'activity-hash-1', - 'Ordinal', - 'multiple_choice', - 'word_problem', - 'Signal ID', - 'Rule and quality details', - 'session_only', - '0.92', - '0.5796', - 'conflict', + expect(report.evidence).toHaveLength(1); + expect(html).toContain('Show exact contributing evidence'); + expect(html.match(/
{ ]); }); - it('keeps narration provenance behind its existing technical boundary', () => { - expect(narrationProvenance(entry)).toBe( - 'Deterministic fallback · degraded: model-unavailable · catalog catalog-3 · renderer renderer-8' - ); + it('keeps deterministic fallback as a concise, non-expandable status cue', () => { const trust = renderToStaticMarkup(createElement(NarrationTrust, { entry })); - expect(trust).toContain('Technical provenance'); - expect(trust).toContain('Reason: model unavailable.'); + + expect(trust).toContain('Deterministic fallback'); + expect(trust).toContain('aria-label="Wording status"'); + expect(trust).not.toContain('Narration provenance'); + expect(trust).not.toContain(' { diff --git a/specs/001-huddle-triage-board/contracts/application-interfaces.md b/specs/001-huddle-triage-board/contracts/application-interfaces.md index ee6f09c..abb3753 100644 --- a/specs/001-huddle-triage-board/contracts/application-interfaces.md +++ b/specs/001-huddle-triage-board/contracts/application-interfaces.md @@ -288,17 +288,22 @@ Variant B — **Evidence Desk** is the quick-demo shell: unauthorized, cross-guide, missing, or superseded/unselected runs return the same `not-found` result and expose no student fact. -Evidence is presented in three ordered, visible layers without changing its source: - -1. cause, severity, final confidence, narration/degraded status, and concrete opener; -2. personal-baseline comparison, prerequisite check, and concise evidence-linked additional causes; -3. one visible, deduplicated evidence list with attempted skills, timestamps, outcomes, selected - answers, useful misconceptions, and compact work/session duration context. The presentation names - active versus elapsed time when that distinction is available, renders durations in seconds, keeps - missing duration explicit, and uses record identity only as an unexposed rendering key. - -Every displayed fact points to a stored record or deterministic bundle path. The visible layers never -fetch broader ambient student context. +The teacher-facing report presents: + +1. cause, rank, priority, final confidence, concrete opener, and a concise wording-status cue; +2. personal-baseline comparison and prerequisite check; +3. one accessible **Show exact contributing evidence** disclosure containing only the dominant + finding's deduplicated attempts and sessions: skills, timestamps, results, selected answers, + useful misconceptions, and compact duration context. The presentation names active versus elapsed + time when that distinction is available, renders durations in seconds, keeps missing duration + explicit, and uses record identity only as an unexposed rendering key. + +`EvidenceView.comparison.additionalCauses` and `additionalEvidence` remain intact for deterministic +traceability and downstream contracts. The teacher-facing projection does not render them, rule or +quality details, or expandable technical provenance. + +Every displayed fact points to a stored record or deterministic bundle path. The report never fetches +broader ambient student context. ### Automatic acknowledgment diff --git a/specs/001-huddle-triage-board/contracts/evidence-bundle.md b/specs/001-huddle-triage-board/contracts/evidence-bundle.md index e99eb53..c8da51e 100644 --- a/specs/001-huddle-triage-board/contracts/evidence-bundle.md +++ b/specs/001-huddle-triage-board/contracts/evidence-bundle.md @@ -119,7 +119,8 @@ cross-skill. The bundle contains only synthetic pseudonymous identity plus first `additionalCauses[].signalId` is not sufficient evidence by itself: `EvidenceReader` resolves each ordered additional signal to its own complete bundle-backed computed and derived values, prerequisite check, conflicts, attempts, and sessions so every remaining finding and its causal -evidence is reachable in the Evidence Desk. +evidence remains addressable by the backend contract. The teacher-facing Evidence Desk projects only +the dominant finding's exact evidence and does not render these additional signals. ## Closed catalog and output diff --git a/specs/001-huddle-triage-board/contracts/rule-contract.md b/specs/001-huddle-triage-board/contracts/rule-contract.md index 6d9d5c3..153a6d6 100644 --- a/specs/001-huddle-triage-board/contracts/rule-contract.md +++ b/specs/001-huddle-triage-board/contracts/rule-contract.md @@ -162,7 +162,8 @@ Dominant finding selection and board ranking use the same lexicographic comparat `severity × confidence` is prohibited. A unique signal identity over `(student_id, scope_kind, coalesce(skill_id,''), rule_id, window_start, window_end, behavior_fingerprint)` means the comparator is total. After one dominant finding is selected per -student, remaining findings are drill-down `additionalCauses` in the same order. +student, remaining findings stay in backend `additionalCauses` order; the teacher-facing projection +omits them. ## Complete behavior fingerprint diff --git a/specs/001-huddle-triage-board/plan.md b/specs/001-huddle-triage-board/plan.md index 5898a4a..198d3bc 100644 --- a/specs/001-huddle-triage-board/plan.md +++ b/specs/001-huddle-triage-board/plan.md @@ -244,14 +244,14 @@ cause-specific fallbacks, a restricted runtime database role, and redacted opera repository physically names the dedicated data-access package `packages/db`; this implementation keeps that path. -The Evidence Desk shell combines route state and ordered, always-visible cause, context, and -deduplicated evidence layers with the framework-neutral `EvidenceReader` visible-open boundary -through guide-scoped PostgreSQL adapters. The board reads only the selected immutable head; evidence -opens receive signed one-use grants, acquire a current-head reveal lease, and write replay-safe -first-open acknowledgments to PostgreSQL. The fixed portfolio corpus verifies deterministic fallback -and grounding with zero model calls and no accuracy claim. Optional model-backed narration -attachment, deployment scheduler wiring, and the full simulator/accuracy gates remain implementation -gaps, not alternate contracts. +The current Evidence Desk presentation is owned by the +[application interface contract](./contracts/application-interfaces.md). Its framework-neutral +`EvidenceReader` visible-open boundary runs through guide-scoped PostgreSQL adapters. The board reads +only the selected immutable head; evidence opens receive signed one-use grants, acquire a current-head +reveal lease, and write replay-safe first-open acknowledgments to PostgreSQL. The fixed portfolio +corpus verifies deterministic fallback and grounding with zero model calls and no accuracy claim. +Optional model-backed narration attachment, deployment scheduler wiring, and the full +simulator/accuracy gates remain implementation gaps, not alternate contracts. ### Future gates preserved diff --git a/specs/001-huddle-triage-board/quickstart.md b/specs/001-huddle-triage-board/quickstart.md index 6992d67..14fe164 100644 --- a/specs/001-huddle-triage-board/quickstart.md +++ b/specs/001-huddle-triage-board/quickstart.md @@ -18,9 +18,8 @@ npm run dev ``` Then sign in at `/login`, open `/import`, upload `apps/web/public/synthetic-huddle-sample.csv`, -validate, commit, refresh, return to `/board`, open a report, review the ordered visible cause, -context, and single deduplicated evidence layers, and observe the visible-open acknowledgment. All -roster/activity data in this path is synthetic. +validate, commit, refresh, return to `/board`, and follow the Evidence Desk review flow in the root +[README](../../../README.md). All roster/activity data in this path is synthetic. Explicit reset for the fixed synthetic scope: diff --git a/specs/001-huddle-triage-board/research.md b/specs/001-huddle-triage-board/research.md index cbd579a..877fad7 100644 --- a/specs/001-huddle-triage-board/research.md +++ b/specs/001-huddle-triage-board/research.md @@ -416,9 +416,8 @@ visible placeholder calls the storage-neutral `authorizeVisibleOpen` boundary be same credentials are submitted for acknowledgment only after visibility. A protected internal job handler accepts scheduled dispatch; no public product API or generic repository layer is added. -Variant B — Evidence Desk is the quick-demo shell. On desktop it is a ranked rail plus an ordered -cause → context → deduplicated-evidence workspace; on mobile the same URL-addressable queue/detail -states are mutually exclusive. The current presentation contract is owned by +Variant B — Evidence Desk is the quick-demo shell. The current desktop/mobile presentation contract +is owned by [`contracts/application-interfaces.md`](./contracts/application-interfaces.md). Prefetch reads are side-effect free and grant-free. When navigation actually opens a report, the adapter bypasses prefetched evidence and performs a fresh authorized `openEntry` read, which returns diff --git a/specs/001-huddle-triage-board/spec.md b/specs/001-huddle-triage-board/spec.md index 55910b2..fe9d222 100644 --- a/specs/001-huddle-triage-board/spec.md +++ b/specs/001-huddle-triage-board/spec.md @@ -42,7 +42,7 @@ confidence value, and an opening line. Fully testable without any other story im board, **Then** the higher-severity student is ranked above the lower-severity one. 5. **Given** generated narration is delayed, unavailable, timed out, or rejected by grounding, **When** the guide opens the board, **Then** every entry still has a non-empty, cause-specific, - evidence-grounded deterministic fallback opener, the entry is visibly marked `degraded`, and no + evidence-grounded deterministic fallback opener, the entry shows a concise fallback cue, and no student, cause, confidence, or rank changes. 6. **Given** an authorized synthetic guide, **When** they open the board on desktop, **Then** Variant B — Evidence Desk displays a ranked rail beside the selected evidence workspace; on mobile, the @@ -59,36 +59,39 @@ confidence value, and an opening line. Fully testable without any other story im ### User Story 2 - Evidence Drill-Down (Priority: P2) A guide reads an entry claiming a student is guessing and wants to know why the system believes that -before acting on it. They open the entry and see cause, context, and one teacher-friendly, -deduplicated list of the specific attempts and sessions that support the conclusion. Each attempt -names the skill, result, selected answer, useful misconception when available, readable date/time, -and an honest work duration or missing-duration label. Nothing on the screen is unsourced. +before acting on it. They open the entry, see its cause and student comparison, then expand one clear +disclosure for the exact attempts and sessions that support the conclusion. Each attempt names the +skill, result, selected answer, useful misconception when available, readable date/time, and an honest +work duration or missing-duration label. Nothing on the screen is unsourced. **Why this priority**: A guide who cannot verify a claim will stop trusting the board within a week, and an unverifiable claim about a child is not acceptable to act on. This converts the board from an oracle into an instrument. **Independent Test**: For any board entry, open the drill-down and confirm every number and claim -maps to its exact stored activity or deterministic evidence-bundle path, while each attempt/session -appears only once in the teacher-facing evidence list. Testable against fixed records with no other -story implemented. +maps to its exact stored activity or deterministic evidence-bundle path, while one accessible +disclosure contains each exact contributing attempt/session once. Testable against fixed records +with no other story implemented. **Acceptance Scenarios**: -1. **Given** a board entry with root cause `guessing`, **When** the guide opens its drill-down, - **Then** every contributing attempt is listed once with its attempted skill, result, selected - answer, useful misconception when available, Chicago-local date/time, and readable active, - elapsed, or unavailable duration, alongside the student's own baseline used for comparison. +1. **Given** a board entry with root cause `guessing`, **When** the guide opens its drill-down and + expands **Show exact contributing evidence**, **Then** every exact contributing attempt is listed + once with its attempted skill, result, selected answer, useful misconception when available, + Chicago-local date/time, and readable active, elapsed, or unavailable duration, alongside the + student's own baseline used for comparison. 2. **Given** a board entry that cites a prerequisite check, **When** the guide opens its drill-down, **Then** the prerequisite skill and its mastery value are shown. 3. **Given** any generated or deterministic-fallback sentence on the board, **When** it is compared against the drill-down evidence, **Then** every factual value and qualitative proposition is authorized by that evidence, including every quantity, date, skill, and student attribute. -4. **Given** a guide selects a ranked entry, **When** the evidence workspace opens, **Then** it first - shows the cause, full priority, confidence, narration status, and opener; then baseline, - prerequisite, and concise additional-cause context; then one visible deduplicated evidence list. - Normal flow does not expose attempt/activity/rule/signal identifiers, ordinals, hashes, confidence - math, multipliers, raw pattern dumps, or conflict-adjustment jargon. +4. **Given** a guide selects a ranked entry, **When** the evidence workspace opens, **Then** it shows + the cause, full priority, confidence, concrete opener, student comparison, prerequisite context, + and a concise deterministic-fallback cue when applicable; one clear accessible disclosure reveals + only the dominant finding's exact deduplicated attempt/session evidence. The teacher-facing report + does not expose additional causes/evidence, rule or quality details, expandable technical + provenance, attempt/activity/rule/signal identifiers, ordinals, hashes, confidence math, + multipliers, raw pattern dumps, or conflict-adjustment jargon. 5. **Given** an authorized report becomes visibly open, **When** the automatic acknowledgment action submits the fresh opening-read-issued short-lived one-use grant and its same-opening renewal capability, **Then** expiry after visibility or in flight uniquely claims the expired source nonce, @@ -261,13 +264,13 @@ denied. - **Student returning after a long absence**: a drop in activity volume must not by itself be reported as disengagement when the gap is explained by absence. - **Student with two simultaneous root causes** (e.g., a genuine prerequisite gap *and* guessing): - the entry reports the cause selected by the single FR-027 comparator and discloses that an - additional cause is present, rather than silently discarding it. + the entry reports only the cause selected by the single FR-027 comparator. Remaining causes and + their evidence stay intact in the backend contracts without appearing in the teacher-facing report. - **Student who is genuinely fine**: must be classifiable as `fine` and excluded from the board. Producing an intervention for a student who needs none is a defect, not a harmless extra. - **Contradictory evidence** (timing suggests guessing, answer choices suggest a specific - misconception): confidence is reduced deterministically and the teacher sees concise - additional-cause context rather than confidence math or conflict-adjustment jargon. + misconception): confidence is reduced deterministically; the teacher sees the selected cause and + confidence label rather than additional-cause, confidence-math, or conflict-adjustment details. - **A single attempt with an implausibly long recorded duration**: treated as unknown, not as evidence of effort. - **Every student is fine**: the board renders an explicit empty state, not a blank screen. @@ -276,7 +279,7 @@ denied. - **Activity referencing an unknown skill code**: recorded and reported as unmapped rather than silently dropped or guessed into an adjacent skill. - **Language generation unavailable or slow**: the board still renders with ranking and root causes - intact, a cause-specific grounded fallback opener, and explicit degraded provenance. + intact, a cause-specific grounded fallback opener, and a concise deterministic-fallback cue. - **Refresh fails after a prior success**: the current `board_head` remains unchanged and visible; the failed request is shown separately and never becomes an all-clear. - **Refresh fails before any success**: the board reports `not-built`/unavailable, not successful-empty. @@ -393,21 +396,23 @@ denied. Severity and confidence MUST NOT be multiplied for selection or ranking. - **FR-028**: System MUST exclude students classified `fine` from the board. - **FR-029**: System MUST display an explicit empty state when no student requires attention. -- **FR-030**: System MUST allow an adult to open any entry and view the underlying activity records, - computed values, and comparisons that produced it. +- **FR-030**: System MUST allow an adult to open any entry, review the student comparison, and expand + one accessible disclosure containing the exact attempt/session results, answers, and timing that + contributed to the dominant finding. - **FR-031**: Every claim displayed MUST be traceable to specific recorded activity or to a deterministic computed value over that activity; every qualitative claim MUST also resolve to an eligible closed-catalog proposition and validated evidence-slot binding. -- **FR-032**: System MUST disclose when an entry has an additional root cause beyond the dominant - one reported and MUST retain the underlying signal/evidence link for drill-down. +- **FR-032**: System MUST retain every additional root cause and its underlying signal/evidence link + in the backend data contract, but MUST NOT expose additional causes or their evidence in the + teacher-facing report. - **FR-033**: System MUST NOT report reduced activity as disengagement when the reduction is explained by a recorded absence. Absence MUST be read from recorded attendance, never inferred from gaps in activity — a student who is present and refusing to work produces the same gap as a student who is home sick, and the two require opposite responses. - **FR-050**: System MUST present at most one entry per student per board. Where a student has - several findings, the entry MUST headline the one selected by the complete FR-027 comparator, and - every remaining finding and its evidence MUST be reachable from that entry's drill-down. Ranking - is therefore over students, not over findings. + several findings, the entry MUST headline the one selected by the complete FR-027 comparator. + Every remaining finding and its evidence MUST remain addressable in the backend data contract but + absent from the teacher-facing drill-down. Ranking is therefore over students, not over findings. #### Synthetic Data @@ -468,10 +473,12 @@ denied. - **FR-054**: The quick demo MUST use Variant B — Evidence Desk: a ranked rail and URL-addressable evidence workspace on desktop, and equivalent queue/detail states on mobile. Every queue card MUST expose rank for today, full priority, and confidence accessibly before selection. Each selected - report MUST keep cause → context → evidence visible and end in one teacher-friendly, deduplicated - attempt/session list; internal IDs, ordinals, hashes, rule-quality internals, confidence math, and - conflict-adjustment jargon MUST stay out of normal flow. Returning MUST restore the selected row's - focus and position. + report MUST retain the cause, concrete opener, student comparison, and concise fallback cue, with + one accessible **Show exact contributing evidence** disclosure for the dominant finding's + deduplicated attempt/session results, answers, and timing. Additional causes/evidence, rule and + quality details, expandable technical provenance, internal IDs, ordinals, hashes, confidence math, + and conflict-adjustment jargon MUST stay out of the teacher-facing report. Returning MUST restore + the selected row's focus and position. - **FR-055**: System MUST automatically acknowledge the exact finding after its authorized evidence report is visibly opened. Prefetch MUST create and carry no acknowledgment grant. Actual opening MUST bypass prefetched evidence and perform a fresh authorized read that returns evidence plus a @@ -609,7 +616,7 @@ published number names both seeds. See [`contracts/eval-harness.md`](./contracts none. - **SC-014**: Across every board-visible cause and model failure mode, 100% of entries retain the same membership/cause/confidence/rank, render a grounded non-empty cause-specific fallback opener, and - display degraded provenance. + display a concise deterministic-fallback cue without expandable technical provenance. - **SC-015**: In refresh failure injection, the previous committed board's deterministic projection — head/run selection, membership, ranks, causes, evidence, scopes, confidence, and freshness — remains byte-identical and visible in 100% of cases; narration may attach asynchronously but MUST @@ -746,14 +753,14 @@ quickstart artifacts. The current captain direction additionally fixes the implementation path without reopening the Slice 0 diagnosis contracts: -1. **Shell**: Variant B — Evidence Desk, with explicit queue rank/priority/confidence, visible - cause → context → evidence, one deduplicated teacher evidence list, and route-addressable - master/detail behavior. +1. **Shell**: Variant B — Evidence Desk, with explicit queue rank/priority/confidence, retained cause, + opener, student comparison, one accessible exact-evidence disclosure, no teacher-facing + additional/technical detail, and route-addressable master/detail behavior. 2. **Acknowledgment**: authorize reveal atomically at the visible placeholder, then automatically persist first open after the report is shown; no separate guide action and no prefetch/list side effect. -3. **Narration fallback**: mandatory deterministic cause-specific catalog fallback, visibly degraded, - never blocking or reranking. +3. **Narration fallback**: mandatory deterministic cause-specific catalog fallback with a concise + teacher-facing cue, never blocking or reranking. 4. **Import**: guide-facing bounded synthetic CSV validation/commit in the product. 5. **Platform/security**: Supabase Postgres + Auth; all student-data access remains server-side in `packages/db`, app-scoped to a verified guide/studio, with no browser data client/credential. RLS diff --git a/specs/001-huddle-triage-board/tasks.md b/specs/001-huddle-triage-board/tasks.md index f597c31..ec1610a 100644 --- a/specs/001-huddle-triage-board/tasks.md +++ b/specs/001-huddle-triage-board/tasks.md @@ -267,8 +267,8 @@ bounds → ingest/rules. Full simulator tune/report data cannot generate calibra - [ ] T058 [US1] Truthful loading/not-built/successful-empty/stale/unavailable states in `apps/web/app/board/board-state.tsx`; only a completed full-roster run may be successful-empty. - [ ] T059 [US1] Entry card exposes rank for today, full priority, and confidence accessibly before - selection, and always renders non-empty fallback/generated diagnosis and opener with text/icon - narration provenance; degraded narration loses no entry. + selection, and always renders non-empty fallback/generated diagnosis and opener with a concise + wording-status cue; degraded narration loses no entry. ## Phase 4 — US2 evidence drill-down @@ -285,12 +285,12 @@ bounds → ingest/rules. Full simulator tune/report data cannot generate calibra authorization result before visible rendering. - [ ] T064 [P] [US2] URL-addressable Evidence Desk detail and deduplicated attempt/session list in `apps/web/app/board/evidence-desk.tsx` and its `lib/teacher-report-view.ts` projection. -- [ ] T065 [P] [US2] Teacher-friendly baseline, prerequisite, and concise additional-cause context in - `apps/web/app/board/evidence-desk.tsx`. +- [ ] T065 [P] [US2] Teacher-friendly baseline, prerequisite, and concise deterministic-fallback cue + in `apps/web/app/board/evidence-desk.tsx`. - [ ] T066 [US2] Preserve each evidence-linked additional cause's exact bundle-backed traceability - while normal flow shows concise additional-cause context without duplicated attempt tables or - rule-quality internals; cross-skill scope, focus/scroll restoration, and mobile queue/detail - behavior live in `apps/web/app/board/`. + in the backend contract while excluding additional causes/evidence, rule-quality details, and + expandable technical provenance from the teacher-facing report; cross-skill scope, focus/scroll + restoration, and mobile queue/detail behavior live in `apps/web/app/board/`. ## Phase 4a — Secure quick-demo application shell (US7 + US1/US2) @@ -349,9 +349,9 @@ bounds → ingest/rules. Full simulator tune/report data cannot generate calibra ### Evidence Desk and automatic acknowledgment - [ ] T128 [P] Evidence Desk rendering acceptance in - `apps/web/test/evidence-desk-rendering.test.ts`: queue rank/priority/confidence, visible cause → - context → one deduplicated evidence list, concise additional-cause context, no normal-flow - internals, narrow-width usability, and visible-open behavior. + `apps/web/test/evidence-desk-rendering.test.ts`: queue rank/priority/confidence, opener, student + comparison, one accessible exact-evidence disclosure, concise fallback cue, no additional or + technical teacher-facing detail, narrow-width usability, and visible-open behavior. - [ ] T129 **After T121** compose the existing framework-neutral `EvidenceReader` boundary with a forward migration and concrete guide-scoped storage: grant-free `readEntry`, fresh authorized `openEntry`, signed five-minute one-use grant, opening-bound renewal, `authorizeVisibleOpen`,