kashi · review-comments-audit · 57–62 reflection
結論:57〜62 の改良インストラクションは、すべて実質的に main に反映&デプロイ済み。 6 pack すべてに専用テストがあり(folder57/58/59/60 + homepage62)、1,710 件のテストが main (eb466f8) で green。未着手 (NOT_DONE) はゼロ、監視・主張安全性の後退もゼロ。残るのは磨き込み・意図的な後回し・テスト網羅の隙間のみ。
「HP(公開ホームページ)」に限れば: 公開ホームページ / の pack は 61 + 62 の2つだけで、両方とも完了・本番デプロイ済み(kashi.ai-labo.workers.dev、最新 = RC62 v3.1)。57〜60 は別サーフェス(アップロード/個人ビュー・ログイン後アプリUX・検出器+/demo・ポリシーConsole)で、これらも反映済み。
監査方法:各 pack の受け入れ基準を Drive から抽出 → 6 体の懐疑エージェントが main (eb466f8) のテスト断言・src・git log・ライブサイトと突き合わせ → 領域ごとに DONE/PARTIAL/SUPERSEDED を根拠付きで分類。生成 2026-06-13。
未着手はゼロ。下記は「磨き込み」「設計上の後回し」「テスト網羅の隙間」「要確認の衛生項目」。意思決定が要るものだけを次の remediation round に回せます。
| 状態 | 受け入れ領域 | 根拠(テスト / ファイル / commit) |
|---|---|---|
| ✓ main 反映 | (1) Upload-first workflow: upload → infer → review-only-uncertain → analyze → result → upload-more/history | src/app/app/admin/upload/upload-form.tsx wires the full chain: inferMetadata (after parse, line 143), needs=new Set(inferred?.needsReview) gating (line 421), computePreviewRow → analyze → <ImportResultSummary> (line 341) with historyHref continuation. Hub at src/app/app/admin/imports/page.tsx. PR #405/#404 merged (commits 870c5d4, 8bf5e55). Locked by folder57-workflow-matrix-lock §M1 (computePreviewRow severity ladder failed→blocked→observational→warning→ready, 6 tests green). |
| ✓ main 反映 | (2) Metadata inference (title/date/platform/lang/speakers/meeting-type+confidence/quality-flags, conservative) | src/lib/ingest/{infer-metadata,language,source-platform,series-recurrence,speaker-member-match,internal-external}.ts all present and real. Orchestrator header states 'Conservative throughout — unknown/low-confidence over hallucination (AC-INFER-017)'. test/folder57-infer-metadata.test.ts (all detectors + needsReview surfacing) and bulk-upload-infer-date.test.ts pass. quality_flags column locked additive in migration 0042 (folder57-schema-foundation.test.ts). PR #404 (commit 8bf5e55). |
| ✓ main 反映 | (3) Metadata review UX (exception-only) | upload-form.tsx surfaces needsReviewBadge ONLY on uncertain fields (line 421-446), high-confidence fields show inferredBadge not a review prompt. folder57-infer-metadata.test.ts 'does not flag high-confidence fields' + workflow-matrix-lock §M2 'high-confidence fields are NOT flagged' / 'fully-evidenced file flags NOTHING' (needsReview===[]). PR #405/#406. |
| ✓ main 反映 | (4) Bulk upload 20+ with batch speaker/team apply | src/app/app/admin/upload-bulk/bulk-upload-form.tsx: single batch-wide teamId selector (line 100), batch meeting-type with bulkTypeConfirmed gate (line 98/384), one speakerMap applied across allUniqueSpeakers for the whole batch (buildSpeakerStates line 304), spreadDatesAcrossWeeks for many files, per-file computePreviewRow. spreadDatesAcrossWeeks tested at count=20 (bulk-upload-infer-date.test.ts 'produces ascending dates' n=20). PR #406 (commit 690129f). |
| ✓ main 反映 | (5) 'Upload another transcript' CTA on every result/trace/record screen in ALL states | src/components/cta/UploadMoreCTA.tsx role-aware (admin/ceo→/app/admin/imports carrying team; member/manager→/app/history, never a 403; demo→/demo/ingest). Injected on /me (line 773), /mirror/[managerId], /ceo (line 277), trace page; ImportResultSummary provides it on upload forms. folder57-state-cta.test.tsx (23 tests) asserts injection on chosen surfaces, absence on reviewer/notices/demo, no double-injection. PR #409/#435. |
| △ 部分 | (6) History/logs page in nav showing completed/pending/failed/partial/observation-only | PAGE is fully built: src/app/app/history/page.tsx renders a real filterable list, role-scoped via loadUploadAnalysisHistory, displayStatus() ladder (failure→partial→observation/insufficient→analyzed), 6 filter buckets (HISTORY_FILTERS incl observation_only). folder57-history-queries.test.ts + workflow-matrix-lock §M3 green. GAP: /app/history is NOT a top-level nav entry — src/lib/navigation/workspaces.ts defines exactly 6 canonical workspaces (home, my-view, team-mirror, organization-summary, review-queue, admin-console) and line 14 explicitly says 'history/trace/coverage have no nav home'. admin-console.ts nav exposes 'Transcript Imports' (/app/admin/imports) but not /app/history. The History page is reachable only via in-page links/CTAs (UploadMoreCTA, ImportResultSummary, /me diagnostic, AdminReadinessCockpit). So the page exists and is complete, but the literal 'in nav' acceptance is not met. |
| ✓ main 反映 | (7) My Personal View auth→member→team→speaker identity-mapping DIAGNOSTIC (never bare 'contact administrator') | src/lib/member-private/member-private-projection.ts resolveIdentityDiagnostic returns first-broken-link reason (NO_TEAM/NO_SPEAKER_ALIAS/NO_MATCHED_MEETINGS/OK). /me page.tsx lines 344-401 render a step panel (signed-in ✓ / team / aliases count / meetings count + suggested fix + history/audit links), comment explicitly 'Never a bare contact administrator'. test/folder57-me-identity-diagnostic.test.ts + workflow-matrix-lock §M5 (monotonic ladder, clamps negatives). PR #411 (commit f831eb5). |
| ✓ main 反映 | (8) Manager Mirror clearly separated from Personal View | workspaces.ts team-mirror is a distinct workspace (id 'team-mirror', href /app/team-mirror, currentRoute /app/mirror) with productBoundaryNote 'Team Mirror reflects the manager back to themselves. NOT a window into reports private states'; my-view ('/app/me') is a separate workspace. PortalHeaderNav renders them as distinct tabs. ExcludedMeetingsDrawer (PR08 #412) bounded metadata-only exclusion reasons locked by workflow-matrix-lock §M4. |
| ✓ main 反映 | (9) Executive view raw-existence vs eligible-count coherence | src/app/app/ceo/page.tsx: projectCeoRoster yields insufficientCount + suppressedCount (k-anon), data-testid='coherence-explainer' (line 312) explains why exec roster shows fewer teams than Admin (k-anonymity suppression), kAnonSuppressedCount surfaced (line 239), reference-window resolution. PR09 #413 (commit ce62be5, marked [BLOCKER]). workflow-matrix-lock §M6/§M7 lock aggregate-only + suppression coherence. |
| ✓ main 反映 | (10) Cross-surface data coherence | test/folder57-workflow-matrix-lock.test.ts is the dedicated cross-cutting lock: §M3 History status ladder pin, §M4 'no meeting type both excluded-by-Mirror and review-worthy' (one-directional gate, client+server union), §M7 scopeForStatus never grants full to non-success states / observational never escalates. 24 matrix tests + 113 total F57 tests green on main. |
| ✓ main 反映 | (11) Demo-date/window coherence | src/lib/config/reference-date.ts: production=live clock + ?asOf IGNORED; demo env=fixed date + ?asOf honored; invalid env degrades to production; invalid ?asOf falls back to env date. test/folder57-reference-date.test.ts + workflow-matrix-lock §M6 'demo coherence cannot move a production window'. Demo-session opaque-token continuity (PR #437) with closed-allowlist sanitizer locked by folder57-demo-session-continuity.test.ts (token scheme, sanitizer no-leak, stateless analyze route). |
| ✓ main 反映 | (12) Governance non-regression (no broad transcript browsing, no manager named-subordinate risk labels, no HR decisions, k-anon/RLS intact) | Migration 0042 locked additive/non-destructive + stores NO raw transcript columns (folder57-schema-foundation.test.ts: vtt_text/cue_text/transcript_text/body_text forbidden; demo_sessions deny-by-default). RLS tests present: test/rls/{folder57-demo-session-scoped-read,folder57-speaker-alias-cross-org,folder57-workflow-tables}.test.ts. history/me pages render no raw-text columns (grep clean). workflow-matrix-lock §M4 (Mirror metadata-only, banned content fields on entry type) + §M8 forbidden-phrase sweep (no harassment/intent/illegality/perf-score, no 'no signal=no problem', EN+JA). Sanitizer drops detail/plain/affectedSpeaker/evidence (demo-session-continuity test). |
| 状態 | 受け入れ領域 | 根拠(テスト / ファイル / commit) |
|---|---|---|
| ✓ main 反映 | 01 — UX code audit doc | Two read-only audit reports merged: docs/reports/ux_repair_prompt_00_codebase_audit.md (F58, 5-agent fan-out over 6e95ed7, route/component/state map + P0 wound list) and docs/kashi-ux-repair-audit.md = Folder-59 C01 (11-reader fan-out, commit 91ebbad #459, extends F58 audit, flags stale findings). Both cite file:line and rank UX risks. Doc-as-deliverable, which is the prompt's intent. |
| ✓ main 反映 | 02 — canonical role/workspace nav model (Home/My View/Team Mirror/Organization Summary/Review Queue/Admin Console) | src/lib/navigation/workspaces.ts (WorkspaceId = exactly the 6 named workspaces; allowedRoles in real OrgRole enum; mustNotExpose encoded as data). Doc docs/kashi-ux-navigation-model.md. Commit ace5a79/d6ed6c9 (C02 #460). Pure deterministic helpers (getVisibleWorkspacesForRoles, userCanAccessWorkspace) pinned by tests. Names match the spec one-to-one. |
| ✓ main 反映 | 03 — role-gated app shell with ROUTE protection (not just hiding) | Real route guards, not hide-only: src/app/app/{home,organization,team-mirror,review-queue}/page.tsx each call resolveWorkspaceAccess() (src/lib/navigation/workspace-access.ts) → unauthenticated redirects /login, forbidden renders <WorkspaceForbidden/> (calm 403), allowed redirects to host. Hosts ALSO keep their own requireRole — double-gated, can only deny what the existing model denies (never widens). PortalHeader nav now built from getVisibleWorkspacesForRoles; hardcoded NAV_LINKS deleted. Admin tightened to Home/My View/Admin Console in primary nav (deliberate sign-off). Tests: folder59-c03-shell.test.ts + folder58-prompt09-navigation.test.tsx (108 passing on re-run). Commit 1813383 (C03 #461). |
| ✓ main 反映 | 04 — admin console structure (Action Center/Teams&Members/Imports/Speaker Mapping/Data Readiness/Notices/Audit/Diagnostics) | src/lib/navigation/admin-console.ts = typed 8-section single source of truth in spec order; Diagnostics last + requiresInternalAccess:true. src/app/app/admin/layout.tsx + AdminConsoleNav wrap every /app/admin/* page. Section shells exist: action-center, teams, imports, speaker-mapping, readiness, notices, audit, diagnostics (all dirs present under src/app/app/admin/). Each guards requireRole(['admin','ceo'],{requireMfa:true}). Commit dc54bd8 (C04 #462). Chrome-only; route protection at page level. |
| ✓ main 反映 | 05 — admin action center (one blocker/one CTA) | src/lib/admin/action-center.ts — pure getAdminPrimaryBlocker(status) applies the 10-step priority order (no team→…→ready), returns ONE AdminPrimaryBlocker (severity + i18n title + impact + one CTA), unit-tested (priority, highest-wins, sparse-no-crash). /app/admin/action-center renders one primary blocker above a compact status row; /app/admin redirects to it. Severity styling = controlled amber/neutral/emerald, no healthy/safe language. Commit 3ce9ac5 (C05 #463). |
| ✓ main 反映 | 06 — canonical readiness state machine (Ready/Limited/Blocked/Observation-only/N-A) | src/lib/readiness/readiness-state.ts — ReadinessStatus = ready|limited|blocked|observation_only|not_applicable across 5 areas, 17 dependencies, 5 pure calculators, conservative getReadinessSummary + buildReadinessInputFromAdminState adapter. Doctrine header explicitly forbids health-score, no-signal=safety, and that readiness≠access. Doc docs/kashi-readiness-state-machine.md. Merged DRAFT-needing-signoff but C07 consumes it and final audit recorded PASS. Commit 32f58c5 (C06 #468). |
| ✓ main 反映 | 07 — readiness UI plain language (no 'no signal=no problem') | src/app/app/admin/readiness/page.tsx imports getReadinessSummary + renders ReadinessCard (src/components/admin/readiness/). Outcome-language not system-language. folder58-prompt08-empty-states.test.tsx pins forbidden reassurance denylist ('no problem','safe team','all clear', JA 問題なし/安心してください/健全なチーム) and that abstention blocks carry caveat + next action + semantic-lane disclosure. Forbidden-phrase scan clean across src/** + messages (Prompt-16 audit §4). Commit cff6439 (C07 #469). |
| ✓ main 反映 | 08 — universal transcript importer (one flow, file=batch-of-one) | src/lib/imports/import-batch.ts typed spine ('one file = a batch of one', single status enum). src/app/app/admin/imports/page.tsx renders the real TranscriptImporter that ingests through the live /api/meetings/upload pipeline (not a stub — loads teams/profiles, real UploadDropzone). Legacy /app/admin/upload + upload-bulk redirect here (guards preserved). Doc docs/kashi-transcript-importer.md. Commit 7c26b46 (C08 #464). |
| △ 部分 | 09 — exception-only import review | Model DONE: src/lib/imports/import-review.ts — pure classifier surfacing ONLY uncertain/blocking/limiting exceptions (clean file → 0 items → 'ready'), 13 review categories, i18n copy, no absence=safety. UI DONE: src/components/admin/imports/ImportReviewPanel.tsx (exception-first, calm clean state). BUT the panel's own header states wiring to the importer's live parsed batch is a documented follow-up: 'the reused engine does not yet emit a TranscriptImportBatch.' So model+UI+tests are complete and merged, but the live exception-review data flow is staged (PD-3 persistence gap). Commit 1113ca0 (C09 #465). |
| △ 部分 | 10 — partial-import/repair queue (ready files import, bad files queued not lost) | Model DONE: import-batch.ts adds partially_imported/needs_repair/discarded states + per-file ignored/removed/replaced. UI route exists: src/app/app/admin/imports/repair/page.tsx (entry below the upload panel per spec §10). Tests pin counts (folder58-fix-bulk-mapped-count.test.ts, folder59-seqC C10). Same PD-3 caveat: repair queue is fed by persisted batches the importer does not yet emit server-side, so it renders its empty state live. Models/UI/tests merged, live wiring staged. Commit bbdc1a7 (C10 #466). |
| △ 部分 | 11 — batch speaker mapping (durable, confidence, confirm-all/guest/ignore/undo/apply-future) | Model DONE: src/lib/speakers/speaker-mapping.ts — SpeakerMappingActionType includes confirm_all_high_confidence, mark_guest, ignore_for_person_level, undo (+apply-future status), SpeakerMappingConfidence high/medium/low/none, member-match suggestions with evidence, durable SpeakerAliasStatus. canConfirmAllHighConfidence gate. UI: SpeakerMappingPanel.tsx. Tests: folder58-prompt04-speaker-resolver. BUT src/app/app/admin/speaker-mapping/page.tsx hardcodes groups:[] with explicit comment 'PERSISTENCE (documented gap, PD-3): aliases/groups come from imported batches, which are not yet persisted server-side… panel shows its empty state.' Model+panel complete+tested; live durable persistence is the staged follow-up. Commit 083a424 (C11 #467). |
| ✓ main 反映 | 12 — meeting-type validity (observation-only fallback) | src/lib/meeting-types/meeting-type-model.ts — getMeetingTypeValidity returns supported|low_confidence|observation_only|unsupported; grievance/interview→unsupported(never review-worthy), training/incident_bridge/exec_review/unknown→observation_only, scoreable+high/med-conf→supported. Anchored to the live calibration gate (scoringModeFor). Admin selector + import-surface consistency. Tests folder58-prompt05-meeting-type.test.ts + regression §4.4. Commit dc457b9 (C12 #470) — this is also the calibration sign-off that closed the 15B-1 server Rule-3 hole. |
| ✓ main 反映 | 13 — diagnostics separation (debug gated to Admin/Diagnostics) | src/app/app/admin/diagnostics/page.tsx = the ONE home for raw technical detail (parser/transcript/result-state traces, raw payloads, fixtures), guarded requireRole(['admin','ceo'],{requireMfa:true}); raw-internal sections marked internal:true and visually de-emphasized + positionally last. Header: 'raw detail must never be reachable by a non-admin role or the public demo.' Test folder59-c13-diagnostics-separation.test.tsx (passing). Commit 7ba7e7d (C13 #471). |
| ✓ main 反映 | 14 — governance/audit/anti-retaliation UX (private concern not leaked; forbidden-use sentence) | src/app/app/admin/notices/page.tsx renders forbiddenUse.label + forbiddenUse.sentence + body in-product (lines 87-92). src/app/app/admin/audit/page.tsx = typed governance audit log. Employee trust layer: EmployeeTrustLayerSummary with data-employer-visible-on-view='false', non-leak guarantee (page-open/notes/drafts/vault private to employee). Tests: folder58-prompt13-employee-trust-layer.test.tsx (private-non-leak guarantee, managers-NOT-notified, member-private-projection unchanged) + folder59-c14-{no-leak-locks,notices-governance,private-state-policy,audit-event}.test.ts + c14b-panel-wiring (30+ passing on re-run). Codex adversarial round closed 3 fail-open anti-retaliation defects (commit 7a96da6). C14b wired panels to owner-only tables (#473). Commits ed4cd0d..576a43a (C14/C14b #472/#473). |
| ✓ main 反映 | 15 — full regression QA | test/folder58-prompt15-regression-cross-role.test.ts = 59 it/describe cross-role harness (state-model integrity, readiness ladder distinctness, configured-vs-aggregate no-naked-0, no-review-items≠exoneration, unknown/unsupported-type never review-worthy, speaker cross-form parity, server scoringMode↔classifier agreement guard). test/folder58-prompt15b-rule3-exploitability.test.ts is the durable boundary guard (now asserts the remediated clamped end-state). Folder-59 C15 = final regression QA verdict GO + 4 small safe fixes (commit 1368623 #474). Prompt-16 final acceptance audit = PASS (condition satisfied 2026-06-10, #433/#470). |
| ✓ main 反映 | BOUNDARIES — no surveillance/HR-decision/health-score/no-signal=no-problem/debug-leak/private-state-leak | Encoded as data + tests, not folklore: workspaces.ts mustNotExpose per workspace; readiness-state.ts doctrine bars health-score + absence=safety + readiness-grants-no-access; folder58-prompt08 denylist test (EN+JA reassurance forbidden); folder58-prompt13 + folder59-c14-no-leak-locks pin private-state non-leak (employer_visible_on_view:false, managers NOT notified); C13 gates all raw debug to admin+MFA Diagnostics; meeting-type model + 15b guard block unsupported types from review-worthy output; executive-summary verified to carry no transcript/named-individual/private-state field. Prompt-16 forbidden-phrase scan (harassment/intent/legal/discipline/performance-score/exonerated) clean across src + messages. |
| 状態 | 受け入れ領域 | 根拠(テスト / ファイル / commit) |
|---|---|---|
| ✓ main 反映 | (1) End-to-end audit + 24-fixture manifest | test/fixtures/folder59/ has exactly 24 VTTs (C01-03/D01-06/M01-07/R01-08). test/fixtures/folder59-manifest.ts FOLDER59_MANIFEST has 24 entries with per-fixture expected parse/quality/exposure/detector states. folder59-fixture-runner.test.ts asserts 'manifest covers exactly the 24 fixtures on disk' + runs the REAL POST /api/demo/analyze per fixture. C01 audit = commit 02158e6 (#459). I ran the runner: 24-fixture suite PASSES. |
| ✓ main 反映 | (2) Canonical result-state type (concern separation) | src/lib/pipeline/demo-result-state.ts frozen 5-state DemoResultState; demo-display-model.ts adds 3 display states + PRIMARY_STATE_ELIGIBLE_LANES={STRUCTURAL_TIMING,STRUCTURAL_TURN_PATTERN}. folder59-p03-canonical-state-conformance.test.ts mutation-locks the EXACT state set and asserts ResolvedDemoResultContract splits parse/quality/metric-availability/evidence/abstention/interpretation/displayPrivacyMode into distinct typed fields. 12 tests pass. Commit 8ac72ec (#445). |
| ✓ main 反映 | (3) Parser diagnostics | folder59-p04-parser-diagnostics-conformance.test.ts locks parse-turns.ts/transcript-parser.ts/substrate-quality.ts surface structured speakerCount/per-speaker counts/timestampCoverage/typed reason codes (not prose). Debug payload exposes parser.parsedTurnCount/speakerCount/timestampCoverage (p23 test asserts numeric). Passes. |
| ✓ main 反映 | (4) Quality-vs-exposure split | folder59-p05-quality-vs-exposure-conformance.test.ts: INPUT_QUALITY_FAILURE_CODES (LOW_TRANSCRIPT_QUALITY/BLOCKED_SUBSTRATE) kept DISJOINT from EXPOSURE_LIMITATION_CODES (INSUFFICIENT_TURNS/SPEAKERS/DURATION); a valid short VTT must NOT carry an input-quality code AND substrate quality must NOT be 'low'/blocked (mutation-proven both directions). Semantic-off => unavailable_semantic_off NOT no_signal (p15 + fixture-runner). Passes. |
| ✓ main 反映 | (5) Abstention reason codes | src/lib/ux/kashi-ux-states.ts ABSTENTION_REASONS; folder59-p06-reason-code-taxonomy.test.ts asserts each code carries severity/scope/blockedCapabilities/title/explanation+i18n keys and the full 22-code spec union is present; semantic-off + cold-start are CAVEAT/LIMITATION never input-quality BLOCKER; canRenderCanAnalyzeNo requires capability detail. src/lib/analysis/abstention.ts decideAbstention. Passes. Commit 22cf81c (#444). |
| ✓ main 反映 | (6) Raw-metrics vs interpretation labeling | folder59-p07-raw-vs-interpretation-conformance.test.ts (commit 8ac72ec) passes. ResolvedDemoResultContract.metrics (participantCount/turnCount/floorTimeAvailable/interruptionDetectorRan/candidateCount/topInterruptionDyad) is a distinct object from abstention/interpretation, asserted in p03. demo-result-state.ts ZERO_COUNT_NEUTRAL_FALLBACK + allowsCategoryDistributionInterpretation guard against reading 0-count as imbalance. |
| ✓ main 反映 | (7) Floor-time/evidence taxonomy (floor-time-only != directional) | folder59-p08-floor-time-demotion + p08b-floortime-universal-demotion (commit 057b2ed #452) UNIVERSALLY demote floor-time-only concentration to descriptive (drops the facilitatorLed gate); D06/M07 display.state moved STRUCTURAL_SIGNAL_OBSERVED->NO_CONCERN. fixture-runner asserts floor-time status is evaluated_*/suppressed_*, never producing a directional dyad. p09-evidence-taxonomy passes. src/lib/analysis/evidence-grade.ts + comparable-exposure.ts. |
| ✓ main 反映 | (8) Meeting-type+role policy (standup/incident/1on1/training/exec protected) | folder59-p10-meeting-type-guardrail-conformance.test.ts: scoringModeFor maps incident_bridge/training/exec_review/brainstorm->observation_only (protective, never escalatory), grievance/interview->suppressed, weekly_sync/design_critique->scoreable (disjoint control = mutation-proven). applyMeetingTypeNormalization in demo-result-state.ts NEVER downgrades REVIEW_WORTHY/discourse signals. p11-role-facilitator (exec_review greylist + project_review facilitator-protected, #448). 24-fixture M01-M07 all assert no_signal. Passes. |
| ✓ main 反映 | (9) Interruption vs overlap (D03/R01 Kenji->Mika; R02/M04 no false-fire) | fixture-runner NAMED_INVARIANT_FIXTURES set {D03,R01,R02,M04}; D03/R01 assert top dyad = 'Kenji Morita->Mika Sato' (TOP_DYAD_KENJI_MIKA); R02 (fast handoff) + M04 (brainstorm overlap) assert intrusive-interruption status != evaluated_candidate with '*** NAMED-INVARIANT REGRESSION ***' shout. folder59-p12-interruption-overlap-conformance.test.ts. src/lib/analysis/structural-metrics/interruption-directionality.ts. All pass. |
| ✓ main 反映 | (10) Detector availability + semantic-off (unavailable != no-signal) | src/lib/pipeline/detector-availability-matrix.ts + detector-capability-registry.ts; folder59-p14-detector-availability-matrix + p14-matrix-render + p14-matrix-route-leaksafe + p15-semantic-off-output-rules. Matrix emits unavailable_semantic_off / unavailable_longitudinal_public_demo distinct from evaluated_no_signal; render shows 'Not evaluated' (JA 未評価) never 'no signal'. fixture-runner enforces semantic detectors == unavailable_semantic_off per fixture. Commit b383a99 (#447). Passes. |
| ✓ main 反映 | (11) Discourse detector cards (5 cards, no intent/emotion) | folder59-p16 (unanswered-question), p17 (chilling-delta), p18 (topic-credit), p19 (agreement-shift), p20 (agenda-preclosure) — each VERIFY-locks the card maps to a real detector, sits on CONVERSATIONAL_SEMANTIC lane (cannot drive primary state solo), and FORBIDDEN_TERMS (deliberately/intentional/misconduct/harassment/felt/intended-to/neglect/exclusion) absent from label+affirmative summary. Commit a80f8a0 (#449). All pass. |
| ✓ main 反映 | (12) Fixture QA harness (24 fixtures, no external semantic API) | folder59-fixture-runner.test.ts header + code: runs POST /api/demo/analyze with analyzeContent:false and KASHI_ENABLE_SEMANTIC_LANE='false' stubbed — 'NO external semantic / Anthropic API is ever called'; compares STRUCTURED state only, never screenshots. folder59-p22-batch-report.test.ts emits JSON+MD grouped report (scripts/folder59-batch-report.ts, commit ebee741). Ran 24-fixture oracle: passes. |
| ✓ main 反映 | (13) Result-page UX (summary above fold, collapsible evidence, save-CTA below) | folder59-p24-result-hierarchy.test.tsx mounts DemoVisualAnalysisResult (SSR) and asserts DemoResultHero + DemoMetricStrip render ABOVE DemoDetectorMatrix in document order; unavailable rows distinct from no-signal; caveats deduped to exactly 1; render-safe on minimal/absent-fields payloads (2026-06-06 lesson vectors). DemoVisualAnalysisResult.tsx:21 comment 'save below comprehension' (save CTA rendered below). Commit a608fe4 (#455). Passes. |
| ✓ main 反映 | (14) Privacy/display-identity (DisplayPrivacyMode, public_anonymized default, Kimura leak removed) | src/lib/pipeline/display-privacy-mode.ts: DISPLAY_PRIVACY_MODES=[public_anonymized,fixture_debug_named,tenant_role_based], DEFAULT=public_anonymized; buildSpeakerDisplayMap is single label source (no mixed Kenji/Participant-A). folder59-p25-display-privacy.test.ts §3 firebreak: 'Kimura (Manager)' lives ONLY in src/data/seeds/people.json and is asserted ABSENT from all 6 LIVE_INGEST_RESULT_PATH components + those components do NOT import seeds; a live result from non-Kimura speakers renders only Participant A/B/C. Exec aggregate de-identified (commit eb8686a #481). Passes. SEE GAP NOTE re live editorial pages. |
| ✓ main 反映 | (15) Copy/localization | folder59-p26-copy-cleanup.test.tsx (commit ffcef61 #458) mounts the real SSR stack from a real route payload and locks: typo 'storedin' absent; storage wording distinguishes processing (transcript not stored) from optional metadata snapshot; no-emotion/intent/misconduct boundary visible in always-rendered hero; JA matrix shows 未評価 never シグナルなし; JA-mode localizes (no half-English core page). Passes. |
| ✓ main 反映 | (16) Privacy/security/governance (no transcript body stored, sanitizer, secret-phrase no-leak) | folder59-p27-public-payload-no-content-leak.test.ts: SECRET-phrase + hostile + cross-speaker-repetition + D03 shared_tokens transcript -> ZERO leak in semantic-off payload (case-insensitive + token-split deep scan); POSITIVE CONTROL with lane ON re-admits fields (gate is the only switch, not a permanent strip = mutation-proven). p23-debug-export-leaksafe.test.ts: debug payload privacy.includesTranscriptBody=false, redactionApplied=true; redactTranscriptDebugFields strip is load-bearing (builder fed injected secret-bearing fields, proven to bite). p27b-governance forbids automated decisions/formal findings. __FORBIDDEN_KEYS_FOR_TEST sweep. Passes. |
| ✓ main 反映 | (17) Final checks (no formal finding/HR/emotion/intent in public demo) | fixture-runner asserts display.state NEVER REVIEW_WORTHY_EVENT (strongest public = STRUCTURAL_SIGNAL_OBSERVED candidate) + FORBIDDEN_PHRASES (emotion/intent/misconduct/harassment/harm/employment lexicon incl パワハラ/terminate) absent from EVERY fixture's serialized payload. p27b forbids formal-finding/automated-decision output. Live /demo 'harassment'/'パワハラ' occurrences are all legal-context (MHLW/EU AI Act positioning) + the explicit cannotSay disclaimer block ('Kashi が言えないこと: ハラスメントがあったかどうか') — boundary copy area 17 requires, not analyzer assertions. Passes. |
| 状態 | 受け入れ領域 | 根拠(テスト / ファイル / commit) |
|---|---|---|
| ✓ main 反映 | P01 governance constants + safety floors | commit 3910894 (#484). src/lib/governance/communication-policy-constants.ts. test/folder60-p01-governance-constants.test.ts (15KB, ~30 its): safety_floor_version stable, prohibited inferences/uses complete, k>=5 non-lowerable, 4 profile presets exact keys/labels, 6 evidence grades, 5 routing destinations, 14 meeting types, 10 prohibited detectors locked_off, floor_time/interruption/chilling sole-escalation locks. |
| ✓ main 反映 | P02 validation engine + snapshot hash + runtime assertion | commit a8f2747 (#485). communication-policy-{validation,snapshot,defaults,runtime-assertions}.ts. test/folder60-p02-validation-engine.test.ts (18KB) covers spec PART-10 tests 1-28: stable-stringify hash determinism, volatile-field exclusion, default factory pins floor/engine/retention versions, 14 validator rejection cases incl. value-leak vectors (16b/16c reject non-canonical keys without echoing), safe-policy acceptance. |
| ✓ main 反映 | P03 durable model + repository (schema sign-off) | commit 5a59554 shipped as '[DRAFT — NEEDS SCHEMA SIGN-OFF]' but sign-off was RESOLVED: migration 0050 (5 tables, RLS admin/ceo/hr_compliance default-deny, partial unique indexes one-active/one-draft-per-org, published-snapshot immutability trigger, append-only audit triggers) dated 2026-06-10; downstream P16/P17 commits carry '[SIGN-OFF · stacked]' tags and 0051 header reads '[SIGN-OFF: schema] apply via Supabase dashboard'. test/folder60-p03-repository.test.ts (12 spec tests): draft clone, second-draft/second-active rejection, hash recompute, published immutability, optimistic-concurrency hash mismatch, cross-org no-leak. Caveat (c19ac8b doc): DB-floor invariants are mock/read-confirmed, no live-Postgres/RLS test yet. |
| ✓ main 反映 | P04 draft/publish API spine | commit 822c45b. src/app/api/admin/communication-policy/draft/{route,validate,publish,simulate,notices}. test/folder60-p04-routes.test.ts (16KB): full RBAC (admin/ceo create, hr_compliance/manager/member 403, unauth 401), draft lifecycle (reason required, 409 second-draft, stale-hash 409, 404 missing), publish (typed-confirmation, POLICY_PUBLISH_BLOCKED, retire+activate), rollback. |
| ✓ main 反映 | P05 audit writer + audit API | commit 649e4c4. communication-policy-audit.ts + /api/admin/communication-policy/audit/route.ts. test/folder60-p05-audit.test.ts: sanitizer redacts transcript/quote/snippet/evidence_vault/speaker_id at depth+in-arrays, keeps config keys; writer sanitizes before/after; reader org-scoped+publish_events_only+limit-cap 200+cursor; API hides request_context_json; per-action recording (draft_created/updated/deleted, publish_blocked, policy_published, rollback). Known gap (c19ac8b): audit is best-effort not transactional — a mutation can succeed with no audit row if insert fails (logged, not thrown); fail-closed needs atomic RPC follow-up. |
| ✓ main 反映 | P06 overview screen | commit 350da9f. overview/page.tsx + SafetyFloorPanel.tsx + presentation.ts. test/folder60-p06-overview.test.tsx: renders active+draft+safety floors+readiness+nav, honest empty states, floors sourced from constants. |
| ✓ main 反映 | P07 profile & scope editor | commit cde0cd5. profile-scope/{page,MaterialChangeWarning,copy}. test/folder60-p07-profile-scope.test.tsx: 4 profile cards as radiogroup with constant admin_labels, earlier_awareness/custom floor-invariant statements. |
| ✓ main 反映 | P08 meeting-type calibration | commit 92946f3. meeting-types/{page,copy}. test/folder60-p08-meeting-types.test.tsx: 14 types render, locked types show badge+reason+no mode select, never offers locked mode as selectable. |
| ✓ main 反映 | P09 detector configuration | commit 174693c. detectors/{page,SemanticLaneGatePanel,copy}. test/folder60-p09-detectors.test.tsx: 3 lanes, prohibited detectors visible+locked_off+badged+no toggle, 'Kashi does not' doctrine language, semantic-lane gate. |
| ✓ main 反映 | P10 evidence & routing | commit ca24456. evidence-routing/{page,copy}. test/folder60-p10-evidence-routing.test.tsx: 6 evidence grades with 'not a finding' language, 5 routing destinations no forbidden labels, locked routing floors + human-review locks + automatic-action off. |
| ✓ main 反映 | P11 visibility & rights | commit 1ed505e. visibility-rights/{page,VisibilityRightsEditor,copy}. test/folder60-p11-visibility-rights.test.tsx: 6-role matrix, locked rules (manager telemetry off / universal browsing off / perf-use off / auto-HR off / audit on), k>=5 floor enforced via min attribute. |
| ✓ main 反映 | P12 notice & versions | commit 49e6e7f. notice-versions/page + communication-policy-notice{,-locks}.ts. test/folder60-p12-notice-versions.test.tsx: 9 required locked statements, deterministic floor-version-sensitive hash, notice renderer. |
| ✓ main 反映 | P13 simulator engine + API | commit ee19f4b. communication-policy-simulator{,-privacy,-confidence}.ts + /draft/simulate route. test/folder60-p13-simulator.test.ts (9KB): estimated-mode binds draft hash + low confidence, aggregate-only fields, review routes labeled 'candidates not findings', non-canonical meeting-key genericized, k=5 cell suppression+count, sanitizer strips identifiers at depth, RBAC (member 403), stores run bound to draft hash. |
| ✓ main 反映 | P14 simulator screen | commit bc49c5b. simulator/PolicyImpactSimulator.tsx. test/folder60-p14-simulator-screen.test.tsx: required disclaimer+privacy boundary, 30/90/180 windows, admin sees Run / HR does not, estimated-mode caution + low-confidence no-overclaim. |
| ✓ main 反映 | P15 publish screen | commit 4dafe47. publish/PublishClient.tsx + readiness publishBlockers. test/folder60-p15-publish.test.tsx: safety-floor reminder + typed confirmation + effective time + attestation, server blockers with fix links disable publish, empty form cannot publish. |
| △ 部分 | P16 runtime policy integration + analysis-output binding | commit 99498e0 '[SIGN-OFF]' + runtime-policy-{routing,context}.ts + resolve-communication-policy.ts + migration 0051 (meeting_metrics policy-binding columns, closed enum bound/legacy_unbound/failed_policy_resolution, FK). test/folder60-p16-runtime-binding.test.ts: most-restrictive routing, evidence-grade conservatism, context resolver throws on no-active-policy (no silent unsafe fallback), legacy rows never rebound. PR-1 fbaea0f binds active-policy VERSION at INGEST (wired into all 5 ingest routes: upload/teams/meet/zoom/notta). GAP: per-output ANALYSIS-TIME binding (writing evidence_grade/routing_destination/reason-codes to meeting_metrics during analysis) is NOT wired — no analysis-pipeline file (run-conversational-case-analysis.ts etc.) writes those columns; this is the documented deferred follow-up. |
| ✓ main 反映 | P17 emergency pause kill-switch | commits cc68242 (lib+API+UI) + dd5ece7 (live suppression PR-2) + eed1558 (4 refinements). communication-policy-emergency-pause.ts + emergency-pause-surface-guard.ts + emergency-pause/page.tsx + /api/admin/communication-policy/emergency-pause. test/folder60-p17-emergency-pause.test.tsx: input validators (>=1 surface, meaningful reason, future expiry, 7-day max), active-non-expired-only listing, overlay union, create-never-publishes/disable-never-deletes, RBAC (hr_compliance read-only), forbidden-claim+no-leak copy EN/JA. The c19ac8b-documented 'overlay computed but wired only into tests' gap is RESOLVED: guard now imported live into me/ceo/mirror/reviewer/* pages + mutation routes + send-drilldown-notice; test/folder60-pause-suppression.test.tsx (SPLIT fail-open/fail-closed) + folder60-pause-notification-suppress.test.ts (SUPPRESSED_BY_PAUSE, records nothing) prove live suppression. |
| △ 部分 | P18 full tests + accessibility + hardening | commits 46956b6 (scanners+docs) + c19ac8b (honest caveats) + d50ffff (4 adversarial findings closed). test/folder60-p18-{copy-safety,privacy-leakage,console-consistency}.test.ts: copy-safety scans >=10 screens with mutation-proof adjacent-sentence laundering check; privacy-leakage redacts content keys at depth + k=5 suppression + runtime-context no-identifier; console-consistency nav<->filesystem honesty + canonical enum stability. docs/communication-policy-console{,-test-plan}.md exist. GAP: accessibility is asserted manually/structurally (radiogroup, min-attr, text queries) — NO automated a11y tooling (no jest-axe/axe-core/toHaveNoViolations anywhere in repo); the 'automated a11y tooling' item remains a deferred follow-up per the original note. |
| 状態 | 受け入れ領域 | 根拠(テスト / ファイル / commit) |
|---|---|---|
| ✓ main 反映 | RC61 merged + deployed (provenance) | Both PRs on main, HEAD=eb466f8. e691b81 'feat(homepage): destructive rebuild of public homepage / (Review Comment 61) (#506)'; eb466f8 'feat(homepage): v3.1 progressive-disclosure upgrade (Review Comment 62) (#507)'. git branch --contains both -> main. RC61 is SUPERSEDED-IN-PLACE by RC62 in the same surface (same page.tsx/HomeSections.tsx). |
| ✓ main 反映 | Locked 8-section IA (Hero->Sample->Measures->How->WhoSeesWhat->Does/Does-not->Governance->FinalCTA) | SUPERSEDED-but-satisfied: RC62 expands the spine to 11 sections that strictly contain RC61's 8. page.tsx:45-55 composes HomeHero->HomeLocalNav->HomeSampleOutput->HomeTrustStrip->HomeMetrics->HomeHowItWorks->HomeWhoSeesWhat->HomeDoesDoesNot->HomeGovernance->HomeFaq->HomeFinalCta. Pinned by homepage62-gates.test.ts:261-273 'page composes the v3.1 sections in order' (ordered indexOf). Live HTML has all 6 anchored section ids (sample/metrics/how-it-works/visibility/governance/faq each =1). RC61's 'Measures' == RC62 §4 Metrics 「Kashiが整理するもの」; additions (Trust strip §3, FAQ §9) are net-new, not removals. |
| ✓ main 反映 | Sans-serif (no Fraunces on /) | Gate 5 homepage62-gates.test.ts:206-218: SECTIONS_SRC/PAGE_SRC/DISCLOSURE_SRC never match /font-serif/; .home-v61 block contains var(--font-jp) + /font-variation-settings:\s*normal/. globals.css .home-v61 :where(h1,h2,h3){font-family:var(--font-jp);font-variation-settings:normal}. Live: the only 'fraunces' string is the layout-level CSS-module class on root <html> (fraunces_36c709ed-module__...) from global font wiring — NOT applied to homepage headings, which are scoped+reset by .home-v61. |
| ✓ main 反映 | Locked JA copy | Copy-lock suite homepage62-gates.test.ts:240-278 pins exact sentences: heroHeadline='会議をまたいで、発言機会の偏りを確認する。', heroTrust='Kashiの出力は確認用です。最終判断は人が行います。', metricsTitle='Kashiが整理するもの', sampleCardLabel='確認候補', role2Summary contains '自分が関与する会議'. Live HTML contains each locked string (grep count=1 each): 会議をまたいで…/最終判断は人が行います/Kashiが整理するもの/確認候補. RC62 evolved a few tokens (発話->発言の遮り, 「見るもの」->「整理するもの」, manager scope narrowed) — these are deliberate v3.1 supersessions, still within RC61's enterprise-JA register and re-locked by tests. |
| ✓ main 反映 | Banned-copy + claim-safety gates | RC61's homepage61-gates.test.ts was DELETED by RC62 and REPLACED with stronger homepage62-gates.test.ts (Gate 1 banned-copy, Gate 3 claim-safety) + 3 forbidden-phrase gates extended (i18n-banned-words.test.ts +9, i18n-r17-forbidden-marketing.test.ts +9). 58/58 RC62 gate+disclosure tests PASS on main (just ran). Gate 1 BANNED scans rendered keys for ハラスメントを検知/感情を検知/監視-style positive phrasings; Gate 3 REDFLAGS_JA/EN blocks 監視/退職予測/生産性スコア/health score etc on non-negation keys. Live banned hits (ハラスメントを検知 / 監視 / 生産性スコア) are ALL in legitimate negation/forbidden copy — verified context: 'ハラスメントを検知しません', '部下を個別に監視する設計ではありません', '個人の生産性スコアとして扱う' (inside forbidden-use list). doesNot1-4 pinned = 発言内容の評価/感情推定/ハラスメント判定/人事判断の自動化 (test:96-98). |
| ✓ main 反映 | Mobile-first 0-overflow | Both commit messages record '/browse 0-overflow 320-1440' verification (RC61 320-1440; RC62 320-1440 + accordion toggle + inert collapsed). Mobile-first construction in source: clamp() hero (home-h1 clamp(26px,5.4vw,40px) + 23px <=narrow override), responsive grids (sm:grid-cols-2, md:grid-cols-3), DisclosureCard 44px tap rows pinned by homepage62-disclosure.test.tsx:42-46 (w-full, min-h-[44px], focus-visible:ring). Note: scrollWidth sweep is a /browse runtime check, not a committed automated regression test — but recorded as run, and no overflow-prone fixed widths in source. |
| ✓ main 反映 | Functionality / navigability preserved | Gate 4 homepage62-gates.test.ts:176-203: no placeholder href='#'; all 6 section ids exist; local nav chips link to real anchors; CTAs target real routes /demo+/pilot+/governance; hero has exactly one primary CTA. Live confirms href=/governance, href=/pilot x4, href=/demo x5, 20 collapsed accordion buttons (aria-expanded=false) rendered server-side. RC61's additive mobile consultation CTA preserved in SiteHeader.tsx:102-105 (md:hidden, min-h-[44px], ->/pilot). Disclosure a11y by construction: real <button aria-expanded aria-controls> + inert panel + role=region (homepage62-disclosure.test.tsx 58 passing assertions). |
| 状態 | 受け入れ領域 | 根拠(テスト / ファイル / commit) |
|---|---|---|
| ✓ main 反映 | Visible-first/foldable-second doctrine (trust line, trust strip, does-not summary, role summaries NEVER inside a collapsed accordion) | HomeSections.tsx: HomeTrustStrip (L114-131) renders trust1-4 as a plain <ul>, no DisclosureCard; heroTrust rendered as a plain <p> in HomeHero L47; HomeDoesDoesNot L268-280 renders doesNot1-4 in a visible <ul> BEFORE the only DisclosureCard (forbiddenFoldLabel L282); HomeWhoSeesWhat L219 renders {r.summary} in a visible <p>, only see/hide/note go inside the per-role fold. Pinned by homepage62-gates.test.ts 'Core visibility' describe block (L113-143): asserts trust block contains trust1-4 AND not DisclosureCard; does-not idx < fold idx; role summary outside fold. All 58 tests pass at HEAD eb466f8. Live HTML confirms trust strip line '確認用の表示です' renders outside any aria-expanded button. |
| ✓ main 反映 | Accessible DisclosureCard (real button + aria-expanded + aria-controls + inert + Enter/Space + 44px + reduced-motion) | DisclosureCard.tsx L48-63: real <button type=button> with aria-expanded={open} (L51), aria-controls={panelId} (L52); panel L67-71 has id=panelId, role=region, aria-labelledby, inert={!open}; trigger className has w-full + min-h-[44px] + focus-visible:ring (L54). homepage62-disclosure.test.tsx pins all of this via renderToStaticMarkup: real-button, aria-expanded=false default, aria-controls→matching region id, inert on collapsed region, min-h-[44px], focus-visible ring, defaultExpanded→aria-expanded=true+non-inert. Live HTML: 20 buttons w/ aria-expanded, 20 unique aria-controls, 19 inert region panels. Enter/Space = native button (PARTIAL caveat: keyboard TOGGLE itself is /browse-verified per test header, not unit-pinned, but native <button> gives Enter/Space for free and is pinned). reduced-motion pinned: gates 'motion respects prefers-reduced-motion' asserts globals.css has prefers-reduced-motion + home-disclosure-motion; CSS L400-406 sets transition-duration:0.01ms. |
| ✓ main 反映 | Trust strip (always-visible boundary strip) | HomeSections.tsx HomeTrustStrip L114-131 renders trust1-4. ja.json: trust1=確認用の表示です。 / trust2=感情推定は行いません。 / trust3=ハラスメント判定は行いません。 / trust4=人事判断は自動化しません。 Pinned by gates 'the always-visible trust strip has its 4 lines' (L89-94) + core-visibility 'NO DisclosureCard' (L115-123). Live HTML contains '確認用の表示' in visible (non-script) markup. |
| ✓ main 反映 | FAQ (6 Q&A) | HomeSections.tsx HomeFaq L330-348 maps faqQ1-6/faqA1-6 into AccordionGroup. ja.json has exactly 6 Q + 6 A (verified: faqQ count 6, faqA count 6). Pinned by gates 'the FAQ has 6 questions and 6 answers' (L105-110). Live HTML renders heading 'よくあるご質問' in visible text. |
| ✓ main 反映 | Local section nav | HomeSections.tsx HomeLocalNav L55-69 builds 5 chips (#sample,#metrics,#visibility,#governance,#faq) via reused StickyAnchorNav (src/components/sales-hub/StickyAnchorNav.tsx exists, real <nav> w/ aria-current). Pinned by gates Gate-4 'local nav links every chip to an existing anchor' (L187-191) + 'hero secondary anchor + section anchors exist' (L181-186). Live HTML contains navAria 'ページ内ナビゲーション' + chip labels サンプル/FAQ in visible text. |
| ✓ main 反映 | Copy v3.1 (発話→発言, 「Kashiが整理するもの」, manager narrowed) | ja.json: heroBody uses 発言の遮り (NOT 発話); metricsTitle='Kashiが整理するもの'; role2Summary='自分が関与する会議の運営傾向を確認できます。' (manager narrowed). Pinned by gates Copy-lock (L240-277): heroBody contains 発言の遮り AND not 発話 (L246-249); metricsTitle === 'Kashiが整理するもの' (L250-252); role2Summary contains '自分が関与する会議' (L258-260); also pins locked heroHeadline + heroTrust + sample 確認候補/根拠を見る. Live visible HTML (script-payload stripped): 発話=absent, Kashiが見るもの=absent, 発言の遮り + Kashiが整理するもの present. |
| △ 部分 | 0-overflow 320–1440 | No committed automated overflow/responsive test exists (grep of test/ for scrollWidth/overflow/viewport = none). Both RC62 test headers explicitly state the responsive + keyboard + reduced-motion runtime gates 'run via /browse (no Playwright in this repo)' and are 'recorded in the PR'. So the 0-overflow 320-1440 criterion is manual-QA-verified-in-PR only, not pinned by a test that would re-bite on regression. Structural mitigations exist (mobile-first layout, .home-v61 scope, max-w wrappers) but no acceptance test asserts it on main. |
| ✓ main 反映 | Gates (CI test gates: banned-copy, required-copy, core-visibility, claim-safety, CTA/link, typography, disclosure-ARIA, copy-lock, section3Card guard) | homepage62-gates.test.ts (Gates 1-5 + disclosure-source + copy-lock + section3Card guard) and homepage62-disclosure.test.tsx (ARIA DOM) — 2 files, 58 tests, all PASS at HEAD eb466f8 (run confirmed). Merged as part of #507 (eb466f8 'feat(homepage): v3.1 progressive-disclosure upgrade (Review Comment 62)'). HEAD eb466f8 is the deployed commit. |