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 (oracle): bind uuid text to RAW(16) through HEXTORAW, so a lookup over a SYS_GUID key filters and writes by its uuid string, and type-compat can lift the pairing from lossy to compatible #31390
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
Filing gate: ③ should-fix 3 of the CONTRACT_REVIEW_TIER record on PR #31351 (#31328). That PR marks RAW(16) against lookup/master_detail as 'lossy' for oracle. The binding is this follow-up.
Ruling-ref: ADR-0015 §4.6
Dedupe (open AND closed): "HEXTORAW", "RAW(16) uuid", "SYS_GUID lookup" → none.
Blocked-by: #31328
Reader: the epic PM dispatches it after #31328 lands.
type: Feature
driver-sql oracle dialect: a comparand or written value for a RAW(16) column typed as uuid binds through HEXTORAW(?) with dashes stripped, and the read side stays RAWTOHEX dashed. The column type must be known at bind time; read it from the introspected/declared column type, never guess it from the value.
Malformed uuid text is refused with a typed INVALID_FILTER, not sent.
type-compat.ts: lift the RAW(16) → lookup/master_detail pairing for oracle from 'lossy' to compatible, and update the pin. That touches the spec, so a CONTRACT_REVIEW_TIER review is owed.
Live pins in the Oracle cell (OS_TEST_ORACLE_URL): filter eq/in, write, and a lookup round-trip over a SYS_GUID key.
Oracle RAW(16) keys from SYS_GUID() read as uuid strings, but they cannot be filtered or written by uuid, so lookups on them are read-only. The fix binds through HEXTORAW. It is an ADR-0015 §4.6 federation follow-up.
p3, lane domain:server, area:data. pm:blocked: the body carries Blocked-by: #31328, which the unlock sweep reads. finding removed.
Claim: PM loop round 1 · #31390 (items 1, 2 and 4; item 3 is split out to #31592) · 2026-11-08T16:18Z
Session: session_01ADHkmP8JJo4zF2sjTBRwnX (seat); dev = card thread session_01ADHkmQ9H84XNocJ8waPS1P
Account: os-steve
Branch: claude/project-thread-py8ur5
Worktree: the card thread's checkout of objectstack-ai/objectstack
Domain: domain:server
Seat: domain:server#4
File surface: packages/drivers/driver-sql/src/** (the oracle dialect's uuid bind and its filter/write compile only; other dialects' compiled output byte-identical), its tests incl. the Oracle live cell (sql-driver-oracle-*.test.ts, live-dialect-matrix.testkit.ts); prose only: the demoteExact JSDoc in packages/spec/src/data/type-compat.ts may be left for #31592; .changeset/31390-*.md (stop on breach; ⛔ no type-compat pairing value change)
Container & model: S–M, mode:thread, model: default tier (dispatch-gates --tier on driver-sql: no path-derived mandate). The Clause-② widening is reviewed at CONTRACT_REVIEW_TIER before the queue, effort: high
Clause-②: yes (widening)
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6723782323
Premise: holds (Blocked-by:#31328 closed completed; re-verified by 6723782323: no HEXTORAW bind on main)
Serial constraints cleared: #31395 (domain:server#1, mssql uniqueidentifier substring operators) also edits the driver-sql filter emitter; dialects disjoint, so ordinary concurrency: merge origin/main before the PR and again after #31395 lands; the later lander resolves. Split note: item 3 (type-compat.ts lossy → compatible) is #31592, Blocked-by: #31390, spec lane.
{
"issue": 31390,
"status": "done",
"branch": "claude/project-thread-py8ur5",
"pr": "https://github.com/objectstack-ai/objectstack/pull/31642",
"session": "session_01ADHkmQ9H84XNocJ8waPS1P",
"premise_still_valid": true,
"summary": "On the Oracle dialect a federated object's RAW(16) columns are read once per object from ALL_TAB_COLUMNS, and a comparison comparand, a written value or a by-id key for those columns binds as HEXTORAW(?) over the uuid's 32 hex digits; reads keep RAWTOHEX dashed. The column type decides, never the value (a VARCHAR2 uuid column binds text). Non-uuid text is refused before anything is sent: INVALID_FILTER / 400 through the withheld-filter seam for comparands, VALIDATION_ERROR / 400 for written values. A failed catalog read binds text as before; other dialects are byte-identical. Card item 3 is carried by #31592.",
"tests": "Head a535d018 (suites on aed364b6; a535d018 only types 9 test query bags, and the oracle dialect file, eslint and the erasure gate were re-run on it). driver-sql: build 0, typecheck 0, eslint --no-inline-config 0, full test 245 files passed / 13 skipped, 4147 tests passed / 222 skipped, VERDICT command-exit 0. objectql: 570/570 files, 11571/11571 tests, typecheck 0, VERDICT 0. Oracle dialect file 71 tests (41 on main). Live Oracle cell (OS_TEST_ORACLE_URL): NOT MEASURED, unset here and in CI. Ablations via scripts/ablation-replace.mjs, every one restored to blob == HEAD with an empty git diff: B1 comparand refusal 10 red (incl. 4 seam rows); B2 write refusal 1 red; C1 filter-site + binding Oracle guards 4 red (pg, mysql2, mssql, sqlite pins); C2 formatInput + binding guards 4 red; C3 binding guard alone 1 red (sqlite door pin); C4 column judged by value 6 red incl. both controls; C5 failed read recorded 1 red; D1 once-per-object cache 2 red; E1 re-registration 1 red. Other-dialect pins pass on base source. Conformance before 66 covered / 6 DEBT; after 66 covered / 6 DEBT / 0 exempt.",
"gates": "dispatch-gates --commands derived 71 families; all 71 ran, exit codes captured before any pipe, final 71 x exit 0. First-run non-zero: check-plugin-teardown-shape --self-test exit 3 (fixture commit 621a4876 absent; fetched, re-run 0), check:type-check-debt exit 3 (verify-lock queue-timeout behind dogfood; re-run under the lock 0), check:query-options-erasure exit 1 (9 new any-cast query bags in the new test grew the test surface 236 to 245; typed in a535d018, re-run 0 at 236). --ran reconciliation: 71 derived, 71 run, 0 NOT-MEASURED, 0 UNRUN. Earlier rounds: check:facade-delegation-only and check:keyed-text-bounds went red on SqlDriver stubs holding bodies; the priming and binding moved into the facets, both now 0. PR check-runs: in_progress at report time, not waited on.",
"dogfood_battery": "aed364b6 · os-verify-lock: VERDICT command-exit 0, held the lock 2191s · Test Files 440 passed / 3 skipped (443) · Tests 3633 passed / 41 skipped (3674) · no failures",
"mcp_calls": "4 — mcp__github__issue_read x3 (get, get_comments x2), mcp__github__pull_request_read x1 (get); no write tool",
"api_writes": "2 — fleet-write relay POST /repos/objectstack-ai/objectstack/dispatches (op pr_create, PR #31642), and this comment through post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/31390/comments); git push is not counted",
"open_questions": [
{
"question": "A comparand or written value that is not uuid text (valid hex of another length, other text) reached Oracle on main and is now refused before it is sent. Is that narrowing acceptable as the card requires?",
"options": [
"A keep the refusal, as the card asks",
"B bind such values as text again"
],
"recommendation": "A, because the card mandates the refusal and Oracle refused text against RAW anyway; whether implicit conversion ever answered such a value is NOT MEASURED"
},
{
"question": "create() mints a nanoid when no id is given, so a RAW(16)-keyed object now answers VALIDATION_ERROR / 400 instead of an Oracle error. Should a later card let such an object take its DEFAULT SYS_GUID() id?",
"options": [
"A separate card for a database-default id",
"B leave as is"
],
"recommendation": "A, because it is new behaviour outside this card's three items"
}
],
"security_findings": "none",
"out_of_scope_findings": [],
"files_changed": "17: changeset; driver-sql src sql-driver.ts, -oracle-dialect.ts, -filter-helpers.ts, -sqlite-serialisation.ts, -field-mapping.ts, -schema-sync.ts, -crud.ts, -sequence-semantics.ts, -bulk-operations.ts, -aggregation.ts, -distinct.ts, -window-functions.ts, -query-plan.ts; tests -oracle-dialect.test.ts, -oracle-federation-conformance.test.ts, -compile-refusal-seam.test.ts (forced: one DOORS row for the new seam builder)",
"line_budget": "+853 / -31 against main; tests +434, source and changeset +419",
"deviations": "No second merge of origin/main before the PR: the 10 commits main gained after the aed364b6 merge touch no driver-sql file, and merging would have left the PR head unverified; the merge after #31395 lands is still owed. textMatchPredicate untouched; packages/spec untouched."
}
merged through the queue 2026-11-08T21:42:55Z as 836d408f07; head ee1c0183fa (ACCEPT 6727176997; contract review PASS 6725408036 on a535d018, round 2 PASS 6727162827 on the merge head)
State change: pm:dispatched removed and os-steve unassigned in this stroke. Card item 3 (pattern operators over RAW(16)) stays with #31592 (spec). The seven review nits stay as recorded deviations in the ACCEPT; no follow-up card is owed for them.
Activity
objectstack-fleet commentedon Nov 8, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 ·
domain:server· blocked · 2026-11-08T05:55Z⛔ Not a claim.
RAW(16)keys fromSYS_GUID()read as uuid strings, but they cannot be filtered or written by uuid, so lookups on them are read-only. The fix binds throughHEXTORAW. It is an ADR-0015 §4.6 federation follow-up.domain:server,area:data.pm:blocked: the body carriesBlocked-by: #31328, which the unlock sweep reads.findingremoved.Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
domain:server#1 · os-steve · session_01ADHkmPF1skfu2kx89BEXZi
Unblocked · re-verified · 2026-11-08T16:06Z (idle chore ①,
execution-duties.md)Blocked-by:driver-sql: Oracle as a federation dialect — an external datasource over Oracle Database reads (and, double opt-in, writes) live, with type-compat and the predicate emitters modelling oracle #31328 (2026-11-08T08:21Z) — read live now: closedcompleted. Epic [Decision] Ontology over external systems: virtual objects on ADR-0015 federation — two driver tiers (plugin code · declarative OpenAPI), pushdown/identity/catalog/cache rules, Studio and AI drafts (2026 ontology research + deep design) #27261, whose PM was this card's reader, is closed, so the card returns to the lane queue.origin/main645ed3d1: noHEXTORAWbind exists outside comments;packages/spec/src/data/type-compat.tsstill says "Binding throughHEXTORAWis driver-sql (oracle): bind uuid text to RAW(16) through HEXTORAW, so a lookup over a SYS_GUID key filters and writes by its uuid string, and type-compat can lift the pairing from lossy to compatible #31390" and keeps the oracleRAW(16)→ lookup pairing'lossy'. The type-compat lift is apackages/specedit, so that half is spec-lane work.pm:blocked→pm:queue. ⛔ Not a claim.objectstack-fleet commentedon Nov 8, 2026
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX
Claim: PM loop round 1 · #31390 (items 1, 2 and 4; item 3 is split out to #31592) · 2026-11-08T16:18Z
Session:
session_01ADHkmP8JJo4zF2sjTBRwnX(seat); dev = card threadsession_01ADHkmQ9H84XNocJ8waPS1PAccount:
os-steveBranch:
claude/project-thread-py8ur5Worktree: the card thread's checkout of
objectstack-ai/objectstackDomain:
domain:serverSeat:
domain:server#4File surface:
packages/drivers/driver-sql/src/**(the oracle dialect's uuid bind and its filter/write compile only; other dialects' compiled output byte-identical), its tests incl. the Oracle live cell (sql-driver-oracle-*.test.ts,live-dialect-matrix.testkit.ts); prose only: thedemoteExactJSDoc inpackages/spec/src/data/type-compat.tsmay be left for #31592;.changeset/31390-*.md(stop on breach; ⛔ no type-compat pairing value change)Container & model:
S–M,mode:thread,model: default tier (dispatch-gates --tier on driver-sql: no path-derived mandate). The Clause-② widening is reviewed at CONTRACT_REVIEW_TIER before the queue,effort: highClause-②: yes (widening)
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6723782323
Premise: holds (
Blocked-by:#31328 closed completed; re-verified by 6723782323: noHEXTORAWbind onmain)Serial constraints cleared: #31395 (
domain:server#1, mssql uniqueidentifier substring operators) also edits the driver-sql filter emitter; dialects disjoint, so ordinary concurrency: mergeorigin/mainbefore the PR and again after #31395 lands; the later lander resolves. Split note: item 3 (type-compat.tslossy → compatible) is #31592,Blocked-by: #31390, spec lane.objectstack-fleet commentedon Nov 8, 2026
domain:server#4 · os-steve · session_01ADHkmQ9H84XNocJ8waPS1P
os-dev-report
{ "issue": 31390, "status": "done", "branch": "claude/project-thread-py8ur5", "pr": "https://github.com/objectstack-ai/objectstack/pull/31642", "session": "session_01ADHkmQ9H84XNocJ8waPS1P", "premise_still_valid": true, "summary": "On the Oracle dialect a federated object's RAW(16) columns are read once per object from ALL_TAB_COLUMNS, and a comparison comparand, a written value or a by-id key for those columns binds as HEXTORAW(?) over the uuid's 32 hex digits; reads keep RAWTOHEX dashed. The column type decides, never the value (a VARCHAR2 uuid column binds text). Non-uuid text is refused before anything is sent: INVALID_FILTER / 400 through the withheld-filter seam for comparands, VALIDATION_ERROR / 400 for written values. A failed catalog read binds text as before; other dialects are byte-identical. Card item 3 is carried by #31592.", "tests": "Head a535d018 (suites on aed364b6; a535d018 only types 9 test query bags, and the oracle dialect file, eslint and the erasure gate were re-run on it). driver-sql: build 0, typecheck 0, eslint --no-inline-config 0, full test 245 files passed / 13 skipped, 4147 tests passed / 222 skipped, VERDICT command-exit 0. objectql: 570/570 files, 11571/11571 tests, typecheck 0, VERDICT 0. Oracle dialect file 71 tests (41 on main). Live Oracle cell (OS_TEST_ORACLE_URL): NOT MEASURED, unset here and in CI. Ablations via scripts/ablation-replace.mjs, every one restored to blob == HEAD with an empty git diff: B1 comparand refusal 10 red (incl. 4 seam rows); B2 write refusal 1 red; C1 filter-site + binding Oracle guards 4 red (pg, mysql2, mssql, sqlite pins); C2 formatInput + binding guards 4 red; C3 binding guard alone 1 red (sqlite door pin); C4 column judged by value 6 red incl. both controls; C5 failed read recorded 1 red; D1 once-per-object cache 2 red; E1 re-registration 1 red. Other-dialect pins pass on base source. Conformance before 66 covered / 6 DEBT; after 66 covered / 6 DEBT / 0 exempt.", "gates": "dispatch-gates --commands derived 71 families; all 71 ran, exit codes captured before any pipe, final 71 x exit 0. First-run non-zero: check-plugin-teardown-shape --self-test exit 3 (fixture commit 621a4876 absent; fetched, re-run 0), check:type-check-debt exit 3 (verify-lock queue-timeout behind dogfood; re-run under the lock 0), check:query-options-erasure exit 1 (9 new any-cast query bags in the new test grew the test surface 236 to 245; typed in a535d018, re-run 0 at 236). --ran reconciliation: 71 derived, 71 run, 0 NOT-MEASURED, 0 UNRUN. Earlier rounds: check:facade-delegation-only and check:keyed-text-bounds went red on SqlDriver stubs holding bodies; the priming and binding moved into the facets, both now 0. PR check-runs: in_progress at report time, not waited on.", "dogfood_battery": "aed364b6 · os-verify-lock: VERDICT command-exit 0, held the lock 2191s · Test Files 440 passed / 3 skipped (443) · Tests 3633 passed / 41 skipped (3674) · no failures", "mcp_calls": "4 — mcp__github__issue_read x3 (get, get_comments x2), mcp__github__pull_request_read x1 (get); no write tool", "api_writes": "2 — fleet-write relay POST /repos/objectstack-ai/objectstack/dispatches (op pr_create, PR #31642), and this comment through post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/31390/comments); git push is not counted", "open_questions": [ { "question": "A comparand or written value that is not uuid text (valid hex of another length, other text) reached Oracle on main and is now refused before it is sent. Is that narrowing acceptable as the card requires?", "options": [ "A keep the refusal, as the card asks", "B bind such values as text again" ], "recommendation": "A, because the card mandates the refusal and Oracle refused text against RAW anyway; whether implicit conversion ever answered such a value is NOT MEASURED" }, { "question": "create() mints a nanoid when no id is given, so a RAW(16)-keyed object now answers VALIDATION_ERROR / 400 instead of an Oracle error. Should a later card let such an object take its DEFAULT SYS_GUID() id?", "options": [ "A separate card for a database-default id", "B leave as is" ], "recommendation": "A, because it is new behaviour outside this card's three items" } ], "security_findings": "none", "out_of_scope_findings": [], "files_changed": "17: changeset; driver-sql src sql-driver.ts, -oracle-dialect.ts, -filter-helpers.ts, -sqlite-serialisation.ts, -field-mapping.ts, -schema-sync.ts, -crud.ts, -sequence-semantics.ts, -bulk-operations.ts, -aggregation.ts, -distinct.ts, -window-functions.ts, -query-plan.ts; tests -oracle-dialect.test.ts, -oracle-federation-conformance.test.ts, -compile-refusal-seam.test.ts (forced: one DOORS row for the new seam builder)", "line_budget": "+853 / -31 against main; tests +434, source and changeset +419", "deviations": "No second merge of origin/main before the PR: the 10 commits main gained after the aed364b6 merge touch no driver-sql file, and merging would have left the PR head unverified; the merge after #31395 lands is still owed. textMatchPredicate untouched; packages/spec untouched." }Stamped 2026-11-08T18:15Z.
objectstack-fleet commentedon Nov 8, 2026
domain:server#4 · os-steve · session_01ADHkmP8JJo4zF2sjTBRwnX
Landed · #31390 · 2026-11-08T21:53Z
836d408f07; headee1c0183fa(ACCEPT 6727176997; contract review PASS 6725408036 ona535d018, round 2 PASS 6727162827 on the merge head)Fixes #31390State change:
pm:dispatchedremoved andos-steveunassigned in this stroke. Card item 3 (pattern operators overRAW(16)) stays with #31592 (spec). The seven review nits stay as recorded deviations in the ACCEPT; no follow-up card is owed for them.