Repository navigation
Commit cdeabec
feat(spec,cli): a structured relevance question takes a semantic notice off os migrate meta's default list (counted; --all lists it) (#22115)
Fixes #22072
Clause-②: yes
> **Patch round 1** (head `5104a5d74`) answers the contract review FAIL
`6044604409` with the seat's REWORK `6044626135`: (1) four entries whose
surface also names a code door lose their question, so the batch is 25;
(2) disposition B: `todos` stays whole and `absentTodos` names the
proven-absent subset; (3) a declared `tiers` answers `unknown`, like
`plugins` / `devPlugins`; (4) `--all` is listed in
`content/docs/upgrading.mdx`. This body was updated by the seat from the
dev's report `6045718354`.
> **Merge round** (head `1d6efd229`): the contract review `6045970836`
PASSed `5104a5d74`. Since then, the branch has merged `origin/main`
`db4c45b8c` in merge commit `e74764dbb` (parents `5104a5d74`,
`db4c45b8c`). That brings in main's `os migrate meta --write` and eight
new step-18 entries.
> - **Conflicts:** two, resolved by stacking both intents. In `meta.ts`,
the `--all` and `--write` flags are now both declared. In
`upgrading.mdx`, the flags table carries the `--all` row and main's
`--out` and `--write` rows.
> - **Catalogue:** 391 entries (77 + 314).
> - **Changeset:** commit `1d6efd229` makes the `--step` sentence
precise, as the review asked.
> **Merge round 2** (head `16cb55b8d`): `1d6efd229` was red on CI once
merged with main. `Type Check · workspace` failed in `@objectstack/cli`
`check:test-typecheck`, on #22121's new
`test/migrate-meta-out-snapshot.test.ts`.
> - **The merge:** `origin/main` `54ace18c6` is merged in merge commit
`5fc3a5a2a` (parents `1d6efd229`, `54ace18c6`). It brings #22121, which
makes `os migrate meta --out` write its snapshot on a run with nothing
to migrate. The merge was a clean auto-merge, with no conflict and no
hand edit.
> - **The fix:** commit `16cb55b8d` adds `all: false` to the
`MigrationReport` literal in that test.
> - The measured error was `TS2741: Property 'all' is missing … but
required in type 'MigrationReport'` at line 274. That is this PR's
required `--all` field on the CLI-internal report type, not
`absentTodos`.
> - No assertion changed.
`os migrate meta` now has the one exit that #20620's triage
(`5888087153`) allows a notice: a structured proof, derived from the
stack, that the notice's surface is absent. An entry that carries a
question leaves the default list only when the chain answers `absent`
for this stack. The run counts those entries on one line, and `--all`
lists them in full. ⛔ Nothing matches the prose of `surface`.
## The question: `SemanticMigration.relevantWhen`
(`packages/spec/src/migrations/types.ts`)
- It is an optional field beside `conversionIds`, following the
precedent #20697 set. Its type is a closed union, `SemanticRelevance`.
This release has one member, `StackDeclaresRelevance`: `{ kind:
'stack-declares', keys: [...] }`. It asks one question: does the stack
declare anything under one of these top-level keys?
- `keys` is a non-empty tuple of `SemanticRelevanceKey`, which is
`StackDefinitionKey` minus the five carrier keys (`manifest`,
`packages`, `plugins`, `devPlugins` and `tiers`). A typo does not
compile. A key later retired from the stack makes the entry that names
it fail to compile.
- ⛔ There is no callback form (H4). A callback could do arbitrary work,
and it could not be enumerated or pinned. A new kind of question is a
new union member, evaluated in `chain.ts`.
## Evaluation (`chain.ts`)
The answer has three values, and only `absent` moves an entry (H2, built
in):
| what the question reads | answer |
| --- | --- |
| the key is missing, or holds `[]` or `{}` | absent |
| a non-empty array or map (the authored map form included) | present |
| any other value: a function, a promise, a scalar, `null`, or a getter
that throws | unknown |
| a stack that is not a plain object, or no stack at all | unknown |
| any entry in `plugins` / `devPlugins` / `tiers` (unless the stack
visibly declares the key itself) | unknown |
| an assembled `packages[].manifest` body | read like the top level; an
unreadable body is unknown |
- The question is asked of the stack the chain was handed and of every
hop's checkpoint. Present in any of them counts as present, and absent
needs all of them, so a conversion that renames or removes a key cannot
make the key read as absent on either side.
- An entry whose `conversionIds` names a conversion that applied an edit
in the same run is always listed. The applied edit proves the surface is
there.
- `MigrationChainResult` and `MigrationHopResult` gain a required
member, `absentTodos`. `todos` keeps every semantic entry of every hop
crossed, exactly as before; `absentTodos` names the proven-absent subset
of it (the same objects, in chain order).
## The output (`packages/cli/src/commands/migrate/meta.ts`; the
cross-lane half, declared on the `domain:cli` seat post)
- ③ lists `todos` minus `absentTodos`, and its header counts that
difference. A new group ④ follows it. It is two lines. The first counts
the entries proven absent and names `--all`. The second says the proof
covers the stack this run loaded, and not metadata a deployment stores
(Studio, the metadata API).
- `--all` prints each of those entries in full, as the same block ③
prints, followed by `absent: nothing is declared under` and the keys.
- `--json` always carries `absentTodos`, and `hops[].absentTodos` with
`--step`. `--step` adds a `not listed` count to a hop's line when that
count is not zero.
- A run whose only notices are proven absent still counts them in ④ and
writes `--out`.
- **With #22121's `--out` on both exits**, the early return is guarded
by the original condition `applied.length === 0 && todos.length === 0`.
- Because `todos` is whole, a run whose only notices are proven absent
never takes that branch. It goes down the main path: ④, then the one
`writeStackSnapshot`, then `--write`.
- Measured in-process on the merged code, with and without `--all`.
Every arm writes the snapshot exactly once and names it on exactly one
line:
| arm | exit taken | ④ printed |
| --- | --- | --- |
| the real hop-18 run (314 todos, 20 absent) | main path | yes |
| only-absent (`todos` = `absentTodos` = the 20 questioned) | main path
| yes |
| nothing listed and nothing absent | early return | no |
| an empty range | early return | no |
- **With main's `--write`**, its own group (⑤ in the report docstring)
prints after ④ and before the data-migration advice.
- `--write` reads only the chain's `applied`, `stack` and the normalized
input. It never reads `todos` or `absentTodos`, and neither of them
changes what it writes.
- Measured on a probe project with one dashboard `refreshInterval` and
no cubes (`--from 17`):
- The dry run and `--write --json` report identical `todos` (314) and
`absentTodos` (17).
- The written sites equal `applied` (1 of 1).
- The idempotent re-run applies 0 and still names the same 17.
- `--write --all` lists ④ in full, then prints ⑤ (`Wrote 1 of 1 …`).
- A run with no applied edit prints `--write`'s "no mechanical change"
line in either branch.
hotcrm's default report now ends like this:
```text
302 manual change(s) require your judgment:
…
12 more manual change(s) not listed: their surfaces are absent from this stack (run with --all to list them).
Absent is proven over the stack this run loaded; metadata a deployment stores (Studio, the metadata API) is not read here.
```
## The first batch: 25 of the 391 entries carry a question
| keys the question names | protocol 17 | protocol 18 | entries |
| --- | ---: | ---: | --- |
| `analyticsCubes` | 0 | 8 | `cube-join-sql-and-relationship-retired`,
`cube-member-inner-name-retired`, `cube-member-sql-expression-retired`,
`cube-metric-expression-types-retired`, `cube-metric-filters-retired`,
`cube-refresh-key-retired`,
`analytics-cube-public-default-visible-enforced`,
`analytics-cube-single-granularity-default-enforced` |
| `dashboards` | 1 | 2 | `dashboard-widget-compareto-offset`,
`dashboard-refresh-interval-unit-in-key`,
`dashboard-header-modal-target-page-only` |
| `dashboards` / `reports` / `pages` | 0 | 1 |
`chart-config-aria-retired` |
| `permissions` | 0 | 1 | `permission-restore-purge-bits-retired` |
| `sharingRules` | 1 | 0 | `sharing-rule-recipient-reconcile` |
| `apis` | 1 | 1 | `declarative-apis-endpoints-live`,
`api-endpoint-cache-ttl-unit-in-key` |
| `jobs` | 1 | 1 | `job-retry-policy-constraints-tightened`,
`job-timeout-unit-in-key` |
| `agents` | 0 | 2 | `agent-memory-store-retired-and-limits-required`,
`agent-structured-output-refused-members-retired` |
| `datasets` | 0 | 2 | `dataset-measure-aggregate-field-type-refused`,
`dataset-measure-selecting-aggregate-field-type-refused` |
| `mappings` | 0 | 1 | `mapping-lookup-params-retired` |
| `hooks` | 0 | 1 | `hook-timeout-unit-in-key` |
| `tools` | 1 | 0 | `tool-requires-confirmation-retired` |
| **total** | **5 of 77** | **20 of 314** | **25 of 391** |
`semantic-relevance.test.ts` pins this table, so every addition is a
reviewed edit. I read each entry against three rules:
1. **Only the named keys.** The surface lives only under the named
top-level key(s). I checked this against the schema: in a stack, the
item schema is referenced only by those collections. `ReportSchema` is
also carried inline in an `object-metric` drill-down, so the
chart-config entry names `pages` too.
2. **No runtime door.** The surface names no runtime request body, no
client, engine or driver API, no kernel or plugin config, and no
platform-shipped item.
3. **No stored row.** The acceptance criteria send the author to no
stored `sys_metadata` row and no runtime door.
Some families are left out on purpose:
- **Rule 3:** flows (their entries send the author to stored flow rows),
the joined-report entries, dashboard widget arity, stage order and chart
structure, RLS `tags`, `check` on select/delete, the cross-class
comparison, and `cel-predicate-list-comparand-refused`.
- **Rule 2:** the analytics row wildcard and the dataset member
expression (both are judged on inline datasets in query bodies too); and
`cel-predicate-one-value-comparand-refused`,
`cel-predicate-variable-root-comparand-refused`,
`rls-predicate-array-comparand-refused` and
`rls-predicate-stored-list-ordering-refused`: their surface also names a
code door, a direct `matchesFilterCondition` / compiler caller (patch
round 1).
- **Rule 1:**
- connectors: a connector document also reaches the runtime through
`engine.registerConnector` from code;
- datasources: driver configs are built in code;
- the hook-body stored-metadata target: it applies to stored hook rows.
- **Main's eight new step-18 entries** (merge round) carry no question:
- `flow-edge-unresolved-or-repeated-refused` falls under rule 3: its
acceptance criteria send the author to stored flow rows in
`sys_metadata`.
- The seven `sys_flow_dispatch` / `sys_job` / `sys_job_queue` /
`sys_job_run` / `sys_migration_journal` / `sys_migration` /
`sys_presence` `organization_id` retirements fall under rule 2: each
surface is a platform-shipped table, not a stack key.
## Measured: listed count before and after
"Before" is `todos`, which is whole again (disposition B). "After" is
`todos` minus `absentTodos`, which is what ③ lists. I read both from
`--json` of this branch's CLI at the merge head `e74764dbb`.
`absentTodos` was a subset of `todos` on every row.
| stack | `--from` | before | after | left the list |
| --- | ---: | ---: | ---: | ---: |
| hotcrm `c967803` | 17 | 314 | 302 | 12 |
| hotcrm `c967803` | 16 | 391 | 376 | 15 |
| `examples/app-crm` | 17 | 314 | 301 | 13 |
| `examples/app-todo` | 17 | 314 | 300 | 14 |
| `examples/app-multi-package` (assembled `packages[]`) | 17 | 314 | 294
| 20 |
| `examples/app-showcase` (lists runtime plugins) | 17 | 314 | 314 | 0
(H2: a listed plugin makes every answer unknown) |
| a minimal stack with one object | 17 | 314 | 294 | 20 |
| a minimal stack with one object | 16 | 391 | 366 | 25 |
- **hotcrm** is a read-only clone at `c967803`, the commit the card
measured, loaded with this branch's CLI and spec.
- At the card's time it reproduced the baseline exactly: 304 manual
notices and 12 applied edits.
- The base is 314 now because `main` has added ten step-18 entries
since. The 12 entries that leave the list, and the 12 applied edits, are
unchanged.
- hotcrm's `--step` hop line reads `12 mechanical, 302 manual, 12 not
listed (surface absent)`.
- **The ceiling:** most of the remaining notices govern surfaces that
are not stack keys at all (kernel and plugin configs, client, engine and
driver APIs, exported types). No `stack-declares` question can reach
them, and each needs a different kind of question.
## For the contract review
- **`todos` membership — disposition B (patch round 1).**
`applyMetaMigrations().todos`, `MigrationHopResult.todos` and `--json`'s
`todos` are unchanged: every semantic entry, as their TSDoc promised.
`absentTodos` is a new required member of `MigrationChainResult` and
`MigrationHopResult` naming the proven-absent subset.
`migrations.test.ts`'s original equality pin is restored, with a subset
pin beside it. `Clause-②: yes`, `minor`, no BREAKING line.
- **What the proof covers.** The proof is about the definition this run
loads. Rows a deployment stores (Studio, the metadata API, AI-authored
rows) are a separate subject. `os migrate meta --stored` reports D2
conversion TODOs per row and never reports the D3 catalogue. The printed
scope line states this boundary.
- **Internal exports: two functions and one type.** `chain.ts` exports
the functions `semanticRelevanceVerdict` and `semanticTodoAbsent` and
the type `SemanticRelevanceVerdict` for its own tests only. None of them
is re-exported from `@objectstack/spec/migrations`; the
`api-surface/migrations.json` shard gains only the three published
types.
## Verification (head `16cb55b8d`; the merge `5fc3a5a2a` with
`54ace18c6`)
- **build:** the turbo build of the CLI closure, the CLI, the showcase
closure and `client-react` gave 61 tasks, all successful.
- **The `--out` / report pins against the merged code:**
`test/migrate-meta-out-snapshot.test.ts` (#22121, whole file),
`src/commands/migrate/meta.report-order.test.ts` (ORDER, SET, PAIR,
ABSENT, including 'a run whose only notices are proven absent still
counts them and still writes --out') and
`test/migrate-meta-write.test.ts` gave `Test Files 3 passed (3)`, `Tests
52 passed (52)`.
- **spec, the 58 test files that read the registry or the chain:** `Test
Files 58 passed (58)`, `Tests 2331 passed (2331)`. That covers the
ENUMERATION (25: 5 + 20), SHAPE, EVALUATION and CHAIN pins, and
`migrations.test.ts`'s equality and subset pins.
- **typecheck:**
- `pnpm --filter @objectstack/spec typecheck` exit 0.
- `pnpm --filter @objectstack/cli typecheck` exit 0,
`check:test-typecheck` included: `OK — … 3 file(s) / 28 error(s) / 6
pinned signature(s) held in test-typecheck-debt.json`.
- `tsc -p tsconfig.test.json` gave 29 errors before the fix (the 28 the
ledger holds, plus the new TS2741) and 28 after. The ledger is not
touched.
- **cli unit tier:** `Test Files 263 passed (263)`, `Tests 3874 passed
(3874)`.
- **cli integration tier:** `test/migrate-meta-engine-guidance.test.ts`
(it passes `--all`) and `test/migrate-meta-default-range.test.ts` gave
`Test Files 2 passed (2)`, `Tests 10 passed | 1 skipped (11)`.
- **Generated artifacts:** `check:migration-registry` reports `391
semantic`; #22121 adds no entry. `registry.ts` carries 25 `relevantWhen`
lines.
- **Gates:** `dispatch-gates --commands` derived 117 families at
`16cb55b8d`. 116 exited 0. 1 is NOT MEASURED:
`check:dual-build-cjs-loads` exited 3, PREREQUISITE NOT MET.
- `check:vendor-version-stamps` first exited 1 on ENOENT for a temp file
the concurrently running CLI unit tier created under
`packages/cli/tmp/`. Re-run alone, it exited 0.
- `--ran` accounted for all 117.
- **ESLint, narrowed to the 35 changed TS files** against the merge base
`54ace18c6`: 35 files, 0 errors, 0 warnings. There is no type-aware
linting, so no untouched file's verdict can move.
## Mechanism hypotheses, measured
- **H1 held.** `SemanticMigration` was at `types.ts:38` and
`conversionIds` at `:73`. The chain mapped every `step.semantic` entry
into `todos` (`chain.ts:102`). Since the order and pair work, ③ prints
from `meta.ts` around `:439`.
- **H2 held and is built in** (see the evaluation table). `app-showcase`
measures it: 314 before and 314 after.
- **H3: hotcrm was reachable read-only** (it is a public repository), so
its before/after is measured rather than NOT MEASURED.
- **H4:** the closed form covers the first batch, so no callback form
exists.
## Acceptance notes
- **A pre-existing defect.** `os migrate meta --from 18 --to 18 --out
FILE` covers a range with no step: its human report writes no snapshot
and says nothing about it, while `--json` writes the file. Unchanged
here (an empty range has no `absentTodos`). Filed by the seat as #22116.
- **Upgrade skill.** `skills/objectstack-upgrade/SKILL.md` (Tier H)
loops over `--json`'s `todos`; under disposition B its reading is
unchanged, so no governed edit is owed.
- **Merges.** The branch carries three merges of `origin/main`:
- `de8ccbcfa` (with `a543e244f`, clean);
- `e74764dbb` (with `db4c45b8c`, two conflicts resolved by stacking both
intents, see the merge-round note at the top);
- `5fc3a5a2a` (with `54ace18c6`, clean, see merge round 2).
- Every line the branch added to `meta.ts` and `upgrading.mdx` survives
the merge, and so does every line main added, except two that were
changed by hand. Both are comments.
- The comment on main's `--write` group is relabelled from ④ to ⑤,
because this PR's ④ is the absent group.
- The report docstring's ④ item now ends with `;`, and a ⑤ item follows
it for `--write`.
- None of main's ten new step-18 entries carries a question, so the
enumeration pin is unaffected.
- The measured before/after table was read at `e74764dbb`. The catalogue
(391) and every `relevantWhen` are unchanged since, so it still holds.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01RPo7FUd6bSnAfkWMAKi848)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 54ace18 commit cdeabec
39 files changed
Lines changed: 942 additions & 64 deletions
File tree
- .changeset
- content/docs
- packages
- cli
- src/commands/migrate
- test
- spec
- api-surface
- export-origins
- src/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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
215 | 215 | | |
216 | 216 | | |
217 | 217 | | |
| 218 | + | |
218 | 219 | | |
219 | 220 | | |
220 | 221 | | |
| |||
Lines changed: 151 additions & 20 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
15 | 18 | | |
16 | 19 | | |
17 | 20 | | |
| |||
45 | 48 | | |
46 | 49 | | |
47 | 50 | | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
48 | 54 | | |
49 | 55 | | |
50 | 56 | | |
| |||
126 | 132 | | |
127 | 133 | | |
128 | 134 | | |
| 135 | + | |
129 | 136 | | |
130 | 137 | | |
131 | 138 | | |
| |||
137 | 144 | | |
138 | 145 | | |
139 | 146 | | |
| 147 | + | |
| 148 | + | |
140 | 149 | | |
141 | 150 | | |
142 | 151 | | |
| |||
159 | 168 | | |
160 | 169 | | |
161 | 170 | | |
162 | | - | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
163 | 191 | | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
171 | 207 | | |
172 | 208 | | |
173 | 209 | | |
| |||
233 | 269 | | |
234 | 270 | | |
235 | 271 | | |
236 | | - | |
| 272 | + | |
237 | 273 | | |
238 | 274 | | |
239 | 275 | | |
| |||
250 | 286 | | |
251 | 287 | | |
252 | 288 | | |
253 | | - | |
254 | | - | |
| 289 | + | |
| 290 | + | |
255 | 291 | | |
256 | 292 | | |
257 | 293 | | |
| |||
273 | 309 | | |
274 | 310 | | |
275 | 311 | | |
| 312 | + | |
276 | 313 | | |
277 | 314 | | |
278 | 315 | | |
| |||
414 | 451 | | |
415 | 452 | | |
416 | 453 | | |
417 | | - | |
| 454 | + | |
418 | 455 | | |
419 | 456 | | |
420 | 457 | | |
421 | | - | |
| 458 | + | |
422 | 459 | | |
423 | 460 | | |
424 | 461 | | |
| |||
435 | 472 | | |
436 | 473 | | |
437 | 474 | | |
438 | | - | |
| 475 | + | |
439 | 476 | | |
440 | 477 | | |
441 | 478 | | |
442 | 479 | | |
443 | 480 | | |
| 481 | + | |
444 | 482 | | |
445 | 483 | | |
446 | 484 | | |
| |||
493 | 531 | | |
494 | 532 | | |
495 | 533 | | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
0 commit comments