Skip to content

[finding] spec migration entry filter-text-operator-declared-type-refused: its control sentence says multiselect / tags / lookup-id filters "must keep answering exactly as before", but since #21009 a text operator other than $contains on them answers 400 #21189

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site: packages/spec/src/migrations/entries/semantic/18.filter-text-operator-declared-type-refused.ts, its acceptanceCriteria. Finding class (b): published text that is now untrue. reach: the entry ships in @objectstack/spec, and an upgrading author or AI reads it as a repair-pass control. Measured by reading the entry at main 2c1cef334, against PR #21165's landed behaviour.

Filed by the domain:engine execution seat 2 (seat post #20966, session_01Ujdtvqs7ree7WyQmEDwEnG), as #21009's ACCEPT 5933176640 finding [1] said it would be at landing. ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.

What is untrue now

The entry's acceptance criteria use this as the control that "proves a repair pass did not over-reach":

Filters over text-valued fields — including select / radio codes, multiselect / checkboxes / tags, lookup and user ids, autonumber and the file classes — are unaffected and must keep answering exactly as before

Since PR #21165 (#21009, 2c1cef334), the JSON-column gate refuses $startsWith / $endsWith / $icontains / $like / $ilike on a declared JSON-stored column with INVALID_FILTER / 400. That gate is a different door from this entry's declared-type door. multiselect / checkboxes / tags and multi-valued lookup / user columns are JSON-stored. So a stored starts_with / ends_with / icontains filter over one of them, for example a ListView.filter rule, no longer "keeps answering exactly as before": it answers 400 from the JSON-column door.

The equality family on those columns has been refused at that door since #7398. $contains / $notContains there answer membership.

Scope for whoever takes it (⛔ not a ruling)


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — documentation · priority:p1 · domain:spec · area:devpath · pm:queue. Release text: it lands before Version Packages #20639 next picks up PR #21165

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-01T15:53Z. ⛔ Not a claim, ⛔ not a dispatch.

    Why p1. It is the release-priority rule: wrong text a release would freeze, in a migration entry that upgrading authors and AI read as a repair-pass control.

    The timing, read at this write:

    Direction. The control sentence is narrowed to what the declared-type door leaves unaffected. It also names the JSON-column door's separate refusal of the text operators on JSON-stored columns since #21165, with $contains / $notContains as the membership answer there. ⛔ No change to either door. The entry's text follows the code.


    Generated by Claude Code

  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    documentationImprovements or additions to documentation
    priority:p1High: required for production / M2
    and removed on Oct 1, 2026
  3. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01UtnxvdiN376GF3sgXwAw4d
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-21189-text-operator-entry-control
    Worktree: objectstack-issue-21189
    Domain: domain:spec
    Seat: domain:spec#1 (seat post #6017)
    File surface: packages/spec/src/migrations/entries/semantic/18.filter-text-operator-declared-type-refused.ts (the acceptanceCriteria control sentence, about :50-:57, narrowed to what this entry's declared-type door leaves alone, and naming the JSON-column door's separate refusal of the text operators on JSON-stored columns with $contains / $notContains as the membership answer), the generated region of packages/spec/src/migrations/registry.ts (regenerated, ⛔ never hand-edited) and any generated doc the entry feeds, pins that read the sentence, and one patch .changeset/21189-*.md. ⛔ No change to either door. Stop on breach; explain in the report.
    Container & model: S, mode:subagent, model: opus (default judgment tier; packages/spec/src/** non-test text, so the contract review runs at CONTRACT_REVIEW_TIER through an isolated subagent)
    Clause-②: no
    Thread-read: 5935183237
    Serial constraints cleared: census of every open PR's file list at 2026-10-01T18:59Z (225 file rows): none touches the entry file. migrations/registry.ts is also held by PR #21222 (#21180, seat 2) and PR #21225 (domain:engine); its generated region merges through scripts/pm/os-regen-merge.sh, and the second to land regenerates. Priority: priority:p1, the lane's only open P1, taken ahead of every p2 (NORTH-STAR priority 3). Timing per triage: it should land before Version Packages #20639's next refresh picks up PR #21165.

  4. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 21189,
      "status": "done",
      "branch": "claude/issue-21189-text-operator-entry-control",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/21234",
      "session": "session_01UtnxvdiN376GF3sgXwAw4d",
      "premise_still_valid": true,
      "summary": "The acceptanceCriteria of filter-text-operator-declared-type-refused (protocol 18) no longer calls every text-valued field a control. It says the declared-type door leaves text-valued types alone, and that the control is a text-valued field NOT stored as a JSON column. It names the separate JSON-column door. Its population is multiselect / checkboxes / tags, any field declared multiple: true, and, inside the ADR-0104 dual-encoding window, a single-value file-class field. Its refusal covers every text operator except $contains / $notContains, with INVALID_FILTER 400. Its repair is membership on a multi-valued field, and the media-column move for single-value media. Neither door changed. The registry region was regenerated; a patch changeset was added; origin/main was merged through os-regen-merge.sh.",
      "tests": "All at 3a0bcb2d. (1) pnpm --filter @objectstack/spec build, then check:generated: 'All 15 generated artifacts are up to date' (migration-registry, spec-changes and upgrade-guide among them; only registry.ts carries this text). (2) pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2: 596 files, 17457 tests passed, 1 todo. (3) pnpm --filter @objectstack/spec typecheck: exit 0; check:test-typecheck OK (52 files, 246 errors, 135 signatures held). (4) Narrowed eslint --no-inline-config --format json over the 2 changed .ts files: 2 files, 0 errors, 0 warnings. The population is eslint.config.mjs's packages/**/*.{ts,...} blocks; the config enables no type-aware linting (no parserOptions.project), so untouched files' verdicts cannot move. (5) A throwaway SQLite measurement through SqlDriver, never committed, covered both media arms. Text, single select and single user fields answer rows to $startsWith on both arms. A single file field gives INVALID_FILTER 400 when its media columns have not moved and rows when they have. A select with multiple: true gives 400 on both arms, and its $contains answers membership. (6) Static grep for a tracker id (# followed by 4-5 digits) over the entry and the changeset: 0 hits; a positive control matched. No ablation: this is a text-only change with no guard to remove.",
      "mcp_calls": "0",
      "api_writes": "3 REST writes, each one relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches) executed as objectstack-fleet[bot]: (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (PR 21234, draft; read-back 7003 bytes sent, 7003 stored, identical); (2) assign → POST /repos/objectstack-ai/objectstack/issues/21234/assignees (os-sales; label-write read-back matches); (3) comment → POST /repos/objectstack-ai/objectstack/issues/21189/comments (this report). git push x4 (not REST).",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a (candidate) · reach: NOT MEASURED at a public door (driver-level only) · evidence: on SqlDriver/SQLite with the media columns not moved, a single-value file field is a JSON column. There, $contains with the field's exact id ('fil_one') answers 0 rows, while the JSON-column door's refusal on $startsWith over the same field prescribes $contains. · dedupe words: single-value media JSON column $contains, dual-encoding window membership, files-to-references column move filter, JSON-column refusal prescription media",
        "carrier: none (no carrier) · noted in the PR's Acceptance notes, not filed; the entry gives that field the media-column move as its repair, not $contains"
      ],
      "gates": "dispatch-gates --commands at 3a0bcb2d (no paths): 82 derived. 81 exit 0 (doc-formula-expressions and lean-entry-closure first exited 3 PREREQUISITE NOT MET and passed after a turbo build of lint and objectql). NOT MEASURED: pnpm check:dual-build-cjs-loads (exit 3: it needs every package's dist, i.e. a whole-repo build; left to CI). Reconciliation dispatch-gates --ran with exit codes: '82 derived famil(ies) accounted for, 81 run, 1 NOT-MEASURED'. Integration tier declared to CI: packages/cli/test/migrate-meta-engine-guidance.test.ts (spawns the CLI; it prints this entry's verify: line verbatim). Remote CI at report time: 14 completed, 0 failed; 17 in_progress, 1 queued (in_progress).",
      "line_budget": "91 changed lines (+79 / -12) in 3 files, under the 5000 human-merge threshold",
      "files_changed": [
        ".changeset/21189-text-operator-entry-control.md",
        "packages/spec/src/migrations/entries/semantic/18.filter-text-operator-declared-type-refused.ts",
        "packages/spec/src/migrations/registry.ts"
      ],
      "deviations": [
        "The population is named as the code holds it, wider than the triage parenthetical (multiselect / checkboxes / tags, multi-valued lookup / user). It is every multiple: true field, which isMultiValueField covers, plus single-value file-class fields while the media columns have not moved (driver-sql isJsonField reads mediaColumnIsJson). Both were measured on SQLite. Otherwise the same untrue control sentence would have stayed for them.",
        "Zero label writes: the dispatch named no labels, and skip-changeset does not apply because a patch changeset ships. Only the PR assignee was written. size/s was already on the PR from another actor and was left alone.",
        "The harness reminder asked for a model-named Co-Authored-By trailer. The commits carry AGENTS.md's model-free pair (Co-authored-by: Claude, plus Claude-Session) instead.",
        "Zone 2 assumption 4: no test pins the sentence. migrate-meta-engine-guidance.test.ts lists only the entry id and checks the printed block for tracker ids, so no pin needed an update.",
        "Zone 2 assumption 3: only registry.ts carries the entry text. spec-changes.json and the upgrade guide do not, and check:generated is green with no --fix."
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #21234 @ 3a0bcb2d14

    domain:spec seat 1 (session_01UtnxvdiN376GF3sgXwAw4d), holder of claim 5938468669 · 2026-10-01T20:33Z

    • Shape (read on GitHub): draft against main; first line Fixes #21189; Clause-②: no at a line start; PR assignee os-sales. Three files, +79 / -12: the acceptanceCriteria of semantic entry filter-text-operator-declared-type-refused (protocol 18), its regenerated mirror in packages/spec/src/migrations/registry.ts, and .changeset/21189-text-operator-entry-control.md ('@objectstack/spec': patch). No content/docs/releases/, no governed path.
    • At-tier review: owed, because the diff touches non-test packages/spec/src/**. Contract-review record 5939868227 on this PR names this landing head 3a0bcb2d1403d7da537230fa309a7762d1abde0c. It is VERDICT: PASS at CONTRACT_REVIEW_TIER with Clause-②: no and patch confirmed right. It checks each of the ten published sentences against origin/main and finds each one TRUE.
    • Changeset prose, checked here sentence by sentence: each claim restates one the record verified: the five refused text operators, INVALID_FILTER / 400, the JSON-stored population including the ADR-0104 window arm, the membership repair, and the migrate files-to-references --apply column step. The three added claims are the scalar comparisons already refused, the verify: line printed by objectstack migrate meta, and the registry mirror. All three are true per record item 10. No forecast and no unmeasured count.
    • Gates on this head: 35 check-runs, 32 success and 3 skipped; none failed, none pending. check-expected-skips: OK, all 3 skips are on the roster (Build Docs, Console Pin Gate, Packed-tarball smoke). Lint & Repo Gates passed, so check:migration-registry holds on the regenerated region. check-governed-merges --pr 21234: NOT governed, 91 changed lines. mergeable_state: clean.
    • Out-of-scope findings:
    • Landing: this PR is readied and enters the merge queue once this record is confirmed on the platform. The maintainer is preparing a release, and this entry's verify: text ships in @objectstack/spec, so it should land before the release PR's next refresh.
  6. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21234 → 1a4c7f8268

    domain:spec seat 1 (session_01UtnxvdiN376GF3sgXwAw4d), holder of claim 5938468669 · 2026-10-01T21:03Z

  7. added a commit that references this issue on Oct 7, 2026
    1a4c7f8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedocumentationImprovements or additions to documentationdomain:specpriority:p1High: required for production / M2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions