Commit 8305ad6
Fixes #17528
Clause-②: no
Re-derived from the delivered diff rather than carried over from the
claim: no schema key, no closed-set member, no published export and no
registry entry moves. `lintConfig` and `scoreMetadata` keep their
signatures and their return types, `os build`'s accept set is untouched,
and no authorable key changes. What changes is which stack the existing
checks are handed.
## The defect
`lintConfig` (`packages/cli/src/commands/lint.ts`) runs two families:
the shared author-time rule registry, and `os lint`'s **own**
hand-written rubric — naming, labels, empty field maps, the
intra-package duplicate advisory, hook-body lowering, and the data-model
conventions. #17069 folded the **registry call inside that function**
and scoped itself the way `compile.ts` scopes its own, writing down
exactly what it left behind:
> **Scoped to this call, as it is in `compile.ts`: the hand-written
checks above and `scoreMetadata` (which reaches `lintConfig` through
`lint/score.js`) keep reading the caller's own stack**, so nothing about
what this function returns for a top-level stack moves.
This is the other half of that staged change, not a reversal of it.
Under ADR-0130 D4 / option B every definition lives in `packages[]` and
the top level carries none, so the family that was left behind read an
**empty stack**.
## Acceptance 1 — the card's repro, both shapes, through the real binary
`node packages/cli/bin/run.js lint --score`, built from this branch's
tree in both directions. One object, authored two ways; the metadata is
byte-identical and only its location differs.
**BEFORE** (`origin/main` `c9eb773ba`):
```
packages[] exit 0 ✓ All checks passed
Metadata quality: 100/100 (A)
0 schema · 0 error(s) · 0 warning(s) · 0 suggestion(s)
top level exit 0 ⚠ Label "order" should start with an uppercase letter
convention/label-case at objects[0].label
ℹ Object "ob_order" has no nameField and no name-like field …
object/missing-name-field at objects[0].fields
Metadata quality: 96/100 (A)
```
**AFTER**, same two projects:
```
packages[] exit 0 ⚠ convention/label-case at objects[0].label
ℹ object/missing-name-field at objects[0].fields
Metadata quality: 96/100 (A)
top level exit 0 — unchanged (see acceptance 3)
```
Diffed rather than eyeballed: with the config path and the elapsed-time
token normalised, the two faces are **identical**.
## Acceptance 2 — the parity is pinned, and here is what it covers
`test/lint-handwritten-checks-package-fold.test.ts`. One set of
declarations is rendered into **three** shapes — top-level-only,
`packages[]`-only, and today's additive artifact that carries both — and
the assertion is that the findings are equal, field for field, in order.
A test that only asserted "a finding appears" would stay green against a
fold that reached one check and missed four, so the file also names the
checks and the count each owes (`NAMED_HAND_WRITTEN_COVERAGE`):
| hand-written check | findings owed | read site it proves |
|:--|--:|:--|
| `convention/label-case` | 4 | `stack.objects` (object label + field
label), `stack.views`, `stack.apps` |
| `required/label` | 1 | `stack.objects` |
| `structure/empty-fields` | 1 | `stack.objects[i].fields` |
| `naming/namespace-prefix` | 2 | the `PREFIXED_TYPES` loop's
`stack[key]`, on **two** different keys (`apps`, `flows`) |
| `hook-body/not-lowerable` | 1 | `checkHookBodyLowering(stack)` reading
`stack.hooks` |
| `object/missing-name-field` | 1 | `lintDataModel(objects)`, fed from
the same `stack.objects` local |
**Two checks are deliberately NOT covered, and the file says so.**
`authoringRuleUnionStack` resolves package order through
`resolveArtifactPackageOrder`, whose ADR-0112 refusals are not
swallowed, so a `packages[]` stack whose body does not parse is refused
before any rule runs — it already was, since `lintConfig` has driven
that seam for the registry tier since #17069. Every carrier of
`naming/snake-case` (a non-snake_case machine name) and of
`structure/no-fields` (an object with no `fields` at all) is
schema-invalid, so no option-B stack can reach them. They read the same
`stack.KEY` locals every covered rule reads.
`protocol/missing-engines-range` reads `manifest`, an artifact-envelope
key present in both shapes by construction, so it is not a fold site at
all.
The third shape is the one that can regress silently: a fold that
**unioned** instead of resolving would double every finding on today's
additive artifact while both other shapes stayed correct.
`authoringRuleUnionStack` is present-wins, so it does not — and that is
now pinned.
## Acceptance 3 — identity control
A top-level-only project's `os lint` output, before and after, driven
through the real binary:
```
15c15
< 1 warning(s), 1 suggestion(s) (134ms)
---
> 1 warning(s), 1 suggestion(s) (62ms)
```
That is the whole diff, on both faces (`os lint` and `os lint --score`):
with the elapsed-time token normalised the two outputs are
**byte-identical**. It holds by construction — the seam returns a stack
that carries its own collections by identity — and it is measured
anyway, because that is the claim. The same control on a multi-package
**additive** project (flattened top level plus `packages[]`) is likewise
byte-identical before and after.
## Acceptance 4 — `scoreMetadata`, and why the fork does not fire
**The number moves, on the option-B repro only: `100/100 (A)` becomes
`96/100 (A)`, with counts `0 schema · 0 error · 0 warning · 0
suggestion` becoming `0 · 0 · 1 · 1`.** That is the right number because
it is the number the same metadata already scored when spelled at the
top level. `100/100 (A)` with every count at zero is byte-for-byte the
verdict a genuinely clean project gets, published by a rubric that had
judged nothing.
**The card's fork — whether the score should be per-project or
per-package on a multi-package artifact — is not forced by this change,
and that is measured, not assumed.** Two readings:
1. **The scorer already scores the whole project, and always has.** Its
schema half parses the artifact whole: on a `packages[]`-only stack
carrying one schema-invalid object, `scoreMetadata` reports
`packages.0.manifest.objects.0: Unrecognized key(s) on this object …`
**today, with no fold anywhere**. Only its lint half was blind.
2. **Per-project is what its lint half already computes for every
multi-package artifact that exists.** A two-package project, one object
each, driven through the real binary:
| shape | before | after |
|:--|:--|:--|
| additive (what the platform emits today) | `89/100 (B)` · 3 warnings,
2 suggestions | **unchanged**, byte-identical |
| `packages[]`-only (option B) | `97/100 (A)` · 1 warning | `89/100 (B)`
· 3 warnings, 2 suggestions |
The additive column is the union across both packages — a per-project
score, computed by the code on `main`. The fold makes the option-B
spelling agree with it.
So there is no decision in it: the scorer computes the same thing it
computed before, over a stack that is no longer empty. Clause-② stays
`no`.
## Acceptance 5 — the acceptance pin owes new rows, and they are paid
`test/option-b-reader-acceptance.pin.test.ts` held `OPTION_B_LOSSES`
empty and stayed green through this defect because its probe carried
**no row** for either reader. Two rows added to
`test/fixtures/option-b-reader-probe.ts`, both counted over the reader's
**return value** per that file's own rule, never over `project.KEY`:
- `B2/B3 · cli lint hand-written rubric (lintConfig — naming, labels,
structure) · objects`
- `B2/B3 · cli metadata-quality rubric (scoreMetadata — os lint --score,
metadata eval) · objects`
Two rows and not one, because they are two doors: the command calls
`lintConfig` directly, while `os lint --score` and the metadata eval
reach it through `lint/score.js` after `normalizeStackInput`.
**The zoo gained one deliberately lint-dirty label**, for the same
reason #15229 gave it a federated object — watching the reader required
carrying something it can report. `lintConfig` says nothing at all about
a clean stack, so on the zoo as it stood both rows returned the same
four registry findings in both shapes: a row that could never go red.
Exactly one label is lower-cased, on the **module** package's object so
the row is a cross-package resolution (`PROBE_DIRTY_LABEL` /
`PROBE_DIRTY_LABEL_RULE`, both commented at the site).
**The floor is raised 36 to 38, and measured at the boundary** the way
this file requires — written `toBeGreaterThanOrEqual(39)`, the run
reports `expected 38 to be greater than or equal to 39`, so the floor is
the exact count with no slack. A **named-row** test is added beside
#15006's and #17527's, because a count cannot tell "this row left" from
"this row left and another arrived". ⛔ No floor lowered, no ledger line
added.
## The guard this fix had to teach, rather than weaken
`test/validate-build-gate-parity.test.ts` carries a **source-level**
rule — deliberately so, per its own docblock — that each of the three
authoring commands hands the rule table a folded stack. It matched one
literal spelling:
```
\b(normalized|parsed)\s*:\s*authoringRuleUnionStack\s*\(
```
Hoisting the fold to `lintConfig`'s entry hands the tiers `normalized:
stack` and `parsed: lowered` instead. The value is still folded — more
of it than before, since the hand-written checks now see it too — but
the spelling was gone, and **both** tiers went red in CI (`Test Core
(4/6)`, 1 failed / 1519 passed, on `d52f22dfc`).
⛔ **Nothing here weakens the guard.** Relaxing the regex to any
identifier, deleting the assertion or dropping `lint.ts` from
`AUTHORING_COMMANDS` were all available and all refused: broadened to
`\w+` it would pass on `normalized: config`, which is the defect the
guard exists for. Instead the identifier is **resolved**: follow `const`
bindings in the same source, at most four hops, and answer true only
when some hop is a literal `authoringRuleUnionStack(` call. That turns a
**spelling** match into a **value-provenance** one.
⭐ The old spelling match had a hole the red never showed, and it is the
reason this is the right direction rather than an accommodation: **a
pure spelling match would be satisfied BY a cosmetic re-fold whatever
the surrounding code did.** A door could have written `normalized:
authoringRuleUnionStack(x)` for any `x` — or kept the wrapper while
every other read in the function drifted onto the caller's own stack,
which is exactly the state `lint.ts` was in and this guard reported
green on for as long as it existed.
**Negative controls on the same pass**, against fabricated sources,
because a guard that cannot fail is not a guard:
| fabricated tier expression | verdict |
|:--|:--|
| `normalized: config` (the pre-#17069 defect itself) | rejected, both
tiers |
| `normalized: normalized` where `const normalized =
normalizeStackInput(config)` | rejected |
| the fold IS called in the file, on an unused binding, tier handed
something else | **rejected** — the line between "this file mentions the
fold" and "this value came from the fold" |
| a six-hop chain against a four-hop budget | rejected (fail-closed) |
| `parsed: authoringRuleUnionStack(lowered)` (compile.ts / validate.ts)
| accepted |
| hoisted `normalized: stack`, and `parsed: lowered` one hop further |
accepted |
`tierExpression` reads each tier's value with bracket-depth tracking
rather than to the next comma, which also answers the slice-truncation
hazard: measured, `ruleTableCallIn`'s cut still bounds the whole object
literal in all three commands.
**The claim the resolver now trusts is pinned behaviourally, not left in
a comment.** `parsed: lowered` reaches the fold through
`lowerCallables`, on the argument that it shallow-clones the top level
it is handed. `THE CHAIN` in
`test/lint-handwritten-checks-package-fold.test.ts` asserts that
directly: every collection the fold filled survives `lowerCallables` at
the same length, and `authoringRuleUnionStack(lowered)` returns it **by
identity** — which is why the second call was dropped rather than kept
as insurance.
**Two bounds are stated in the resolver's docblock** rather than
implied: it follows every identifier in an expression, so it is
source-level reachability and not dataflow; and `constBindingOf` takes
the first `const NAME =` in the file, so a shadowed binding would
resolve to the wrong one. Neither is a hole today; both are named so a
future shape outgrows this resolver visibly instead of defeating it
quietly.
## Reverse verification
The fix commit reverted to its `origin/main` base (`c9eb773ba`), proved
on disk before anything was read: the fold line went `1 to 0`
occurrences, the pre-fix top-level read went `0 to 1`, and the blob
moved `cc731022 to b62eb82`. Restored from `HEAD` afterwards and
re-verified byte-identical (`cc731022`), `git diff HEAD` empty. The
readers are reached from **source** by relative path, so no build leg
applies.
**`test/lint-handwritten-checks-package-fold.test.ts` — 4 of 7 red:**
```
AssertionError: The two shapes declare byte-identical metadata and must be judged identically.
top-level reported 12 finding(s), packages[] reported 2
AssertionError: The hand-written check `convention/label-case` reported 0 finding(s) on the
packages[]-only shape, not the 4 it owes
AssertionError: expected 94 to be 56 (the scorer, packages[] vs top level)
AssertionError: expected [] to deeply equal [ 2 findings ] (the card's own repro)
```
**`test/option-b-reader-acceptance.pin.test.ts` — red, naming both new
rows:**
```
A subsystem lost a collection that the ledger does not carry …
B2/B3 · cli lint hand-written rubric (lintConfig — naming, labels, structure) · objects
B2/B3 · cli metadata-quality rubric (scoreMetadata — os lint --score, metadata eval) · objects
LOST … lintConfig … = 0
LOST … scoreMetadata … = 0 hand-written finding(s) · score 90/A
```
In the same run the additive BASELINE and both anti-vacuity controls
stayed green, which is what makes the red a discrimination rather than a
broken fixture.
## The fix
The fold moves to `lintConfig`'s entry and every check below it reads
the resolved stack — the shape #17775 landed for `collectMetadataStats`
in this same package:
```ts
const stack: any = authoringRuleUnionStack(config);
```
⛔ **One fold, one helper, no second implementation.**
`authoringRuleUnionStack` (`utils/stack-collections.ts`) is this
package's single resolution rule for a package-owned collection:
present-wins, identity return, key set derived from the two schemas
rather than transcribed. The registry call below now takes `normalized:
stack` and `parsed: lowered` directly — `lowerCallables` shallow-clones
the top level it is handed, so `lowered` already carries the folded
collections and re-folding it could only ever return by identity.
## Tests
Run on `2c5d49463`, the final commit of this branch.
| command | result |
|:--|:--|
| `pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2
--project unit --shard=1..3/3` | exit **0** × 3 — **199 files, 2838
tests passed** (the whole unit tier, sharded only to stay inside this
session's foreground budget) |
| `… --project integration test/union-fold-command-parity.test.ts
test/authoring-rule-command-parity.test.ts` | exit **0** — 2 files, 17
tests |
| `pnpm --filter @objectstack/lint exec vitest run
src/authoring-rule-wiring.test.ts` | exit **0** — 26 tests (it reads
`packages/cli/src/commands/*.ts`, so this diff moves its inputs) |
| `pnpm --filter @objectstack/cli typecheck` | exit **0** — `tsc
--noEmit` + `check:test-typecheck`; the debt ledger is unchanged at 3
files / 28 errors / 6 pinned signatures |
| `pnpm lint` (repo-wide `eslint . --no-inline-config`) | exit **0** —
the whole population, not a narrowing |
| 19 `check:*` families (`nul-bytes`, `cross-package-test-inputs`,
`test-source-alias`, `tier-file-adoption`, `type-check-coverage`,
`type-check-debt`, `stack-collection-maps`, `comment-mask-adoption`,
`comment-mask-corpus`, `keyed-text-bounds`, `closing-keyword-parity`,
`doc-authoring`, `cli-test-child-env`, `published-files`,
`objectui-changeset`, `changeset-gate-self-tests`, `empty-changeset`,
`changeset-no-major`, `adr-0087-registration`) | exit **0** each; the
ratchet families were re-run on the final head |
The `packages/cli` `integration` tier beyond the two files above is
declared to CI: this diff touches no integration-tier file, no spawn
entry and no driver or kernel boot path. Those two are run locally
anyway because they are the closest neighbours of this seam.
`dispatch-gates --ran` reconciles 19 of 62 derived families run locally;
the remaining 43 are repo-wide or artifact-roster families no path of
this diff narrows, and they are CI's.
## Acceptance notes
- **Filed as #17821** — `os lint`'s `naming/namespace-prefix` reports a
legitimate cross-package name reuse as an intra-package duplicate on a
composed multi-package stack, contradicting the ADR-0048 §3.4 sentence
in its own message. Measured both ways: **1 false positive on the
additive shape before and after this change**, 0 before and 1 after on
the option-B shape — so it is pre-existing on the shape the platform
emits today, and this change only brings the option-B spelling into
parity with it, which is its acceptance. The fix needs per-item package
attribution, a design question rather than a wiring detail, so it is
filed rather than folded in.
- **Noted, not filed:** on today's additive artifact a definition that
is carried twice (flattened AND inside `packages[]`) is reported twice
by `scoreMetadata`'s SCHEMA half — measured, `schemaErrors: 2` for one
bad object, at `objects.0` and at `packages.0.manifest.objects.0`. Both
copies genuinely exist in that artifact, so the parse is accurate;
option B's emitter half (#14512) removes the duplication. The lint half
never double-counts, because the fold is present-wins — pinned by the
third shape in the parity test above.
- **Noted, not filed:** the comment on `LintConfigOptions.sduiManifest`
("`scoreMetadata` deliberately does not — the scorer is a pure function
of a stack and must not read the filesystem") reads, out of context,
like a decision that the scorer must see an unfolded stack. Its subject
is the SDUI manifest and the filesystem; a clarifying clause is added in
this diff so the next reader does not have to open the file to settle
it.
- **Noted, not filed:** my own first verification pass selected the
lint/score/option-B test files by hand and missed
`test/validate-build-gate-parity.test.ts`, which is in the same `unit`
tier and reads `lint.ts` as source. The whole tier is run above; the
targeted selection is what cost a CI cycle.
---
_Generated by [Claude Code](https://claude.ai/code)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 51b024a commit 8305ad6
7 files changed
Lines changed: 731 additions & 24 deletions
File tree
- .changeset
- packages/cli
- src/commands
- test
- fixtures
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
174 | 174 | | |
175 | 175 | | |
176 | 176 | | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
177 | 183 | | |
178 | 184 | | |
179 | 185 | | |
180 | 186 | | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
181 | 231 | | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
182 | 238 | | |
183 | 239 | | |
184 | 240 | | |
185 | 241 | | |
186 | 242 | | |
187 | 243 | | |
188 | 244 | | |
189 | | - | |
| 245 | + | |
190 | 246 | | |
191 | 247 | | |
192 | 248 | | |
| |||
244 | 300 | | |
245 | 301 | | |
246 | 302 | | |
247 | | - | |
| 303 | + | |
248 | 304 | | |
249 | 305 | | |
250 | 306 | | |
| |||
259 | 315 | | |
260 | 316 | | |
261 | 317 | | |
262 | | - | |
| 318 | + | |
263 | 319 | | |
264 | 320 | | |
265 | 321 | | |
| |||
273 | 329 | | |
274 | 330 | | |
275 | 331 | | |
276 | | - | |
| 332 | + | |
277 | 333 | | |
278 | 334 | | |
279 | 335 | | |
| |||
283 | 339 | | |
284 | 340 | | |
285 | 341 | | |
286 | | - | |
| 342 | + | |
287 | 343 | | |
288 | 344 | | |
289 | 345 | | |
| |||
309 | 365 | | |
310 | 366 | | |
311 | 367 | | |
312 | | - | |
| 368 | + | |
313 | 369 | | |
314 | 370 | | |
315 | 371 | | |
| |||
369 | 425 | | |
370 | 426 | | |
371 | 427 | | |
372 | | - | |
| 428 | + | |
373 | 429 | | |
374 | 430 | | |
375 | 431 | | |
| |||
427 | 483 | | |
428 | 484 | | |
429 | 485 | | |
430 | | - | |
| 486 | + | |
431 | 487 | | |
432 | 488 | | |
433 | 489 | | |
| |||
456 | 512 | | |
457 | 513 | | |
458 | 514 | | |
459 | | - | |
| 515 | + | |
460 | 516 | | |
461 | 517 | | |
462 | 518 | | |
| |||
523 | 579 | | |
524 | 580 | | |
525 | 581 | | |
526 | | - | |
527 | | - | |
528 | | - | |
529 | | - | |
530 | | - | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
531 | 592 | | |
532 | | - | |
533 | | - | |
| 593 | + | |
| 594 | + | |
534 | 595 | | |
535 | 596 | | |
536 | 597 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
115 | 115 | | |
116 | 116 | | |
117 | 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 | + | |
118 | 150 | | |
119 | 151 | | |
120 | 152 | | |
| |||
241 | 273 | | |
242 | 274 | | |
243 | 275 | | |
244 | | - | |
| 276 | + | |
| 277 | + | |
245 | 278 | | |
246 | 279 | | |
247 | 280 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
84 | 90 | | |
85 | 91 | | |
86 | 92 | | |
| |||
98 | 104 | | |
99 | 105 | | |
100 | 106 | | |
| 107 | + | |
101 | 108 | | |
102 | 109 | | |
103 | 110 | | |
| |||
513 | 520 | | |
514 | 521 | | |
515 | 522 | | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 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 | + | |
516 | 574 | | |
517 | 575 | | |
518 | 576 | | |
| |||
0 commit comments