Commit 5d095a0
fix(driver-sql,service-analytics): bucket the ISO week natively on SQLite, and the SQL echo refuses a bucket SQLite cannot run (#21629)
Fixes #21595
Clause-②: no
## What changes
**(a) `week` on SQLite, in `driver-sql`.** The SQLite capability row now
advertises `week`, and `SqlDriver.buildDateBucketExpr`'s SQLite arm
renders the ISO 8601 week as `YYYY-Www`, the label the PostgreSQL arm's
`IYYY"-W"IW` and the MySQL arm's `%x-W%v` answer:
```sql
(strftime('%Y', ARG, '-3 days', 'weekday 4') || '-W' ||
printf('%02d', (cast(strftime('%j', ARG, '-3 days', 'weekday 4') as integer) - 1) / 7 + 1))
```
It is the Thursday rule. `'-3 days', 'weekday 4'` moves any day to the
Thursday of its Monday-start week, so that Thursday's `%Y` is the
week-numbering year and its day of year gives the week number. It uses
no `%V` or `%G`, and both date modifiers predate every SQLite the
platform ships. `ARG` is the existing `sqliteTemporalArg`: a bare column
for TEXT storage, and the legacy repair for an un-backfilled
`Field.datetime`. No zone is read, so a `Field.date` stays its calendar
day (H2 holds). Both callers follow without a second edit:
`aggregate()`'s GROUP BY and the public `dateBucketSql()` the analytics
echo reads.
**(b) A non-UTC zone on SQLite, in `service-analytics`' echo.**
`ObjectQLStrategy.generateSql` no longer prints `date_trunc(...)` on a
SQLite datasource, since SQLite has no such function. Where no driver
expression answers and the executing driver's dialect (`sqlDialectFor`)
is `sqlite`, the echo refuses with `NOT_IMPLEMENTED` / 501 and `refusal:
true`. The shipped composition reaches that branch for a non-UTC
`timezone`: the engine then buckets in memory on that zone's calendar,
and SQLite has no time-zone database. The refusal reaches each door as
follows:
- `POST /api/v1/analytics/sql` answers the refusal in the error
envelope. `refusal: true` is the declared channel
(`ApiErrorSchema.refusal`) for a 5xx whose prose is addressed to the
caller, so the boundaries keep the message.
- `POST /api/v1/analytics/query` still answers the rows. `execute()`
already calls `generateSql` inside a `try`, so the answer simply carries
no `sql`. This is the reach the existing cross-field decline has.
- With `timezone: 'UTC'`, or none, the echo still prints the driver's
expression. On a dialect the host cannot name, it still prints the
representative `date_trunc`.
**Riders.**
- R1: `packages/objectql/src/engine.ts`. The ADR-0053 D2 comment above
`tzRequiresInMemory` now names driver-sql's `to_char` / `date_format` /
`strftime`. In the same block, the comment's example "partial-support
dialects (e.g. SQLite + week)" is false after this change; it now names
the Turso remote transport, which advertises none. Comments only: 8
changed lines, 0 non-comment.
- R2: `driver-turso`'s `REMOTE_FACE_ANSWERS` row `dateBucketSql:
'inherited'` is now pinned by running it. The remote face renders the
expression with no connection, and the pin sends it through the remote
face's own `execute()` to a real `@libsql/client` `file:` client, beside
a better-sqlite3 local control. All five granularities answer the local
labels, and `week` answers the written-out ISO weeks of the boundary
days. The row's text needed no change (H4).
**Comment corrections carried from #21485's ACCEPT 5971379160.**
`objectql-strategy.ts`, `strategies/types.ts` and the echo pin's
docblock quoted PostgreSQL's `to_char((col)::timestamptz AT TIME ZONE
'UTC', ...)` as the bucket expression. Since 440cd32 that is the
`datetime` expression only; each now names `(col)::date::timestamp` for
a `date`.
## Measured first: each SQLite client's bundled SQLite
| client | package | `sqlite_version()` | `strftime('%V', '2021-01-03')`
|
|:--|:--|:--|:--|
| better-sqlite3 13.0.3 | `driver-sql`, `driver-turso` local face |
3.53.4 | `53` |
| `@libsql/client` 0.18.0 | `driver-turso` remote face (`file:` client)
| **3.45.1** | **NULL** |
| sql.js 1.14.2 | `driver-sqlite-wasm` | 3.49.1 | `53` |
The platform ships three SQLite clients, not two: `SqliteWasmDriver` is
a `SqlDriver` subclass that overrides `isSqlite`, so it inherits this
arm. libSQL bundles 3.45.1, so by triage's rule `%V` is out, and the
expression is version-independent.
## The expression, measured before it was written
- **On each client:** 12,454 inputs per client, with 0 mismatches
against `@objectstack/core`'s `bucketDateKey` on better-sqlite3, libSQL
and sql.js alike. The inputs are every day from 1999-01-01 to
2032-12-31, datetimes at 00:00, 12:00 and 23:59:59.999Z on the ISO-year
boundary days, the years 0001 / 0049 / 0050 / 0999 / 1000 / 9999, and
unparseable and empty values, which answer NULL as the in-memory face
does.
- **Against PostgreSQL's own arm:** PostgreSQL 16.14
`to_char(d::date::timestamp, 'IYYY"-W"IW')` over 1999-01-01..2032-12-31,
12,419 days, 0 mismatches. The boundary days: 2020-12-31 and 2021-01-03
are `2020-W53`, 2021-01-04 is `2021-W01`, 2024-12-30 is `2025-W01`,
2026-12-28 and 2027-01-03 are `2026-W53`.
- **MySQL's `%x-W%v`:** NOT MEASURED here, because no MySQL server is
available in this container. It is pinned to the same `bucketDateKey` by
CI's live Temporal Conformance.
## (b): the declared response contract, read first
- `/analytics/sql`: `AnalyticsSqlResponseSchema` declares `data: { sql:
z.string(), params }` over `BaseResponseSchema`, whose `error` is the
refusal envelope. A `null` statement with a reason is **not** admitted,
so it is not the shape, and the contract is not widened. A refusal
**is** admitted, and this door already refuses a cross-field comparison
(the #7598 ruling, "一致的响亮答案,不半渲染").
- `/analytics/query`: `sql` is `z.string().optional()`, "Generated SQL
(if available)", so an answer without it is admitted.
So the shape is the refusal. The status is `NOT_IMPLEMENTED` / 501
rather than a 400: the query is spelled correctly and served, and the
gap is the backend's. This is the reasoning driver-sql's own bucket
refusal gives (#6212 / #5907), and the `/meta/:type/:name/references`
501 is the precedent for `refusal: true`.
## Fixture triage: pins that held the removed branch
| file | disposition |
|:--|:--|
| `driver-sql/src/sql-driver-date-bucket.test.ts` | `caps.week` is now
`true`, and `week` joins the parity sweep. The #6212 refusal pin moves
off SQLite `week` to the population that still reaches it: an unmodeled
client (`mssql`, whose capability row is empty; the refusal is raised
before any connection). Code, status and message as before, with the
tail now `Bucketed here: none (dialect 'mssql')`. |
| `driver-sql/src/sql-driver-date-bucket-storage.test.ts` | `week` joins
both storage forms. One new case covers `week` over the legacy
mixed-form column (epoch INTEGER, ISO TEXT, zone-naive TEXT, NULL),
where the repair is expanded twice. |
| `driver-sql/src/sql-driver-temporal-dialect.test.ts` | `week` joins
the dialect-gating granularities, so the legacy repair, the plain column
form and the binding count are pinned for the new arm. New assertion: no
SQLite arm reads a `Field.date` through `'localtime'` or `'utc'` (H2). |
| `driver-sql/src/sql-driver-21485-date-bucket-calendar-day.test.ts` |
SQLite's `BUCKETED_IN_SQL` gains `week`, so `aggregate()` and the
`dateBucketSql` echo run it on the date/datetime boundary rows. |
| `driver-sql/src/sql-driver-13714-...test.ts` | Comment only. The sweep
is data-driven by the capability row and now serves `week`. |
| `driver-sqlite-wasm/src/sqlite-wasm-driver-date-bucket.test.ts` |
`caps.week` is now `true`, and `week` joins the parity sweep on sql.js.
Its refusal twin is removed: no granularity reaches that refusal on this
driver any more. |
| `driver-turso/src/remote-transport-groupby-node.test.ts` | The #5240
parity case ("one condition, one wording") compares the remote transport
with an unmodeled `SqlDriver`, the only SqlDriver face that still
declines. The `month` asymmetry case is parameterized over `month` and
`week`. The case that pinned the SQLite face's `week` refusal tail is
removed. |
| `qa/dogfood/test/date-bucket-parity-turso.test.ts` | The tripwire made
a local driver advertise `week` because SqlDriver could not run it. It
now keeps the real row (which advertises `week`) and makes the `week`
arm answer `null`, the incoherent pair a revert of the arm alone would
ship. `checkDateBucketParity` still names it. |
| `service-analytics/src/__tests__/objectql-echo-date-bucket.test.ts` |
The SQLite cell groups `week`. The in-memory-granularity FALLBACK case
is removed, because its only input was SQLite `week`. The non-UTC case
is per cell: on SQLite it pins the refusal (rows served with no `sql`;
`/analytics/sql` refuses with `NOT_IMPLEMENTED`, 501 and `refusal:
true`; `declaredRefusalMessage(err) === err.message`; a UTC control
renders). On PostgreSQL it is unchanged (see the finding below). A unit
case pins the refusal for a SQLite host that wires no hook. |
Also swept and left alone: `checkDateBucketParity`'s real-driver half in
`date-bucket-parity-conformance.test.ts` now exercises `week` on
better-sqlite3 and sql.js with no edit. Its `week: false` fake is
self-contained. `timedimension-granularity-driver-alias.test.ts` is
data-driven and green; see the Acceptance notes.
## Reverse verification (commit first, then revert only the arm)
Taken at head `59a751f4ad`, through `scripts/ablation-replace.mjs` (wrap
mode: literal anchor, restore armed on exit, INT and TERM). The mutation
replaced the whole SQLite `week` block with the original `case 'week':
return null; // see capabilities note`. Anchor 1 to 0, blob
`5f6b143dbe1a` to `5e80a2795453`. The capability row stayed `week:
true`.
- Rebuilt `@objectstack/driver-sql`, then `ablation-dist-preflight.mjs
@objectstack/driver-sql "'-3 days', 'weekday 4'" --absent`: exit 0, so
the arm was out of the `dist/` that driver-turso, driver-sqlite-wasm,
service-analytics and dogfood consume.
- **Red on every client (the predicted direction):**
- better-sqlite3 (`driver-sql`): 3 failed, the three `week` cases.
- libSQL (`driver-turso` R2): 2 failed, `week: libSQL answers the labels
the local face answers` and `week: libSQL answers the ISO week of each
boundary day`.
- sql.js (`driver-sqlite-wasm`): 1 failed, `granularity=week`.
- The echo (`service-analytics`): 2 failed, `closed_on, week` and
`closed_at, week`.
- Dogfood conformance: 2 failed, both drivers.
- **Restore:** `git checkout HEAD -- ABSOLUTE_PATH`. The blob after
restore is `5f6b143dbe1a`, equal to HEAD, `git diff HEAD` is empty and
`git status --porcelain` shows 0 entries. Then a rebuild and the
presence preflight: the marker is in 2 built files and the tree reading
is clean.
## Tests
Package suites at head `9328c3c6cc` (the merge of `origin/main` came
after; its incoming commits touch none of these packages except
driver-mongodb, where this diff is comments only):
- `@objectstack/driver-sql`, with the live PostgreSQL cell at
`TZ=America/New_York`: 225 files passed, 3 skipped; 4571 tests passed,
104 skipped (the MySQL cells: no server here).
- `@objectstack/service-analytics`, with the live PostgreSQL cell: 176
files passed; 4421 tests passed, 2 skipped.
- `@objectstack/driver-turso`: 88 files passed; 2373 tests passed, 33
skipped.
- `@objectstack/driver-sqlite-wasm`: 36 files passed; 675 tests passed.
- typecheck: `driver-sql`, `driver-sqlite-wasm`, `driver-turso`,
`service-analytics`, `driver-mongodb` (with `check:test-typecheck`) and
`objectql` (all three `tsc` programs and `check:test-typecheck`) are all
clean.
On the merged head `0e7e975a32`, after a post-merge turbo build and spec
`check:generated` (15 of 15 artifacts up to date), every changed pin
passed again:
| package | files | tests |
|:--|:--|:--|
| driver-sql | 5 | 99 passed, 2 skipped |
| driver-turso | 2 | 109 |
| driver-sqlite-wasm | 1 | 8 |
| service-analytics | 2 | 31 |
| dogfood | 2 | 13 |
| driver-mongodb `mongodb-date-bucket-parity` | 1 | 39 |
Declared narrowings, so they read as such:
- `objectql` and `driver-mongodb` suites were not run in full. Their
diffs are comment-only (`engine.ts` 8 changed lines,
`mongodb-aggregation.ts` 14 and its test 4, all comment lines), and both
packages typecheck.
- `packages/qa/dogfood` was not run in full; the two date-bucket files
it changes were. The rest is CI's Dogfood Regression Gate.
- MySQL cells were not run.
The live PostgreSQL was a throwaway 16.14 instance this run started on a
random port with server `TimeZone` Asia/Shanghai; it has been stopped
and removed.
## Gates
`node scripts/pm/dispatch-gates.mjs --commands` with no paths, at head
`0e7e975a32`: 101 derived (the 58 the dispatch named plus 43 the change
set adds). All 101 ran on that head and each exited 0. `--ran`
reconciliation: "101 derived famil(ies) accounted for — 101 run, 0
NOT-MEASURED (a DERIVED zero — all 101 recorded an exit code and none of
them is 3)". On the first run at `59a751f4ad`, `check:skill-examples`
and `check:dual-build-cjs-loads` answered exit 3 (PREREQUISITE NOT MET,
unbuilt packages). After a full build both passed, and on the final head
all 101 are exit 0.
Driver-card ledger, `pnpm check:driver-conformance`: before (at BASE
`5c9138b4b6`) and after (at `0e7e975a32`), both 50 covered cells, 0 in
the DEBT ledger, 0 exempt. No new DEBT.
**Lint, a proven narrowing at `0e7e975a32`:**
- Population, read from eslint's own config: the 16 changed `.ts` files,
run as `pnpm lint` runs (`--no-inline-config`). None was reported as
ignored.
- `--format json` count: 16 files, 0 errors, 0 warnings.
- Invariance: `eslint.config.mjs` never enables type-aware linting (no
`parserOptions.project`, no typed rules), so this diff cannot move the
verdict on an untouched file.
## File surface, and what this adds to the claim's
The claim named `sql-driver.ts`, the `driver-turso` pin, the
`service-analytics` echo, its pin and two comment files, `engine.ts` R1,
tests and the changeset. Each addition below is forced by this change,
and none is a behaviour change outside the claim:
- Test files that pinned the removed branch (see the triage table):
`driver-sqlite-wasm`, `driver-turso`'s
`remote-transport-groupby-node.test.ts`, and `qa/dogfood`'s Turso parity
tripwire.
- Statements this change makes false, each corrected as a sentence:
- `driver-mongodb`'s TSDoc on the exported `MONGODB_DATE_GRANULARITIES`
("driver-sql sets `week: false`", which ships in its `.d.ts`), and its
test's comment.
- `content/docs/data-modeling/queries.mdx` ("SQLite reports `week:
false`, for instance").
- The second `engine.ts` comment, in R1's own block.
Changeset `.changeset/21595-sqlite-week-bucket.md`: `patch` for
`@objectstack/driver-sql` and `@objectstack/service-analytics`.
`driver-turso` ships no code change, so it gets none, and the
`driver-mongodb` and `objectql` changes are comments.
## Acceptance notes
- Not filed, and left outside this diff:
-
`service-analytics/src/__tests__/timedimension-granularity-driver-alias.test.ts`'s
header still says SQLite declines `week`. The test is data-driven and
green; the file is outside the declared cross-lane set.
- The spec's `queryDateGranularity` TSDoc example (`{ day: true, week:
false }` "for a SQLite build whose `strftime` lacks ISO week") is still
a valid hypothetical, but no shipped SQLite driver declares it now.
- `objectql/src/engine-aggregate-timezone.test.ts`'s header names native
bucketing `date_trunc`, R1's drift in a test file. None of these is made
false by behaviour in this PR in a way any test reads.
- `skills/objectstack-ui/rules/dashboards.md`'s `week` label row ("ISO
date of the bucket (`YYYY-MM-DD`)"; the key is `YYYY-Www`) and
`skills/objectstack-query/rules/aggregation.md` line 82 ("`DATE_TRUNC`
etc.") were inaccurate before this change. They belong with #21588, the
open card for the same `dashboards.md` engine sentence, on a Tier H
surface this PR does not touch.
- **For the seat to file, (b)'s foreseen follow-up on PostgreSQL and
MySQL.** On PostgreSQL the echo for a non-UTC zone still prints
`date_trunc('month', closed_at)`; this PR leaves it, and the echo pin's
PostgreSQL cell still asserts it. That statement was run on PostgreSQL
16.14 (server `TimeZone` Asia/Shanghai) over the pin's five rows:
- It answers `2026-01-01 00:00:00+08`-shaped keys on the session zone's
calendar, where the face answers `2026-01` on the request zone's.
- For `timezone: 'America/New_York'` the groupings differ too: the echo
gives January 20 and February 8, where the face gives January 27 and
February 1.
- On MySQL `date_trunc` is not a function. That is NOT MEASURED here (no
server).
---
_Generated by [Claude
Code](https://claude.ai/code/session_017ErfyP2Rx7XWHJA27QjyUi)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 3f1bc81 commit 5d095a0
18 files changed
Lines changed: 397 additions & 162 deletions
File tree
- .changeset
- content/docs/data-modeling
- packages
- drivers
- driver-mongodb/src
- driver-sqlite-wasm/src
- driver-sql/src
- driver-turso/src
- objectql/src
- qa/dogfood/test
- services/service-analytics/src
- __tests__
- strategies
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
677 | 677 | | |
678 | 678 | | |
679 | 679 | | |
680 | | - | |
681 | | - | |
682 | | - | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
683 | 683 | | |
684 | 684 | | |
685 | 685 | | |
| |||
Lines changed: 8 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
294 | 294 | | |
295 | 295 | | |
296 | 296 | | |
297 | | - | |
298 | | - | |
| 297 | + | |
| 298 | + | |
299 | 299 | | |
300 | 300 | | |
301 | 301 | | |
| |||
Lines changed: 3 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
88 | | - | |
89 | | - | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
90 | 90 | | |
91 | 91 | | |
92 | 92 | | |
| |||
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | | - | |
| 91 | + | |
| 92 | + | |
92 | 93 | | |
93 | 94 | | |
94 | | - | |
| 95 | + | |
95 | 96 | | |
96 | 97 | | |
97 | 98 | | |
| |||
Lines changed: 26 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
30 | 30 | | |
31 | | - | |
32 | | - | |
| 31 | + | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
57 | 68 | | |
58 | 69 | | |
59 | 70 | | |
| |||
243 | 254 | | |
244 | 255 | | |
245 | 256 | | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
246 | 269 | | |
247 | 270 | | |
248 | 271 | | |
| |||
Lines changed: 44 additions & 31 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
107 | 107 | | |
108 | 108 | | |
109 | 109 | | |
110 | | - | |
111 | | - | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
112 | 113 | | |
113 | 114 | | |
114 | 115 | | |
115 | | - | |
| 116 | + | |
116 | 117 | | |
117 | 118 | | |
118 | 119 | | |
| |||
141 | 142 | | |
142 | 143 | | |
143 | 144 | | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
154 | 161 | | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
173 | 186 | | |
174 | 187 | | |
175 | 188 | | |
| |||
Lines changed: 9 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
150 | 150 | | |
151 | 151 | | |
152 | 152 | | |
153 | | - | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
154 | 156 | | |
155 | 157 | | |
156 | 158 | | |
| |||
190 | 192 | | |
191 | 193 | | |
192 | 194 | | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
193 | 200 | | |
194 | 201 | | |
195 | 202 | | |
| |||
231 | 238 | | |
232 | 239 | | |
233 | 240 | | |
234 | | - | |
| 241 | + | |
235 | 242 | | |
236 | 243 | | |
237 | 244 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6101 | 6101 | | |
6102 | 6102 | | |
6103 | 6103 | | |
6104 | | - | |
6105 | | - | |
6106 | | - | |
| 6104 | + | |
| 6105 | + | |
| 6106 | + | |
| 6107 | + | |
| 6108 | + | |
| 6109 | + | |
| 6110 | + | |
| 6111 | + | |
6107 | 6112 | | |
6108 | 6113 | | |
6109 | 6114 | | |
| |||
6185 | 6190 | | |
6186 | 6191 | | |
6187 | 6192 | | |
6188 | | - | |
| 6193 | + | |
| 6194 | + | |
| 6195 | + | |
| 6196 | + | |
| 6197 | + | |
| 6198 | + | |
| 6199 | + | |
| 6200 | + | |
| 6201 | + | |
| 6202 | + | |
| 6203 | + | |
| 6204 | + | |
| 6205 | + | |
| 6206 | + | |
| 6207 | + | |
| 6208 | + | |
6189 | 6209 | | |
6190 | 6210 | | |
6191 | 6211 | | |
| |||
6195 | 6215 | | |
6196 | 6216 | | |
6197 | 6217 | | |
6198 | | - | |
6199 | | - | |
6200 | | - | |
6201 | | - | |
| 6218 | + | |
| 6219 | + | |
| 6220 | + | |
6202 | 6221 | | |
6203 | 6222 | | |
6204 | 6223 | | |
| |||
0 commit comments