Skip to content

Commit d9fa683

Browse files
os-zhuangclaude
andauthored
feat(spec)!: 退役 DriverCapabilities 31 个零读者能力位 —— 全表活性审计,3 活 31 死(#4634,ADR-0049) (#4783)
* feat(spec)!: 退役 DriverCapabilities 31 个零读者能力位 —— 全表活性审计,3 活 31 死 (#4634) #4484 findStream 收尾发现 streaming 位指向已删除的契约方法;按 issue 自述倾向对 DriverCapabilitiesSchema 全部 34 位做两仓活性审计(objectstack + cloud,objectui 零引用确认):仅 queryDateGranularity(engine 聚合分派 + date-bucket parity)、 autonumber(engine 让渡自增生成)、batchSchemaSync(engine 与方法存在性 AND) 三位有决策读者;其余 31 位人人写、无人读,describe 承诺的引擎降级路径从未存在, 且零读者让写错的值(SqlDriver streaming:false 却实现 findStream;InMemoryDriver streaming:true 却全表物化)三个版本无人发现 —— ADR-0078 假可供性。 - driver.zod.ts:31 位 retiredKey() 墓碑(非 strict schema,裸删会被静默剥离; DriverConfigSchema.capabilities 及 SQL/NoSQL 扩展确有 parse 路径),逐位 prescription 指明真实机制(方法存在性门控:beginTransaction / aggregate / syncSchema;#4001 教训);batchSchemaSync .default(false) → .optional() (两处读者本就按缺省=false 消费) - ADR-0087 评估(#4484/#4764 先例):driver 是代码不是 stack 树元数据, supports 字面量在 driver 类里、DriverConfig 是插件 TS 配置,均非 sys_metadata 形态(stack 树近邻 datasource.capabilities 已于 #4583 单独退役)⇒ 不登记 D2 conversion,登记 D3 semantic migration driver-capabilities-inert-bits-removed - driver 字面量同步:memory {} / mongodb { batchSchemaSync: true } / sql { queryDateGranularity, autonumber, batchSchemaSync: false } - 回归 pin(driver.test.ts):31 位逐位 parse 拒绝 + prescription 断言; compiler-API 断言 34 键形状且退役位类型坍缩为 undefined、活位可写(反空转 守卫);S1(schema 复活 streaming)5 pin 红、S2(driver 字面量复活)TS2416 红,均实跑验证后还原 - 生成物:authorable-surface 31 行 [RETIRED]、spec-changes / upgrade-guide / references docs 全量再生成;14 项 spec 门禁全绿,全仓 typecheck 122 任务绿 - changeset:spec + 三 driver 包 major,FROM→TO 映射与一行修复齐备 Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0176qgxgCXTJCUv4YFLtusP9 * chore(spec): merge main(含 C10 #4767)后按规重整生成物 —— 三敏感文件取 main 版再重生成 json-schema.manifest.json / authorable-surface.json / dual-source-exports.baseline.json 一律先取 origin/main 版本(避免静默复活 C10 蓄意删除的 system/EnvironmentArtifact* 键),再以合并后源码全量重跑 gen:schema/check:generated:DriverCapabilities 31 行 [RETIRED] 由生成器重新写入,manifest 与 authorable-surface 中 C10 删键保持已删 (实测两文件 system/EnvironmentArtifact 零残留)。8/8 生成物门禁 + 8 项源码审计 全 PASS,spec 292 文件 7374 测试全绿。 Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0176qgxgCXTJCUv4YFLtusP9 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 941dec4 commit d9fa683

24 files changed

Lines changed: 723 additions & 1310 deletions
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
"@objectstack/spec": major
3+
"@objectstack/driver-memory": major
4+
"@objectstack/driver-mongodb": major
5+
"@objectstack/driver-sql": major
6+
---
7+
8+
refactor(spec)!: retire the 31 inert `DriverCapabilities` bits — declared by every driver, read by nothing (#4634, ADR-0049)
9+
10+
The #4484 findStream close-out left one loose end: `DriverCapabilities.streaming`
11+
described a contract method that no longer exists — and a full liveness audit of
12+
the record (#4634, across objectstack + cloud, objectui confirmed clean) found
13+
`streaming` was not the exception but the rule. Of 34 declared bits, **three**
14+
have a decision-making reader and **thirty-one** were written by every driver
15+
and consulted by no engine, planner, REST layer or renderer:
16+
17+
- Their `.describe()` strings promised engine adaptation that was never built
18+
("If false, ObjectQL will fetch all records and filter in memory" — no such
19+
fallback ever keyed off the bit).
20+
- Zero readers let values go WRONG unnoticed: `SqlDriver` declared
21+
`streaming: false` while implementing `findStream`; `InMemoryDriver` declared
22+
`streaming: true` over a full-table read — the exact inverse of the guarantee.
23+
- The real mechanism everywhere else is **method presence**: transactions gate
24+
on `driver.beginTransaction`, aggregate pushdown on
25+
`typeof driver.aggregate === 'function'`, schema sync on
26+
`typeof driver.syncSchema === 'function'`, and the REQUIRED CRUD/bulk methods
27+
are called unconditionally.
28+
29+
Survivors (each with a named reader — the bits method presence cannot carry):
30+
31+
| bit | reader |
32+
|---|---|
33+
| `queryDateGranularity` | engine aggregate dispatch (`engine.ts`), `checkDateBucketParity` (`@objectstack/verify`) |
34+
| `autonumber` | engine defers autonumber generation to the driver (`engine.ts`) |
35+
| `batchSchemaSync` | engine ANDs it with `syncSchemasBatch` presence (`engine.ts` / `plugin.ts`) |
36+
37+
Migration (FROM → TO):
38+
39+
- Any of the 31 bits (`create`/`read`/`update`/`delete`, `bulkCreate`/
40+
`bulkUpdate`/`bulkDelete`, `transactions`/`savepoints`/`isolationLevels`,
41+
`queryFilters`/`queryAggregations`/`querySorting`/`queryPagination`/
42+
`queryWindowFunctions`/`querySubqueries`/`queryCTE`/`joins`,
43+
`fullTextSearch`/`jsonQuery`/`geospatialQuery`/`streaming`/`jsonFields`/
44+
`arrayFields`/`vectorSearch`, `schemaSync`/`migrations`/`indexes`,
45+
`connectionPooling`/`preparedStatements`/`queryCache`) in a `supports`
46+
literal or a `DriverConfig.capabilities` object → **delete the key**. Each is
47+
tombstoned (`retiredKey()`), not silently stripped: authoring one is a `tsc`
48+
error against `IDataDriver.supports` and a parse error carrying the per-key
49+
prescription, which names the mechanism that actually decides the behaviour.
50+
- `batchSchemaSync` dropped its `.default(false)` for `.optional()` — absence
51+
already meant `false` at both readers, so `supports: {}` is now a valid,
52+
minimal advertisement. If you read `capabilities.batchSchemaSync` from a
53+
*parsed* config and relied on the materialised `false`, treat absence as
54+
`false` (both engine readers always did).
55+
- Driver packages: `InMemoryDriver.supports` is now `{}`,
56+
`MongoDBDriver.supports` is `{ batchSchemaSync: true }`, `SqlDriver.supports`
57+
is `{ queryDateGranularity, autonumber: true, batchSchemaSync: false }`.
58+
Reading a removed bit off these literals no longer type-checks — and no code
59+
in any repository did.
60+
- A future capability (streaming reads, vector search, …) returns **with its
61+
caller and its reader in the same change** — the enforce route of ADR-0049 —
62+
never as a dangling boolean.
63+
64+
The retirement kit: 31 `retiredKey()` tombstones on the non-strict schema
65+
(parse + `tsc` both audible; the schema IS parsed via
66+
`DriverConfigSchema.capabilities` and its SQL/NoSQL extensions); ADR-0087 D3
67+
semantic migration `driver-capabilities-inert-bits-removed` (a driver is CODE,
68+
never stack metadata — `supports` lives in driver classes and `DriverConfig`
69+
is plugin TS configuration, so there is no stored row or stack source for a D2
70+
conversion to rewrite; the stack-tree neighbour `datasource.capabilities` was
71+
retired separately in #4583); baselines (`authorable-surface.json` [RETIRED]
72+
lines, `json-schema.manifest.json`) regenerated deliberately; compiler-API pin
73+
asserting every retired bit is unwritable (`undefined`) and every live bit is
74+
not, sabotage-verified both ways (S1 schema resurrection, S2 driver literal
75+
resurrection).
76+
77+
No runtime behaviour changes — that impossibility is the point: every removed
78+
bit had zero readers, and the three live bits keep theirs.

content/docs/protocol/objectql/query-syntax.mdx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -749,8 +749,9 @@ form.
749749
The `search` parameter does **not** reach a full-text index. The engine expands it into
750750
an `$or` of `$contains` predicates across the object's server-resolved searchable fields
751751
(ADR-0061) and deletes `search` from the AST before the driver sees it — every driver
752-
already runs `$or`/`$contains`, so no driver support is needed (`SqlDriver` reports
753-
`supports.fullTextSearch: false`).
752+
already runs `$or`/`$contains`, so no driver support is needed (which is also why the
753+
old `supports.fullTextSearch` capability bit had no reader and was retired in 17.0.0,
754+
#4634).
754755

755756
`search` takes the **query text itself** — that is the canonical spelling (ADR-0061 D1:
756757
the client says *what* to search for, the server decides *which fields*), and it is what

content/docs/references/data/driver-nosql.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ const result = AggregationPipelineSchema.parse(data);
123123
| :--- | :--- | :--- | :--- |
124124
| **name** | `string` || Driver instance name |
125125
| **type** | `'nosql'` || Driver type must be "nosql" |
126-
| **capabilities** | `{ create: boolean; read: boolean; update: boolean; delete: boolean; … }` || Driver capability flags |
126+
| **capabilities** | `{ queryDateGranularity?: Record<string, boolean>; autonumber?: boolean; batchSchemaSync?: boolean; create?: any; … }` || Driver capability flags |
127127
| **connectionString** | `string` | optional | Database connection string (driver-specific format) |
128128
| **poolConfig** | `{ min: number; max: number; idleTimeoutMillis: number; connectionTimeoutMillis: number }` | optional | Connection pool configuration |
129129
| **databaseType** | `Enum<'mongodb' \| 'couchdb' \| 'dynamodb' \| 'cassandra' \| 'redis' \| 'elasticsearch' \| 'neo4j' \| 'orientdb'>` || Specific NoSQL database type |

content/docs/references/data/driver-sql.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const result = DataTypeMappingSchema.parse(data);
6565
| :--- | :--- | :--- | :--- |
6666
| **name** | `string` || Driver instance name |
6767
| **type** | `'sql'` || Driver type must be "sql" |
68-
| **capabilities** | `{ create: boolean; read: boolean; update: boolean; delete: boolean; … }` || Driver capability flags |
68+
| **capabilities** | `{ queryDateGranularity?: Record<string, boolean>; autonumber?: boolean; batchSchemaSync?: boolean; create?: any; … }` || Driver capability flags |
6969
| **connectionString** | `string` | optional | Database connection string (driver-specific format) |
7070
| **poolConfig** | `{ min: number; max: number; idleTimeoutMillis: number; connectionTimeoutMillis: number }` | optional | Connection pool configuration |
7171
| **dialect** | `Enum<'postgresql' \| 'mysql' \| 'sqlite' \| 'mssql' \| 'oracle' \| 'mariadb'>` || SQL database dialect |

0 commit comments

Comments
 (0)