Repository navigation
Commit 975b248
Fixes #20808
Clause-②: no (narrowing)
## What this changes
Two more JSON-stored keys are refused `INVALID_FIELD` / 400 by
`engine.aggregate`, in the engine's words, before any driver is asked.
The aggregate × field-type table stops accepting `count_distinct` over
the JSON-stored types, so every reader of that row refuses the pair too.
Nothing widens.
**The narrowed accept sets, per shape and per door:**
| shape | door | before | now |
|:--|:--|:--|:--|
| `groupBy` entry naming a **multi-value** field (`multiselect`,
`checkboxes`, `tags`; `select`, `lookup`, `user`, `file`, `image`
declared `multiple: true`), as a name or as `{ field }` | engine
`aggregate` (`@objectstack/objectql`): REST query door, flows, hooks,
the analytics ObjectQL strategy | accepted, one answer per driver | `400
INVALID_FIELD` at `groupBy[i]` / `groupBy[i].field` |
| `count_distinct` over a **structured-JSON** field (`json`,
`composite`, `repeater`, `record`, `location`, `address`, `vector`) |
engine `aggregate` | accepted | `400 INVALID_FIELD` at
`aggregations[i].field` |
| `count_distinct` over a **multi-value** field (the same eight
declarations) | engine `aggregate` | accepted | `400 INVALID_FIELD` at
`aggregations[i].field` |
| `count_distinct` × the ten JSON-stored types (structured-JSON seven
plus `multiselect`, `checkboxes`, `tags`) |
`AGGREGATE_FIELD_TYPE_COMPATIBILITY.count_distinct`
(`@objectstack/spec`) | in the row | out of the row;
`isAggregateCompatibleWithFieldType('count_distinct', t)` is `false` |
| a dataset measure `count_distinct` × a JSON-stored type | lint rule
`measure-aggregate-field-type-refused` (`os validate`, and the runtime
gate on a dataset save) | clean | error at authoring / save |
| the same measure | analytics dataset compile leg | compiled | `400
DATASET_INVALID` |
The words, as `POST /api/v1/data/:object/query` returns them (the route
sits inside the 500 characters the REST door keeps; the REST pins assert
it there):
```text
aggregate('probe_20808'): groupBy[0] names 'tags', a declared select field with multiple: true — a multi-value field, which the engine does not group by. The query was NOT run. Filter by one member instead: where { "tags": { "$contains": VALUE } } counts or lists the records that hold VALUE, one query per member. A list of values is no group key the drivers share: one grouped each list apart, one grouped each serialized list apart, one refused the statement.
aggregate('probe_20808'): aggregations[0].field counts distinct 'meta', a declared json field — a structured-JSON value, which the engine does not count distinct. The query was NOT run. Count distinct values of a field that stores one scalar value: store the part you count in a field of its own and count_distinct that field, or count the rows with count. A JSON-stored value is no distinct key the drivers share: one counted every row apart, one compared the serialized text, one refused the statement.
```
The thrown error carries `code: 'INVALID_FIELD'`, `status` and
`httpStatus` 400, `field`, `fields` (every offender), `object` and
`param` (`groupBy` or `aggregations`).
**Landing site.**
- `packages/objectql/src/group-by-structured-json-door.ts`: the
structured-JSON door gains its second class, the multi-value field,
judged by `@objectstack/spec/data`'s `isMultiValueField` in the SAME
walk over the entries, so the first offending position is named
whichever class it is. The export is renamed
`assertGroupByNamesNoJsonStoredField`. The structured-JSON words keep
their verdict and route; their reason clause now also holds for `vector`
(the review note carried on the previous door's landing).
- `packages/objectql/src/count-distinct-json-stored-door.ts` (new):
`assertCountDistinctNamesNoJsonStoredField`. The TYPE half asks the spec
table (`isAggregateCompatibleWithFieldType('count_distinct', type)`),
never a second list. The DECLARATION half asks `isMultiValueField`,
because a per-type table cannot see `multiple: true`. Not judged: any
other function, a `count_distinct` naming no field, an undeclared name,
a host with no field map, and a type outside `FieldType` (the table is
fail-closed on vocabulary, so an introspected `integer` or `object`
column is left alone).
- `packages/objectql/src/engine.ts`: one call each, at the entry of
`aggregate`, right after the credential refusal and in the order
groupBy, then count_distinct.
- `packages/spec/src/data/aggregate-field-type-compatibility.ts`: the
`count_distinct` row is every `FieldType` except
`JSON_STORED_AGGREGATE_FIELD_TYPES` (spelled out, held equal to
`STRUCTURED_JSON_TYPES` ∪ `MULTI_OPTION_TYPES` by the pin, as the file
does for its other classes). The TSDoc states the ground, the
measurement, and the third reader.
`INVALID_FIELD`, an existing code: the verdict is about the named
field's type at a position, the question the structured-JSON door beside
it answers the same way.
## Before, measured on `origin/main` `42d78b97fe`
Through `POST /api/v1/data/:object/query` (the real `RestServer` route
over `ObjectStackProtocolImplementation` and `ObjectQL`). Drivers:
InMemoryDriver, SqlDriver on SQLite (better-sqlite3), and SqlDriver on a
private PostgreSQL 16.13 started for this run. Three rows; two of them
hold EQUAL values under every JSON-stored field.
| query | InMemoryDriver | SQLite | PostgreSQL 16 |
|:--|:--|:--|:--|
| `groupBy` `title` (text) / `status` (single-value select), the
controls | 200, `x` 2 · `y` 1 / `a` 2 · `b` 1 | same | same |
| `groupBy` each of the 8 multi-value declarations, and `{ field: 'tags'
}` | 200, one group per array | 200, one group per serialized array |
**500 `DATABASE_ERROR`** (could not identify an equality operator for
type json) |
| `count_distinct` `title` / `status`, the controls | 2 | 2 | 2 |
| `count_distinct` `json` (three different documents) | 3 | 3 | **500**
|
| `count_distinct` each other structured-JSON type | 3 | 2 | **500** |
| `count_distinct` each multi-value declaration | 3 | 2 | **500** |
| `count` over `json` / `tags` (unchanged) | 3 | 3 | 3 |
## After, the same run on this branch
Every multi-value `groupBy` and every JSON-stored `count_distinct` above
answers `400 INVALID_FIELD` in the engine's words on all three drivers,
naming the position, the field and its declaration. The controls and
`count` answer exactly as before. The InMemoryDriver cells of both runs
come from an uncommitted scratch script over the built packages;
`check:driver-memory-census` refuses a new test consumer of that driver
without a ruling, so the committed memory cell is the recording driver
below, by construction.
## Hypotheses (zone 2): which held
- **H1: held, refined.** The door is `group-by-structured-json-door.ts`
at the aggregate entry, and the multi-value refusal is one more class
there. It is judged on `isMultiValueField`, which reads the declaration
AND the type: `select`, `radio`, `lookup`, `user`, `file`, `image` carry
`multiple` (`MULTI_CAPABLE_TYPES`; `radio` plus `multiple` is already
refused at parse), while `multiselect`, `checkboxes` and `tags` are
multi-valued by type with no `multiple` at all (`MULTI_OPTION_TYPES`).
Those three split exactly the same way (measured), so they are in the
class; judging `multiple: true` alone would have left them grouping per
serialization. A multi-valued `lookup` (and `user`) is in scope: it is a
`multiple: true` field, and it measured the same (PostgreSQL 500).
- **H2: held.** Both layers moved, and the door asks the table. The
table's readers: ① the lint rule `validateDatasetMeasureAggregates`
(`gating`, run by `os validate` / `os lint` and, since the dataset
runtime gate, on a runtime dataset save), which now **refuses at save
time** a dataset measure pairing `count_distinct` with a JSON-stored
field; ② the analytics dataset compile leg
(`assertAggregateFieldTypeCompatible`), `400 DATASET_INVALID`; ③
`measureResultType` (result typing only: a refused pair gets no
corrected type); ④ the new engine door; ⑤ the prose of two step-18
migration entries. The narrowing on authored metadata is dataset
measures only; the census below finds zero authored `count_distinct`
anywhere. Ablation A3 below proves the door reads the table: putting the
old row back reds the engine pins.
- **H3: measured, a reach remains.** Through `AnalyticsService` wired as
`AnalyticsServicePlugin`'s own bridges (`executeAggregate` to
`engine.aggregate`, `executeRawSql` to `engine.execute`), after merging
`origin/main` `00a92e18da` (which carries the analytics structured-JSON
dimension door):
- the ObjectQL strategy (the in-memory driver) reaches this door: a cube
or dataset dimension on a multi-value field and a cube measure
`meta_count_distinct` answer this 400;
- `NativeSQLStrategy` on SQLite and PostgreSQL does NOT: a cube or
dataset dimension on a multi-value field answers one group per
serialized array on SQLite and 500 on PostgreSQL; an inferred cube
measure `FIELD_count_distinct` over a JSON-stored field answers 2 on
SQLite and 500 on PostgreSQL; a dataset measure `count_distinct` over a
`select` declared `multiple: true` (the table sees only `select`)
answers 200 on SQLite (distinct serialized arrays) and 500 on
PostgreSQL;
- a dataset measure `count_distinct` over a JSON-stored TYPE is refused
by the compile leg on every driver (`DATASET_INVALID`).
The native-SQL reach is reported to the seat, not fixed here. The memory
cube (`MemoryAnalyticsService`) has zero constructors outside tests
(`git grep "new MemoryAnalyticsService"` excluding tests: 0; including
them: 5 files), so it was not measured.
- **H4: held; zero hits.** Census below.
## Census (before narrowing)
A `groupBy` / grouping / dimension on a multi-value field, and a
`count_distinct` on a JSON-stored field, in datasets, reports, views,
dashboards, pages and code.
- `examples/**` at `42d78b97fe` (unchanged at this head): the four
`objectstack.config.ts` apps and `embed-objectql`. Stacks loaded through
`tsx` (showcase through its metadata modules, its plugin imports
unbuilt) and walked for every grouping-shaped position.
- Multi-value fields: todo 1 (`todo_task.tags`), showcase 8
(`showcase_field_zoo.f_multiselect`, `f_checkboxes`, `f_tags`,
`f_lookups`, `f_users`; `showcase_project.labels`, `team_members`;
`showcase_task.labels`); crm, multi-package and embed-objectql 0.
Structured-JSON fields: showcase 10.
- Grouping positions naming ANY declared field (the positive control):
showcase 74 (kanban `groupByField`, chart `dimensions`, dataset
dimensions, page `dimensions`, report `xAxis`). Report `rows` /
`columns`: `status`, `priority` (showcase), `status`, `priority`,
`owner`, `category` (todo). **Hits naming a multi-value or
structured-JSON field: 0.**
- `count_distinct`: 0 occurrences in `examples/`.
- The published hotcrm stack: `objectstack-ai/hotcrm` cloned at
`4ca8e2d4bb` (the repository's `main`; the npm tarball itself was not
read). Its dependency tree was not installed, so the census is by source
text over `src/**`, `test/**` and `scripts/**`.
- Multi-value fields: `crm_knowledge_article.tags` (`select`, `multiple:
true`), and `attendee_contacts` / `attendee_users` (`lookup`, `multiple:
true`) in an activity action. Structured-JSON fields: `billing_address`
(contract, quote, account), `shipping_address` (quote), `address`
(lead), `office_location` (account).
- Grouping positions: `groupByField` `status`, `owner_id`, `stage`,
`crm_account`, `channel`; `xAxis` `stage`, `status`, `priority`,
`owner`; report `rows` / `columns` over dataset dimensions `industry`,
`type`, `lead_source`, `last_contacted_date`, `stage`, `owner`,
`forecast_category`, `close_quarter`; dataset dimension `field:` values
none of the fields above. **Hits: 0.** Its `_picklists.ts` already
records why a grouped field stays single-valued ("a `multiple: true`
column groups by the COMBINATION").
- `count_distinct`: 1 occurrence, a comment in
`scripts/analytics-reconcile/reconcile.ts`. **Hits: 0.**
- `packages/platform-objects`: 0 `count_distinct`.
No hit, so neither narrowing went back to triage.
## Scope beyond the declared surface, and why
The claim names `packages/objectql/src/**`, the one spec file, and
`rest` pins. Four more places move, each because the ruled table change
makes a pin red or a shipped sentence false. They sit in separate
commits so each can be judged or dropped on its own:
- `packages/lint`: the table-agreement pin `accepts count and
count_distinct over every declared FieldType` goes red on the ruled row,
so it is triaged (count over every type; count_distinct over every type
but the ten, which it refuses). The refusal hint said "`count` /
`count_distinct` accept every type"; it now says `count_distinct`
accepts every type but the JSON-stored ones.
- `packages/services/service-analytics`: the census pin `the refused set
… 155 pairs` counts the table's refused pairs, so it moves to 165 with a
`distinct` bucket of 10. The compile leg's words for a `count_distinct`
refusal fell into the "derives a NUMBER … coerces the stored form"
branch and then said "`count`/`count_distinct` accept every type";
`DIVERGENCE_BY_AGGREGATE` gains a `count_distinct` branch (equality, not
arithmetic or order), `REMEDY_BY_SOURCE_CLASS` gains the distinct
prescription, and the two other sentences stop claiming `count_distinct`
accepts every type. A new case pins those words. The dispatch said not
to edit `packages/services/**`; the two claims on that package (the
analytics dimension door and the analytics seam lowering) had both
landed (`00a92e18da`, `793fb839`) before this edit, and no file here
overlaps theirs.
-
`packages/spec/src/migrations/entries/semantic/18.dataset-measure-*.ts`
(+ the regenerated `registry.ts`): the min / max entry's route "① …
`count` / `count_distinct`, which accept every type" is false for the
ten types now; the sum / avg entry's surface and acceptance prose name
the `count_distinct` rider this change's ADR-0087 marker points at.
- `content/docs/deployment/validating-metadata.mdx`: the sentence
"`count`/`count_distinct` are accepted over every type".
## Tests
- New
`packages/objectql/src/engine-json-stored-group-distinct-door.test.ts`
(7 tests, recording driver, so the in-memory cell by construction):
every multi-value declaration refused as a `groupBy` with the full
envelope, the declaration and the `$contains` route; the `{ field }`
form and the first offending position across both classes; every
structured-JSON type and multi-value declaration refused as a
`count_distinct`, and the first of two offenders named; the REST door
into `findData`; controls (scalar group keys and distinct counts,
`count` over JSON-stored columns, the `$contains` route itself) reach
the driver; GUARDs: the `count_distinct` door agrees with the spec table
on every `FieldType` (floor: exactly 10 refused) and refuses every
flagged multi-capable type; no verdict without a field map, for an
undeclared name, an off-vocabulary type or any other function.
- New `packages/rest/src/data-json-stored-group-distinct-door.test.ts`:
SQLite always, PostgreSQL / MySQL where `OS_TEST_POSTGRES_URL` /
`OS_TEST_MYSQL_URL` are set. Both shapes answer 400 with the route in
the REST body and zero reads; the controls (`status` groups, `title` and
`status` distinct counts) and the named route (`count` with `where {
tags: { $contains } }` answers `a` 3 · `b` 2) are served by the driver.
⚠️ No CI job sets those URLs for this package, so the live cells run
only locally. Local run with the private PostgreSQL 16.13: **8 passed
(sqlite 4, live postgres 4) / 4 skipped (mysql, no URL)**.
- Fixture triage:
- `engine-group-by-json-door.test.ts` (the structured-JSON door's pin)
named a `multiple: true` select as a CONTROL reaching the driver. That
branch is closed now, so the control is **replaced** by a single-value
select. Its GUARD over every `FieldType` now expects the multi-option
types refused too.
- The lint and service-analytics pins above.
- Suites, all at `fb239eb2f3` (the merge of `origin/main` `00a92e18da`);
the later commits touch only the changeset:
- `pnpm --filter @objectstack/objectql test`: **347 files / 6799
passed**.
- `pnpm --filter @objectstack/rest test` with the live PostgreSQL URL:
**239 files / 4731 passed / 39 skipped**.
- `pnpm --filter @objectstack/spec test`: **582 files / 17164 passed / 1
todo**.
- `pnpm --filter @objectstack/lint test`: **117 files / 5438 passed**.
- `pnpm --filter @objectstack/service-analytics test`: **145 files /
3326 passed**.
- `typecheck` for objectql, spec, lint, rest and service-analytics: exit
0. Each `check:test-typecheck` held its ledger (objectql 40 files / 234
errors / 65 signatures, spec 52 / 249 / 137, lint 2 / 6 / 2, rest 0), so
the new test files compile.
**Reverse verification (three ablations)**, each from committed code
through `scripts/ablation-replace.mjs` WRAP (trap-restored), the package
rebuilt, and `ablation-dist-preflight` finding the marker in the built
files before any reading:
| ablation | mutation | predicted | observed |
|:--|:--|:--|:--|
| A1, multi-value `groupBy` | the `isMultiValueField(...)` class test
fed a global flag that is never set (anchor 1 to 0, marker 0 to 1, blob
`322c8098d2d1` to `39a2feb82b08`); objectql dist marker in 4 files | red
| objectql pins **4 failed / 9 passed** (multi-value groupBy, object
form, findData, the structured-JSON GUARD over `FieldType`); rest pins
**2 failed / 12 passed / 7 skipped** (sqlite + postgres multi-value
groupBy); every count_distinct case and control green |
| A2, `count_distinct` door | the engine call fed an always-undefined
property instead of `query.aggregations` (blob `cd1e9e39967f` to
`3123c092583e`); marker in 4 files | red | objectql **2 failed / 11
passed**; rest **2 failed / 12 passed / 7 skipped** (sqlite + postgres
count_distinct); groupBy cases green |
| A3, the table row | `count_distinct:` fed the old every-type row (blob
`94cf5a2e3f56` to `a343f47f2212`); spec dist marker in 4 files | red,
and the engine door red with it | objectql **3 failed / 10 passed**
(count_distinct refusal, findData, the table GUARD); rest **2 failed**;
spec pin **3 failed / 21 passed**; lint pin **1 failed / 23 passed** |
Restore leg for each: blob equals HEAD, `git diff HEAD` empty. After
rebuilding spec and objectql, `--absent` found all three markers absent
(spec 230 built files, objectql 14), whole-tree porcelain empty, and the
pins green again (objectql 13 passed; rest 14 passed / 7 skipped; spec
24; lint 24).
## Gates
`node scripts/pm/dispatch-gates.mjs --commands` (no paths) at
`f53718f1ee` derived **117** commands over 17 paths vs merge base
`00a92e18d`. All 117 were run at `f53718f1ee` with their exit codes
recorded, and `--ran` reconciles them: **117 derived, 117 run, 0
NOT-MEASURED, 0 UNRUN, all exit 0**. Among them:
- `check:adr-0087-registration --base origin/main`: `not-required
(already-registered dataset-measure-aggregate-field-type-refused)`
accepted.
- `check:changeset-no-major`, `check-empty-changeset` ("No changeset
from the merge base modified or deleted by this diff"),
`check:doc-authoring`, `check:nul-bytes`, `check:issue-citations`,
`check:engine-double-contract`, `check:driver-memory-census`,
`check:query-options-erasure`, `check:cross-package-test-inputs`,
`check:test-source-alias`, `check:type-check-coverage`.
- The `@objectstack/spec` generated-artifact gates,
`check:migration-registry`, `check:spec-changes` and
`check:upgrade-guide` included. The registry was regenerated for the
amended entries, and again after the merge (no diff).
- `check:skill-examples`, `check:dual-build-cjs-loads` and
`check:type-check-debt` first answered PREREQUISITE NOT MET (exit 3).
After `turbo run build --filter='./packages/*'
--filter='./packages/*/*'` they answered 0; that build is of
`fb239eb2f3`, whose package sources equal this head's.
Lint, narrowed and proven at `f53718f1ee`: eslint with inline config
disabled, over the 15 changed `.ts` files, found **15 files, 0 errors, 0
warnings**. Three facts make this narrowing a measurement:
- The population comes from eslint's own config: `isPathIgnored` is
`false` for all 15.
- The count comes from the results: 15.
- Untouched files cannot change verdict: `parserOptions.project` and
`projectService` are `null` for every file, so type-aware linting is not
enabled.
## Changeset
`.changeset/20808-json-stored-group-distinct-refused.md`:
- `@objectstack/objectql` `minor` and `@objectstack/spec` `minor`, each
with its own **BREAKING** banner. `@objectstack/lint` and
`@objectstack/service-analytics` are `patch`, for their words.
- `Clause-②: no (narrowing)`, and exactly one ADR-0087 marker:
`not-required (already-registered
dataset-measure-aggregate-field-type-refused)`. The table row is that
family's narrowing, and the non-temporal sum / avg narrowing rode the
same id the same way; this diff amends that entry's prose to name the
rider. The engine-door halves refuse a query shape, not a stored one.
- It names the two shapes the structured-JSON `groupBy` entry of this
same release lists as unchanged. That pending note is left as it landed:
rewriting it reds `check-empty-changeset` for a human's confirmation.
No export or published type changes
(`assertGroupByNamesNoJsonStoredField` and the new door are internal;
objectql's root and `./core` exports are unchanged).
## Acceptance notes
- **Reported to the PM, not filed here (the same family: a JSON-stored
column as a group, distinct or aggregate key, answering per driver with
a PostgreSQL 500):**
- The native-SQL analytics reach (H3 above). Landing:
`packages/services/service-analytics`, beside its structured-JSON
dimension door.
- `min` / `max` over a JSON-stored field at the engine door: `POST
/api/v1/data/:object/query` with `max(meta)` answered `{a:1}` on memory,
`'{"b":1}'` (a string) on SQLite and 500 on PostgreSQL (function
max(json) does not exist), and `max(tags)` the same way. The table
already refuses those pairs, and its dataset legs enforce that; the
engine enforces only the `count_distinct` row, as ruled here.
- A single-value media field (`file`, `image`, `avatar`, `video`,
`audio`) is a JSON column on a deployment that has not moved its media
columns (`JSON_COLUMN_TYPES`' header in driver-sql), so a `groupBy` or
`count_distinct` on one there would split the same way. This is by
reading, not measured: a fresh deployment creates the string column. Not
judged here, because the type alone cannot tell the two deployments
apart.
- A refusal relayed through the analytics ObjectQL strategy names the
engine's position (`groupBy[0]`, `aggregations[0].field`), not the cube
member the caller wrote. The same note was made on the structured-JSON
door.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0efbdc3 commit 975b248
17 files changed
Lines changed: 1067 additions & 81 deletions
File tree
- .changeset
- content/docs/deployment
- packages
- lint/src
- objectql/src
- rest/src
- services/service-analytics/src
- __tests__
- spec/src
- data
- migrations
- entries/semantic
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
206 | 206 | | |
207 | 207 | | |
208 | 208 | | |
209 | | - | |
210 | | - | |
211 | | - | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
212 | 214 | | |
213 | 215 | | |
214 | 216 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
165 | 165 | | |
166 | 166 | | |
167 | 167 | | |
168 | | - | |
| 168 | + | |
169 | 169 | | |
170 | | - | |
171 | | - | |
172 | | - | |
| 170 | + | |
173 | 171 | | |
174 | 172 | | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
175 | 190 | | |
176 | 191 | | |
177 | 192 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
232 | 232 | | |
233 | 233 | | |
234 | 234 | | |
235 | | - | |
236 | | - | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
237 | 238 | | |
238 | 239 | | |
239 | 240 | | |
| |||
| 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 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
0 commit comments