matelab-python-sdk 0.1.0a19__tar.gz → 0.1.0a21__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/CHANGELOG.md +25 -0
  2. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/PKG-INFO +27 -19
  3. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/README.md +26 -18
  4. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/contracts/matelab-integration-v1.lock.json +3 -3
  5. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/contracts/matelab-integration-v1.openapi.yaml +97 -85
  6. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/docs/operation-coverage.yaml +5 -5
  7. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/pyproject.toml +1 -1
  8. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/_generated/models.py +156 -49
  9. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/records.py +1 -7
  10. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_generation.py +164 -5
  11. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_operation_coverage.py +1 -1
  12. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_record_mutations.py +16 -8
  13. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_records.py +104 -13
  14. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/uv.lock +1 -1
  15. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/.env.example +0 -0
  16. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/.github/workflows/release.yml +0 -0
  17. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/.gitignore +0 -0
  18. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/AGENTS.md +0 -0
  19. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/CONTEXT.md +0 -0
  20. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/LICENSE +0 -0
  21. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/NOTICE +0 -0
  22. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/scripts/check_installed_package.py +0 -0
  23. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/scripts/check_release.py +0 -0
  24. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/scripts/generate_models.py +0 -0
  25. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/__init__.py +0 -0
  26. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/_generated/__init__.py +0 -0
  27. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/_hashes.py +0 -0
  28. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/_transport.py +0 -0
  29. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/_wire_validation.py +0 -0
  30. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/client.py +0 -0
  31. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/__init__.py +0 -0
  32. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/_attachment_content.py +0 -0
  33. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/cloud_drive.py +0 -0
  34. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/groups.py +0 -0
  35. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/literature.py +0 -0
  36. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/notebooks.py +0 -0
  37. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/templates.py +0 -0
  38. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/uploads.py +0 -0
  39. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/domains/users.py +0 -0
  40. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/errors.py +0 -0
  41. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/py.typed +0 -0
  42. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/session.py +0 -0
  43. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/src/matelab/streaming.py +0 -0
  44. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/conftest.py +0 -0
  45. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/provider/test_provider_smoke.py +0 -0
  46. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_async_attachment_upload.py +0 -0
  47. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_client.py +0 -0
  48. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_cloud_drive.py +0 -0
  49. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_comments_and_downloads.py +0 -0
  50. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_consumer_smoke.py +0 -0
  51. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_errors.py +0 -0
  52. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_extended_records.py +0 -0
  53. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_groups.py +0 -0
  54. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_notebook_lifecycle.py +0 -0
  55. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_notebooks.py +0 -0
  56. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_record_lifecycle.py +0 -0
  57. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_release.py +0 -0
  58. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_streaming.py +0 -0
  59. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_template_lifecycle.py +0 -0
  60. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_templates.py +0 -0
  61. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_transport.py +0 -0
  62. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_uploads_and_literature.py +0 -0
  63. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/test_users.py +0 -0
  64. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/typing/consumer.py +0 -0
  65. {matelab_python_sdk-0.1.0a19 → matelab_python_sdk-0.1.0a21}/tests/typing/pyproject.toml +0 -0
@@ -3,6 +3,31 @@
3
3
  This file records release-to-release changes and migration impact. It is not the authority for the current interface;
4
4
  see [README.md](README.md) for current behavior and [AGENTS.md](AGENTS.md) for maintenance policy.
5
5
 
6
+ ## 0.1.0a21 - 2026-08-28
7
+
8
+ - Adopts immutable `matelab-spec v0.4.4` at commit `be070c5f931b2063327a3beaccc53a360204b64e` and OpenAPI
9
+ SHA-256 `2de38e46d3814b8b049af8afd18e85fb20be6ca29cc409390d25df663abc43f9`, aligned with Provider evidence
10
+ `7bd9704286057653632424fa82f413d99cd69ab6`.
11
+ - Accepts the required nullable `readRecord.datetime_locked` wire field for current unlocked records and follows the
12
+ unexposed `/actions/app` rename to `readApplicationBootstrap`; SDK Session identity remains sourced from token issuance.
13
+ - Keeps `RecordFilesAttachmentAppend` root-only. The release describes a safe optional folder path in its dedicated
14
+ staged-name append schema, but `UpdateRecordRequest.add[]` still references `AddValueOperation`, which forbids that
15
+ `path`;
16
+ exposing it would require bypassing whole-request Contract validation. PVD-044 also records that malformed path
17
+ containers can silently append at root.
18
+
19
+ ## 0.1.0a20 - 2026-08-24
20
+
21
+ - Adopts immutable `matelab-spec v0.4.3` at commit `7965ac9803505ae35dc5ce36f52afc3c2c133c45` and OpenAPI
22
+ SHA-256 `6576812dd13f92ad58131f4edb8dc919d1b1fe0f19a695c2d25fbe6d13a8445b`, aligned with Provider evidence
23
+ `a3e6b961800f6b1ab666f0d3f6cd4c64c2a3ce27`.
24
+ - Breaking: tightens record readback to one canonical attachment object or `null` per table file cell, removing the
25
+ obsolete attachment-array compatibility path. Template decoding now accepts nullable JSON-code data and preserves
26
+ empty-string number/boolean cells alongside their scalar and null forms.
27
+ - Records PVD-046 while keeping `templates.save_content()` deliberately narrower than the Provider: the request remains
28
+ a canonical module list, and every table file cell remains one canonical attachment object or `null`, never an
29
+ arbitrary or multi-attachment array.
30
+
6
31
  ## 0.1.0a19 - 2026-08-23
7
32
 
8
33
  - Re-adopts the force-rewritten `matelab-spec v0.4.2` at commit
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matelab-python-sdk
3
- Version: 0.1.0a19
3
+ Version: 0.1.0a21
4
4
  Summary: Reusable async Python client for the Matelab Integration Contract
5
5
  Author-email: 朱天念 <zhutiannian@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -35,10 +35,10 @@ This README describes the current SDK interface, integration semantics, examples
35
35
  [AGENTS.md](AGENTS.md) for durable maintenance rules, and `docs/operation-coverage.yaml` for the machine-readable
36
36
  operation inventory.
37
37
 
38
- The current alpha is `0.1.0a19`. `[project].version` in `pyproject.toml` is the sole SDK version source;
38
+ The current alpha is `0.1.0a21`. `[project].version` in `pyproject.toml` is the sole SDK version source;
39
39
  `uv.lock` only mirrors that source.
40
40
 
41
- The SDK is pinned to the rewritten `matelab-spec v0.4.2` Contract Release. The sole release pin is
41
+ The SDK is pinned to the immutable `matelab-spec v0.4.4` Contract Release. The sole release pin is
42
42
  `contracts/matelab-integration-v1.lock.json`, which records
43
43
  the source tag, commit, OpenAPI path, local snapshot path, and SHA-256.
44
44
 
@@ -64,14 +64,14 @@ To test the same artifact a downstream Consumer will install, build and install
64
64
 
65
65
  ```bash
66
66
  uv build --no-build-isolation --out-dir dist/release
67
- python -m pip install dist/release/matelab_python_sdk-0.1.0a19-py3-none-any.whl
67
+ python -m pip install dist/release/matelab_python_sdk-0.1.0a21-py3-none-any.whl
68
68
  ```
69
69
 
70
70
  Do not infer Provider compatibility from the SDK version alone. A release is also bound to the Contract
71
71
  tag, commit, and checksum recorded below.
72
72
 
73
73
  The Contract and public SDK interface track the current reviewed Provider at
74
- `a3e6b961800f6b1ab666f0d3f6cd4c64c2a3ce27`. Provider limitations that remain relevant to integrations are documented
74
+ `7bd9704286057653632424fa82f413d99cd69ab6`. Provider limitations that remain relevant to integrations are documented
75
75
  alongside the affected interfaces below.
76
76
 
77
77
  ## Design
@@ -121,7 +121,7 @@ success code it does not allow raises `MatelabProtocolError` rather than assigni
121
121
  `MatelabTransportError.status_code` remains available for HTTP failures. Provider response bodies, top-level `msg`,
122
122
  legacy `errmsg`, opaque `errs`, uncontracted debug fields, and request payloads are not attached to exceptions because
123
123
  Provider-authored diagnostics may contain stack traces, credentials, or submitted values.
124
- The pinned v0.4.2 Contract also declares optional code-4 `errs`, but PVD-041 and PCG-015 record opaque array/object
124
+ The pinned v0.4.4 Contract also declares optional code-4 `errs`, but PVD-041 and PCG-015 record opaque array/object
125
125
  containers and insufficient evidence for requiredness, cardinality, or exclusion from other codes. The SDK
126
126
  therefore keeps those diagnostics wire-only and does not expose `errs` as stable public metadata. A typed detail
127
127
  interface remains blocked until a future Contract release can define one from stronger Provider evidence. `retryable`
@@ -316,8 +316,10 @@ supports one file column. A locally rejected target does not spend the handle; o
316
316
  result cannot be retried through the same client.
317
317
 
318
318
  Files-module append and table/files replacement use the general record attachment intents and may be combined with
319
- other non-conflicting record changes. `RecordFilesAttachmentAppend` targets the module root; the current Provider does
320
- not accept a files-folder path (PVD-044):
319
+ other non-conflicting record changes. `RecordFilesAttachmentAppend` currently targets the module root. Although
320
+ v0.4.4 records Provider evidence for safe folder paths, its top-level `UpdateRecordRequest.add[]` schema still excludes
321
+ the `path` property declared by the dedicated staged-name append shape; the SDK therefore does not expose folder paths
322
+ until that wire-schema conflict is resolved (PVD-044):
321
323
 
322
324
  ```python
323
325
  from matelab import RecordAttachmentReplacement, RecordFilesAttachmentAppend, RecordValueUpdate
@@ -348,7 +350,9 @@ await client.records.update(
348
350
 
349
351
  For a files occurrence, `caption=None` preserves the observed string caption (an observed null caption normalizes to
350
352
  the required empty string). Table replacement requires exactly one current attachment in the selected cell and does
351
- not accept a caption. Both forms require the replacement hash to differ from the current occurrence.
353
+ not accept a caption. Record reads likewise accept only one canonical attachment object or `null` in a table file cell;
354
+ an attachment array violates the pinned response contract. Both replacement forms require the replacement hash to
355
+ differ from the current occurrence.
352
356
 
353
357
  All record attachment intents reject handles from another notebook or authenticated uploader, duplicate use within one
354
358
  finalization request, and raw Provider attachment references. Row/index-based operations use an immediate SDK read and
@@ -425,8 +429,8 @@ and `deletePersonalLiteratureItem`.
425
429
 
426
430
  Every other implemented operation is explicitly `experimental`; the exact per-operation list and its
427
431
  PVD/PCG references live in
428
- `docs/operation-coverage.yaml`. `resolveCurrentIdentity` is intentionally unexposed because the SDK accepts only
429
- complete, integration-validated Sessions and does not bind bare external token pairs. `readLiteratureCreateTemplate`
432
+ `docs/operation-coverage.yaml`. `readApplicationBootstrap` is intentionally unexposed because it returns the Provider
433
+ application environment and menu model, while SDK identity is sourced from token issuance. `readLiteratureCreateTemplate`
430
434
  is intentionally unexposed because it returns a frontend form definition and an optional deployment flag rather than
431
435
  a resource needed by the SDK interface. There are no `planned` operations. Experimental support means the SDK
432
436
  validates and exposes the pinned Contract while preserving limitations such as unstable ordering/pagination,
@@ -500,9 +504,12 @@ await client.templates.save_content(template, modules)
500
504
  `TemplateModule.data_present` distinguishes a missing `data` property from an explicit null value, while
501
505
  `attributes` prevents additive canonical properties from being dropped during a read/save cycle. The SDK does not
502
506
  synthesize frontend editor UIDs, layout widths, rows, folders, option encoding, or a fixed set of display module
503
- types. The Provider supports only whole-content replacement and has no atomic patch or compare-and-swap operation
504
- (PCG-007), so
505
- a read-modify-save sequence can overwrite a concurrent change.
507
+ types. A JSON-language code module with style metadata may return its JSON string or explicit `null`; number and boolean
508
+ table cells preserve the Provider's empty string as distinct from scalar and `null` values. The Provider accepts some
509
+ non-canonical module roots and arbitrary table file arrays, but the SDK does not expose that behavior: saved content
510
+ must remain a canonical module list, and a table file cell must be one canonical attachment object or `null` (PVD-046).
511
+ The Provider supports only whole-content replacement and has no atomic patch or compare-and-swap operation (PCG-007),
512
+ so a read-modify-save sequence can overwrite a concurrent change.
506
513
 
507
514
  The market result retains the Provider's `total_count` and derives `has_more` without echoing the caller's page
508
515
  arguments; it does not claim a stable order or continuation token. Template reads remain experimental
@@ -613,8 +620,9 @@ returns the acknowledgement classification
613
620
  issue a post-write read. Database, active-browser, and unclassified acknowledgements remain distinct, and mutation
614
621
  retries stay disabled. Encrypted record content is outside the SDK's public read/update interface: the list-level
615
622
  `RecordSummary.encrypted` flag lets callers identify and skip it, while the Provider password field and frontend-only
616
- password lifecycle remain unexposed. Files-module attachment append is root-only because the current Provider rejects
617
- folder-path segments (PVD-044). A staged attachment is indeterminate once the write has started.
623
+ password lifecycle remain unexposed. Files-module attachment append remains root-only because the pinned top-level
624
+ update request schema does not admit the dedicated staged-name append shape's folder `path`; malformed path containers
625
+ may also silently append at root according to PVD-044. A staged attachment is indeterminate once the write has started.
618
626
 
619
627
  Relation addition reads both endpoints and checks their resolved data server before writing; this reduces PVD-019
620
628
  risk but is not an atomic Provider authorization guarantee. It does not list relations merely to inspect the
@@ -912,6 +920,6 @@ uv run python scripts/check_release.py dist/release/*.whl dist/release/*.tar.gz
912
920
  ```
913
921
 
914
922
  Rebuilding the same commit with the same locked environment and `SOURCE_DATE_EPOCH` must produce
915
- byte-identical wheel and source distribution hashes. The release is bound to the rewritten `matelab-spec v0.4.2`,
916
- commit `1a4b77721d782fccd2b1f26bcc16a7d876347686`, and OpenAPI SHA-256
917
- `1e737421aac636356487122ea89e20d54de07c8b9c0651cf6970a7123fe3b72b`.
923
+ byte-identical wheel and source distribution hashes. The release is bound to immutable `matelab-spec v0.4.4`, commit
924
+ `be070c5f931b2063327a3beaccc53a360204b64e`, and OpenAPI SHA-256
925
+ `2de38e46d3814b8b049af8afd18e85fb20be6ca29cc409390d25df663abc43f9`.
@@ -7,10 +7,10 @@ This README describes the current SDK interface, integration semantics, examples
7
7
  [AGENTS.md](AGENTS.md) for durable maintenance rules, and `docs/operation-coverage.yaml` for the machine-readable
8
8
  operation inventory.
9
9
 
10
- The current alpha is `0.1.0a19`. `[project].version` in `pyproject.toml` is the sole SDK version source;
10
+ The current alpha is `0.1.0a21`. `[project].version` in `pyproject.toml` is the sole SDK version source;
11
11
  `uv.lock` only mirrors that source.
12
12
 
13
- The SDK is pinned to the rewritten `matelab-spec v0.4.2` Contract Release. The sole release pin is
13
+ The SDK is pinned to the immutable `matelab-spec v0.4.4` Contract Release. The sole release pin is
14
14
  `contracts/matelab-integration-v1.lock.json`, which records
15
15
  the source tag, commit, OpenAPI path, local snapshot path, and SHA-256.
16
16
 
@@ -36,14 +36,14 @@ To test the same artifact a downstream Consumer will install, build and install
36
36
 
37
37
  ```bash
38
38
  uv build --no-build-isolation --out-dir dist/release
39
- python -m pip install dist/release/matelab_python_sdk-0.1.0a19-py3-none-any.whl
39
+ python -m pip install dist/release/matelab_python_sdk-0.1.0a21-py3-none-any.whl
40
40
  ```
41
41
 
42
42
  Do not infer Provider compatibility from the SDK version alone. A release is also bound to the Contract
43
43
  tag, commit, and checksum recorded below.
44
44
 
45
45
  The Contract and public SDK interface track the current reviewed Provider at
46
- `a3e6b961800f6b1ab666f0d3f6cd4c64c2a3ce27`. Provider limitations that remain relevant to integrations are documented
46
+ `7bd9704286057653632424fa82f413d99cd69ab6`. Provider limitations that remain relevant to integrations are documented
47
47
  alongside the affected interfaces below.
48
48
 
49
49
  ## Design
@@ -93,7 +93,7 @@ success code it does not allow raises `MatelabProtocolError` rather than assigni
93
93
  `MatelabTransportError.status_code` remains available for HTTP failures. Provider response bodies, top-level `msg`,
94
94
  legacy `errmsg`, opaque `errs`, uncontracted debug fields, and request payloads are not attached to exceptions because
95
95
  Provider-authored diagnostics may contain stack traces, credentials, or submitted values.
96
- The pinned v0.4.2 Contract also declares optional code-4 `errs`, but PVD-041 and PCG-015 record opaque array/object
96
+ The pinned v0.4.4 Contract also declares optional code-4 `errs`, but PVD-041 and PCG-015 record opaque array/object
97
97
  containers and insufficient evidence for requiredness, cardinality, or exclusion from other codes. The SDK
98
98
  therefore keeps those diagnostics wire-only and does not expose `errs` as stable public metadata. A typed detail
99
99
  interface remains blocked until a future Contract release can define one from stronger Provider evidence. `retryable`
@@ -288,8 +288,10 @@ supports one file column. A locally rejected target does not spend the handle; o
288
288
  result cannot be retried through the same client.
289
289
 
290
290
  Files-module append and table/files replacement use the general record attachment intents and may be combined with
291
- other non-conflicting record changes. `RecordFilesAttachmentAppend` targets the module root; the current Provider does
292
- not accept a files-folder path (PVD-044):
291
+ other non-conflicting record changes. `RecordFilesAttachmentAppend` currently targets the module root. Although
292
+ v0.4.4 records Provider evidence for safe folder paths, its top-level `UpdateRecordRequest.add[]` schema still excludes
293
+ the `path` property declared by the dedicated staged-name append shape; the SDK therefore does not expose folder paths
294
+ until that wire-schema conflict is resolved (PVD-044):
293
295
 
294
296
  ```python
295
297
  from matelab import RecordAttachmentReplacement, RecordFilesAttachmentAppend, RecordValueUpdate
@@ -320,7 +322,9 @@ await client.records.update(
320
322
 
321
323
  For a files occurrence, `caption=None` preserves the observed string caption (an observed null caption normalizes to
322
324
  the required empty string). Table replacement requires exactly one current attachment in the selected cell and does
323
- not accept a caption. Both forms require the replacement hash to differ from the current occurrence.
325
+ not accept a caption. Record reads likewise accept only one canonical attachment object or `null` in a table file cell;
326
+ an attachment array violates the pinned response contract. Both replacement forms require the replacement hash to
327
+ differ from the current occurrence.
324
328
 
325
329
  All record attachment intents reject handles from another notebook or authenticated uploader, duplicate use within one
326
330
  finalization request, and raw Provider attachment references. Row/index-based operations use an immediate SDK read and
@@ -397,8 +401,8 @@ and `deletePersonalLiteratureItem`.
397
401
 
398
402
  Every other implemented operation is explicitly `experimental`; the exact per-operation list and its
399
403
  PVD/PCG references live in
400
- `docs/operation-coverage.yaml`. `resolveCurrentIdentity` is intentionally unexposed because the SDK accepts only
401
- complete, integration-validated Sessions and does not bind bare external token pairs. `readLiteratureCreateTemplate`
404
+ `docs/operation-coverage.yaml`. `readApplicationBootstrap` is intentionally unexposed because it returns the Provider
405
+ application environment and menu model, while SDK identity is sourced from token issuance. `readLiteratureCreateTemplate`
402
406
  is intentionally unexposed because it returns a frontend form definition and an optional deployment flag rather than
403
407
  a resource needed by the SDK interface. There are no `planned` operations. Experimental support means the SDK
404
408
  validates and exposes the pinned Contract while preserving limitations such as unstable ordering/pagination,
@@ -472,9 +476,12 @@ await client.templates.save_content(template, modules)
472
476
  `TemplateModule.data_present` distinguishes a missing `data` property from an explicit null value, while
473
477
  `attributes` prevents additive canonical properties from being dropped during a read/save cycle. The SDK does not
474
478
  synthesize frontend editor UIDs, layout widths, rows, folders, option encoding, or a fixed set of display module
475
- types. The Provider supports only whole-content replacement and has no atomic patch or compare-and-swap operation
476
- (PCG-007), so
477
- a read-modify-save sequence can overwrite a concurrent change.
479
+ types. A JSON-language code module with style metadata may return its JSON string or explicit `null`; number and boolean
480
+ table cells preserve the Provider's empty string as distinct from scalar and `null` values. The Provider accepts some
481
+ non-canonical module roots and arbitrary table file arrays, but the SDK does not expose that behavior: saved content
482
+ must remain a canonical module list, and a table file cell must be one canonical attachment object or `null` (PVD-046).
483
+ The Provider supports only whole-content replacement and has no atomic patch or compare-and-swap operation (PCG-007),
484
+ so a read-modify-save sequence can overwrite a concurrent change.
478
485
 
479
486
  The market result retains the Provider's `total_count` and derives `has_more` without echoing the caller's page
480
487
  arguments; it does not claim a stable order or continuation token. Template reads remain experimental
@@ -585,8 +592,9 @@ returns the acknowledgement classification
585
592
  issue a post-write read. Database, active-browser, and unclassified acknowledgements remain distinct, and mutation
586
593
  retries stay disabled. Encrypted record content is outside the SDK's public read/update interface: the list-level
587
594
  `RecordSummary.encrypted` flag lets callers identify and skip it, while the Provider password field and frontend-only
588
- password lifecycle remain unexposed. Files-module attachment append is root-only because the current Provider rejects
589
- folder-path segments (PVD-044). A staged attachment is indeterminate once the write has started.
595
+ password lifecycle remain unexposed. Files-module attachment append remains root-only because the pinned top-level
596
+ update request schema does not admit the dedicated staged-name append shape's folder `path`; malformed path containers
597
+ may also silently append at root according to PVD-044. A staged attachment is indeterminate once the write has started.
590
598
 
591
599
  Relation addition reads both endpoints and checks their resolved data server before writing; this reduces PVD-019
592
600
  risk but is not an atomic Provider authorization guarantee. It does not list relations merely to inspect the
@@ -884,6 +892,6 @@ uv run python scripts/check_release.py dist/release/*.whl dist/release/*.tar.gz
884
892
  ```
885
893
 
886
894
  Rebuilding the same commit with the same locked environment and `SOURCE_DATE_EPOCH` must produce
887
- byte-identical wheel and source distribution hashes. The release is bound to the rewritten `matelab-spec v0.4.2`,
888
- commit `1a4b77721d782fccd2b1f26bcc16a7d876347686`, and OpenAPI SHA-256
889
- `1e737421aac636356487122ea89e20d54de07c8b9c0651cf6970a7123fe3b72b`.
895
+ byte-identical wheel and source distribution hashes. The release is bound to immutable `matelab-spec v0.4.4`, commit
896
+ `be070c5f931b2063327a3beaccc53a360204b64e`, and OpenAPI SHA-256
897
+ `2de38e46d3814b8b049af8afd18e85fb20be6ca29cc409390d25df663abc43f9`.
@@ -2,12 +2,12 @@
2
2
  "schema_version": 1,
3
3
  "contract_line": "integration-v1",
4
4
  "release": {
5
- "tag": "v0.4.2",
6
- "commit": "1a4b77721d782fccd2b1f26bcc16a7d876347686"
5
+ "tag": "v0.4.4",
6
+ "commit": "be070c5f931b2063327a3beaccc53a360204b64e"
7
7
  },
8
8
  "openapi": {
9
9
  "source_path": "openapi/matelab-integration-v1.openapi.yaml",
10
10
  "snapshot": "matelab-integration-v1.openapi.yaml",
11
- "sha256": "1e737421aac636356487122ea89e20d54de07c8b9c0651cf6970a7123fe3b72b"
11
+ "sha256": "2de38e46d3814b8b049af8afd18e85fb20be6ca29cc409390d25df663abc43f9"
12
12
  }
13
13
  }
@@ -1,7 +1,7 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
3
  title: Matelab Integration Contract
4
- version: 0.4.2
4
+ version: 0.4.4
5
5
  description: |
6
6
  Current PHP wire contract for generating SDKs against the selected
7
7
  `matelab-server` Provider version.
@@ -9,7 +9,7 @@ info:
9
9
  x-contract-line: integration-v1
10
10
  x-provider-evidence:
11
11
  repository: /home/tnzhu/projects/matelab-server
12
- commit: a3e6b961800f6b1ab666f0d3f6cd4c64c2a3ce27
12
+ commit: 7bd9704286057653632424fa82f413d99cd69ab6
13
13
  files:
14
14
  - controller/Actions.php
15
15
  - controller/Tokens.php
@@ -39,8 +39,8 @@ info:
39
39
  - sql/matelab.sql
40
40
  - sql/recommend.sql
41
41
  x-provider-audit:
42
- currentCommit: a3e6b961800f6b1ab666f0d3f6cd4c64c2a3ce27
43
- previousReleaseEvidenceCommit: 59101f006e9fd6d6ce0b951dfd34695a7949b54f
42
+ currentCommit: 7bd9704286057653632424fa82f413d99cd69ab6
43
+ previousReleaseEvidenceCommit: a3e6b961800f6b1ab666f0d3f6cd4c64c2a3ce27
44
44
  contractStatus: current-provider-aligned
45
45
  incorporatedChanges:
46
46
  - {operationId: stageTemporaryFile, change: staging-identifiers-expanded-to-100}
@@ -49,7 +49,13 @@ info:
49
49
  - {operationId: importRecordDataset, change: explicit-null-table-file-cells-rejected}
50
50
  - {operationId: extractLiteratureMetadata, change: doi-format-validated-before-extraction}
51
51
  - {operationId: searchRecordData, change: encrypted-records-excluded}
52
- - {operationId: updateRecordData, change: files-folder-path-removed-from-callable-shape}
52
+ - {operationId: updateRecordData, change: safe-files-folder-path-restored-to-callable-shape}
53
+ - {operationId: readApplicationBootstrap, change: identity-and-notifications-moved-out-of-app-response}
54
+ - {operationId: readRecord, change: table-file-cell-readback-modeled-as-attachment-object-or-null}
55
+ - {operationId: readRecord, change: current-unlocked-datetime-locked-may-be-null}
56
+ - {operationId: readTemplateContent, change: json-code-null-readback-accepted}
57
+ - {operationId: saveTemplateContent, change: empty-number-and-boolean-cells-preserved}
58
+ - {operationId: saveTemplateContent, change: noncanonical-module-structures-contract-contained}
53
59
  x-consumer-evidence:
54
60
  - repository: /home/tnzhu/projects/matelab-mcp
55
61
  commit: 94a129b2df0ef0fbcf179c10550fb7c9a5dd2e6f
@@ -64,8 +70,11 @@ info:
64
70
  record and currently resolves its private staging state through a
65
71
  native `#hash` reference.
66
72
 
67
- The MCP identity, ELN-group list, and notebook-list calls currently use
68
- non-contract POST and must migrate to GET.
73
+ At this recorded MCP commit, identity resolution used a non-contract
74
+ POST to `/actions/app`. The current Provider removed identity from that
75
+ response, so this historical call cannot define current wire; session
76
+ identity must come from token issuance. ELN-group and notebook-list
77
+ calls still provide Consumer evidence for their canonical GET forms.
69
78
  - repository: /home/tnzhu/projects/matelab-front
70
79
  commit: 3c356731e883f6035fc4b475b84982739bba4095
71
80
  files:
@@ -81,6 +90,11 @@ info:
81
90
  - src/views/recommend/fav.vue
82
91
  - src/views/recommend/favDetail.vue
83
92
  - src/views/recommend/favItems.vue
93
+ note: |
94
+ This Front commit reads environment/menu and identity/notifications
95
+ from `/actions/app`. The current Provider moved the latter fields out
96
+ of that route; only the still-callable application-bootstrap use case
97
+ defines the current `/actions/app` contract.
84
98
  x-record-attachment-staging:
85
99
  status: contract-contained
86
100
  producerOperationId: uploadRecordAttachment
@@ -128,8 +142,8 @@ info:
128
142
  operationArrays: [add]
129
143
  attachmentOperationSchema:
130
144
  $ref: "#/components/schemas/AppendFilesModuleStagedAttachmentOperation"
131
- folderPath: omitted
132
- readback: one-new-canonical-files-entry
145
+ folderPath: optional-non-empty-safe-segments
146
+ readback: one-new-canonical-files-entry-at-root-or-resolved-folder
133
147
  tableFileCellReplacement:
134
148
  operationArrays: [modify]
135
149
  attachmentOperationSchema:
@@ -223,15 +237,15 @@ tags:
223
237
  paths:
224
238
  /actions/app:
225
239
  get:
226
- operationId: resolveCurrentIdentity
240
+ operationId: readApplicationBootstrap
227
241
  tags: [Authentication]
228
- summary: Resolve the authenticated Matelab identity and application environment
242
+ summary: Read the authenticated Matelab application bootstrap
229
243
  description: |
230
- Read-only application bootstrap used by Matelab Front and the only
231
- `/actions/app` method in integration-v1. The MCP
232
- consumer uses `user.userid`, `user.username`, and required-nullable
233
- `user.email`; the remaining fields drive the Provider UI and are retained
234
- because they are part of the PHP wire response.
244
+ Read-only environment, product-name, AI and menu bootstrap used by
245
+ Matelab Front and the only `/actions/app` method in integration-v1.
246
+ The current Provider no longer returns `user` or `notifications` from
247
+ this route; authenticated identity is available from token issuance
248
+ flows and is not inferred from this response.
235
249
  security:
236
250
  - bearerAuth: []
237
251
  responses:
@@ -241,22 +255,16 @@ paths:
241
255
  application/json:
242
256
  schema:
243
257
  oneOf:
244
- - $ref: "#/components/schemas/AppIdentityResponse"
258
+ - $ref: "#/components/schemas/AppBootstrapResponse"
245
259
  - $ref: "#/components/schemas/ErrorResponse"
246
260
  examples:
247
261
  success:
248
- summary: Authenticated identity with no unread notifications
262
+ summary: Application bootstrap with enabled ELN navigation
249
263
  value:
250
264
  code: 0
251
265
  msg: ""
252
266
  errcode: 0
253
267
  errmsg: ""
254
- user:
255
- username: Example User
256
- avatar: null
257
- email: user@example.invalid
258
- userid: 101
259
- notifications: []
260
268
  env:
261
269
  ai: false
262
270
  smtp: true
@@ -288,22 +296,12 @@ paths:
288
296
  url: /db/eln
289
297
  order: 1
290
298
  nullable:
291
- summary: Identity fields backed by nullable user columns
299
+ summary: Application bootstrap with no licensed institute features
292
300
  value:
293
301
  code: 0
294
302
  msg: ""
295
303
  errcode: 0
296
304
  errmsg: ""
297
- user:
298
- username: null
299
- avatar: null
300
- email: null
301
- userid: 102
302
- notifications:
303
- - id: 501
304
- showtext: null
305
- datetime_add: "2026-01-02 08:00:00"
306
- datetime: "2026-01-02 08:00"
307
305
  env:
308
306
  ai: false
309
307
  smtp: false
@@ -827,6 +825,7 @@ paths:
827
825
  operationId: saveTemplateContent
828
826
  tags: [Templates]
829
827
  summary: Replace canonical modules for an owned template
828
+ x-known-provider-issues: [PVD-046]
830
829
  security: [{bearerAuth: []}]
831
830
  requestBody:
832
831
  required: true
@@ -1688,8 +1687,10 @@ paths:
1688
1687
  or replacing an exact table file cell, appending a table row and
1689
1688
  setting its file cell in the same request, appending one root files
1690
1689
  entry, and replacing one files entry by an immediately read index.
1691
- Files-module folder `path` is not part of the callable request shape
1692
- because the current Provider rejects valid path segments under PVD-044.
1690
+ Files-module folder `path` accepts a non-empty list of safe folder-name
1691
+ segments. PVD-044 remains because malformed or empty path containers are
1692
+ not reliably rejected by the Provider; those shapes stay outside the
1693
+ callable request schema.
1693
1694
  Form-file replacement remains unsafe under PVD-014. Richtext only
1694
1695
  recognizes hash-bearing `elnurl://` references; `#file{name}` is plain
1695
1696
  text there, while the hash path can fall back to an existing quote and
@@ -2541,6 +2542,19 @@ paths:
2541
2542
  name: Notes
2542
2543
  uid: module-example
2543
2544
  data: Sanitized content
2545
+ - type: table
2546
+ name: Measurements
2547
+ uid: table-example
2548
+ rows: [row-example]
2549
+ data:
2550
+ - type: file
2551
+ name: Evidence
2552
+ uid: column-example
2553
+ data:
2554
+ - filename: evidence.txt
2555
+ hash: 74034daeef860e12596c34f7e83703e668d578f4a85e72ec1645117223d4e6a7
2556
+ size: 26
2557
+ timestamp: 1767946200000
2544
2558
  template_id: 8
2545
2559
  datetime_modify: 1767946200000
2546
2560
  username: Example User
@@ -2554,7 +2568,7 @@ paths:
2554
2568
  uid: REC-EXAMPLE-001
2555
2569
  current_version: 70001
2556
2570
  item_id: 9001
2557
- datetime_locked: 0
2571
+ datetime_locked: null
2558
2572
  locked: false
2559
2573
  signs: []
2560
2574
  signed: false
@@ -4450,13 +4464,11 @@ components:
4450
4464
  filename: {type: string, minLength: 1}
4451
4465
  size: {type: integer, minimum: 0}
4452
4466
  hash: {$ref: "#/components/schemas/Sha256"}
4453
- AppIdentityResponse:
4467
+ AppBootstrapResponse:
4454
4468
  allOf:
4455
4469
  - $ref: "#/components/schemas/ResponseEnvelope"
4456
4470
  - type: object
4457
4471
  required:
4458
- - user
4459
- - notifications
4460
4472
  - env
4461
4473
  - ai_enable
4462
4474
  - ai_text
@@ -4470,13 +4482,6 @@ components:
4470
4482
  const: 0
4471
4483
  errcode:
4472
4484
  const: 0
4473
- user:
4474
- $ref: "#/components/schemas/AppUser"
4475
- notifications:
4476
- type: array
4477
- maxItems: 5
4478
- items:
4479
- $ref: "#/components/schemas/AppNotification"
4480
4485
  env:
4481
4486
  $ref: "#/components/schemas/AppEnvironment"
4482
4487
  ai_enable:
@@ -4498,36 +4503,6 @@ components:
4498
4503
  type: array
4499
4504
  items:
4500
4505
  $ref: "#/components/schemas/AppMenu"
4501
- AppUser:
4502
- type: object
4503
- required: [username, avatar, email, userid]
4504
- properties:
4505
- username:
4506
- type: [string, "null"]
4507
- description: Raw nullable `login_user.realname`.
4508
- avatar:
4509
- type: [string, "null"]
4510
- description: Raw id-photo path, normalized to null when empty.
4511
- email:
4512
- type: [string, "null"]
4513
- userid:
4514
- type: integer
4515
- minimum: 1
4516
- AppNotification:
4517
- type: object
4518
- required: [id, showtext, datetime_add, datetime]
4519
- properties:
4520
- id:
4521
- type: integer
4522
- minimum: 1
4523
- showtext:
4524
- type: [string, "null"]
4525
- datetime_add:
4526
- type: [string, "null"]
4527
- description: Raw database datetime retained by the PHP response.
4528
- datetime:
4529
- type: string
4530
- description: Provider-formatted `Y-m-d H:i`.
4531
4506
  AppEnvironment:
4532
4507
  type: object
4533
4508
  required:
@@ -4914,7 +4889,7 @@ components:
4914
4889
  required: [data]
4915
4890
  properties:
4916
4891
  data:
4917
- type: string
4892
+ type: [string, "null"]
4918
4893
  contentMediaType: application/json
4919
4894
  additionalProperties: true
4920
4895
  TemplateTableColumn:
@@ -4949,6 +4924,7 @@ components:
4949
4924
  oneOf:
4950
4925
  - {type: number}
4951
4926
  - {type: string, pattern: '^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$'}
4927
+ - {type: string, const: ""}
4952
4928
  - {type: "null"}
4953
4929
  - if:
4954
4930
  properties: {type: {const: bool}}
@@ -4957,7 +4933,11 @@ components:
4957
4933
  properties:
4958
4934
  data:
4959
4935
  type: array
4960
- items: {type: [boolean, "null"]}
4936
+ items:
4937
+ oneOf:
4938
+ - {type: boolean}
4939
+ - {type: string, const: ""}
4940
+ - {type: "null"}
4961
4941
  - if:
4962
4942
  properties: {type: {const: file}}
4963
4943
  required: [type]
@@ -4967,9 +4947,25 @@ components:
4967
4947
  type: array
4968
4948
  items:
4969
4949
  oneOf:
4970
- - {type: array}
4950
+ - {$ref: "#/components/schemas/RecordAttachment"}
4971
4951
  - {type: "null"}
4972
4952
  additionalProperties: true
4953
+ RecordAttachment:
4954
+ type: object
4955
+ required: [filename, hash, size, timestamp]
4956
+ properties:
4957
+ filename:
4958
+ type: string
4959
+ description: Original filename; the Provider's canonical empty attachment uses an empty string.
4960
+ hash:
4961
+ type: string
4962
+ pattern: "^(?:[0-9a-f]{64})?$"
4963
+ description: SHA-256 digest, or an empty string in the Provider's canonical empty attachment.
4964
+ size: {type: integer, minimum: 0}
4965
+ timestamp:
4966
+ type: integer
4967
+ minimum: 1
4968
+ description: Provider-generated Unix timestamp in milliseconds.
4973
4969
  TemplateFormItem:
4974
4970
  type: object
4975
4971
  required: [name]
@@ -5603,6 +5599,17 @@ components:
5603
5599
  required: [module, data]
5604
5600
  properties:
5605
5601
  module: {type: string, minLength: 1}
5602
+ path:
5603
+ type: array
5604
+ minItems: 1
5605
+ items:
5606
+ type: string
5607
+ minLength: 1
5608
+ maxLength: 245
5609
+ pattern: '^[^/:*?"<>\\|]+$'
5610
+ description: |
5611
+ Ordered folder names below the files-module root. Existing folders
5612
+ are reused by exact name and parent; missing folders are created.
5606
5613
  data:
5607
5614
  type: object
5608
5615
  required: [file, text]
@@ -5612,8 +5619,10 @@ components:
5612
5619
  additionalProperties: false
5613
5620
  additionalProperties: false
5614
5621
  description: |
5615
- Appends one staged attachment to the root of an existing files module.
5616
- Folder `path` is intentionally outside the verified shape.
5622
+ Appends one staged attachment to the root of an existing files module
5623
+ when `path` is absent, or below the resolved folder path when present.
5624
+ Empty and malformed path containers are intentionally outside the
5625
+ callable shape because the Provider treats some of them as root append.
5617
5626
  ReplaceFilesModuleStagedAttachmentOperation:
5618
5627
  type: object
5619
5628
  required: [path, data]
@@ -6518,9 +6527,12 @@ components:
6518
6527
  type: integer
6519
6528
  minimum: 1
6520
6529
  datetime_locked:
6521
- type: integer
6530
+ type: [integer, "null"]
6522
6531
  minimum: 0
6523
- description: Unix timestamp in milliseconds, or zero.
6532
+ description: |
6533
+ Unix timestamp in milliseconds; null for the current unlocked
6534
+ record. Provider paths that normalize the absent timestamp may
6535
+ return zero.
6524
6536
  locked:
6525
6537
  type: boolean
6526
6538
  signs: