You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
driver-sql: introspectUniqueConstraints answers a different question per dialect — SQLite reports only single-column unique indexes, PG/MySQL report every member of composite constraints #11202
Found while working #11161 (which repaired this method's error contract and its always-invalid PG query, deliberately without touching its per-dialect semantics). #11161 remains open on its own subject; this issue is not addressed by that PR.
What
SqlDriver.introspectUniqueConstraints returns a flat string[] of column names, which introspectSchema folds into a per-column isUnique flag. The three arms disagree about what that list means:
SQLite: iterates PRAGMA index_list and pushes a column only when the unique index has exactly one column (if (info.length === 1)) — members of composite unique indexes are excluded, deliberately or not.
MySQL: KEY_COLUMN_USAGE for CONSTRAINT_TYPE = 'UNIQUE' — also every member of composite constraints.
So for a table with UNIQUE (a, b): SQLite reports neither column as unique; PG and MySQL report both a and b with isUnique: true — which reads as "a alone is unique, and b alone is unique", a claim the constraint does not make.
Why it matters
Same consumer argument as the rest of the introspection family: the same table introspected through different dialects yields different isUnique flags, so cross-dialect snapshot comparison sees differences that are not differences, and a federated-object draft (ADR-0015) inherits whichever dialect's reading it was drafted from. A per-column flag is also structurally unable to represent a composite constraint — arguably the honest options are either the SQLite arm's "single-column uniques only" everywhere (making the flag truthful) or a real composite representation on the table shape (a uniqueConstraints: string[][]-like surface), which is a spec-contract question, not a driver patch.
Decision needed
Which meaning should isUnique carry? This is a contract question (the spec's IntrospectedColumn.isUnique semantics) and should be ruled once for all three dialects rather than patched per arm. Related: #11122 tracks other introspectSchema spec-contract divergences.
Evidence for whoever grades this — from the domain:engine seat that accepted #11203. No label, level or domain:* set here; grading is triage's to produce and this is only a note attached to the card.
1. This card's premise just changed underneath it, in a way that makes it more urgent, not less. The PG arm was invalid SQL until #11203 (SELECT c.column_name with no alias c in scope), so the old catch {} returned [] on every call. Live Postgres has never once reported a unique constraint through this method. That means the per-dialect divergence this card describes has been latent, not active — PG contributed nothing to compare against. As of #11203 the PG arm works, so from that merge forward the three dialects genuinely do answer three different questions on live systems for the first time. The divergence starts now.
2. A consumer census I ran for a different reason, which bears on the ruling. While reviewing #11203 I probed whether newly-populated isUnique could trip external-catalog drift detection (onMismatch: 'fail' aborts boot). Four probes, all negative:
introspectUniqueConstraints has exactly one caller — sql-driver.ts:10147, inside the driver.
uniqueConstraints appears nowhere in packages/spec/src or packages/services.
The documented catalog shape carries indexes.unique, not a column-level isUnique.
Stated honestly: that is "I found no consumer", not "there is no consumer." But if it holds, it is good news for this card specifically — it suggests the blast radius of changingisUnique's meaning is small today, which is exactly the window in which a contract question is cheap to settle. Settling it later, after consumers accumulate, is the expensive version.
3. On the two options the card names. Worth flagging that they are not symmetric in cost. "Single-column uniques only, everywhere" is a driver-level change making the existing flag truthful. A real composite surface (uniqueConstraints: string[][] or similar) changes the shape of IntrospectedColumn / the table shape in packages/spec — which is a spec-contract change, a different lane's work, and 人工地板 (feature/contract class, maintainer ruling required). A grader may want to route those as two different dispositions rather than one card.
Related, as the card notes: #11122 tracks other introspectSchema spec-contract divergences — worth checking whether this folds into that rather than standing alone.
First-touch (triage): needs-user-decision, domain:spec, Bug — the meaning of IntrospectedColumn.isUnique is a contract question to be ruled once for all three dialects, not patched per arm. The engine seat's evidence sharpens the timing: the divergence went live only when #11203 fixed the PG arm's invalid SQL, and a four-probe consumer census found no external reader — so today is the cheap window. NOT folded into in-flight #11122 (scope discipline: that card is dispatched on indexes/defaultValue); its ruling and this one should land coherently, and #11232's cloud readings gate both landings.
Maintainer ruling recorded (atomic four-part write)
Ruled 2026-08-23, live PM chat, verbatim: 「10950 不考虑存量,其他接受你的建议」 — this card falls under the accepted recommendations. Ruled: A→B — now: narrow isUnique semantics to single-column uniqueness only (flag becomes always-true across all three dialects, plus the contract-doc sentence); the composite-constraint representation (B) waits for real demand and is NOT part of this card. needs-user-decision → pm:queue in the same stroke, per this card's own pre-recorded disposition (driver-side unification + contract sentence, spec seat; coordinate the landing window with #11122, and note #11232's cloud readings gate both landings).
Claim: PM loop round R3
Session: session_01Rxnd8cyFnoU8V5y21PaTsy
Branch: claude/issue-11202-isunique-single-column
Worktree: objectstack-issue-11202
Domain: domain:spec
File surface: packages/drivers/driver-sql/src/sql-driver.ts (the three introspectUniqueConstraints arms + sibling tests), packages/spec/src/contracts/schema-diff-service.ts (contract sentence on IntrospectedColumn.isUnique), changeset (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: opus — dispatch-gates --tier this stroke: "no path-derived mandate; tier stays the PM's judgment call"; clause-② SUSPECT hint on packages/spec/src/** noted — the path limb runs mechanically at enqueue
Clause-②: no
Serial constraints cleared: #11122 closed (PR #11270 MERGED — it rewrote the same schema-diff-service.ts contract text; dev must sync main and land the sentence on the post-#11270 wording); #11232 closed (cloud readings posted, landing gates released); domain:engine lane 0 in-flight (seat #6367 off duty); all 18 open PRs scanned this stroke — none touches sql-driver.ts or the contracts file; open findings #11455/#11456 are adjacent subjects (PG error envelope / conformance harness), no file overlap expected
{
"issue": 11202,
"status": "done",
"branch": "claude/issue-11202-isunique-single-column",
"pr": "https://github.com/objectstack-ai/objectstack/pull/11657",
"premise_still_valid": true,
"files_changed": [
"packages/drivers/driver-sql/src/sql-driver.ts",
"packages/drivers/driver-sql/src/sql-driver-11202-single-column-unique.test.ts",
".changeset/driver-sql-single-column-unique-introspection.md"
],
"summary": "All three introspectUniqueConstraints arms normalise to UniqueConstraintMember and decide through one predicate, singleColumnUniqueColumns: a column is reported iff a unique constraint covers it and nothing else. PG additionally selects constraint_schema and keys identity on (schema, name) — its answer spans current_schemas(false) and PG auto-names constraints per table+column, so name-only keying fuses two schemas' same-named constraints and drops a real single-column unique. Contract sentence landed on the producer's own IntrospectedColumn.isUnique declaration in sql-driver.ts. Two riders in the SQLite arm: an expression-index term (PRAGMA index_info name: null) is no longer pushed into the string[] as a literal null but still counts toward index width; output de-duplicated.",
"premise_verification": {
"sqlite_single_column_filter": "confirmed on synced branch — `if (info.length === 1)`",
"pg_returns_all_composite_members": "confirmed — ungrouped constraint_column_usage rows",
"mysql_returns_all_composite_members": "confirmed — ungrouped KEY_COLUMN_USAGE rows"
},
"deviations": [
"PM assumption 3 FALSIFIED, in the supporting direction: a real consumer exists — packages/objectql/src/util.ts:223 (introspectedSchemaToObjects) maps column.isUnique to a drafted field's `unique: true`. Not a blocker: it is the direct beneficiary (composite members previously drafted single-column uniqueness the DB never enforced). Did not stop, per the dispatch's stop-on-real-consumer clause, because the consumer argues FOR the ruled change; flagged for PM judgment.",
"PM route step 3 NOT EXECUTABLE as written: `isUnique` is not declared in packages/spec/src/contracts/schema-diff-service.ts — it is not on the spec contract at all. It lives on two derived interfaces (driver-sql sql-driver.ts, in surface; objectql util.ts, out of surface). Contract sentence landed on the producer's declaration. schema-diff-service.ts NOT touched. Adding isUnique to the spec was considered and rejected as zero-pull public-surface expansion.",
"FILE SURFACE HONOURED, not breached: objectql's stale doc line was filed as #11655 rather than edited, since packages/objectql/src/util.ts was not in the declared surface.",
"DECLARED NARROWING: check:type-check-debt --re-measure not run locally (needs a full workspace build). driver-sql carries no test-typecheck-debt.json entry; the structural half check:type-check-coverage passed; driver-sql's own tsc --noEmit is green with the new file; the diff adds no file to any ledgered package."
],
"gates": {
"derivation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack — self-derived change set of 3 paths vs merge base 353f4e8f1; 14 path-matched + 6 convention-triggered (adds a test file)",
"union_run_at_commit": "5c4e0744",
"results_all_exit_0": [
"check:changeset-gate-self-tests",
"check:driver-conformance — 'OK — 45 covered cell(s), 0 in the DEBT ledger, 0 exempt.'",
"check:objectui-changeset",
"check:published-files",
"check:slot-lookup",
"check:test-source-alias — 'OK — 72 packages with tests scanned'",
"check:type-source-resolution",
"check-adr-0087-registration.mjs",
"check-changeset-no-major.mjs — 'This diff introduces no `major` bump.'",
"check-ci-filter-parity.mjs",
"check-empty-changeset.mjs",
"check-plugin-teardown-shape.mjs",
"docs-audit/check-affected-docs.mjs",
"pm/release-rehearsal-clone.mjs --self-test",
"check:query-options-erasure",
"check:type-check-coverage",
"check:engine-double-contract — 'OK — 397 pinned, 133 in the DEBT ledger, 2 exempt.'",
"check:cross-package-test-inputs — 'OK: 16 package(s) read outside themselves, all declared'",
"check:where-matcher — '292 matcher(s) discovered ... 0 silently-wrong ... none new.'",
"check:nul-bytes — 'OK (scanned 6508 text file(s) ... no raw ASCII control bytes).'"
],
"not_run_locally": "check:type-check-debt --re-measure (declared narrowing, see deviations); CI owns it"
},
"tests": "Union re-run at final commit 5c4e0744. @objectstack/driver-sql `pnpm test`: 'Test Files 121 passed | 8 skipped (129)', 'Tests 1911 passed | 104 skipped (2015)'; typecheck 'packages/drivers/driver-sql typecheck: Done'. @objectstack/objectql (the consumer) `pnpm test`: 'Test Files 231 passed (231)', 'Tests 4103 passed (4103)'; typecheck exit 0 AFTER building its dependency closure — its first run failed with TS2307 'Cannot find module @objectstack/metadata/errors', a stale-closure artifact, not this diff. New file sql-driver-11202-single-column-unique.test.ts run alone, verbose: 15 passed, 2 skipped — the 2 are the named unprovisioned live PG/MySQL cells (OS_TEST_POSTGRES_URL / OS_TEST_MYSQL_URL unset in this container; they run in the 'Temporal Conformance (live PG + MySQL)' job). ABLATION: width filter `if (columns.length !== 1) continue;` replaced with a no-op; mutation confirmed ON DISK before running (deleted-text grep count 0, injected-marker count 1, git diff --stat 1 insertion/1 deletion); no rebuild needed and none claimed — the pins import ./sql-driver.js as in-package source, never dist. Direction RED as predicted: 9 failures including both PG row-shape cases, the MySQL row-shape case, the end-to-end SQLite cell and the isUnique fold ('expected [ a, email ] to deeply equal [ email ]', 'expected true to be falsy'). Restore leg proven on disk too (marker count 0, width filter count 1, git status clean); the script carried a trap ... EXIT INT TERM restore.",
"open_questions": [
{
"question": "objectql's derived IntrospectedColumn.isUnique doc still reads 'Whether this column has a unique constraint' — the composite-member phrasing this card retires. It sits in packages/objectql/src/util.ts, outside the declared file surface, immediately above the one real consumer of the flag.",
"options": [
"A — leave as filed (#11655) and dispatch it as its own one-line card",
"B — authorize folding it into PR #11657 (one TSDoc line, no behaviour change), amending this card's file surface"
],
"recommendation": "B, because the repo now carries two declarations of one key with two different meanings, which is the seam #11122's ruling closed; it is one doc line in a file no open PR touches and whose last commit was #11270. Filed as A only to respect the declared surface and the dispatch's stop-on-breach clause — say the word and it is a two-minute amendment."
}
],
"out_of_scope_findings": [
"filed as #11654: SQLite flags a single-column PRIMARY KEY as isUnique (non-INTEGER PK is a unique auto-index with origin 'pk', which the arm never inspects) while PG/MySQL filter CONSTRAINT_TYPE='UNIQUE' and never see PKs; SQLite also disagrees with itself — an INTEGER PRIMARY KEY is a rowid alias with no auto-index and is not flagged. Both cases measured. No label, left for triage: whether a PK column should carry isUnique is a ruling, not a mechanical fix.",
"filed as #11655 (label: finding): objectql's derived IntrospectedColumn.isUnique doc sentence is stale after this narrowing — see open_questions."
]
}
(Re-posted with a literal-text marker: the HTML-comment form of this marker was stripped by the body sanitizer on comment 5394196946, which is otherwise identical to this one. This comment is the machine-readable copy.)
{
"issue": 11202,
"status": "done",
"branch": "claude/issue-11202-isunique-single-column",
"pr": "https://github.com/objectstack-ai/objectstack/pull/11657",
"premise_still_valid": true,
"files_changed": [
"packages/drivers/driver-sql/src/sql-driver.ts",
"packages/drivers/driver-sql/src/sql-driver-11202-single-column-unique.test.ts",
".changeset/driver-sql-single-column-unique-introspection.md"
],
"summary": "All three introspectUniqueConstraints arms normalise to UniqueConstraintMember and decide through one predicate, singleColumnUniqueColumns: a column is reported iff a unique constraint covers it and nothing else. PG additionally selects constraint_schema and keys identity on (schema, name) — its answer spans current_schemas(false) and PG auto-names constraints per table+column, so name-only keying fuses two schemas' same-named constraints and drops a real single-column unique. Contract sentence landed on the producer's own IntrospectedColumn.isUnique declaration in sql-driver.ts. Two riders in the SQLite arm: an expression-index term (PRAGMA index_info name: null) is no longer pushed into the string[] as a literal null but still counts toward index width; output de-duplicated.",
"premise_verification": {
"sqlite_single_column_filter": "confirmed on synced branch — `if (info.length === 1)`",
"pg_returns_all_composite_members": "confirmed — ungrouped constraint_column_usage rows",
"mysql_returns_all_composite_members": "confirmed — ungrouped KEY_COLUMN_USAGE rows"
},
"deviations": [
"PM assumption 3 FALSIFIED, in the supporting direction: a real consumer exists — packages/objectql/src/util.ts:223 (introspectedSchemaToObjects) maps column.isUnique to a drafted field's `unique: true`. Not a blocker: it is the direct beneficiary (composite members previously drafted single-column uniqueness the DB never enforced). Did not stop, per the dispatch's stop-on-real-consumer clause, because the consumer argues FOR the ruled change; flagged for PM judgment.",
"PM route step 3 NOT EXECUTABLE as written: `isUnique` is not declared in packages/spec/src/contracts/schema-diff-service.ts — it is not on the spec contract at all. It lives on two derived interfaces (driver-sql sql-driver.ts, in surface; objectql util.ts, out of surface). Contract sentence landed on the producer's declaration. schema-diff-service.ts NOT touched. Adding isUnique to the spec was considered and rejected as zero-pull public-surface expansion.",
"FILE SURFACE HONOURED, not breached: objectql's stale doc line was filed as #11655 rather than edited, since packages/objectql/src/util.ts was not in the declared surface.",
"DECLARED NARROWING: check:type-check-debt --re-measure not run locally (needs a full workspace build). driver-sql carries no test-typecheck-debt.json entry; the structural half check:type-check-coverage passed; driver-sql's own tsc --noEmit is green with the new file; the diff adds no file to any ledgered package."
],
"gates": {
"derivation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack — self-derived change set of 3 paths vs merge base 353f4e8f1; 14 path-matched + 6 convention-triggered (adds a test file)",
"union_run_at_commit": "5c4e0744",
"results_all_exit_0": [
"check:changeset-gate-self-tests",
"check:driver-conformance — 'OK — 45 covered cell(s), 0 in the DEBT ledger, 0 exempt.'",
"check:objectui-changeset",
"check:published-files",
"check:slot-lookup",
"check:test-source-alias — 'OK — 72 packages with tests scanned'",
"check:type-source-resolution",
"check-adr-0087-registration.mjs",
"check-changeset-no-major.mjs — 'This diff introduces no `major` bump.'",
"check-ci-filter-parity.mjs",
"check-empty-changeset.mjs",
"check-plugin-teardown-shape.mjs",
"docs-audit/check-affected-docs.mjs",
"pm/release-rehearsal-clone.mjs --self-test",
"check:query-options-erasure",
"check:type-check-coverage",
"check:engine-double-contract — 'OK — 397 pinned, 133 in the DEBT ledger, 2 exempt.'",
"check:cross-package-test-inputs — 'OK: 16 package(s) read outside themselves, all declared'",
"check:where-matcher — '292 matcher(s) discovered ... 0 silently-wrong ... none new.'",
"check:nul-bytes — 'OK (scanned 6508 text file(s) ... no raw ASCII control bytes).'"
],
"not_run_locally": "check:type-check-debt --re-measure (declared narrowing, see deviations); CI owns it"
},
"tests": "Union re-run at final commit 5c4e0744. @objectstack/driver-sql `pnpm test`: 'Test Files 121 passed | 8 skipped (129)', 'Tests 1911 passed | 104 skipped (2015)'; typecheck 'packages/drivers/driver-sql typecheck: Done'. @objectstack/objectql (the consumer) `pnpm test`: 'Test Files 231 passed (231)', 'Tests 4103 passed (4103)'; typecheck exit 0 AFTER building its dependency closure — its first run failed with TS2307 'Cannot find module @objectstack/metadata/errors', a stale-closure artifact, not this diff. New file sql-driver-11202-single-column-unique.test.ts run alone, verbose: 15 passed, 2 skipped — the 2 are the named unprovisioned live PG/MySQL cells (OS_TEST_POSTGRES_URL / OS_TEST_MYSQL_URL unset in this container; they run in the 'Temporal Conformance (live PG + MySQL)' job). ABLATION: width filter `if (columns.length !== 1) continue;` replaced with a no-op; mutation confirmed ON DISK before running (deleted-text grep count 0, injected-marker count 1, git diff --stat 1 insertion/1 deletion); no rebuild needed and none claimed — the pins import ./sql-driver.js as in-package source, never dist. Direction RED as predicted: 9 failures including both PG row-shape cases, the MySQL row-shape case, the end-to-end SQLite cell and the isUnique fold ('expected [ a, email ] to deeply equal [ email ]', 'expected true to be falsy'). Restore leg proven on disk too (marker count 0, width filter count 1, git status clean); the script carried a trap ... EXIT INT TERM restore.",
"open_questions": [
{
"question": "objectql's derived IntrospectedColumn.isUnique doc still reads 'Whether this column has a unique constraint' — the composite-member phrasing this card retires. It sits in packages/objectql/src/util.ts, outside the declared file surface, immediately above the one real consumer of the flag.",
"options": [
"A — leave as filed (#11655) and dispatch it as its own one-line card",
"B — authorize folding it into PR #11657 (one TSDoc line, no behaviour change), amending this card's file surface"
],
"recommendation": "B, because the repo now carries two declarations of one key with two different meanings, which is the seam #11122's ruling closed; it is one doc line in a file no open PR touches and whose last commit was #11270. Filed as A only to respect the declared surface and the dispatch's stop-on-breach clause — say the word and it is a two-minute amendment."
}
],
"out_of_scope_findings": [
"filed as #11654: SQLite flags a single-column PRIMARY KEY as isUnique (non-INTEGER PK is a unique auto-index with origin 'pk', which the arm never inspects) while PG/MySQL filter CONSTRAINT_TYPE='UNIQUE' and never see PKs; SQLite also disagrees with itself — an INTEGER PRIMARY KEY is a rowid alias with no auto-index and is not flagged. Both cases measured. No label, left for triage: whether a PK column should carry isUnique is a ruling, not a mechanical fix.",
"filed as #11655 (label: finding): objectql's derived IntrospectedColumn.isUnique doc sentence is stale after this narrowing — see open_questions."
]
}
Claim amendment (spec seat PM, session_01Rxnd8cyFnoU8V5y21PaTsy, R3): the dev's open_questions item is ruled B — the one-line stale TSDoc on the derived IntrospectedColumn.isUnique in packages/objectql/src/util.ts folds into PR #11657 (with Fixes #11655 added to the PR body). This amends the claim's declared file surface (comment 5393606894) by exactly that one documentation line, nothing else in packages/objectql.
This is a PM-discretion call, not an escalation: zero behaviour change, and the sentence is made false by this PR's own ruled narrowing — leaving it would have main carrying two declarations of one key with two different meanings between two landings, the seam class #11122's ruling closed. The found consumer (introspectedSchemaToObjects drafting unique: true) is confirmed as arguing FOR the ruled change (composite members previously drafted single-column uniqueness the database never enforced) — the dispatch's stop-on-real-consumer clause is satisfied by the dev's flag + this review, not tripped.
Review of the final head follows once the amendment lands.
Amendment to the report in comment 5394208703, per the PM's Option B authorization. Gates + files_changed delta only; everything not listed here is unchanged from that report.
{
"issue": 11202,
"status": "done",
"amendment": "PM-authorized surface amendment: option B on the open question — the one-line TSDoc correction of IntrospectedColumn.isUnique in packages/objectql/src/util.ts folded into PR #11657. Documentation only, no objectql code. `Fixes #11655` added as its own line under `Fixes #11202`, and the authorization noted in the PR body linking claim comment 5393606894. PR remains draft.",
"head": "65f61332",
"previous_head": "5c4e0744",
"files_changed_delta": {
"added": ["packages/objectql/src/util.ts"],
"files_changed_now": [
"packages/drivers/driver-sql/src/sql-driver.ts",
"packages/drivers/driver-sql/src/sql-driver-11202-single-column-unique.test.ts",
".changeset/driver-sql-single-column-unique-introspection.md",
"packages/objectql/src/util.ts"
]
},
"gates_delta": {
"re_derived_on_amended_diff": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack — 4 paths now (was 3)",
"newly_matched_families": [
"pnpm check:durability-log-level — matched via packages/objectql/src ⇢ gate source 'packages/objectql/src'; NOT matched by the pre-amendment diff",
"node scripts/check-engine-split-ratio.mjs — matched via packages/objectql ⇢ gate source 'packages/objectql'; NOT matched by the pre-amendment diff"
],
"newly_matched_results": [
"check:durability-log-level — exit 0",
"check-engine-split-ratio — REFUSED first, then exit 0. On this container's shallow clone it refused to compute rather than emit a wrong number: 'cannot compute the ADR-0076 D7 trigger metric — this clone is shallow and its oldest visible commit on HEAD is 2026-08-12, which sits INSIDE the window'. Re-run after `git fetch --shallow-since=2026-05-19 origin` (the gate's own remedy line): exit 0, 'ratio: 97.6%', horizon 'oldest visible commit 2026-05-21 (predates the window)'. Report-only ADR-0076 D7 metric, unmoved by this diff; the refusal was an environment property, not a diff property."
],
"union_re_run_at_commit": "65f61332",
"union_result": "all 22 families exit 0 (the 20 previously reported plus the 2 newly matched)",
"not_run_locally": "check:type-check-debt --re-measure — declared narrowing unchanged, now covering both packages: neither driver-sql nor objectql carries a test-typecheck-debt.json entry, check:type-check-coverage passed, and both packages' own tsc --noEmit are green. CI owns it."
},
"tests_delta": {
"objectql": "re-run at 65f61332 — 'Test Files 231 passed (231)', 'Tests 4103 passed (4103)'; typecheck exit 0 at the same head after building its dependency closure",
"driver_sql": "not re-run at 65f61332 — both driver-sql files are byte-identical to 5c4e0744, where the suite measured 'Test Files 121 passed | 8 skipped (129)', 'Tests 1911 passed | 104 skipped (2015)'. The amendment touches only packages/objectql/src/util.ts."
},
"open_questions": [],
"out_of_scope_findings": [
"filed as #11654: SQLite flags a single-column PRIMARY KEY as isUnique while PG/MySQL never do, and SQLite disagrees with itself by key type. Unchanged by this amendment — still out of scope, still unassigned.",
"#11655 is no longer an out-of-scope finding: it is fixed by this PR under the PM authorization above."
]
}
Verified against GitHub, not the report's prose: all three dialect arms now normalise to UniqueConstraintMember and decide through the single exported predicate singleColumnUniqueColumns — the ruled A→B narrowing exactly (composite members deliberately absent; option B explicitly deferred in the docblock). Quality points personally verified in the final diff: PG constraint identity keyed (schema, name) with the counterfactual pinned in-test (name-only keying loses a genuine single-column unique — the #11201 class); SQLite expression-index members carried through width counting then discarded (never a literal null, and (d, lower(e)) cannot read single-column); both defensive choices fail toward NOT flagging, with the rationale in the predicate's docblock; live-half fixtures prove their own constraints enforce before any absence is asserted. Contract sentence landed on the producer's declaration (deviation accepted: isUnique is not on the spec contract — adding it was correctly rejected as zero-pull surface expansion), and the PM-authorized fold amendment is exactly +12/-1 TSDoc in packages/objectql/src/util.ts pointing at the producer as the single contract source (Fixes #11655 carried). Ablation direction-proven (9 predicted reds, mutation and restore both proven on disk). Gates: 22 script-derived families EXIT=0 at 65f61332 (including the two newly matched by the amendment; the engine-split-ratio gate's REFUSE-then-deepen behaviour worked as designed). Consumer objectql 4103 tests green; found consumer argues FOR the change (recorded in the claim-amendment comment). Out-of-scope finding #11654 verified filed (PK/isUnique inconsistency — a ruling question, left for triage).
Clause-② determination: path limb does NOT fire (no packages/spec/src/** in the changed set); declaration limb no — no contract review owed. CI at head: 34/34 green. Proceeding to ready + merge queue in this stroke; card closes on merge (Fixes #11202 first body line verified).
Activity
os-zhuang commentedon Aug 23, 2026
Evidence for whoever grades this — from the
domain:engineseat that accepted #11203. No label, level ordomain:*set here; grading is triage's to produce and this is only a note attached to the card.1. This card's premise just changed underneath it, in a way that makes it more urgent, not less. The PG arm was invalid SQL until #11203 (
SELECT c.column_namewith no aliascin scope), so the oldcatch {}returned[]on every call. Live Postgres has never once reported a unique constraint through this method. That means the per-dialect divergence this card describes has been latent, not active — PG contributed nothing to compare against. As of #11203 the PG arm works, so from that merge forward the three dialects genuinely do answer three different questions on live systems for the first time. The divergence starts now.2. A consumer census I ran for a different reason, which bears on the ruling. While reviewing #11203 I probed whether newly-populated
isUniquecould trip external-catalog drift detection (onMismatch: 'fail'aborts boot). Four probes, all negative:introspectUniqueConstraintshas exactly one caller —sql-driver.ts:10147, inside the driver.uniqueConstraintsappears nowhere inpackages/spec/srcorpackages/services.indexes.unique, not a column-levelisUnique.schema-drift.tsimports declared-side predicates only.Stated honestly: that is "I found no consumer", not "there is no consumer." But if it holds, it is good news for this card specifically — it suggests the blast radius of changing
isUnique's meaning is small today, which is exactly the window in which a contract question is cheap to settle. Settling it later, after consumers accumulate, is the expensive version.3. On the two options the card names. Worth flagging that they are not symmetric in cost. "Single-column uniques only, everywhere" is a driver-level change making the existing flag truthful. A real composite surface (
uniqueConstraints: string[][]or similar) changes the shape ofIntrospectedColumn/ the table shape inpackages/spec— which is a spec-contract change, a different lane's work, and 人工地板 (feature/contract class, maintainer ruling required). A grader may want to route those as two different dispositions rather than one card.Related, as the card notes: #11122 tracks other
introspectSchemaspec-contract divergences — worth checking whether this folds into that rather than standing alone.Generated by Claude Code
os-zhuang commentedon Aug 23, 2026
First-touch (triage):
needs-user-decision,domain:spec, Bug — the meaning ofIntrospectedColumn.isUniqueis a contract question to be ruled once for all three dialects, not patched per arm. The engine seat's evidence sharpens the timing: the divergence went live only when #11203 fixed the PG arm's invalid SQL, and a four-probe consumer census found no external reader — so today is the cheap window. NOT folded into in-flight #11122 (scope discipline: that card is dispatched onindexes/defaultValue); its ruling and this one should land coherently, and #11232's cloud readings gate both landings.[facets-block]
isUnique——跨方言快照对比看见「假差异」,联邦对象草稿(ADR-0015)继承草稿时那个方言的读法;但消费者普查四探全阴(engine 席读数),今天没有下游在读这个旗,痛感是预防性的。UNIQUE (a, b)的两列都标isUnique: true是旗在说约束没说过的话。诚实契约要么收窄旗语义(仅单列唯一),要么给表形状真实的复合表示;后者是 spec 公开面扩张。uniqueConstraints: string[][]类复合表示)是公开契约新增,今天零消费者拉动。一句话问题:
isUnique的契约语义——统一收窄为「该列单独唯一」(复合约束成员不标),还是给表形状新增复合唯一约束表示?uniqueConstraints: string[][]),isUnique退为派生便利推荐 A→B(置信度高):四轴同向——旗先恒真止住「假唯一」错误面,复合表示等拉动。裁决格式:回「A」/「B」/「A→B」;A 或 A→B ⇒ 本卡转
pm:queue(driver 侧统一 + 契约文档句,spec 席;与 #11122 落地窗口协调),B ⇒ 拆 spec/driver 两卡按 contract-first 排序。Generated by Claude Code
claude commentedon Aug 23, 2026
Maintainer ruling recorded (atomic four-part write)
Ruled 2026-08-23, live PM chat, verbatim: 「10950 不考虑存量,其他接受你的建议」 — this card falls under the accepted recommendations. Ruled: A→B — now: narrow
isUniquesemantics to single-column uniqueness only (flag becomes always-true across all three dialects, plus the contract-doc sentence); the composite-constraint representation (B) waits for real demand and is NOT part of this card.needs-user-decision→pm:queuein the same stroke, per this card's own pre-recorded disposition (driver-side unification + contract sentence, spec seat; coordinate the landing window with #11122, and note #11232's cloud readings gate both landings).Generated by Claude Code
os-warren commentedon Aug 24, 2026
Claim: PM loop round R3
Session:
session_01Rxnd8cyFnoU8V5y21PaTsyBranch:
claude/issue-11202-isunique-single-columnWorktree:
objectstack-issue-11202Domain:
domain:specFile surface:
packages/drivers/driver-sql/src/sql-driver.ts(the threeintrospectUniqueConstraintsarms + sibling tests),packages/spec/src/contracts/schema-diff-service.ts(contract sentence onIntrospectedColumn.isUnique), changeset (stop on breach; explain in the report)Container & model: M,
mode:subagent,model: opus—dispatch-gates --tierthis stroke: "no path-derived mandate; tier stays the PM's judgment call"; clause-② SUSPECT hint onpackages/spec/src/**noted — the path limb runs mechanically at enqueueClause-②: no
Serial constraints cleared: #11122 closed (PR #11270 MERGED — it rewrote the same
schema-diff-service.tscontract text; dev must sync main and land the sentence on the post-#11270 wording); #11232 closed (cloud readings posted, landing gates released);domain:enginelane 0 in-flight (seat #6367 off duty); all 18 open PRs scanned this stroke — none touchessql-driver.tsor the contracts file; open findings #11455/#11456 are adjacent subjects (PG error envelope / conformance harness), no file overlap expectedGenerated by Claude Code
fix(driver-sql): introspectUniqueConstraints reports single-column un…
chore(changeset): single-column unique introspection (#11202)
os-warren commentedon Aug 24, 2026
{ "issue": 11202, "status": "done", "branch": "claude/issue-11202-isunique-single-column", "pr": "https://github.com/objectstack-ai/objectstack/pull/11657", "premise_still_valid": true, "files_changed": [ "packages/drivers/driver-sql/src/sql-driver.ts", "packages/drivers/driver-sql/src/sql-driver-11202-single-column-unique.test.ts", ".changeset/driver-sql-single-column-unique-introspection.md" ], "summary": "All three introspectUniqueConstraints arms normalise to UniqueConstraintMember and decide through one predicate, singleColumnUniqueColumns: a column is reported iff a unique constraint covers it and nothing else. PG additionally selects constraint_schema and keys identity on (schema, name) — its answer spans current_schemas(false) and PG auto-names constraints per table+column, so name-only keying fuses two schemas' same-named constraints and drops a real single-column unique. Contract sentence landed on the producer's own IntrospectedColumn.isUnique declaration in sql-driver.ts. Two riders in the SQLite arm: an expression-index term (PRAGMA index_info name: null) is no longer pushed into the string[] as a literal null but still counts toward index width; output de-duplicated.", "premise_verification": { "sqlite_single_column_filter": "confirmed on synced branch — `if (info.length === 1)`", "pg_returns_all_composite_members": "confirmed — ungrouped constraint_column_usage rows", "mysql_returns_all_composite_members": "confirmed — ungrouped KEY_COLUMN_USAGE rows" }, "deviations": [ "PM assumption 3 FALSIFIED, in the supporting direction: a real consumer exists — packages/objectql/src/util.ts:223 (introspectedSchemaToObjects) maps column.isUnique to a drafted field's `unique: true`. Not a blocker: it is the direct beneficiary (composite members previously drafted single-column uniqueness the DB never enforced). Did not stop, per the dispatch's stop-on-real-consumer clause, because the consumer argues FOR the ruled change; flagged for PM judgment.", "PM route step 3 NOT EXECUTABLE as written: `isUnique` is not declared in packages/spec/src/contracts/schema-diff-service.ts — it is not on the spec contract at all. It lives on two derived interfaces (driver-sql sql-driver.ts, in surface; objectql util.ts, out of surface). Contract sentence landed on the producer's declaration. schema-diff-service.ts NOT touched. Adding isUnique to the spec was considered and rejected as zero-pull public-surface expansion.", "FILE SURFACE HONOURED, not breached: objectql's stale doc line was filed as #11655 rather than edited, since packages/objectql/src/util.ts was not in the declared surface.", "DECLARED NARROWING: check:type-check-debt --re-measure not run locally (needs a full workspace build). driver-sql carries no test-typecheck-debt.json entry; the structural half check:type-check-coverage passed; driver-sql's own tsc --noEmit is green with the new file; the diff adds no file to any ledgered package." ], "gates": { "derivation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack — self-derived change set of 3 paths vs merge base 353f4e8f1; 14 path-matched + 6 convention-triggered (adds a test file)", "union_run_at_commit": "5c4e0744", "results_all_exit_0": [ "check:changeset-gate-self-tests", "check:driver-conformance — 'OK — 45 covered cell(s), 0 in the DEBT ledger, 0 exempt.'", "check:objectui-changeset", "check:published-files", "check:slot-lookup", "check:test-source-alias — 'OK — 72 packages with tests scanned'", "check:type-source-resolution", "check-adr-0087-registration.mjs", "check-changeset-no-major.mjs — 'This diff introduces no `major` bump.'", "check-ci-filter-parity.mjs", "check-empty-changeset.mjs", "check-plugin-teardown-shape.mjs", "docs-audit/check-affected-docs.mjs", "pm/release-rehearsal-clone.mjs --self-test", "check:query-options-erasure", "check:type-check-coverage", "check:engine-double-contract — 'OK — 397 pinned, 133 in the DEBT ledger, 2 exempt.'", "check:cross-package-test-inputs — 'OK: 16 package(s) read outside themselves, all declared'", "check:where-matcher — '292 matcher(s) discovered ... 0 silently-wrong ... none new.'", "check:nul-bytes — 'OK (scanned 6508 text file(s) ... no raw ASCII control bytes).'" ], "not_run_locally": "check:type-check-debt --re-measure (declared narrowing, see deviations); CI owns it" }, "tests": "Union re-run at final commit 5c4e0744. @objectstack/driver-sql `pnpm test`: 'Test Files 121 passed | 8 skipped (129)', 'Tests 1911 passed | 104 skipped (2015)'; typecheck 'packages/drivers/driver-sql typecheck: Done'. @objectstack/objectql (the consumer) `pnpm test`: 'Test Files 231 passed (231)', 'Tests 4103 passed (4103)'; typecheck exit 0 AFTER building its dependency closure — its first run failed with TS2307 'Cannot find module @objectstack/metadata/errors', a stale-closure artifact, not this diff. New file sql-driver-11202-single-column-unique.test.ts run alone, verbose: 15 passed, 2 skipped — the 2 are the named unprovisioned live PG/MySQL cells (OS_TEST_POSTGRES_URL / OS_TEST_MYSQL_URL unset in this container; they run in the 'Temporal Conformance (live PG + MySQL)' job). ABLATION: width filter `if (columns.length !== 1) continue;` replaced with a no-op; mutation confirmed ON DISK before running (deleted-text grep count 0, injected-marker count 1, git diff --stat 1 insertion/1 deletion); no rebuild needed and none claimed — the pins import ./sql-driver.js as in-package source, never dist. Direction RED as predicted: 9 failures including both PG row-shape cases, the MySQL row-shape case, the end-to-end SQLite cell and the isUnique fold ('expected [ a, email ] to deeply equal [ email ]', 'expected true to be falsy'). Restore leg proven on disk too (marker count 0, width filter count 1, git status clean); the script carried a trap ... EXIT INT TERM restore.", "open_questions": [ { "question": "objectql's derived IntrospectedColumn.isUnique doc still reads 'Whether this column has a unique constraint' — the composite-member phrasing this card retires. It sits in packages/objectql/src/util.ts, outside the declared file surface, immediately above the one real consumer of the flag.", "options": [ "A — leave as filed (#11655) and dispatch it as its own one-line card", "B — authorize folding it into PR #11657 (one TSDoc line, no behaviour change), amending this card's file surface" ], "recommendation": "B, because the repo now carries two declarations of one key with two different meanings, which is the seam #11122's ruling closed; it is one doc line in a file no open PR touches and whose last commit was #11270. Filed as A only to respect the declared surface and the dispatch's stop-on-breach clause — say the word and it is a two-minute amendment." } ], "out_of_scope_findings": [ "filed as #11654: SQLite flags a single-column PRIMARY KEY as isUnique (non-INTEGER PK is a unique auto-index with origin 'pk', which the arm never inspects) while PG/MySQL filter CONSTRAINT_TYPE='UNIQUE' and never see PKs; SQLite also disagrees with itself — an INTEGER PRIMARY KEY is a rowid alias with no auto-index and is not flagged. Both cases measured. No label, left for triage: whether a PK column should carry isUnique is a ruling, not a mechanical fix.", "filed as #11655 (label: finding): objectql's derived IntrospectedColumn.isUnique doc sentence is stale after this narrowing — see open_questions." ] }Generated by Claude Code
Generated by Claude Code
os-warren commentedon Aug 24, 2026
os-dev-report
(Re-posted with a literal-text marker: the HTML-comment form of this marker was stripped by the body sanitizer on comment 5394196946, which is otherwise identical to this one. This comment is the machine-readable copy.)
{ "issue": 11202, "status": "done", "branch": "claude/issue-11202-isunique-single-column", "pr": "https://github.com/objectstack-ai/objectstack/pull/11657", "premise_still_valid": true, "files_changed": [ "packages/drivers/driver-sql/src/sql-driver.ts", "packages/drivers/driver-sql/src/sql-driver-11202-single-column-unique.test.ts", ".changeset/driver-sql-single-column-unique-introspection.md" ], "summary": "All three introspectUniqueConstraints arms normalise to UniqueConstraintMember and decide through one predicate, singleColumnUniqueColumns: a column is reported iff a unique constraint covers it and nothing else. PG additionally selects constraint_schema and keys identity on (schema, name) — its answer spans current_schemas(false) and PG auto-names constraints per table+column, so name-only keying fuses two schemas' same-named constraints and drops a real single-column unique. Contract sentence landed on the producer's own IntrospectedColumn.isUnique declaration in sql-driver.ts. Two riders in the SQLite arm: an expression-index term (PRAGMA index_info name: null) is no longer pushed into the string[] as a literal null but still counts toward index width; output de-duplicated.", "premise_verification": { "sqlite_single_column_filter": "confirmed on synced branch — `if (info.length === 1)`", "pg_returns_all_composite_members": "confirmed — ungrouped constraint_column_usage rows", "mysql_returns_all_composite_members": "confirmed — ungrouped KEY_COLUMN_USAGE rows" }, "deviations": [ "PM assumption 3 FALSIFIED, in the supporting direction: a real consumer exists — packages/objectql/src/util.ts:223 (introspectedSchemaToObjects) maps column.isUnique to a drafted field's `unique: true`. Not a blocker: it is the direct beneficiary (composite members previously drafted single-column uniqueness the DB never enforced). Did not stop, per the dispatch's stop-on-real-consumer clause, because the consumer argues FOR the ruled change; flagged for PM judgment.", "PM route step 3 NOT EXECUTABLE as written: `isUnique` is not declared in packages/spec/src/contracts/schema-diff-service.ts — it is not on the spec contract at all. It lives on two derived interfaces (driver-sql sql-driver.ts, in surface; objectql util.ts, out of surface). Contract sentence landed on the producer's declaration. schema-diff-service.ts NOT touched. Adding isUnique to the spec was considered and rejected as zero-pull public-surface expansion.", "FILE SURFACE HONOURED, not breached: objectql's stale doc line was filed as #11655 rather than edited, since packages/objectql/src/util.ts was not in the declared surface.", "DECLARED NARROWING: check:type-check-debt --re-measure not run locally (needs a full workspace build). driver-sql carries no test-typecheck-debt.json entry; the structural half check:type-check-coverage passed; driver-sql's own tsc --noEmit is green with the new file; the diff adds no file to any ledgered package." ], "gates": { "derivation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack — self-derived change set of 3 paths vs merge base 353f4e8f1; 14 path-matched + 6 convention-triggered (adds a test file)", "union_run_at_commit": "5c4e0744", "results_all_exit_0": [ "check:changeset-gate-self-tests", "check:driver-conformance — 'OK — 45 covered cell(s), 0 in the DEBT ledger, 0 exempt.'", "check:objectui-changeset", "check:published-files", "check:slot-lookup", "check:test-source-alias — 'OK — 72 packages with tests scanned'", "check:type-source-resolution", "check-adr-0087-registration.mjs", "check-changeset-no-major.mjs — 'This diff introduces no `major` bump.'", "check-ci-filter-parity.mjs", "check-empty-changeset.mjs", "check-plugin-teardown-shape.mjs", "docs-audit/check-affected-docs.mjs", "pm/release-rehearsal-clone.mjs --self-test", "check:query-options-erasure", "check:type-check-coverage", "check:engine-double-contract — 'OK — 397 pinned, 133 in the DEBT ledger, 2 exempt.'", "check:cross-package-test-inputs — 'OK: 16 package(s) read outside themselves, all declared'", "check:where-matcher — '292 matcher(s) discovered ... 0 silently-wrong ... none new.'", "check:nul-bytes — 'OK (scanned 6508 text file(s) ... no raw ASCII control bytes).'" ], "not_run_locally": "check:type-check-debt --re-measure (declared narrowing, see deviations); CI owns it" }, "tests": "Union re-run at final commit 5c4e0744. @objectstack/driver-sql `pnpm test`: 'Test Files 121 passed | 8 skipped (129)', 'Tests 1911 passed | 104 skipped (2015)'; typecheck 'packages/drivers/driver-sql typecheck: Done'. @objectstack/objectql (the consumer) `pnpm test`: 'Test Files 231 passed (231)', 'Tests 4103 passed (4103)'; typecheck exit 0 AFTER building its dependency closure — its first run failed with TS2307 'Cannot find module @objectstack/metadata/errors', a stale-closure artifact, not this diff. New file sql-driver-11202-single-column-unique.test.ts run alone, verbose: 15 passed, 2 skipped — the 2 are the named unprovisioned live PG/MySQL cells (OS_TEST_POSTGRES_URL / OS_TEST_MYSQL_URL unset in this container; they run in the 'Temporal Conformance (live PG + MySQL)' job). ABLATION: width filter `if (columns.length !== 1) continue;` replaced with a no-op; mutation confirmed ON DISK before running (deleted-text grep count 0, injected-marker count 1, git diff --stat 1 insertion/1 deletion); no rebuild needed and none claimed — the pins import ./sql-driver.js as in-package source, never dist. Direction RED as predicted: 9 failures including both PG row-shape cases, the MySQL row-shape case, the end-to-end SQLite cell and the isUnique fold ('expected [ a, email ] to deeply equal [ email ]', 'expected true to be falsy'). Restore leg proven on disk too (marker count 0, width filter count 1, git status clean); the script carried a trap ... EXIT INT TERM restore.", "open_questions": [ { "question": "objectql's derived IntrospectedColumn.isUnique doc still reads 'Whether this column has a unique constraint' — the composite-member phrasing this card retires. It sits in packages/objectql/src/util.ts, outside the declared file surface, immediately above the one real consumer of the flag.", "options": [ "A — leave as filed (#11655) and dispatch it as its own one-line card", "B — authorize folding it into PR #11657 (one TSDoc line, no behaviour change), amending this card's file surface" ], "recommendation": "B, because the repo now carries two declarations of one key with two different meanings, which is the seam #11122's ruling closed; it is one doc line in a file no open PR touches and whose last commit was #11270. Filed as A only to respect the declared surface and the dispatch's stop-on-breach clause — say the word and it is a two-minute amendment." } ], "out_of_scope_findings": [ "filed as #11654: SQLite flags a single-column PRIMARY KEY as isUnique (non-INTEGER PK is a unique auto-index with origin 'pk', which the arm never inspects) while PG/MySQL filter CONSTRAINT_TYPE='UNIQUE' and never see PKs; SQLite also disagrees with itself — an INTEGER PRIMARY KEY is a rowid alias with no auto-index and is not flagged. Both cases measured. No label, left for triage: whether a PK column should carry isUnique is a ruling, not a mechanical fix.", "filed as #11655 (label: finding): objectql's derived IntrospectedColumn.isUnique doc sentence is stale after this narrowing — see open_questions." ] }Generated by Claude Code
Generated by Claude Code
os-warren commentedon Aug 24, 2026
Claim amendment (spec seat PM,
session_01Rxnd8cyFnoU8V5y21PaTsy, R3): the dev'sopen_questionsitem is ruled B — the one-line stale TSDoc on the derivedIntrospectedColumn.isUniqueinpackages/objectql/src/util.tsfolds into PR #11657 (withFixes #11655added to the PR body). This amends the claim's declared file surface (comment 5393606894) by exactly that one documentation line, nothing else inpackages/objectql.This is a PM-discretion call, not an escalation: zero behaviour change, and the sentence is made false by this PR's own ruled narrowing — leaving it would have main carrying two declarations of one key with two different meanings between two landings, the seam class #11122's ruling closed. The found consumer (
introspectedSchemaToObjectsdraftingunique: true) is confirmed as arguing FOR the ruled change (composite members previously drafted single-column uniqueness the database never enforced) — the dispatch's stop-on-real-consumer clause is satisfied by the dev's flag + this review, not tripped.Review of the final head follows once the amendment lands.
Generated by Claude Code
docs(objectql): align the derived IntrospectedColumn.isUnique sentenc…
os-warren commentedon Aug 24, 2026
os-dev-report amendment
Amendment to the report in comment 5394208703, per the PM's Option B authorization. Gates + files_changed delta only; everything not listed here is unchanged from that report.
{ "issue": 11202, "status": "done", "amendment": "PM-authorized surface amendment: option B on the open question — the one-line TSDoc correction of IntrospectedColumn.isUnique in packages/objectql/src/util.ts folded into PR #11657. Documentation only, no objectql code. `Fixes #11655` added as its own line under `Fixes #11202`, and the authorization noted in the PR body linking claim comment 5393606894. PR remains draft.", "head": "65f61332", "previous_head": "5c4e0744", "files_changed_delta": { "added": ["packages/objectql/src/util.ts"], "files_changed_now": [ "packages/drivers/driver-sql/src/sql-driver.ts", "packages/drivers/driver-sql/src/sql-driver-11202-single-column-unique.test.ts", ".changeset/driver-sql-single-column-unique-introspection.md", "packages/objectql/src/util.ts" ] }, "gates_delta": { "re_derived_on_amended_diff": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack — 4 paths now (was 3)", "newly_matched_families": [ "pnpm check:durability-log-level — matched via packages/objectql/src ⇢ gate source 'packages/objectql/src'; NOT matched by the pre-amendment diff", "node scripts/check-engine-split-ratio.mjs — matched via packages/objectql ⇢ gate source 'packages/objectql'; NOT matched by the pre-amendment diff" ], "newly_matched_results": [ "check:durability-log-level — exit 0", "check-engine-split-ratio — REFUSED first, then exit 0. On this container's shallow clone it refused to compute rather than emit a wrong number: 'cannot compute the ADR-0076 D7 trigger metric — this clone is shallow and its oldest visible commit on HEAD is 2026-08-12, which sits INSIDE the window'. Re-run after `git fetch --shallow-since=2026-05-19 origin` (the gate's own remedy line): exit 0, 'ratio: 97.6%', horizon 'oldest visible commit 2026-05-21 (predates the window)'. Report-only ADR-0076 D7 metric, unmoved by this diff; the refusal was an environment property, not a diff property." ], "union_re_run_at_commit": "65f61332", "union_result": "all 22 families exit 0 (the 20 previously reported plus the 2 newly matched)", "not_run_locally": "check:type-check-debt --re-measure — declared narrowing unchanged, now covering both packages: neither driver-sql nor objectql carries a test-typecheck-debt.json entry, check:type-check-coverage passed, and both packages' own tsc --noEmit are green. CI owns it." }, "tests_delta": { "objectql": "re-run at 65f61332 — 'Test Files 231 passed (231)', 'Tests 4103 passed (4103)'; typecheck exit 0 at the same head after building its dependency closure", "driver_sql": "not re-run at 65f61332 — both driver-sql files are byte-identical to 5c4e0744, where the suite measured 'Test Files 121 passed | 8 skipped (129)', 'Tests 1911 passed | 104 skipped (2015)'. The amendment touches only packages/objectql/src/util.ts." }, "open_questions": [], "out_of_scope_findings": [ "filed as #11654: SQLite flags a single-column PRIMARY KEY as isUnique while PG/MySQL never do, and SQLite disagrees with itself by key type. Unchanged by this amendment — still out of scope, still unassigned.", "#11655 is no longer an out-of-scope finding: it is fixed by this PR under the PM authorization above." ] }Generated by Claude Code
Generated by Claude Code
os-warren commentedon Aug 24, 2026
ACCEPT — reviewer of record: spec seat,
session_01Rxnd8cyFnoU8V5y21PaTsy(R3 W1). PR: #11657 (head65f61332, amendment included).Verified against GitHub, not the report's prose: all three dialect arms now normalise to
UniqueConstraintMemberand decide through the single exported predicatesingleColumnUniqueColumns— the ruled A→B narrowing exactly (composite members deliberately absent; option B explicitly deferred in the docblock). Quality points personally verified in the final diff: PG constraint identity keyed(schema, name)with the counterfactual pinned in-test (name-only keying loses a genuine single-column unique — the #11201 class); SQLite expression-index members carried through width counting then discarded (never a literalnull, and(d, lower(e))cannot read single-column); both defensive choices fail toward NOT flagging, with the rationale in the predicate's docblock; live-half fixtures prove their own constraints enforce before any absence is asserted. Contract sentence landed on the producer's declaration (deviation accepted:isUniqueis not on the spec contract — adding it was correctly rejected as zero-pull surface expansion), and the PM-authorized fold amendment is exactly +12/-1 TSDoc inpackages/objectql/src/util.tspointing at the producer as the single contract source (Fixes #11655carried). Ablation direction-proven (9 predicted reds, mutation and restore both proven on disk). Gates: 22 script-derived families EXIT=0 at65f61332(including the two newly matched by the amendment; the engine-split-ratio gate's REFUSE-then-deepen behaviour worked as designed). Consumer objectql 4103 tests green; found consumer argues FOR the change (recorded in the claim-amendment comment). Out-of-scope finding #11654 verified filed (PK/isUnique inconsistency — a ruling question, left for triage).Clause-② determination: path limb does NOT fire (no
packages/spec/src/**in the changed set); declaration limbno— no contract review owed. CI at head: 34/34 green. Proceeding to ready + merge queue in this stroke; card closes on merge (Fixes #11202first body line verified).Generated by Claude Code
fix(driver-sql): a PRIMARY KEY is not a unique constraint on the SQLi…
fix(driver-sql): a PRIMARY KEY is not a unique constraint on the SQLi…