Skip to content

spec(ai): BlueprintViewSchema and StrictView declare filters (ViewFilterRule[]) and sort, so an AI-built view carries its own filter (ruling A on cloud#2932) #24129

Closed

Description

@objectstack-fleet

Filed by the director seat (summon #43 continuation 3, session_01QJC7i981TSs9L1CGJK59Ax) on the maintainer's ruling A on objectstack-ai/cloud#2932 (batch #358 item 5, 「2932 同意」; the ruling record is that card's Ruled: line). ⛔ Not a claim. Filing gate ①: a measured gap in a published declaration with a named producer and consumer.

What is measured (objectstack origin/main be076dad28a0)

  • packages/spec/src/ai/solution-blueprint.zod.ts:113 BlueprintViewSchema and :341 StrictView carry object, name, label, type, columns, groupBy — no filters, no sort. A plan can say 「overdue only」 in a view's name and nowhere else, so apply_blueprint ships an unfiltered grid and verify_build passes it (objectstack-ai/cloud#2922: 12 rows shown where the plan promised 3, on staging).
  • ViewFilterRuleSchema (packages/spec/src/ui/view.zod.ts) is the declared rule format ListView.filter already uses; views declare sort too. Nothing new is invented.
  • objectstack-ai/cloud PR feat(lint): bidirectional binding-root check for visibility predicates (ADR-0089 D3b) #2931 carries a temporary .extend() of both schemas in cloud (tools/plan-view-intent.ts), the bounded exception ruling A allows until this card lands; its removal card is filed on the cloud board in the same act and is Blocked-by: this card.

Scope

  1. BlueprintViewSchema: filters (an array of ViewFilterRuleSchema, optional) and sort (the shape ListView declares) in the loose shape.
  2. StrictView: the same two keys in the strict, model-facing shape — nullable per the strict pattern, so the model states a view's filter or says null; the descriptions tell the model that a view named by a condition (「overdue」, 「my open」) must carry the matching filter.
  3. The strict/loose conformance test (solution-blueprint.test.ts, the key-set parity) extended to the view shape; the published strict JSON schema regenerates.
  4. Clause-②: yes (widening); minor changeset for @objectstack/spec. No consumer other than cloud's propose_blueprint / apply_blueprint is affected (measured on the card: the blueprint schema's only producer and consumer).

Done when

  • Both schemas declare the keys; the parity test is green; the published strict JSON schema carries filters and sort on views.
  • The cloud removal card can start (the pin bump then deletes the cloud extension and imports from @objectstack/spec/ai).

Related: objectstack-ai/cloud#2932 (the ruling), objectstack-ai/cloud#2922 and its PR #2931 (the defect and the interim fix), objectstack-ai/cloud#2150 (the precedent: navigation viewName, spec first, then the pin).

Activity

  1. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 (takeover shift, serial) · 2026-10-17T03:49Z · #24129: BlueprintViewSchema and StrictView declare filters (ViewFilterRule[]) and sort (ruling A on objectstack-ai/cloud#2932, 「2932 同意」)
    Session: session_01HSDGREvqxQUt7K7pjHXMyC (the seat; the dev is an os-dev subagent of this session)
    Account: huangyiirene (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24129-blueprint-view-filters-sort
    Worktree: objectstack-issue-24129
    Domain: domain:spec (filed by the director seat; this lane's table holds packages/spec)
    Seat: domain:spec#2 (seat post #18549)
    File surface (paths on origin/main 462d02f00a or later; stop on a breach and explain it in the report):


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 24129,
      "status": "done",
      "branch": "claude/issue-24129-blueprint-view-filters-sort",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/24152",
      "session": "session_01HSDGREvqxQUt7K7pjHXMyC (subagent; the parent seat's id, as the claim names it)",
      "premise_still_valid": true,
      "summary": "BlueprintViewSchema (lenient) gains filters: z.array(ViewFilterRuleSchema).optional() and sort: z.array(SortItemSchema).optional(); StrictView in SolutionBlueprintStrictSchema gains filters: z.array(StrictViewFilterRule).nullable() and sort: z.array(StrictSortItem).nullable(). The strict rule has the same three keys {field, operator, value}: value is present and nullable, operator is the plain z.enum(VIEW_FILTER_OPERATORS) (canonical only, with no preprocess fold), and the operator/value-shape refinement is omitted because it has no JSON-Schema form (the lenient parse refuses it). The strict sort entry is {field, order: SortDirectionEnum}. Both describes say that a view named by a condition (overdue, my open) MUST carry the matching filter, with worked rules using {today} and {current_user_id}. Key parity is extended to the VIEW shape and to the nested rule and sort-entry key sets, plus operator and order enum parity. The published json-schema/ai/SolutionBlueprintStrict.json now requires filters and sort on views (required: object, name, label, type, columns, groupBy, filters, sort). Premise A1 held on base 462d02f00a. A2/A3 held: ListView.sort's entry is an inline unexported strictObject, so the lenient side reuses the exported shared SortItemSchema (same keys and vocabulary; it strips unknown keys rather than rejecting them, like every blueprint shape), array-only like ListView. A5 was FALSIFIED on both halves: skills/objectstack-ai/references/_index.md DOES move (+7 pointer lines, because gen:skill-refs lists transitive deps and the blueprint now imports ui/view.zod and shared/enums.zod), and the move does NOT make the PR governed. check-governed-merges --branch verdict on d896c66e6: 'governed-surface predicate: 0 of 8 path(s) hit the register after 1 generated-artifact lift(s) (7 surfaces govern objectstack). NOT governed - ordinary queue landing applies to a PR with exactly this file list.' The PM correction mid-run confirmed keeping it. A6 re-run on head: outside packages/spec, only the comment in packages/cli/src/lint/metadata-eval.ts plus the generated docs. files_changed (8): .changeset/24129-blueprint-view-filters-sort.md; content/docs/references/ai/solution-blueprint.mdx; docs/audits/2026-07-unknown-key-strictness-ledger.counts/ai.md; packages/spec/authorable-surface/ai.json; packages/spec/dropped-refinements.baseline.json; packages/spec/src/ai/solution-blueprint.test.ts; packages/spec/src/ai/solution-blueprint.zod.ts; skills/objectstack-ai/references/_index.md. Size: +318/-7.",
      "tests": "pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2 src/ai/solution-blueprint.test.ts → 60 passed (60), verify-lock VERDICT command-exit 0. The first run had 1 failure from my own test: a missing nullable-union key reports invalid_union, not invalid_type, so the expectation was corrected. Full spec: pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2 → Test Files 692 passed (692), Tests 20969 passed | 1 todo, VERDICT command-exit 0, at 0b87a3245. pnpm --filter @objectstack/spec typecheck → VERDICT command-exit 0 (check:test-typecheck OK). pnpm --filter @objectstack/spec build → VERDICT command-exit 0. The first build exited 1 on the dropped-refinements ledger, then passed after the two printed lines were declared. These ran at 0b87a3245; the merge to d896c66e6 brings only docs/qa/** and examples/app-showcase/**. New cases: lenient carry, optional, identity pins (filters element toBe ViewFilterRuleSchema, sort element toBe SortItemSchema), and refusals asserted as {path, code}: bad operator at views.0.filters.0.operator invalid_value; in with a scalar at views.0.filters.0.value custom; bad order at views.0.sort.0.order invalid_value; string sort at views.0.sort invalid_type. Strict: carry (including an in list and is_null null), null for both keys, missing filters or sort is invalid_type at the key, missing rule value is invalid_union, eq is invalid_value, bad order is invalid_value. Parity: view key sets equal, nested rule and sort key sets equal, operator and order enums equal. No ablation: these are new keys, and no existing tested behaviour changed. The test:repo project and the CLI integration tier were not run locally (CI).",
      "gates": "Final head d896c66e6: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 113 commands (same list as at 0b87a3245); all 113 ran with exit 0, captured before any pipe. --ran: 'Run reconciliation - 113 derived, 113 run, 0 NOT-MEASURED, 0 UNRUN.' check:generated: 'All 14 generated artifacts are up to date'. First pass at 0b87a3245: 106 exit 0, 7 exit 3 (PREREQUISITE NOT MET: check-plugin-teardown-shape --self-test needed fixture commit 621a4876; lint check:doc-formula-expressions, check:doc-security-posture, spec check:skill-examples, check:docs-transcript-drift, check:dual-build-cjs-loads and check:lean-entry-closure needed built formula, lint, client, client-react and objectql). These were re-run exit 0 after turbo run build (35/35 cache hits; spec dist input hash 2153a49d verified unchanged) and git fetch --depth=1 of 621a4876. pnpm check:dev-prereqs exit 0 (local-only family). check-governed-merges --branch: NOT governed (verdict quoted in summary). CI check-runs on d896c66e6 at report time (38 total): success = Check Documentation Links, Check PR Size, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, The card this PR closes must claim this branch, filter; skipped = Console Pin Gate, Dogfood Regression Gate (matrix placeholder), Dogfood Verify CLI, Packed-tarball smoke (opt-in), Temporal Conformance (live PG + MySQL); in_progress = Build Core, Build Docs, Check Changeset, Governed Surface Queue Guard, Lint (CI release and engine gates, ESLint, PM dispatch-gates, docs and code guards, repo and tooling gates, three scoped lanes), Spec property liveness, Test Core 1-6/6, Type Check (consumer gates, debt ledger, source gates, workspace), Dogfood Regression Gate, Auto Label, Flag docs affected by code changes. CI convergence was NOT MEASURED by me (left to PM).",
      "mcp_calls": "0",
      "api_writes": "2 relay dispatches from this session (POST /repos/objectstack-ai/objectstack/dispatches, fleet-write), executed as objectstack-fleet[bot] as 3 REST writes: POST /repos/objectstack-ai/objectstack/pulls (draft PR #24152), POST /repos/objectstack-ai/objectstack/issues/24152/assignees (huangyiirene), POST /repos/objectstack-ai/objectstack/issues/24129/comments (this report). Plus 6 git pushes to the branch (not REST). 0 label writes: none named, and skip-changeset does not apply.",
      "deviations": [
        "Surface beyond the claim's file list, all mechanically required: packages/spec/dropped-refinements.baseline.json (hand-edited ledger; build-schemas.ts refused until ai/BlueprintView: [filters.element] and views.element.filters.element on ai/SolutionBlueprint were declared, sites 764 to 766, schemas 234 to 235; the same ViewFilterRule gap ui/ListView declares as filter.element), docs/audits/2026-07-unknown-key-strictness-ledger.counts/ai.md (gen:strictness-ledger, ai 78 to 80), and skills/objectstack-ai/references/_index.md (gen:skill-refs; kept per the PM correction, NOT governed by the register).",
        "Clause-② spelling: the claim comment 6229261312 carries 'Clause-②: yes'; the dispatch and the card carry 'Clause-②: yes (widening)'. The PR body and changeset use 'Clause-②: yes (widening)'.",
        "Merged origin/main (5c92b0130, 9ffe8af09: docs/qa and examples/app-showcase only) before opening the PR, per AGENTS §10, then re-ran the full 113-command union and check:generated on merge head d896c66e6.",
        "git fetch --depth=1 origin 621a487607881c66b2899b7e3477115229a156b4 into the shared object store, to let check-plugin-teardown-shape --self-test read its pinned fixture. This adds a shallow root; it is additive only.",
        "To measure the skill index move before deciding, gen:skill-refs was run twice with a trap restore. Restoration was proven by git hash-object == HEAD blob 0b0123455 and an empty git diff HEAD. The regenerated file was committed only after the governance verdict.",
        "No describe-prose pin was added (the dev contract forbids pinning prose); the describe content is stated in the PR body instead.",
        "Not run locally, declared to CI: the test:repo project, path-scheduled CI jobs (Test Core shards, Build Core, Build Docs, dogfood) and the CI-only type-check lanes."
      ],
      "open_questions": [
        {
          "question": "For the contract review: the strict mirror's own accept set narrows. A strict document whose views lack filters/sort parsed before and is refused now, because the new keys are required-nullable. Does that stay 'Clause-②: yes (widening)' / minor as the card rules?",
          "options": [
            "A keep yes (widening), minor: the strict mirror is a generation contract whose only producer is the model, which receives the new JSON Schema; viewName, nameField, sharingModel and expression were added the same way under Minor Changes; the lenient schema, which apply_blueprint parses, only widens.",
            "B reclassify yes (narrowing), BREAKING with an ADR-0087 disposition: treats the strict schema as an accept-set contract in its own right."
          ],
          "recommendation": "A, because no stored or hand-authored document is validated against the strict mirror, the precedent for every prior strict key is minor, and the card's ruling names yes (widening)."
        }
      ],
      "out_of_scope_findings": [
        "class: none (observation, not a/b/c: a blueprint is never persisted, so it is not stored re-authored metadata) · The blueprint key is filters (ruled) while ListView's is filter; the lenient blueprint z.object strips undeclared keys, so a hand-authored blueprint view writing the singular filter drops it silently (the same posture as every undeclared blueprint key; the strict path cannot emit it) · carrier: 承接者:无 · noted in PR #24152 Acceptance notes, not filed",
        "class: none (unmeasurable here) · cloud PR #2931's interim .extend() key spelling was not compared (cloud unreadable) · carrier: the cloud removal card that is Blocked-by #24129 · noted, not filed"
      ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #24152 → 9f024d8a2c (Fixes #24129) · domain:spec seat 2 · huangyiirene · session session_01HSDGREvqxQUt7K7pjHXMyC · 2026-10-17T06:08Z

    probe reading
    PR object merged 2026-10-17T06:07Z out of the merge queue (enqueued 2026-10-17T05:35Z); squash 9f024d8a2c on parent 6dede7a51a
    origin/main git merge-base --is-ancestor 9f024d8a2c origin/main → exit 0
    merged vs reviewed head the squash tree b6acb0e639 equals git merge-tree --write-tree 6dede7a51a d896c66e62 (the reviewed head)
    queue branch no gh-readonly-queue/main/pr-24152-* ref remains
    mis-close scan the body's only closing keyword is Fixes #24129; this card closed completed, and no other lane card left the open set
    chain claim 6229261312 · report 6229921125 · ACCEPT → PR #24152 comment 6230084330 · contract review PASS → PR #24152 comment 6230090474 (CONTRACT_REVIEW_TIER, adopted after spot-checks)
    • What now holds on main: BlueprintViewSchema carries optional filters (ViewFilterRuleSchema[]) and sort (SortItemSchema[]); the strict mirror's StrictView carries both as required-nullable, with a strict filter rule of the same three keys and the canonical operator vocabulary. The published SolutionBlueprintStrict.json requires both on views.
    • Downstream: objectstack-ai/cloud#2954 (delete cloud's interim extension, Blocked-by: this card) unlocks for cloud when an installable @objectstack/spec release carries this change, not at this merge: a merge to main publishes nothing.
    • State: pm:dispatched is removed in the write after this comment; the card stays closed.

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:aiAI-native — agent / tool / skill metadata, and the MCP surface an agent drivesdomain:specpriority:p1High: required for production / M2target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions