Repository navigation
Commit e02833c
Refs #15206 (S2)
Clause-②: no
**Stage S2 of #15206: managed content is sealed (ADR-0131 D6, regime
C).** The operator hatch `OS_METADATA_WRITABLE`, and its legacy spelling
`OBJECTSTACK_METADATA_WRITABLE`, no longer opens an overlay write onto
an item a managed package ships, and no longer opens a removal of one.
Such a request now answers `403 NOT_OVERRIDABLE`, and the refusal's
first sentence names "a managed package". These stay as they were:
- disabling a managed flow or action (operator-gated, under its wall);
- cloning a flow under a new name, which records no linkage;
- creating a new flow in Studio (the positive control).
Declared test change outside the card surface:
`packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts`
(declared to `domain:services` on #6021). Its two hatch-OPEN cases now
pin that the protocol's package door answers, not the lock; see Patch
round 1.
## The mechanism (M3: one predicate)
`isSealedManagedItem(type, name)` holds when the item is artifact-backed
and its type's registry entry opens no overlay channel. The registry
half is `registryAllowsOverlay(type)`, which is `isOverlayAllowed`
without the environment variable. These all read this one predicate:
- the save door (`refusePackagedBaseOverride`);
- the removal door (`refusePackagedBaseRemoval`);
- the read envelope (`packagedBaseRefusal`, which sets `editable` /
`deletable`).
The `/automation` definition doors ask the same protocol doors.
The repository (`SysMetadataRepository.assertAllowed`) applies the same
rule one layer down. With the hatch open, only `intent: 'runtime-only'`
(a new item no package ships) passes. An `override-artifact` intent gets
the sealed sentence; that covers draft promotion, restore and revert.
For a shipped item, two other places no longer consult the hatch: the
code-only check in `saveMetaItem`, and the repository route in
`deleteMetaItem`.
The sentence comes from one builder, `managedItemSealedSentence` in
`packaged-base-regime.ts`. It is internal and not reachable from the
package entry.
- A type with an ADR-0126 regime row (`flow`, `action`, `permission`)
keeps naming its sanctioned route: the clone or the switch.
- Every other type says it is sealed, says that the hatch does not open
a managed item, and keeps the source remedy.
`SysMetadataRepository.readOnlyBaseOverrideError` drops its third
parameter, `hatchOpen`, because nothing it chose survives the seal.
**Built entry declarations (`dist/index.d.ts`), measured.** Nothing
widens:
- two new private members: `private static registryAllowsOverlay;` and
`private isSealedManagedItem;`;
- `static readOnlyBaseOverrideError(type: string, packageId: string):
Error` loses its optional third parameter, which narrows it; no caller
outside the package exists (`git grep`);
- `managedItemSealedSentence` is not exported.
## Door table (M1, M2, M4, M5), measured on a real boot
Setup:
- The CRM example, booted through `bootStack(crmStack, { automation:
true })`.
- Base is `8311650228`. Head is this branch.
- Two transports: REST is the `RestServer` `/api/v1/meta` routes; DISP
is the runtime `HttpDispatcher`.
- Hatch modes:
- OS: `OS_METADATA_WRITABLE=flow,object,field,permission,position`.
- LEGACY: the same value under `OBJECTSTACK_METADATA_WRITABLE`.
- NONE: no hatch.
- JOB: `OS_METADATA_WRITABLE=job`.
The two transports read the same unless a row notes otherwise. The
dispatcher serves no `DELETE` on `/meta` items: it answers `405
METHOD_NOT_ALLOWED` in every mode, at base and at head. The DELETE rows
are therefore REST.
| Probe | OS base | OS head | LEGACY base | LEGACY head | NONE and JOB
(base = head) |
|:--|:--|:--|:--|:--|:--|
| PUT `/meta/flow/crm_convert_lead_wizard` (shipped) | 200 | **403**
NOT_OVERRIDABLE | 403 | 403 | 403 |
| PUT `/meta/object/crm_lead` (field relabel) | 200 | **403** | 403 |
403 | 403 |
| PUT `/meta/permission/crm_sales_user` | 403 (plugin-security lock) |
403 (protocol door) | 403 | 403 | 403 |
| PUT `/meta/position/sales_rep` (M5) | 200 | **403** | 403 | 403 | 403
|
| PUT `/automation/crm_convert_lead_wizard` | 200 | **403** | 403 | 403
| 403 |
| DELETE `/meta/flow` over a legacy overlay row | 200 | **403** | 403 |
403 | 403 |
| DELETE `/meta/flow` with no row | 200 | **403** | 403 | 403 | 403 |
| DELETE `/meta/object/crm_lead` over a legacy row | 200 | **403** | 403
| 403 | 403 |
| DELETE `/meta/object/crm_lead?dropStorage=true` | 200, and the object
leaves the data plane (POST `/data/crm_lead` 404 OBJECT_NOT_FOUND, GET
500 DATABASE_ERROR) | **403**, and the data plane stays up (201 / 200) |
not run | not run | not run |
| DELETE `/meta/permission`, `/meta/position` over a legacy row | 200 |
200 (the #6960 repair, kept) | 200 | 200 | 200 |
| DISP envelope of the shipped flow, `editable` / `deletable` | true /
true | **false / false** | true / true | **false / false** | false /
false |
| `/meta/types` entry for `flow`, `allowOrgOverride` / `overrideSource`
| true / env | true / env (Q2) | true / env | true / env | false /
registry |
Controls, measured in every mode, on both transports, with base equal to
head:
- PUT of a view overlay (`crm_opportunity.all`): 200. Its REST DELETE:
200.
- PUT `/meta/flow/NEW`: 200.
- POST `/automation` (create): 200.
- Toggle off, then on: 200 / 200.
- Clone: 200, and the clone carries no linkage keys.
- PUT `/meta/job/NEW`: 403 NOT_CREATABLE under NONE, OS and LEGACY; 200
under JOB, unchanged (M6, out of scope, below).
**M2: the two hatch readers diverge on the legacy spelling.** This is
measured.
- The protocol's reader, `envWritableTypes()`, reads both spellings
through `readEnvWithDeprecation`.
- The repository's reader, `envWritableMetadataTypes()`, reads
`OS_METADATA_WRITABLE` only.
At base, the legacy spelling advertised managed items as writable, while
every write onto them answered 403:
- the listing read `allowOrgOverride: true`;
- the DISP envelope read `editable: true`;
- every write answered 403, because the repository's hatch never opened.
At head the seal makes both readers irrelevant for managed items, and
the envelope reads false under both spellings. For creating an item no
package ships, the divergence remains, and it is reported below.
**M4.** This PR does not touch the toggle path or its gate. The gate is
measured by `automation-activation-posture-gate.test.ts` and
`action-activation-posture-gate.test.ts`: 2 files, 46 passed. In the
`group` and `isolated` postures a tenant admin is refused and the
operator is allowed; enable is gated as well as disable; the clone door
is not gated. In the `single` posture the gate is inert, which is why
the CRM boot reads 200 on the toggle. As measured above, the clone
carries no linkage, and a new flow and POST `/automation` answer 200.
**M5.** A position overlay through the hatch is refused at save time
(the table above).
## Pins
New:
- `packages/rest/src/rest-meta-managed-seal-hatch.test.ts`, 6 cases. The
REST door relays the seal for flow, object, field, permission and
position, under both spellings and both kernel shapes. Each answer is
byte-equal to the hatch-shut answer and names "managed package". It also
covers DELETE of a flow and an object.
- `packages/runtime/src/meta-managed-content-seal.test.ts`, 12 cases. It
drives the real `HttpDispatcher`, protocol and repository:
- a PUT is refused and writes no row;
- the GET envelope reads `editable` / `deletable` false;
- controls: a view overlay and a new flow answer 200.
- `packages/qa/dogfood/test/managed-content-sealed.dogfood.test.ts`, 10
cases, on CRM under the OS hatch:
- the premise: the listing advertises the hatch;
- PUT of a flow, object, permission and position, each refused with no
row;
- PUT `/automation` refused;
- DELETE of a flow and an object over a legacy row, refused with the row
kept;
- `dropStorage` refused with the data plane up;
- the #6960 removal still 200;
- controls: a view overlay, a new flow (both doors), toggle, and clone
without linkage.
Re-premised: the existing pins that carried "the hatch opens a managed
item" now pin the seal. They are in `metadata-protocol` (10 files),
`objectql` (5), `rest` (3), `runtime` (2), and the dogfood showcase
scalar-divergence file. That file now seeds its pre-seal rename as a
legacy row and cold-boots, so its read assertions keep a premise.
Patch round 1 adds two more: the plugin-security lock-gate cases, and
#22365's cold-boot catalog control (below).
## Reverse verification, at `c2d18e52f5`, under a trap restore
Two mutations reopen the hatch for managed items:
- In the protocol, `registryAllowsOverlay` also reads
`envWritableTypes()`.
- In the repository, `if (hatchOpen && intent === 'runtime-only')
return;` becomes `if (hatchOpen) return;`.
Both landed on disk (`ablation-replace`: anchor 1 → 0, blob changed).
Both reached `dist/`: the preflight found the marker in 2 built files.
| Suite | Mutated | Restored |
|:--|:--|:--|
| metadata-protocol seal pins | 13 failed / 72 passed | 85 / 85 |
| rest | 6 failed / 6 | 6 / 6 |
| runtime | 8 failed / 4 passed (the 4 passing are the controls) | 12 /
12 |
| dogfood | 4 failed / 6 passed (the 6 passing are the premise, #6960,
view, new flow, toggle and clone) | 10 / 10 |
The restore was proved three ways:
- each blob equals HEAD (`6df9a994bc36` and `690b710cc415`);
- `git diff HEAD` is empty and the working tree is clean;
- after a rebuild, `--absent` passed for both markers.
The direction was an ordinary red.
## Changeset and ADR-0087
The changeset is `.changeset/15206-managed-content-sealed.md`:
`@objectstack/metadata-protocol` minor, with the BREAKING paragraph for
the v18 prerelease line. Changesets is in pre mode.
The ADR-0087 marker is `not-required (no-migration-prescription)`: no
spec key, stored shape or export changes, and every stored row loads and
serves unchanged. `check:adr-0087-registration` reads it as
`[BREAKING+bang+clause-②-narrowing] not-required`.
The `OS_METADATA_WRITABLE` row in
`content/docs/deployment/environment-variables.mdx` now says what the
hatch opens and what it never opens, and lists the sanctioned route for
each type.
## Tests and gates
Package suites, at `63ea4b2a32`: `origin/main` `11d119ab18` merged, plus
the plugin-security test change. `49f00d1b39` then changed one dogfood
test file only, and shard 2/3 was re-run there.
| Suite | Files | Tests |
|:--|:--|:--|
| `@objectstack/metadata-protocol` | 223 passed + 3 skipped | 28323
passed + 19 skipped |
| `@objectstack/rest` | 270 passed | 5151 passed + 327 skipped |
| `@objectstack/runtime` | 345 passed | 5551 passed + 19 skipped |
| `@objectstack/objectql` | 390 passed | 7666 passed |
| `@objectstack/plugin-security` | 187 passed | 3915 passed + 45 skipped
|
Dogfood shards:
- shard 1/3, at `63ea4b2a32`: 78 files, 574 passed;
- shard 2/3, at `49f00d1b39`: 77 files, 551 passed + 1 skipped;
- shard 3/3, at `63ea4b2a32`: 76 files + 1 skipped file, 679 passed + 8
skipped.
`typecheck` exits 0 for plugin-security (its test layer included) and
dogfood at `49f00d1b39`, and for metadata-protocol, rest, runtime and
objectql in the first round. No source in `metadata-protocol` has
changed since `c2d18e52f5`.
Gate families come from `node scripts/pm/dispatch-gates.mjs --commands`,
run with no paths at `49f00d1b39`. All 109 commands ran, and every one
exits 0. `--ran` reconciles: 109 derived, 109 run, 0 NOT-MEASURED, 0
UNRUN.
**Lint.** CI owns the repo-wide lint. Here, a narrowed run of `eslint
--no-inline-config --format json` over the diff's 29 `.ts` files, at
`49f00d1b39`, gives 29 files, 0 errors and 0 warnings. The proof that
narrowing excludes nothing:
- The population comes from eslint's own config: `eslint.config.mjs:971`
matches `**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}`.
- The file count comes from the JSON output.
- Type-aware linting is never enabled (`eslint.config.mjs:327-328`), so
this diff cannot move the verdict on any file it does not touch.
## Serial constraints
- S1, #22374, is merged into this branch (merge `3c4873ce32`).
- #22323: none of its lines are touched. `git merge-tree` against its
head `81cd9291bc` exits 0, and its hunks (protocol.ts around
22697-22780; the repository around 81, 195, 1318, 1337) do not overlap.
- `origin/main` `11d119ab18` is merged (merge `d68163d1fc`).
`origin/main` has moved since, to `27a8b33dec` (12 commits); `git
merge-tree` against it exits 0.
- #22416 (`domain:services`) also edits
`security-catalog-cold-boot-environment-holder.dogfood.test.ts`, at its
`mkdtempSync` line and its cleanup. This PR leaves those lines alone.
#22416 has since landed on `main`; `git merge-tree` against `main`
`27a8b33dec`, which contains it, exits 0.
## Open questions
**Q1: legacy overlay rows of types that do not merge at read are
stranded.** These are flow, action, hook, object and similar types. A
row the hatch wrote earlier keeps serving, and can no longer be edited
or removed through `/meta`, with the hatch set or not.
- **A, as ruled and implemented:** no `/meta` route removes such a row.
- **B, as a separate decision:** extend the #6960 repair so that
removing an existing stored overlay row of any managed item is allowed,
while `dropStorage` of a managed object stays refused.
This touches ADR-0029 D9.6 ("the hatch … the one door for the life of
the customization") and the ADR-0086 D1 env-overlay tighten path. Both
texts now describe a door that is shut; that is a Tier H edit.
Triage answered Q1 with C: S2 stays as built, and S5 reports
hatch-written environment overlay rows on sealed items at boot and stops
serving them. Nothing changes for Q1 in this PR.
**Q2:** the `/meta/types` listing still reports `allowOrgOverride: true,
overrideSource: 'env'` for a type named in the hatch. Studio's per-item
lock reads the envelope, which is now correct. The listing flag is about
the type, not the item. The carrier is the rename in #22340.
Q2 was answered A: the flag stays, because the per-item envelope is the
truthful signal and the key belongs to #22340.
## Acceptance notes
Out of scope. These are reported for the seat to file; nothing was filed
here.
- **The hatch opens runtime creation of code-only types (M6), class b.**
Reach: on CRM, `OS_METADATA_WRITABLE=job`, PUT
`/api/v1/meta/job/s2_job_job_rest` answers 200 "Saved job
's2_job_job_rest' (env-wide, state=active)". This holds at base and at
head, on both transports.
- **The legacy spelling diverges between the two readers, class a.**
Reach: under `OBJECTSTACK_METADATA_WRITABLE=job`, PUT `/meta/job/NEW`
answers 403 NOT_CREATABLE and prescribes `OS_METADATA_WRITABLE`, while
the protocol's own reader honours the legacy spelling.
Carriers, noted, not filed. These are dead or stale after the seal:
- dead or unreachable code:
- the write-side `OBJECT_OVERLAY_PACKAGE_MISMATCH`;
- the packaged-baseline R1 branch in plugin-security
`object-posture-gate`;
- `DELETE_RESTRICTED` at the `/automation` door;
- the plugin-security lock gate's metadata-door registration;
- the D9.7 subtraction through `/meta`;
- stale comments:
- `runtime/src/domains/automation.ts:1488`;
- in plugin-security, declared to `domain:services` as theirs to carry:
the `packaged-permission-set-lock-gate.ts` header,
`permission-set-projection.ts` (around 1203, 1301, 1393),
`object-posture-gate.ts:14` and `:93`, and `security-plugin.ts:4841`;
- stale docs:
- `permission-sets.mdx:363`;
- `plugins/adding-a-metadata-type.mdx:59-63`;
- `docs/qa/platform-checklist/areas/studio-authoring.json` (it says the
hatch clears the read-only badge).
## Cross-lane paths
These are outside the card's declared surface, and each is a test
re-premised by the seal or a new pin:
- rest:
- `packages/rest/src/meta-object-owd-gate.test.ts`
- `rest-meta-packaged-action-permission-refusal.test.ts`
- `rest-meta-packaged-flow-refusal.test.ts`
- `rest-meta-managed-seal-hatch.test.ts` (new)
- runtime:
- `packages/runtime/src/domains/automation-packaged-base-lock.test.ts`
- `meta-overlay-read-your-writes.test.ts`
- `meta-managed-content-seal.test.ts` (new)
- objectql:
- `packages/objectql/src/protocol-commit-history.test.ts`
- `protocol-destructive.test.ts`
- `protocol-meta.test.ts`
- `protocol-object-overlay-layer.test.ts`
- `protocol-registry-shadow.test.ts`
- dogfood:
-
`packages/qa/dogfood/test/showcase-object-extension-scalar-divergence.dogfood.test.ts`
- `managed-content-sealed.dogfood.test.ts` (new)
- `security-catalog-cold-boot-environment-holder.dogfood.test.ts` (from
#22365, re-premised in Patch round 1; `domain:cli`, declared by the
seat; #22416 edits other lines of it)
- plugin-security (declared to `domain:services` on #6021):
-
`packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts`
- docs (declared to `domain:devx` on #6023):
- `content/docs/permissions/authorization.mdx` (Patch round 2)
- `scripts/engine-double-contract.pinned.json` (three rows for the new
runtime double)
## Patch round 1
- **The declared test change.**
`packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts`
was declared to `domain:services` on #6021. Its two hatch-OPEN cases ("a
package-less save targeting a package-declared set", and "a DRAFT save
of the packaged name") are retitled "refused by the protocol package
door". Each now asserts
`not.toBeInstanceOf(PackagedPermissionSetLockedError)`, keeps
`toMatchObject({ code: 'NOT_OVERRIDABLE', status: 403 })` and the no-row
assertion, and no longer asserts that the message contains the package
id. The header says which layer answers. No plugin-security source file
changes, and no other plugin-security file. plugin-security is now
green: 187 files, 3915 passed + 45 skipped.
- **`origin/main` merged** (`11d119ab18`, merge `d68163d1fc`, no
conflict). The merge brought #22365's
`security-catalog-cold-boot-environment-holder.dogfood.test.ts`, which
went red in shard 2/3:
- Its CONTROL case saved stored definitions under the built-in positions
`org_admin` and `everyone` through `OS_METADATA_WRITABLE=position`, and
expected 200.
- Those positions ship in the platform's own package, so the seal now
answers `403 NOT_OVERRIDABLE`. This is the same M5 refusal as above.
- The control now pins that refusal. It writes the two rows at the
driver, the way an older release left them, as the same file's
legacy-row case already does. Its own assertions are kept: the restart
boots, and the stored definition answers.
- The file is 4 / 4 green, and shard 2/3 is green at `49f00d1b39`.
- The `mkdtempSync` line and the cleanup are untouched; #22416 owns
them. #22416 has not landed, and the two merge cleanly.
- **M4** now carries the toggle-gate measurement (46 pins).
- **Q2** answered A. **Q1** answered C by triage (S5 carries it).
Nothing changes for either in this round.
## Patch round 2
The contract review found one published sentence this PR made false: the
"Runtime OWD posture gate" bullet in
`content/docs/permissions/authorization.mdx` (about lines 480-486). At
this head, an environment overlay of a packaged object is refused `403
NOT_OVERRIDABLE` in both directions, hatch open or shut;
`packages/rest/src/meta-object-owd-gate.test.ts` pins exactly that. The
page was declared to `domain:devx` on #6023. Only that sentence changed
(commit `09eff73814`); nothing else on the page, and no code or test.
Before:
```text
An environment overlay of a
**packaged** object may only *tighten* `sharingModel` /
`externalSharingModel`, never widen them beyond the packaged declaration
(`403 owd_widening_forbidden` — widen it in the package source and
publish instead; this closes the `OS_METADATA_WRITABLE=object` escape
hatch as an unvalidated widening path, ADR-0086 D1).
```
After:
```text
An environment overlay of a
**packaged** object is refused outright, whether it tightens or widens
`sharingModel` / `externalSharingModel`, and with `OS_METADATA_WRITABLE`
set or not (`403 NOT_OVERRIDABLE` — managed content is sealed, ADR-0131
D6): change the posture in the package source and publish instead. The
package door answers ahead of this gate, so its packaged-baseline rule
(`403 owd_widening_forbidden`, ADR-0086 D1) is not reached through the
metadata API.
```
The route named is the one the bullet already used, and the one the page
names for packaged permission sets: change the package source and
publish. An object has no linkage-free clone. The bullet's other
sentences are unchanged and still true: the gate is registered on the
seam, the write path only is gated, and R2 is retired.
Gates at `09eff73814`. `dispatch-gates --commands`, run with no paths,
derives 110 commands: round 1's 109 plus `check:merge-driver`. All 110
exit 0, and `--ran` reconciles 110 derived, 110 run, 0 NOT-MEASURED, 0
UNRUN. That set includes every docs family:
- `check-doc-frontmatter` and its self-test;
- `check:doc-authoring` and `check:doc-anchors`;
- `check:docs-redirects`, `check:docs-single-h1`,
`check:docs-audit-scope`, `check:docs-transcript-drift` and
`check:docs-spec-enumerations`;
- `check-affected-docs` and `check:published-readme-links`.
Outside the derived set, `check:docs-locale-catch-all`,
`check:docs-image-tag`, `check:docs-image-tag-sync` and
`check:adr-links` also exit 0. #22416 has since landed on `main`. `git
merge-tree` of this head against `main` `27a8b33dec`, which contains it,
exits 0.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01EUBvqtauTDmHi2ZgY759p2)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent c64130b commit e02833c
33 files changed
Lines changed: 1680 additions & 664 deletions
File tree
- .changeset
- content/docs
- deployment
- permissions
- packages
- metadata-protocol/src
- objectql/src
- plugins/plugin-security/src
- qa/dogfood/test
- rest/src
- runtime/src
- domains
- scripts
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
306 | 306 | | |
307 | 307 | | |
308 | 308 | | |
309 | | - | |
| 309 | + | |
310 | 310 | | |
311 | 311 | | |
312 | 312 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
479 | 479 | | |
480 | 480 | | |
481 | 481 | | |
482 | | - | |
483 | | - | |
484 | | - | |
485 | | - | |
486 | | - | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
487 | 489 | | |
488 | 490 | | |
489 | 491 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
99 | 112 | | |
100 | 113 | | |
101 | 114 | | |
| |||
262 | 275 | | |
263 | 276 | | |
264 | 277 | | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | | - | |
269 | | - | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
270 | 284 | | |
271 | 285 | | |
272 | 286 | | |
273 | | - | |
274 | | - | |
275 | | - | |
276 | | - | |
277 | | - | |
278 | | - | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
279 | 292 | | |
280 | 293 | | |
281 | 294 | | |
| |||
286 | 299 | | |
287 | 300 | | |
288 | 301 | | |
289 | | - | |
| 302 | + | |
290 | 303 | | |
291 | 304 | | |
292 | 305 | | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
Lines changed: 18 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
372 | 372 | | |
373 | 373 | | |
374 | 374 | | |
375 | | - | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
376 | 381 | | |
377 | 382 | | |
378 | 383 | | |
379 | 384 | | |
380 | | - | |
381 | | - | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
382 | 397 | | |
383 | 398 | | |
384 | 399 | | |
| |||
0 commit comments