Repository navigation
Commit 7399080
Fixes #22663
Clause-②: yes (narrowing)
A configured cube, or a dataset registered through `registerDataset`,
whose base object or declared join is an object the spec's
`apiExposureDenialReason` denies for the `aggregate` operation is now
refused when it is registered. `GET /analytics/meta` no longer lists it.
This is the card's preferred shape (a). It reuses the decision PR #22645
put at the query door (`api-exposure-door.ts`), for the same operation,
over the same object set. There is no second rule, no new gate, and no
lint rule.
Dispatched by the `domain:services` seat 1 (session
`session_013j5gkUCpqQiti4GgPqqmnt`, seat post #6021) under claim
`6096404246`. File surface held:
`packages/services/service-analytics/src/**` and one
`.changeset/22663-*.md`. Nothing in `packages/spec`, `packages/lint` or
`content/docs/releases/` is touched.
## Step 1: census (before any edit, on `origin/main` `ee3ae0360d`)
| Producer | Count | Over a denied object? |
|---|---|---|
| Authored cubes (`analyticsCubes` / `defineCube`), examples and
platform | 1: `showcase_delivery` (`showcase_task`, joined to
`showcase_project`) | No. Neither object declares an `enable` block. |
| Datasets (`defineDataset`): `examples/**` 6, `platform-objects` 5 | 11
| No. The five `sys_*` bases grant `list` or are not declared in this
repo (`sys_package_installation` is a cloud object). None of the eleven
enters the cube registry: stack datasets are compiled per request by
`queryDataset` (request scope), never by `registerDataset`. |
| `registerDataset` callers outside tests | 0 | n/a |
| Writers of `service.cubeRegistry` / `inferFromObject` outside tests |
0 | n/a |
| `analytics:ready` listeners that register cubes | 0 | n/a |
| Dogfood suites (`packages/qa/dogfood`) with a cube or dataset over an
`apiEnabled: false` / no-`list` object | 0 | n/a |
| Test fixtures | 2: `hidden_cube` and `nolist_cube` in
`api-exposure-door.test.ts` (PR #22645) | Yes. Re-triaged below. |
There is no real producer that shape (a) breaks, so shape (b) (keep the
registration and hide the cube from `getMeta`) was not taken. Deployed
and cloud-held definitions were NOT MEASURED.
## Registration entry points
The before column was read on `ee3ae0360d`.
| Door | Reached by | Bad definition, before | After |
|---|---|---|---|
| `AnalyticsServiceConfig.cubes` | the plugin's `cubes`, which `os
serve` fills from `analyticsCubes` (`CAPABILITY_PROVIDERS.analytics`),
inside the plugin's `init()` | **accept** (no check at all) | **warn and
skip**: one `warn` per cube names the cube, the object and the
declaration, and every other cube still registers |
| `AnalyticsServiceConfig.datasets` | constructor → `registerDataset` |
accept; a dataset that cannot compile was warned and skipped (the #5115
channel) | **warn and skip**, through that same existing channel |
| `registerDataset()` | an embedder | accept; a dataset that cannot
compile threw | **refuse**: throws a located error and registers nothing
|
| `service.cubeRegistry.register()` / `registerAll()` /
`inferFromObject()` | the public `cubeRegistry` field (no in-repo
caller) | accept | **refuse**: the registry's own admission throws, and
nothing is stored |
| `queryDataset()` / ad-hoc `query()` / `generateSql()` | requests |
never write the shared registry (#20356, #20381) | unchanged |
**Refusal channel, measured and reused.** The constructor already had a
per-definition boot channel: a pre-registered dataset that cannot
compile is warned and skipped, so the boot continues and the other
datasets register (`dataset-cross-datasource-registration.test.ts`,
#5115). Config cubes now take that channel. `registerDataset` already
threw for a definition it could not compile, and it now throws for this
one too. The thrown error carries the query door's envelope for the same
declaration:
- `code: OBJECT_API_DISABLED`, `status: 404` for `enable.apiEnabled:
false`;
- `code: OBJECT_API_METHOD_NOT_ALLOWED`, `status: 405` for an
`enable.apiMethods` whitelist that does not grant the operation, plus
`allowed`.
Both carry `object`. The message names the definition, the object, the
declaration and the denial reason. Both codes are already ledgered under
`@objectstack/service-analytics` (`check:error-code-provenance` OK).
**Level.** The boot-time line is `warn`, as for its dataset sibling.
Under AGENTS.md's degradation rule this is a functional degradation: the
refused cube is visibly absent from `getMeta`, and nothing claimed as
persisted is lost.
## Timing finding
The service registers configured cubes when the plugin's `init()`
constructs it, so an object is judged only if its declaration exists at
that moment. I measured this with a throwaway probe: a `LiteKernel` with
the real `ObjectQLPlugin`, three `apiEnabled: false` objects registered
through the `manifest` service, and an observer plugin inited just
before analytics. The probe is not committed.
| Object registered | Declared when analytics inits? | `getMeta` before
this change | `getMeta` after |
|---|---|---|---|
| by a plugin whose `init()` precedes analytics | yes | listed |
**refused** |
| by a plugin whose `init()` follows analytics | no | listed | listed
(window) |
| in a plugin's `start()` | no | listed | listed (window) |
After boot, all three objects are declared. In `os serve`, read from
source: `AppPlugin` (an app's own objects) and `PlatformObjectsPlugin`
are `kernel.use`d before the capability resolver mounts `analytics`, so
a cube over an app's own objects or a platform object is judged. Objects
contributed by a capability provider that follows `analytics` in
`requires` order, `start()`-time registrations and `kernel:ready`
installs fall in the window.
That is the #5115 probes' ordering: `registerDataset` compile gating
asks `getObjectDatasource` / `isExternalObject` at the same moment and
takes "cannot answer, do not block". This reuses it:
- an object with no declaration yet is not refused;
- a declaration lookup that throws is not refused either (the plugin's
bridge throws when no data engine is registered);
- in both cases the query door still refuses every query of the cube,
fail-closed.
The conclusion drawn is never "absent, therefore refused", so
`check:startup-registry-verdict` holds (45 seams, none recording a
verdict the boot can contradict). Whether the window is owed a second
judgment is left to the seat (see Acceptance notes).
## Change
- **`api-exposure-door.ts`**: `assertDefinitionExposed(kind, name,
objects, provider)`, the registration face. It makes the same
`apiExposureDenialReason(enable, 'aggregate')` call and returns the same
codes. It does not block when it cannot answer.
- **`cube-registry.ts`**: an optional `CubeAdmission` constructor
parameter, asked by `register` before storing. Every write path goes
through `register`. A registry constructed without one admits
everything, as before. The parameter is additive.
- **`analytics-service.ts`**:
- The registry is constructed with the admission, which judges
`cubeObjects(cube)` (base object plus declared joins), the set the query
door's first check reads.
- Configured cubes register one at a time, after the probes are
assigned, through the warn-and-skip channel.
- `registerDataset` judges as a dataset first, so the refusal names the
dataset, then registers. The registry's admission repeats the same check
on the same cube and gets the same answer.
- A host with no `getObjectDeclaration` hook gets no gate, as on the
query door.
## Pins (`unexposed-definition-registration.test.ts`, 12 cases)
Refusals:
- **Configured cubes, base object.** `apiEnabled: false` and a
`get`-only whitelist are each warned once, located, absent from the
registry and from `getMeta()` / `getMeta(name)`. The other cubes
register.
- **Configured cube, joined object.** A cube whose joined object is
unexposed is refused, and the warning names the joined object.
- **Envelope.** The refusal carries `OBJECT_API_DISABLED`/404 or
`OBJECT_API_METHOD_NOT_ALLOWED`/405, with `object`.
- **Direct registry write.** It is refused, and nothing is stored.
- **`registerDataset`.** It throws for an unexposed base object (404 and
405 variants) and for an unexposed joined object (via `include`), naming
the dataset and the object. Nothing is registered, and `getMeta(name)`
is empty.
- **Constructor `datasets`.** Each refused dataset is warned once and
skipped, and the exposed one registers.
- **Shipped wiring.** `AnalyticsServicePlugin` over a real `ObjectQL`
engine with a SQLite driver: configured cubes over unexposed objects are
refused at `init()`, warned, and absent from `getMeta`.
`registerDataset` on the plugin's service refuses, and an exposed
dataset registers.
Controls and tiering:
- **CONTROL.** A dataset over an exposed object, joined to an exposed
object, registers and lists as before. The exposed cubes in every case
above register and list.
- **Tiering: no declaration yet.** The cube registers. The query door
refuses it 404 once the object is declared.
- **Tiering: lookup throws.** The cube registers. The query door refuses
it `PERMISSION_DENIED`/403.
- **Tiering: no probe wired.** Every definition registers as before.
**Fixture triage, `api-exposure-door.test.ts`.** Its `hidden_cube` and
`nolist_cube` were configured cubes over denied objects, and the
"configured cube" rows pinned the query door for them. They are now
refused at registration whenever the declaration is known. The suite's
`beforeAll` therefore inits the plugin before the subjects are declared,
so those rows pin the query door in the window. They now measure the
only state in which that door is reachable for a configured cube. Every
assertion in the file is unchanged.
**Ablation.** I ran it with `scripts/ablation-replace.mjs` in wrap mode,
under the verify lock, at `c8dae0a783`. The test imports the service
from `src` by a relative path, with no `dist` hop.
- **Anchor.** The one call in `assertRegistrable`:
`assertDefinitionExposed(kind, cube.name, this.cubeObjects(cube),
provider);`. It hit once, as declared.
- **Mutation.** The anchor went from 1 to 0 and the replacement from 0
to 1. The blob moved `07cb9454e93f` → `ea44bf4cd373`.
- **Result.** 8 failed and 4 passed of 12. Every refusal pin went red.
The 4 green are the dataset control and the three tiering pins, which is
the predicted direction.
- **Restore.** The blob is back to `07cb9454e93f`, equal to HEAD, and
`git diff HEAD` is empty. I re-checked independently afterwards: the
ablation marker count is 0 and the anchor count is 1.
## Verification (final HEAD `dcc38d4413`, after merging `origin/main`)
- `pnpm turbo run build --filter=@objectstack/service-analytics
--concurrency=1`: 15/15 tasks.
- `pnpm --filter @objectstack/service-analytics exec vitest run
--maxWorkers=2`: 182 files passed; 4485 passed, 262 skipped.
- `pnpm --filter @objectstack/service-analytics typecheck`: `tsc
--noEmit` clean.
- Gates: `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 65 commands, the same set as before
the merge. I ran all 65, plus 4 implicated ones:
`check:startup-registry-verdict`, `check:durability-log-level`,
`check:adr-anchors`, and spec `check:error-code-provenance`. Each exit
was captured before any pipe, and all 69 exited 0. `--ran` reports: 65
derived, 65 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero because all 65
recorded an exit code.
- Selected verdict lines:
- `check:adr-0087-registration`: the `no-migration-prescription`
exemption is accepted.
- `check:empty-changeset`: one declaring changeset added.
- `check:nul-bytes`: OK.
- `check:test-source-alias`: OK.
- `check:cross-package-test-inputs`: OK.
- The dist-reading gates (`check:dts-closure`,
`check:dual-build-cjs-loads`, `check:lean-entry-closure`,
`check:published-files`, `check:sourcemap-no-sources-content`) ran after
the rebuild at this HEAD.
- Not run locally, and declared to CI: the repo-wide `pnpm lint` and the
other packages' suites. The public surface that changed is one additive
optional constructor parameter, on a class no other workspace package
constructs.
## Changeset
`.changeset/22663-analytics-unexposed-cube-registration.md` is a `minor`
bump of `@objectstack/service-analytics`, BREAKING as an accept-set
narrowing under the launch-window convention. It records FROM and TO and
the ADR-0087 disposition `not-required (no-migration-prescription)`: no
metadata moves, and the remedy is to point the definition at an exposed
object or remove it.
## Acceptance notes
1. **The registration window (see Timing).** A configured cube over an
object declared after the analytics plugin's `init()` still registers
and lists. This covers a later capability provider's objects, a
`start()` registration, a `kernel:ready` install, and an object authored
at runtime. Every query of such a cube is still refused by the query
door. Closing the window needs a second judgment after the boot settles,
for example at `kernel:ready`, which is beyond reusing the #5115 timing.
It is raised as an open question in the report, not built here.
2. **A relationship hop one member walks is not judged at
registration.** It refuses that member's queries, not the whole cube, so
refusing the cube for it would over-refuse. The query door judges it per
member, as PR #22645 pins.
3. **A lookup that throws at registration is not logged.** That is the
stand-down tier. In the shipped plugin the throw means no data engine
yet, which the plugin already warns about at `init()`, and the query
door logs the same failure at `error` when a query meets it.
4. **`CubeRegistry.registerAll` stops at the first refused cube**, and
the cubes before it stay registered. This is documented on the method.
The service no longer uses `registerAll`, and registers config cubes one
at a time.
5. **An authoring-time check is not added.** A `packages/lint` rule in
the style of `validate-nav-object-servability`, refusing an
`analyticsCubes` entry over an unexposed object at `os validate`, would
catch the pair before boot and inside the window. The claim fences
`packages/lint` off and no producer is measured, so it is noted here and
not filed.
6. **Card relation.** This PR closes #22663. It does not touch PR
#22645's codes or its query-door behaviour.
## Seat's note: line 2 re-declared
Written by `domain:services` seat 1 (`session_013j5gkUCpqQiti4GgPqqmnt`)
at 2026-10-10T11:54Z. Line 2 now reads `Clause-②: yes (narrowing)`,
following the contract review of `dcc38d4413` (`6097218872`, ①.5 and ②).
- `CubeRegistry` is re-exported from the package entry, so its new
optional constructor parameter enlarges the published surface. That is a
widening, beside the accept-set narrowing.
- The changeset's line is re-declared in the patch round. The level
stays `minor`.
## Seat's append: patch round 1 (head `3a646f5ffb`)
Appended by `domain:services` seat 1
(`session_013j5gkUCpqQiti4GgPqqmnt`) at 2026-10-10T12:49Z, from the
dev's round-1 report on #22663. The dev's text follows, unedited except
for heading levels. The seat read the head against GitHub, in a
seat-owned ref:
- the 16 `producer` quotes match `serve.ts` and the per-cube loop in
`analytics-service.ts` at this head;
- 16 rows carry `verifiedAt: 2026-10-10`;
- `registerAll` is gone from the ledger;
- the changeset line reads `Clause-②: yes (narrowing)`.
### Round 1 (patch)
Head: `3a646f5ffb`. That is `393b179be6` (re-anchor), then `dabf17b4b8`
(contract-review addendum), then a clean merge of `origin/main`
`243dd3c625` with no regeneration debt.
**Cause.** `Test Core (1/6)` at `dcc38d4413` failed in
`@objectstack/spec`'s liveness gate. Sixteen rows in
`packages/spec/liveness/analytics_cube.json` anchored their producer at
`packages/services/service-analytics/src/analytics-service.ts#registerAll`.
This PR replaced the constructor's `registerAll` call, so the anchored
symbol left the file. Reproduced on `dcc38d4413` before any edit:
- `check-liveness.test.ts` (local): 24 failed, 47 passed, exit 1.
- `evidence.test.ts` (repo): 1 failed, 41 passed, exit 1.
- `check:liveness`: exit 1, with "16 anchored citation(s) name a symbol
the cited file does not contain".
Round 0's local set missed it. The derived set held no spec family for a
diff outside `packages/spec`, and nothing that ran read the ledger's
anchors into `service-analytics` source. That blind spot is filed as
#22680.
**Re-anchored symbol: `analytics-service.ts#register`.** The constructor
now registers configured cubes through
`this.cubeRegistry.register(cube)`, one call per cube. `register` is the
symbol that call uses, the direct successor of `registerAll` in the same
position. Nothing in `analytics-service.ts` changed to fit the anchor.
**Contract-review addendum (`6097218872`), value-only in the same
ledger.** No status, key or row moved, and no other spec file was
touched. The before/after JSON has the same key paths and 0 status
changes; the changed leaves are `_note` 1, `producer` 16 and
`verifiedAt` 16.
- **`verifiedAt: 2026-10-10` on the 16 rows.** Their shared producer
string now quotes the code at this head. This covers the `serve.ts`
fallback `resolveStackCollection(config, 'analyticsCubes')`, which had
been stale since #22288 and was a `?? []` quote, and the constructor's
per-cube `register` behind the exposure admission. A `verifiedAt` stamp
attests the whole producer, so a known-stale quote could not stay under
it.
- **`_note`.** It now reads "registered one cube at a time by
`register`".
- **Changeset `Clause-②: yes (narrowing)`.** `CubeRegistry` is
re-exported from the package entry, and its optional `admit` parameter
enlarges the published surface. The bump is still `minor`, and the
ADR-0087 marker still discloses the additive parameter.
`check-adr-0087-registration --base origin/main` exits 0
(`[BREAKING+bang+clause-②-narrowing]`, `not-required
(no-migration-prescription)`), and `check-changeset-no-major --base
origin/main` exits 0.
**Gate exits at `3a646f5ffb`.** All runs went through the verify lock
with slot `issue-22663`, a 3 GB heap, turbo `--concurrency=1` and vitest
`--maxWorkers=2`.
- **Liveness pair.** `check-liveness.test.ts`: 71/71, exit 0.
`evidence.test.ts`: 42/42, exit 0. `check:liveness`: exit 0.
- **Spec suites.** `test` (local): 642 files, 19159 passed and 1 todo,
exit 0. `test:repo`: 55 files, 971 passed, exit 0.
- **`@objectstack/service-analytics`.** 182 files, 4485 passed and 262
skipped, exit 0. Typecheck exit 0.
- **Builds.** The service-analytics closure built 15/15. A full `turbo
run build --filter=!@objectstack/docs` built 72/72 (71 cached) for the
dist-reading gate.
- **Derived set.** `dispatch-gates --commands --repo
objectstack-ai/objectstack` derived 72 commands, 7 of them new spec/repo
families (including `check:liveness`). All 72 ran, plus
`check:startup-registry-verdict`, `check:durability-log-level`,
`check:adr-anchors` and the spec `check:error-code-provenance`. 75
exited 0 and 1 exited 1. `--ran` reports 72 derived, 72 run, 0
NOT-MEASURED and 0 UNRUN, a derived zero.
- **`check:dual-build-cjs-loads`.** It first answered exit 3,
`PREREQUISITE NOT MET` (64 packages had no `dist` in the fresh
worktree), which is not a measurement. After the full build it exited 0:
107 require entry points across 66 packages load.
- **`check:platform-checklist` exit 1, main-side.** It reports 7
problems, all ABSENT SYMBOL anchors. Five are in
`areas/access-security.json`, against
`metadata-protocol/src/protocol.ts`
(`anonymousFormIntakeOrgScopeRefusal`,
`anonymousFormIntakeReopenRefusal`, `envWideRawViewRows`). Two are in
`areas/attachments-storage.json`: `#canEdit`, and the symbol-anchor
floor at 27 of 28. None of those files is in this diff. Control leg: the
same gate on a clean `origin/main` `243dd3c625` tree exits 1 with the
identical 7 problems.
- **Seat's disposition:** dropped as a duplicate. The red is the
watchdog card #22594's, which triage closed `not_planned` with its
re-entry conditions (`6095872178`). The gate is kept out of per-PR CI by
maintainer decision (`lint.yml`'s note), and the daily watchdog files it
again.
**CI at `3a646f5ffb`:** 32 success and 3 skipped (`Build Docs`, `Console
Pin Gate`, `Packed-tarball smoke (opt-in)`), read
latest-run-per-check-name. The red `TypeScript Type Check` and `Test
Core` events at `dabf17b4b8` and `393b179be6` were cancellations by the
next push, not verdicts.
## Seat's append: patch round 2 (head `0dd4426835`)
Appended by `domain:services` seat 1
(`session_013j5gkUCpqQiti4GgPqqmnt`) at 2026-10-10T13:36Z, from the
dev's round-2 report on #22663. The seat folded flag ③.4 of `6097791315`
into this branch (`6097801200`). The dev's text follows, unedited except
for heading levels.
The seat read the head against GitHub, in a seat-owned ref:
- The diff against `3a646f5ffb` is one file, `analytics_cube.json`, with
17 lines in and 17 out.
- `joinTable` is gone from the ledger.
- 16 rows cite
`packages/core/src/capability-providers.ts#CAPABILITY_PROVIDERS`.
- Each new quote is present at head: `const joined =
joins?.[alias]?.name;` in `hop-object.ts`, `const CAPABILITY_PROVIDERS =
Serve.CAPABILITY_PROVIDERS` and `spec.configKey === 'analyticsCubes'` in
`serve.ts`, and `object: hop.object` in `native-sql-strategy.ts`.
### Round 2 (ledger)
Head: `0dd4426835` (one commit on `3a646f5ffb`). `origin/main` is still
`243dd3c625`, which round 1 merged, so no merge was owed. Only
`packages/spec/liveness/analytics_cube.json` changed, and only values.
The contract review of `3a646f5ffb` (`6097791315`, flag ③.4) named two
pre-existing stale leaves sitting under the round-1 `verifiedAt:
2026-10-10` stamp.
**1. `joins.children.name`, first `evidence` citation.** It quoted
`const joinTable = cube?.joins?.[alias]?.name ?? alias` at
`native-sql-strategy.ts#qualifyAndRegisterJoin`. `joinTable` has 0
occurrences in that file at head. The citation is re-sited at
`packages/services/service-analytics/src/hop-object.ts#resolvePathHops`,
quoting `const joined = joins?.[alias]?.name;` verbatim (tier 1 of the
one hop resolver). It keeps
`native-sql-strategy.ts#qualifyAndRegisterJoin` as the emitter of the
LEFT JOIN against that object, quoting `object: hop.object`, which is
verbatim at head. The row's other three citations are unchanged.
**2. The 16 `producer` strings.**
- The `configKey` declaration clause is re-sited at
`packages/core/src/capability-providers.ts#CAPABILITY_PROVIDERS`, which
declares `configKey: 'analyticsCubes'` on the `analytics` entry.
- The `serve.ts` threading quote stays where it lives, at
`packages/cli/src/commands/serve.ts#CAPABILITY_PROVIDERS`. That is the
resolver's own declared handle on the table (`const CAPABILITY_PROVIDERS
= Serve.CAPABILITY_PROVIDERS`), which the resolver loop indexes. The
clause now quotes the test it applies, `spec.configKey ===
'analyticsCubes'`, and the existing `const cubes = … ; arg = { cubes }`
quote.
- Every anchor names a declaration in its cited file, and every quote
occurs exactly once at head.
**Fence proof.** The JSON walk against `origin/main` finds the same 91
key paths and 0 status changes. Changed leaves by field: `_note` 1,
`verifiedAt` 16, `producer` 16, `evidence` 1. Against the round-1 head,
only `producer` 16 and `evidence` 1 moved.
**Gates at `0dd4426835`.** All runs went through the verify lock with
slot `issue-22663`, a 3 GB heap, turbo `--concurrency=1` and vitest
`--maxWorkers=2`, with each exit captured before any pipe.
- `check-liveness.test.ts` (local): 71/71, exit 0.
- `evidence.test.ts` (repo): 42/42, exit 0.
- `pnpm --filter @objectstack/spec run check:liveness`: exit 0.
- Spec `test:repo`: 55 files, 971 passed, exit 0.
- Full `turbo run build --filter=!@objectstack/docs`: 72/72 tasks, exit
0.
- `dispatch-gates --commands --repo objectstack-ai/objectstack` derived
72 commands, the same set as round 1. All 72 ran, plus 4 implicated
ones. 75 exited 0 and 1 exited 1. `--ran` reports 72 derived, 72 run, 0
NOT-MEASURED and 0 UNRUN, a derived zero.
- `check:platform-checklist` still exits 1 with the identical 7
main-side ABSENT SYMBOL problems that round 1's clean `origin/main`
`243dd3c625` control showed. None of them is in this diff.
---
_Generated by [Claude
Code](https://claude.ai/code/session_013j5gkUCpqQiti4GgPqqmnt)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 80b2da2 commit 7399080
7 files changed
Lines changed: 589 additions & 59 deletions
File tree
- .changeset
- packages
- services/service-analytics/src
- __tests__
- spec/liveness
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
109 | 109 | | |
110 | 110 | | |
111 | 111 | | |
112 | | - | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
113 | 116 | | |
114 | 117 | | |
115 | 118 | | |
| |||
217 | 220 | | |
218 | 221 | | |
219 | 222 | | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
220 | 245 | | |
221 | 246 | | |
222 | 247 | | |
| |||
236 | 261 | | |
237 | 262 | | |
238 | 263 | | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | | - | |
251 | | - | |
252 | | - | |
253 | 264 | | |
254 | 265 | | |
255 | 266 | | |
| |||
0 commit comments