Skip to content

AGENTS.md documents the broken related-list filter spelling as correct, cites a rejected line as the example, and forbids fixing it #1257

Description

@os-zhuang

AGENTS.md documents the broken related-list filter spelling as correct, cites a rejected line as the canonical example, and forbids fixing it

The instruction

AGENTS.md lines 79–81, in the ObjectQL section every metadata author is required to read before their first edit:

*.flow.ts node config takes filter: (44 occurrences across 17 of the 21 flow files; where: in none), and a page component config takes filter: in the AST-array form (src/pages/lead_detail.page.ts:217). Do not "fix" one surface's spelling into another's.

The line it cites

src/pages/lead_detail.page.ts:217:

filter: [['status', '!=', 'completed']],

What the build says about that line

⚠ page "lead_detail_page" · record:related_list: filter.0: Invalid input: expected object, received array
  rule: component-props-invalid

record:related_list declares filter as an array of rule objects ({ field, operator, value }), with operator drawn from a closed enum. The AST-array form is not a second legal spelling — it is rejected, dropped, and the list renders unfiltered. On that page the consequence is user-visible: an "Open Tasks" list that lists completed tasks.

Why this is worse than the three defects it produced

Three different broken spellings of the same filter now exist across the record pages, each dropped silently:

site spelling build verdict
case_detail.page.ts op: 'neq' Unrecognized key(s) on this filter rule: op
opportunity_detail.page.ts operator unset filter.0.operator: Invalid option … (nothing is set there)
lead_detail.page.ts:217 bare AST array filter.0: Invalid input: expected object, received array

They were filed as #1248 and, for the third, as a comment on it. But the spellings are not three independent typos — the instruction file blesses one of them and tells the next author not to correct it. An AI author who reads AGENTS.md, follows it exactly, and copies the cited line will reproduce this defect and believe they got it right. The prohibition (Do not "fix" one surface's spelling into another's) is aimed at a real hazard — flow filter: versus hook where: genuinely are different surfaces — but it was extended to a third case where the two spellings are not two surfaces, just one correct shape and one rejected one.

This repo's charter makes that expensive: 「展品撒谎等于教每个照抄的 AI 撒谎」. Here the exemplar's instruction manual is the thing that lies, which reaches further than any single page — every fork inherits AGENTS.md.

What needs to change

  1. Correct the claim: page component filter: takes rule objects, not the AST array. Keep the flow/hook half of the paragraph — it is right and it is load-bearing.
  2. Cite a line that actually validates, or cite none. A citation to a rejected line is a trap with a footnote.
  3. Narrow the prohibition so it stops covering "do not conform to the declared props schema".
  4. Worth considering: the reason all three spellings survive is that PageComponentSchema.properties is an open bag and the build's rejection is advisory only (objectstack#5068). Until that closes, AGENTS.md is doing the enforcement — which is exactly why it has to be right.

Found while dispatching #1209; the third spelling was measured by the dev on that card, and the AGENTS.md citation was verified by the PM against origin/main @ a0bc5e8d.

Activity

  1. added
    bugSomething isn't working
    documentationImprovements or additions to documentation
    on Aug 23, 2026
  2. self-assigned this
    on Aug 23, 2026
  3. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    Claim: PM loop round 4 (hotcrm seat)
    Session: session_61f28fb9-8e31-4a6f-b4d8-10f749a092d2
    Branch: claude/issue-1257-agents-md-filter-spelling
    Worktree: hotcrm-issue-1257
    Domain: (hotcrm has no domain:* taxonomy — repo-wide seat)
    File surface: AGENTS.md only (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus
    Clause-②: no — instruction-file correction; no contract behaviour change.
    Serial constraints cleared: the AGENTS.md serial queue is drained — #856/PR #1232 merged at 65fdf424 (verified on origin/main); base your worktree on a ref that includes it. No other in-flight claim touches AGENTS.md.

    Authorization — maintainer direct-dispatch, verbatim (未译): 「加种子互动,顺带把 #1257 排了」

  4. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor
    {
      "issue": 1257,
      "status": "done",
      "branch": "claude/issue-1257-agents-md-filter-spelling",
      "pr": "https://github.com/objectstack-ai/hotcrm/pull/1263",
      "premise_still_valid": true,
      "summary": "Corrected the ObjectQL paragraph in AGENTS.md (one paragraph, +14/-5, plus a changeset). Re-measured on base d9a9aaf9: #1254 did NOT remove the cited line — it fixed the record:activity `types` binding on the same page (#1209), and src/pages/lead_detail.page.ts:217 still reads `filter: [['status','!=','completed']]`. Re-measured the PM's mechanism premise and it HELD: no record:related_list filter in src/pages/ passes validation on this base, so the paragraph now cites the SCHEMA rather than a repo line — RecordRelatedListProps.filter in @objectstack/spec/ui is z.array(strictObject({field, operator, value})) with operator = z.preprocess(normalizeFilterOperator, z.enum(VIEW_FILTER_OPERATORS)), which is why the bare AST array and the `op:` key are both refused. Falsified one detail of the card's table: case_detail.page.ts:188 and opportunity_detail.page.ts:222 carry the SAME shape ({field, op, value}) and each raises BOTH diagnostics (unrecognized key `op` AND operator unset) — not two different spellings across two files. The prohibition is narrowed to the flow-`filter:`-vs-hook-`where:` hazard, prefaced by the boundary it lacked: a different surface never licenses a shape that surface's own schema rejects. The three broken pages are untouched (#1248's scope, still open).",
      "tests": "Full eight-gate `pnpm verify` chain + the CI first-step gate, re-run on the COMMITTED head 5fcddb47 with a clean tree (`git status --porcelain` empty), each exit captured by redirect (never through a pipe), each gate run individually so no && short-circuit could hide a later one. All 0: check-stackblitz-lock ('package-lock.json is in sync with package.json (v3).'), validate, typecheck, lint ('76 warning(s), 10 suggestion(s)'), lint:i18n-gate ('OK i18n lint gate: 0 `i18n/missing-*` issues'), hygiene ('OK source hygiene clean'), hygiene:tokens ('OK source token ratchet clean'; authored total ~134,680 / ceiling ~140,000), build ('Artifact: dist/objectstack.json'), test ('Test Files 121 passed (121)', 'Tests 2851 passed | 2 skipped (2853)'). AGENTS.md consumers enumerated and checked rather than assumed: test/docs-drift.test.ts (inline src/<dir>/ guard + drawn-tree guard), docs-role-hierarchy, docs-object-coverage, source-hygiene-header-position, source-hygiene-scan-surface, scripts/check-source-hygiene.mjs root text-file list. Grepped test/ scripts/ docs/ content/ .changeset/ for 'AST-array', \"one surface's spelling\", '44 occurrences', 'lead_detail.page.ts:217' — zero hits, so no drift guard pinned the old wording and none needed updating. Token ratchet is structurally unmoved (its surface is src/**/*.ts; this diff contains no src/ path). Base-tree measurement that drove the edit came from `pnpm build` on d9a9aaf9, which printed component-props-invalid / component-props-unknown-key on all three sites. Flow-side counts re-derived and corrected in the file: filter: 47 code occurrences across 18 of 22 flow files (was 44/17/21; 48 raw grep hits, one a comment at demo-bootstrap.flow.ts:296), where: still 0. Both touched files scanned for control bytes — clean.",
      "open_questions": [],
      "out_of_scope_findings": []
    }
  5. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    PM review — ACCEPT. PR #1263. The instruction file stops lying, and it now explains why instead of pointing at a line.

    Verified against the diff and the installed spec

    • The corrected paragraph cites the schema, not a repo line — and I confirmed the schema claim in the shipped @objectstack/spec dist: normalizeFilterOperator exists exactly as described, preprocessing aliases (neq→not_equals, nin→not_in, …) into the closed VIEW_FILTER_OPERATORS vocabulary. Notably that means op: fails not because neq is unknown — the normalizer would have accepted it as a value — but because the key is wrong; the dev's wording ("no other key accepted") captures precisely that.
    • Grepped the added lines for page.ts:<line> citations: zero. The card's own defect — a citation to a rejected line — is not recreated with a different line number, and the paragraph says on purpose why no in-repo example is cited (every current record:related_list filter is a rejected form, The Open Tasks related lists never filter out completed tasks: op / neq are not the spellings record:related_list accepts #1248).
    • The narrowed prohibition gains the boundary it lacked: "a different surface never licenses a shape that surface's own schema rejects" — the flow-filter:-vs-hook-where: hazard stays protected, the blessing of schema-rejected spellings is gone.

    Two of my dispatch inputs corrected by measurement — both in the right direction

    1. I wrote that fix(pages): filter the lead Activity timeline by feed kind, not object name (#1209) #1254 "may already be gone" for the cited line. Re-measured: fix(pages): filter the lead Activity timeline by feed kind, not object name (#1209) #1254 fixed the record:activity binding on the same page; lead_detail.page.ts:217 still carries the AST array. The dev re-derived instead of inheriting.
    2. My card's three-spelling table was wrong in one detail: case_detail:188 and opportunity_detail:222 carry the same {field, op, value} shape, each raising both diagnostics — two spellings across the repo, not three. Corrected in the changeset's account, and it slightly simplifies The Open Tasks related lists never filter out completed tasks: op / neq are not the spellings record:related_list accepts #1248's eventual fix.

    Flow-side occurrence counts re-derived and updated (44/17/21 → 47/18/22, one raw hit excluded as a comment) — the numbers in the file are now measurements with a dated base, not folklore.

    Verification

    Full eight-gate chain green on the committed head with a clean tree, each gate run individually with redirected exit codes. AGENTS.md consumers enumerated (six candidate guards read; greps for the old wording across test/ scripts/ docs/ content/ .changeset/ — zero hits), so no drift guard pinned the old text. That check is what stops this PR from being the next #1252-shaped surprise.

    Disposition

    Ready + merge queue. Fixes #1257 closes the card on merge. With this, every AI author who reads the repo's instruction file before their first edit — which is all of them, it is the binding file — reads the correct shape and the reason the wrong ones are wrong.

  6. removed their assignment
    on Aug 23, 2026
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

    bugSomething isn't workingdocumentationImprovements or additions to documentationpm:dispatchedDispatched to a dev agent by /pm-dispatch

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions