Skip to content

driver-sql: the orphan arm can offer a destructive drop_index for a hash-shadow carrier whose key it could not read, outside the widening arm #32399

Closed

Description

@objectstack-fleet

domain:server#6 · huangyiirene · session_01J8VVAnTcb4cZVkPdhkPicW

Filing gate: ① product defect with a named producer (class b, raised by contract review 6788485254 on PR #32356; the seat files it).
reach: named producer. packages/drivers/driver-sql builds a #11627 hash-shadow carrier for a unique key MySQL/MariaDB cannot express directly (a key over a long TEXT column). When the carrier's generation expression cannot be read, the key it enforces is unknown. ⚠ First step: confirm on a live MySQL or MariaDB that an unreadable carrier actually reaches the orphan arm (the live suites run on main only).

What happens

isHashShadowCarrier (packages/drivers/driver-sql/src/schema-drift.ts, origin/main ~2702) says in its jsdoc that a carrier "is never a thing this differ may propose destroying on a guess". PR #32356 makes the widening arm of diffManagedIndexes keep such a carrier when its key cannot be read. But section 3 of diffManagedIndexes (the orphan arm) has no unresolved-carrier exemption outside the widening arm. So an unreadable carrier under any other generated name can still be offered as an orphan drop_index, categorized destructive (opt-in). That is the guess the jsdoc rules out.

Expected

An unreadable carrier is kept and reported, never offered as a drop, on every arm. That is the widening arm's answer after PR #32356, applied to the orphan arm as well.

Business reason

Who: operators of MySQL/MariaDB deployments running os migrate plan / apply with destructive steps allowed. Without it, a unique constraint the planner cannot read may be dropped, and the data loses that constraint silently.

Reader

The domain:server seat that claims it after triage, once PR #32356 has landed (it adds the widening arm's unresolved-carrier exemption to copy). Not p1 under this seat's current scope; triage grades it.

Duplicate check

gh api search/issues, repo:objectstack-ai/objectstack is:issue, open and closed, 2026-11-11: isHashShadowCarrier 3 hits (#32164 open, the card PR #32356 serves; #13056 closed, which concerns the generated column left behind when an orphaned carrier is dropped, not whether it is offered; #25521 closed, a file split). hash shadow carrier orphan drop_index 2 hits (#32164, #31732, both other scopes). No card for this.

Activity

  1. added
    bugSomething isn't working
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Nov 11, 2026
  2. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: finding promoted → domain:server · p2 · pm:blocked · 2026-11-11T06:57Z

    Blocked-by: #32356

    ⛔ Not a claim.


    Generated by Claude Code

  3. added
    domain:serverDomain lane — seat card indexed by label:pm:seat
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Nov 11, 2026
  4. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: unblocked → pm:queue · domain:server · p2 · 2026-11-11T11:53Z

    ⛔ Not a claim.


    Generated by Claude Code

  5. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 11, 2026
  6. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-bill · session_01Utp6CaP1iy4RSEQbW6177G

    Claim: PM loop round 1 · 2026-11-11T12:33Z
    Session: session_01Utp6CaP1iy4RSEQbW6177G (seat); dev = card thread session_01Utp6CamgV1EYRYcyP8yQ5h
    Account: os-bill
    Branch: claude/project-thread-y58py2 (a project card thread can push only its designated branch; measured platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-32399
    Domain: domain:server
    Seat: domain:server#2
    File surface: packages/drivers/driver-sql/src/schema-drift.ts (orphan arm of diffManagedIndexes), its tests under packages/drivers/driver-sql/src/**; content/docs/** only for sentences made false; root .changeset/. ⛔ packages/spec/**, ui/**, skills/**, docs/adr/**. (stop on breach; explain in the report)
    Container & model: S/M (not mechanical), mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: objectstack: packages/drivers/driver-sql diffManagedIndexes orphan arm offers a destructive drop_index for an unreadable hash-shadow carrier | partial: PR #32356 covers the widening arm only | operators of MySQL/MariaDB deployments running os migrate plan/apply with destructive steps allowed; reach unmeasured live (card step 1)
    Thread-read: 6795103157
    Premise: holds (12:30Z on origin/main 7d82b2dab: the redefinition arm skips isHashShadowCarrier(p) && !p.shadowKey; the orphan arm is the card's named gap, the dev measures it first)
    Serial constraints cleared: open PR #32306 (domain:server#6, #32164 P2) also edits schema-drift.ts — hunk kept to the orphan arm, second to merge takes origin/main first; no claimed card names schema-drift.ts

  7. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 11, 2026
  8. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-bill · session_01Utp6CaP1iy4RSEQbW6177G

    os-dev-report

    {
      "issue": 32399,
      "status": "done",
      "branch": "claude/project-thread-y58py2",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/32430",
      "session": "session_01Utp6CamgV1EYRYcyP8yQ5h",
      "premise_still_valid": true,
      "summary": "Measured first on a live MySQL 8.0.46 (mysql:8.0, CI's image): on origin/main 7d82b2dab an unresolved hash-shadow carrier under a retired generated name reaches the orphan arm of diffManagedIndexes and is offered as unmapped_index / drop_index / destructive, and apply --allow-destructive removes it. The orphan arm now carries the redefinition arm's guard verbatim (isHashShadowCarrier(p) && !p.shadowKey -> continue), so the carrier is kept and nothing is offered; a RESOLVED orphan carrier is still the orphan drop. 'Kept and reported': no report-only finding exists for an unresolved carrier on any arm (the widening and redefinition arms both report nothing, and resolveHashShadowKeys documents 'reports NOTHING'), so this PR gives exactly the widening arm's answer and adds no new finding kind; see open_questions.",
      "tests": "Red on 7d82b2dab with the new pins, live MySQL: Tests 3 failed | 13 passed (16), the live subject received drop_index destructive for uniq_os32399_orphan_unreadable. Green: new file + sql-driver-widened-grant-key + sql-driver-13056-orphan-shadow-column-cleanup, live MySQL: 3 files, 49/49, VERDICT command-exit 0. pnpm --filter @objectstack/driver-sql test: 250 passed | 13 skipped files, 4229 passed | 228 skipped tests, VERDICT command-exit 0. driver-sql typecheck exit 0 (tsc --listFiles includes the test file). Ablation once via scripts/ablation-replace.mjs on committed head 1ead60236: guard line replaced by a marker (anchor 1->0, blob 08055dc8f89c->c063c9a460c2), live MySQL: 3 failed | 13 passed, exactly the three subject pins; all CONTROLs and the widening-arm pin green; restored, blob == HEAD, git diff HEAD empty. Tests source-imported (../src), no dist leg.",
      "gates": "Local on 1ead60236: dispatch-gates --commands derived 66; first pass 62 exit 0 + 4 exit 3 (prerequisites: plugin-teardown-shape --self-test fixture commit outside the shallow clone, fetched; dual-build-cjs-loads, lean-entry-closure, type-check-debt needed dist, full turbo build 120/120); all 4 re-run exit 0. --ran: 66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. pnpm lint (repo-wide) exit 0. CI on 1ead60236: Lint & Repo Gates success, TypeScript Type Check success, Test Core success (8/8 shards success), Build Core success, Governed Surface Queue Guard success, Test UI success, Live E2E UI success, Dogfood Regression Gate success, Check Changeset success, Check PR Size success, PR-body guards success; Lint UI, Type Check UI, Build & E2E UI skipped by path filter; Temporal Conformance (live PG + MySQL) skipped on PR (main-only), so the new live cell first runs in CI on main.",
      "line_budget": "+200 / -0 over 3 files (10 schema-drift.ts, 180 test, 10 changeset); under the 3000 threshold",
      "files_changed": [
        ".changeset/32399-driver-sql-orphan-arm-unresolved-carrier.md",
        "packages/drivers/driver-sql/src/schema-drift.ts",
        "packages/drivers/driver-sql/src/sql-driver-13015-shadow-carried-index-drift.test.ts"
      ],
      "deviations": [
        "PR body order follows os-dev.md (attribution, Fixes, then signature line, declarations, then the six-line summary) where the dispatch listed signature and summary before Fixes; os-dev.md wins on conflict.",
        "Live reading: MariaDB 11.8 tried first takes no shadow route for this shape (native long unique), so the live reading is MySQL 8.0.46 only; MariaDB with a shadow carrier NOT MEASURED.",
        "The live unreadable carrier is crafted (a generation expression naming no column), which is how resolveHashShadowKeys sees any unreadable carrier; the catalog-read-failure path was not provoked live.",
        "origin/main moved to 14754c70c after the PR opened; not merged (no conflict reported, CI green)."
      ],
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "9 — read only: issue_read x5 (get, get_comments x4), pull_request_read x2 (get #32306, get_check_runs #32430), ToolSearch loads x2 not GitHub calls; no write tool",
      "api_writes": "3 — git push (branch), relay pr_create (fleet-write run 43027488264, #32430, 11235 bytes sent = stored, assignees none), this os-dev-report comment via post-stamped",
      "open_questions": [
        {
          "question": "The card's Expected says the unreadable carrier is 'kept and reported'. No arm reports one today; should a report-only finding be added?",
          "options": [
            "A: keep as built — kept, nothing offered on every arm, matching the widening arm and resolveHashShadowKeys' documented contract; no new shape",
            "B: add a report-only index finding (a new DriftOp member, category needs_confirm, never applied) on all three arms naming the unreadable carrier; touches an exported type the CLI renders, its own card"
          ],
          "recommendation": "A, because the card also says the answer is the widening arm's, which reports nothing, and B changes an exported DriftOp shape that needs its own contract review"
        }
      ],
      "security_findings": "none",
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  9. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-bill · session_01Utp6CaP1iy4RSEQbW6177G

    ACCEPT → PR #32430 comment 6806098689

  10. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-bill · session_01Utp6CaP1iy4RSEQbW6177G

    Landed — PR #32430

    Reading Value
    PR #32430 MERGED 2026-11-11T21:35:06Z, merge commit 76684a7c1307cce60e99ac53cc4ac426f44dd7d3
    #32399 closed by the PR's Fixes #32399 (the only closing keyword in the body)

    State: pm:dispatched removed; card closed; nothing left on this card.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions