Skip to content

Commit c5a7af7

Browse files
committed
feat: improve first review challenge onboarding
1 parent 716f1ed commit c5a7af7

3 files changed

Lines changed: 277 additions & 64 deletions

File tree

src/app/challenges/review/001-sympy-point2d-ai-patch/page.tsx

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ export default function FirstReviewChallengePage() {
3030
<a className="active" href="#review">
3131
第一题
3232
</a>
33+
<a href="#review-flow">审核流程</a>
3334
<a href="#diff">AI 补丁</a>
34-
<a href="#submit">提交审核</a>
35+
<a href="#submit">提交 Review</a>
3536
<a href="#rubric">评分</a>
3637
</nav>
3738
<div className="actions">
@@ -84,7 +85,7 @@ export default function FirstReviewChallengePage() {
8485
SymPy 项目,只需要围绕本页给出的行为规则和 diff 做判断。
8586
</p>
8687
<div className="review-template">
87-
<pre>{`是否可以合并:可以 / 不可以
88+
<pre>{`是否可以合并:可以 / 不可以 / 需要更多信息
8889
8990
问题 1:
9091
- 严重程度:
@@ -112,46 +113,114 @@ export default function FirstReviewChallengePage() {
112113
从而抛出 `Imaginary coordinates are not permitted`。
113114
</p>
114115
<p>
115-
所以这道题的关键不是“只要不报错就行”,而是判断 AI 补丁有没有同时保住两个行为:普通坐标不要误杀,明确的虚数坐标仍然要拒绝
116+
这道题要练的是 code review 判断力:一个补丁修好 happy path 之后,是否仍然保留了原有输入约束和边界语义
116117
</p>
117118
</div>
118119
</section>
119120

120121
<section className="challenge-section card">
121122
<div className="card-head">
122-
<h2>预期行为表</h2>
123-
<span className="mono">review hints</span>
123+
<h2>术语速查</h2>
124+
<span className="mono">不用先学完整 SymPy</span>
125+
</div>
126+
<div className="term-grid">
127+
<div className="term-item">
128+
<strong>PR / diff</strong>
129+
<p>PR 是一次代码变更提议,diff 展示这次变更具体改了哪些行。</p>
130+
</div>
131+
<div className="term-item">
132+
<strong>merge / request changes</strong>
133+
<p>merge 表示接受变更;request changes 表示发现必须修复的问题,暂时不能进主分支。</p>
134+
</div>
135+
<div className="term-item">
136+
<strong>回归</strong>
137+
<p>修一个问题时,把原本正确的行为弄坏。Review Mode 很多题都在考这个。</p>
138+
</div>
139+
<div className="term-item">
140+
<strong>边界条件 / 负例测试</strong>
141+
<p>边界条件是容易暴露错误的输入;负例测试用来确认非法输入仍然会被拒绝。</p>
142+
</div>
143+
<div className="term-item">
144+
<strong>Point / Point2D</strong>
145+
<p>SymPy 里的几何点对象。这里你只需要知道:点坐标有一组原有合法性约束。</p>
146+
</div>
147+
<div className="term-item">
148+
<strong>evaluate(False)</strong>
149+
<p>临时关闭部分自动化简。它可能让表达式保持未化简状态,所以要留意分支判断是否被影响。</p>
150+
</div>
151+
<div className="term-item">
152+
<strong>im(a)</strong>
153+
<p>读取表达式 a 的虚部。你不需要掌握 SymPy 内部,只要知道它参与坐标合法性判断。</p>
154+
</div>
155+
<div className="term-item">
156+
<strong>a.is_number</strong>
157+
<p>判断 a 是否是具体数值。审核时要看它被放进条件判断后,是否改变了输入分类。</p>
158+
</div>
159+
</div>
160+
</section>
161+
162+
<section className="challenge-section card" id="review-flow">
163+
<div className="card-head">
164+
<h2>推荐审核流程</h2>
165+
<span className="mono">review path</span>
166+
</div>
167+
<ol className="review-flow">
168+
<li>
169+
<strong>先看改动点</strong>
170+
<span>先确认 PR 声称修复什么用户问题,再看 diff 改了哪条校验逻辑。</span>
171+
</li>
172+
<li>
173+
<strong>再看新增测试</strong>
174+
<span>新增测试通常能证明一个正向场景,也要检查是否覆盖了反向场景和边界输入。</span>
175+
</li>
176+
<li>
177+
<strong>对照原有约束</strong>
178+
<span>判断补丁是精确修复,还是只让某个 case 通过并顺手放宽了旧规则。</span>
179+
</li>
180+
<li>
181+
<strong>主动找反例</strong>
182+
<span>想一类补丁作者没有写进测试、但原有约束必须继续成立的输入。</span>
183+
</li>
184+
<li>
185+
<strong>给出 merge 结论</strong>
186+
<span>如果有回归风险,就写出 blocking finding、影响和可执行修复方向。</span>
187+
</li>
188+
</ol>
189+
</section>
190+
191+
<section className="challenge-section card">
192+
<div className="card-head">
193+
<h2>审查清单</h2>
194+
<span className="mono">不要只看 happy path</span>
124195
</div>
125196
<div className="behavior-table-wrap">
126197
<table className="behavior-table">
127198
<thead>
128199
<tr>
129-
<th>输入场景</th>
130-
<th>期望行为</th>
131-
<th>审核时要看什么</th>
200+
<th>输入类型</th>
201+
<th>原有约束</th>
202+
<th>你要验证的问题</th>
132203
</tr>
133204
</thead>
134205
<tbody>
135206
<tr>
136207
<td>
137-
<code>with evaluate(False): Point(1, 2)</code>
208+
普通数值坐标
138209
</td>
139-
<td>应该允许创建点</td>
140-
<td>不能再误报 imaginary coordinates</td>
210+
<td>不应因为关闭自动化简被误拒</td>
211+
<td>新增测试是否只证明了这个正向场景</td>
141212
</tr>
142213
<tr>
143-
<td>
144-
<code>with evaluate(False): Point(I, 2)</code>
145-
</td>
146-
<td>应该继续抛出错误</td>
147-
<td>检查这个约束在补丁后是否仍成立</td>
214+
<td>明显非法的坐标</td>
215+
<td>原有非法输入校验仍应清楚可解释</td>
216+
<td>PR 是否改变了合法 / 非法输入的分类边界</td>
148217
</tr>
149218
<tr>
150219
<td>
151-
<code>Point(x, y)</code>
220+
无法静态确定的符号坐标
152221
</td>
153-
<td>符号输入不应被粗暴拒绝</td>
154-
<td>不确定是否为虚数时,不能当成明确非法</td>
222+
<td>不应被粗暴当成非法输入</td>
223+
<td>条件判断是否把 unknown 和 invalid 混成一种</td>
155224
</tr>
156225
</tbody>
157226
</table>
@@ -189,12 +258,13 @@ export default function FirstReviewChallengePage() {
189258

190259
<section className="card">
191260
<div className="card-head">
192-
<h2>看 Diff 顺序</h2>
261+
<h2>审核顺序</h2>
193262
</div>
194263
<div className="section-body compact">
195-
<p>1. 先看 AI 改了哪一行判断条件。</p>
196-
<p>2. 再看新增测试只覆盖了什么场景。</p>
197-
<p>3. 最后用行为表检查是否有回归。</p>
264+
<p>1. 看 AI 改了哪一行条件。</p>
265+
<p>2. 检查新增测试是否覆盖正例和反例。</p>
266+
<p>3. 对照原有约束找回归风险。</p>
267+
<p>4. 写出能阻止 merge 的 finding。</p>
198268
</div>
199269
</section>
200270

src/app/globals.css

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,79 @@ h1 {
667667
gap: 10px;
668668
}
669669

670+
.term-grid {
671+
display: grid;
672+
gap: 10px;
673+
grid-template-columns: repeat(2, minmax(0, 1fr));
674+
padding: 16px;
675+
}
676+
677+
.term-item {
678+
background: var(--surface-soft);
679+
border: 1px solid var(--line);
680+
border-radius: 8px;
681+
padding: 12px;
682+
}
683+
684+
.term-item strong {
685+
display: block;
686+
font-size: 13px;
687+
margin-bottom: 6px;
688+
}
689+
690+
.term-item p {
691+
color: var(--text-soft);
692+
font-size: 13px;
693+
line-height: 1.6;
694+
margin: 0;
695+
}
696+
697+
.review-flow {
698+
counter-reset: review-step;
699+
display: grid;
700+
gap: 10px;
701+
list-style: none;
702+
margin: 0;
703+
padding: 16px;
704+
}
705+
706+
.review-flow li {
707+
align-items: start;
708+
background: var(--surface-soft);
709+
border: 1px solid var(--line);
710+
border-radius: 8px;
711+
counter-increment: review-step;
712+
display: grid;
713+
gap: 4px;
714+
grid-template-columns: 34px 1fr;
715+
padding: 12px;
716+
}
717+
718+
.review-flow li::before {
719+
align-items: center;
720+
background: var(--text);
721+
border-radius: 7px;
722+
color: #ffffff;
723+
content: counter(review-step);
724+
display: grid;
725+
font-family: var(--mono);
726+
font-size: 12px;
727+
font-weight: 800;
728+
height: 26px;
729+
justify-items: center;
730+
width: 26px;
731+
}
732+
733+
.review-flow strong {
734+
font-size: 14px;
735+
}
736+
737+
.review-flow span {
738+
color: var(--text-soft);
739+
font-size: 13px;
740+
line-height: 1.6;
741+
}
742+
670743
.behavior-table-wrap {
671744
overflow-x: auto;
672745
}
@@ -765,6 +838,10 @@ h1 {
765838
gap: 8px;
766839
}
767840

841+
.compact-field {
842+
max-width: 520px;
843+
}
844+
768845
.form-field select,
769846
.form-field textarea {
770847
background: var(--surface);
@@ -872,6 +949,24 @@ h1 {
872949
gap: 10px;
873950
}
874951

952+
.reference-disclosure {
953+
background: var(--surface);
954+
border: 1px solid var(--line);
955+
border-radius: 8px;
956+
padding: 10px;
957+
}
958+
959+
.reference-disclosure summary {
960+
color: var(--text);
961+
cursor: pointer;
962+
font-size: 13px;
963+
font-weight: 700;
964+
}
965+
966+
.reference-disclosure[open] summary {
967+
margin-bottom: 10px;
968+
}
969+
875970
.reference-links a {
876971
background: var(--surface);
877972
border: 1px solid var(--line);
@@ -920,6 +1015,14 @@ h1 {
9201015
flex-direction: column;
9211016
}
9221017

1018+
.term-grid {
1019+
grid-template-columns: 1fr;
1020+
}
1021+
1022+
.review-flow li {
1023+
grid-template-columns: 30px 1fr;
1024+
}
1025+
9231026
.problem-table thead {
9241027
display: none;
9251028
}

0 commit comments

Comments
 (0)