Repository navigation
Commit 8bceb6a
fix(platform-objects): Setup Create User marks Email required while phone sign-in is off (#28707)
domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1XMQYxWuFJTUDhuJ14KLeVrk)_
Fixes #28280
Clause-②: yes (widening)
Metadata-protocol: semantic
## 维护者速读
- **改了什么**:Setup → 用户 →
创建用户:未开启手机号登录(默认)时,「邮箱」在提交前就带必填星标,留空会在对话框里直接拦下;开启手机号登录时,邮箱仍是可选,旁边是手机号。控制台还没拿到
`/auth/config` 的应答时(加载中或请求失败),邮箱不带标记,和 main 上一样。
- **为什么改**:服务器在未开启手机号登录时拒收空邮箱(400 "Email is
required"),但对话框把邮箱画成可选,管理员只有提交后才知道。#28649 已能在提交后标出服务器点名的字段,这张卡补上提交前的标记。
- **风险与回滚**:中低。`sys_user.create_user` 的邮箱参数拆成两个(同一字段,按
`features.phoneNumber` 各自显隐,对话框只画并只提交显示的那个)。为此动作门的参数校验
`validateActionParams`
改了一处语义:同名参数声明多次时,只有每一处都必填才算必填,值形状按第一处(以前是最后一处说了算,会让 REST 动作门把只填手机号的创建拒成
400)。仓库、示例和 hotcrm 里没有别的动作重复声明参数名,所以别处行为不变。外加 `public-auth-features.ts`
登记一条路径。纯 revert 即可回滚。
-
**先看**:`packages/spec/src/ui/action-params.zod.ts`(同名合并那一行);`packages/platform-objects/src/identity/sys-user.object.ts`(两个邮箱参数的顺序与
`visible`);`packages/runtime/src/domains/api-action-create-user-email-param.test.ts`(经真实
REST 动作门的三条路径)。
- **两分钟验证**:`pnpm --filter @objectstack/runtime exec vitest run
src/domains/api-action-create-user-email-param.test.ts`,预期 5
例全绿(只填手机号的创建能到达接口;空邮箱由接口自己答 400 "Email is required")。
- **需要你做的**:无,席位落地(含 `packages/spec` 路径的 Contract review)。
## What changes
- **`sys_user.create_user` declares two params on the one `email`
field** (`packages/platform-objects/src/identity/sys-user.object.ts`). A
param's `required` is a static boolean, and the endpoint requires the
email only while phone sign-in is off, so:
- first `{ field: 'email', required: false, requiresFeature:
'phoneNumber' }`, which lowers to `features.phoneNumber == true`;
- then `{ field: 'email', required: true, visible:
'has(features.phoneNumber) && features.phoneNumber != true' }`.
The console collects and submits only the params whose gate says yes
(`filterVisibleParams`), so exactly one Email input renders. The
rendered order is unchanged: Email, then Phone Number when it shows,
then Name.
- **The action doors judge a twice-declared name by every declaration**
(`packages/spec/src/ui/action-params.zod.ts`, under the one-PR exception
the seat extended to this file). `validateActionParams`, which
`enforceActionParams` runs on the REST action route and the MCP
`run_action` bridge before the handler, keyed params by name with the
LAST declaration winning, so the required second Email param made the
REST door refuse a phone-only create (`400 VALIDATION_ERROR` "Action
param \"email\" is required"). A name declared more than once is now
required only when EVERY declaration is, and its value shape is the
FIRST declaration's; unknown-key handling is unchanged. The door reads
no `visible` or `features`, so the endpoint stays the judge of a blank
email.
- **The registry** (`packages/spec/src/kernel/public-auth-features.ts`):
`PUBLIC_AUTH_FEATURES.phoneNumber.gatedInputs` books
`sys_user.actions.create_user.params.email`. The row's notes say the
path stands for two params, the second negatively gated, and the module
and `gatedInputs` docblocks say a param path resolves to the first param
on its field and the gate is checked as a conjunct. No registry model
change and no required-when predicate, as ruled.
- **The guard's header**
(`packages/platform-objects/src/feature-gate-guard.test.ts`) states that
this one booked path stands for two params, one of them negatively
gated. The guard's logic is untouched.
- **Tests**: a platform-objects pin that evaluates the declared gates
through the canonical CEL engine under the console's show rule; an
app-shell test that opens Create User through the console runtime with
the served `features`; a runtime test that drives the real REST action
route with the real `SysUser` declaration; two `validateActionParams`
cases in `action-params.test.ts`.
- **Changeset** `.changeset/28280-create-user-email-required-mark.md`:
`@objectstack/spec` minor (the semantic change to a twice-declared
param's `required` at the doors) and `@objectstack/platform-objects`
patch. Both packages ship `dist`, and the built `dist` of each carries
the change.
## Tests
<details><summary>Red first on origin/main 49a6a5c, green at
head</summary>
`pnpm --filter @objectstack/platform-objects exec vitest run
src/identity/sys-user-create-user-email-required.test.ts`, with only the
test file on top of `origin/main`:
```
× phone sign-in off: one Email input, and it is required
× the first Email param carries the canonical phoneNumber gate the feature-gate guard resolves
Tests 2 failed | 2 passed (4)
os-verify-lock: VERDICT command-exit 1
```
At head, with the guard file (after `pnpm --filter @objectstack/spec
build`):
```
✓ forward … sys_user.actions.create_user.params.email is gated on phoneNumber
✓ reverse … sys_user.actions.create_user.params.email references registered flag phoneNumber and is booked (x3)
✓ 4/4 of the new pin
Tests 116 passed (116)
```
Whole package: `pnpm --filter @objectstack/platform-objects test` →
`Test Files 107 passed (107) · Tests 1496 passed (1496)`.
</details>
<details><summary>The Create User dialog (app-shell)</summary>
`useConsoleActionRuntime.createUserEmailRequiredMark-28280.test.tsx`
boots the dialog the way #28649's test does (real `ActionRunner` with
the console runtime's api and param handlers, real `ActionParamDialog`,
real Chinese `I18nProvider`), inside the console's own
`ExpressionProvider` fed the served `features`, with `sys_user`'s fields
so the field-backed params resolve through `resolveActionParams`:
- phone sign-in off: one Email input, `aria-required="true"`, no Phone
Number; a blank Confirm shows `邮箱 为必填项`, marks the input invalid, and
sends no request;
- phone sign-in on: one Email input, not required, Phone Number shown; a
blank Confirm goes to the server;
- no served flag (`features` is `{}`): one Email input, not required;
- control: with phone sign-in off a typed email submits once.
`cd ui && pnpm exec vitest run
packages/app-shell/src/hooks/__tests__/useConsoleActionRuntime.createUserEmailRequiredMark-28280.test.tsx
packages/app-shell/src/hooks/__tests__/useConsoleActionRuntime.createUserRequiredField-28289.test.tsx`
→ `Test Files 2 passed (2) · Tests 10 passed (10)` (#28649's six
server-refusal marks stay green).
</details>
<details><summary>The REST action door (runtime), red first and the
merge ablated</summary>
`pnpm --filter @objectstack/runtime exec vitest run
src/domains/api-action-create-user-email-param.test.ts`, driving
`HttpDispatcher.handleActions('/sys_user/create_user', 'POST', …)` over
the `api-action-forward.test.ts` recording target, with the real
`SysUser` from `@objectstack/platform-objects/identity`:
- the declaration carries two email params, `[false, true]`;
- phone-only `{ phoneNumber, name }` passes the door and is forwarded to
`/api/v1/auth/admin/create-user`;
- a blank email passes the door; the caller gets the ENDPOINT's `400
VALIDATION_FAILED` "Email is required" with its `fields`, relayed whole
(the door does not refuse it);
- an email is forwarded with it;
- control: a non-string email is still refused at the door (value shape
from the first declaration).
Red first, with `packages/spec/src/ui/action-params.zod.ts` at 2310b30
and spec rebuilt: `× phone-only … reaches the endpoint` with
`{"code":"VALIDATION_ERROR","message":"Invalid action params: Action
param \"email\" is required","httpStatus":400}`, `× blank email …` (the
seat's finding). That run was on a six-case draft: 3 failed / 3 passed,
the third an MCP case that failed on the system-object exposure refusal
instead and was dropped (see below). Spec unit cases: 2 failed / 33
passed.
Merge ablated through `scripts/ablation-replace.mjs`
(`declared.set(p.name, p)`, last wins), spec rebuilt, `dist` hits of the
merge 0: door test 2 failed / 3 passed, spec cases 2 failed / 33 passed.
Restored to the HEAD blob (`git diff HEAD` empty), rebuilt, `dist` hits
1: 5/5 and 35/35.
The MCP bridge is not driven for this action: `create_user` declares no
`ai.exposed`, so `run_action` refuses it as a system-object action
before any param check (measured). Both doors call the same
`enforceActionParams`.
</details>
<details><summary>Ablations (each through scripts/ablation-replace.mjs,
restored to the HEAD blob, git diff HEAD empty)</summary>
| Leg | Mutation | Reading |
|:--|:--|:--|
| A1 | source: the required Email param made `required: false` | `×
phone sign-in off: one Email input, and it is required` · 1 failed / 115
passed |
| A2 | source: `has(features.phoneNumber) &&` dropped (bare
`features.phoneNumber != true`) | `× no served flag …: one Email input,
optional` · 1 failed / 114 passed |
| A3 | source: the two Email params swapped (required first) | `× the
first Email param carries the canonical phoneNumber gate …` and the
guard's forward row `× sys_user.actions.create_user.params.email is
gated on phoneNumber` · 2 failed / 114 passed |
| U1 | ui mirror: the required param made optional | `× phone sign-in
off: … required mark …` · 1 failed / 3 passed |
| U2 | ui mirror: bare `features.phoneNumber != true` | `× no served
flag …` · 1 failed / 3 passed |
The platform-objects pin imports the object from `src/` (relative
import), and ui vitest aliases `@object-ui/*` to `src/`, so no leg
needed a rebuild. A3 confirms the order matters: the forward guard
resolves the path to the first param on the field.
</details>
## Acceptance notes
- **One reading beyond the order's literal.** The order spelled the
required param's gate `features.phoneNumber != true`. Measured (A2, U2):
while the console holds no served flag (its `features` is `{}` until
`/auth/config` answers, and stays `{}` if that fetch fails) both gates
fault on the absent key, and the dialog shows a param whose gate faults,
so two Email inputs render. The `has(features.phoneNumber) &&` term
keeps the required param hidden then, and Email stays optional as it
was. The precedent spelling is `sys-user.page.ts`'s
`has(features.twoFactor) && features.twoFactor == true`. The first,
optional param keeps the canonical gate the guard wants.
- **The endpoint is unchanged**: it still refuses a blank email with
phone sign-in off; no server file is in this diff.
- **Census for the semantic change**: an AST scan of every `params` /
`actionParams` array literal in this repository (430 arrays, `ui/` and
`examples/` included) and in hotcrm `origin/main` (7 arrays), plus the 2
JSON params arrays, finds no name declared twice except `create_user`'s
`email`. No existing action relied on last-wins.
- **The reverse guard** has three `email` rows (one per
`features.phoneNumber` reference across the two params), all booked by
the one path.
- The reverse guard's red without the booking was measured on the card
(2 failed) and is not re-run here.
## Verification
<details><summary>Local gates at head</summary>
Local gate run at head 9684fb3, derived by dispatch-gates --commands
(87 families), each exit captured before any pipe.
Re-run: pnpm --dir ui exec vitest run scripts/ first exit 1
(unit-registry-absence-collision could not import app-shell modules
while @objectstack/client dist was still being built in this fresh
worktree), then exit 0 (169 files) once it was built.
```
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-adoption.mjs :: exit 0
node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-dev-prereqs.mjs --self-test :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-issue-citations.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0
node scripts/docs-audit/check-affected-docs.mjs :: exit 0
node scripts/docs-audit/check-drift-comment.mjs :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm --filter @objectstack/spec run check:api-surface :: exit 0
pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0
pnpm --filter @objectstack/spec run check:browser-reachable-entries :: exit 0
pnpm --filter @objectstack/spec run check:docs :: exit 0
pnpm --filter @objectstack/spec run check:dual-source-exports :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm --filter @objectstack/spec run check:empty-state :: exit 0
pnpm --filter @objectstack/spec run check:entry-nameability :: exit 0
pnpm --filter @objectstack/spec run check:export-origins :: exit 0
pnpm --filter @objectstack/spec run check:exported-any :: exit 0
pnpm --filter @objectstack/spec run check:liveness :: exit 0
pnpm --filter @objectstack/spec run check:llms-txt :: exit 0
pnpm --filter @objectstack/spec run check:skill-refs :: exit 0
pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0
pnpm --filter @objectstack/spec run check:variant-docs :: exit 0
pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 0
pnpm check:dual-build-cjs-loads :: exit 3
pnpm check:engine-double-contract :: exit 0
pnpm check:error-code-casing :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:i18n :: exit 0
pnpm check:i18n-stale-fill :: exit 0
pnpm check:issue-citations :: exit 0
pnpm check:keyed-text-bounds :: exit 0
pnpm check:lean-entry-closure :: exit 0
pnpm check:logger-receiver-detach :: exit 0
pnpm check:merge-driver :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:objectql-double-limit :: exit 0
pnpm check:org-identifier :: exit 0
pnpm check:page-declaration-shape :: exit 0
pnpm check:platform-object-tenancy-census :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:pm-prior-rulings :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:registry-log-declared :: exit 0
pnpm check:rest-log-spy-declared :: exit 0
pnpm check:route-envelope :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:slot-lookup :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 0
pnpm check:spec-docblock-symbol-anchors :: exit 0
pnpm check:spec-parsed-alias :: exit 0
pnpm check:system-context-census :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
```
dispatch-gates --ran: 87 derived, 86 run, 1 NOT-MEASURED
(check:dual-build-cjs-loads, PREREQUISITE NOT MET: needs every package
dist), 0 UNRUN.
```
Also: pnpm --filter @objectstack/spec test :: exit 0 (783 files, 23175 tests); pnpm --filter @objectstack/spec typecheck :: exit 0; pnpm --filter @objectstack/runtime test :: exit 0 (505 files, 8191 tests); pnpm --filter @objectstack/runtime typecheck :: exit 0; pnpm --filter @objectstack/platform-objects test :: exit 0 (107 files, 1496 tests); eslint --no-inline-config on the touched spec, runtime and platform-objects paths :: exit 0. The app-shell test and type-check are unchanged since 2310b30 (green there).
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FEkQ5nn2N4syy7fVBUEXff)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 1c5b177 commit 8bceb6a
9 files changed
Lines changed: 521 additions & 7 deletions
File tree
- .changeset
- packages
- platform-objects/src
- identity
- runtime/src/domains
- spec/src
- kernel
- ui
- ui/packages/app-shell/src/hooks/__tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
18 | 29 | | |
19 | 30 | | |
20 | 31 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
314 | 314 | | |
315 | 315 | | |
316 | 316 | | |
317 | | - | |
318 | | - | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
319 | 333 | | |
320 | 334 | | |
321 | 335 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
35 | 37 | | |
36 | 38 | | |
37 | 39 | | |
| |||
70 | 72 | | |
71 | 73 | | |
72 | 74 | | |
73 | | - | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
74 | 79 | | |
75 | 80 | | |
76 | 81 | | |
| |||
230 | 235 | | |
231 | 236 | | |
232 | 237 | | |
233 | | - | |
| 238 | + | |
234 | 239 | | |
235 | 240 | | |
236 | 241 | | |
237 | 242 | | |
238 | | - | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
239 | 248 | | |
240 | 249 | | |
241 | 250 | | |
| |||
0 commit comments