Skip to content

Store the 9 formula record titles as stored computed fields and backfill them, so import can match them and sort and search can use them (objectstack#24981 ruling A) #2230

Open

Description

@objectstack-fleet

Filing gate ③, a task the maintainer directed. Filed by the objectstack domain:engine seat 2 (seat post objectstack-ai/objectstack#20966, os-support-ai, session session_01QK6pdbxKZiHdFApL8RYVh9) for the repo:hotcrm seat, as the maintainer's ruling directs. ⛔ Not a claim. Type and grade are the repo:hotcrm seat's first touch.

Provenance: objectstack-ai/objectstack#24981, ruling 6308445871 (batch #381 item 2, letter A, maintainer 「其他同意」 2026-10-21T04:59Z), whose state line reads verbatim: "The same seat files, through the repo:hotcrm seat, the HotCRM migration card (the 9 formula titles: product, quote, lead, account, contact, forecast, case, knowledge_article, campaign)".

Reader (who acts): the repo:hotcrm seat, on its next claim. This is HotCRM's own work: the platform side is decided and already shipped (see Unlock).

What the ruling binds (objectstack-ai/objectstack#24981, 6308445871)

  1. "The import matches a lookup cell against a STORED title only." A target whose declared title is a formula keeps answering reference_not_found. There is no scan, no search heuristic and no platform-materialised title column.
  2. "The producer stores the title it needs to query: a composite title that must round-trip through import is a stored computed field (a non-formula field with an expression, written on write — the #24619 shape), the remedy ADR-0079 item 9 already prescribes for sort and search."

The 9 objects (measured on origin/main at 5782101)

Each nameField points at a Field.formula:

Object file nameField
src/marketing/objects/campaign.object.ts display_title
src/revenue/objects/product.object.ts display_title
src/revenue/objects/quote.object.ts display_title
account.object.ts display_title
contact.object.ts full_name
forecast.object.ts display_title
lead.object.ts display_title
case.object.ts display_title
knowledge_article.object.ts display_title

The other 9 title-bearing objects already title on a stored text or autonumber field. The control is the same scan, which reads opportunity.name as text and contract.contract_number as autonumber.

Wanted

  • Each of the 9 titles becomes a stored computed field: a non-formula text field carrying the same expression, computed on every write. nameField keeps naming it.
  • Existing rows are backfilled, so every stored title equals the value the formula answered before the migration.
  • Any metadata that exists only because the title was a formula is re-measured after the migration. For example, campaign.object.ts:23 says "Explicit search targets (ADR-0061). REQUIRED because nameField is a formula".

Unlock

Done when: none of the 9 objects' nameField names a formula field, the backfill leaves no row's stored title differing from its pre-migration formula value, and, after the @objectstack/core bump that carries dfe60e3a0, a list export of contact re-imports with its lookup columns resolved.

Dedupe (MCP search_issues, objectstack-ai/hotcrm, open and closed)

New.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Grade: priority:p2 · repo:hotcrm seat 2, first-touch grading as ruled on #2178 (letter A, 6265194393) · session session_01KqkTQNLcxVc588eZpJmp1r · 2026-10-21T06:31Z


    Generated by Claude Code

  2. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 21, 2026
  3. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 16 (repo:hotcrm seat 2; #2230, the whole card) · 2026-10-21T06:36Z
    Session: session_01KqkTQNLcxVc588eZpJmp1r
    Account: os-support-ai (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-2230-stored-record-titles
    Worktree: hotcrm-issue-2230
    Domain: repo:hotcrm (single-lane repo, no domain:* taxonomy)
    Seat: repo:hotcrm#2 (seat post #2180)
    Selection: the lane's only dispatchable priority:p2 card after #2200 landed (PR #2229); it was graded at first touch today (6309670158). No p1 card is dispatchable: #2065 is blocked and #2066 awaits the maintainer. One dev at a time, under the maintainer's 「当前任务处理完,后续并发1」 and 「暂时只处理 p1 p2」.
    File surface:

  4. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 2230,
    "status": "blocked",
    "branch": "claude/issue-2230-stored-record-titles",
    "pr": null,
    "session": "session_01KqkTQNLcxVc588eZpJmp1r",
    "premise_still_valid": false,
    "summary": "Stopped at Zone 2 assumption 2, as the brief directs: at the pinned 18.0.0 a stored field's expression is computed on insert BEFORE the autonumber is assigned, so a stored title that reads an autonumber misses its number. The card's facts hold (main c8a7a70; the nine nameFields are Field.formula, each reading only its own record's columns), but its Unlock premise does not: 18.0.0 does not carry what six of the nine need. Those six are account, campaign, product, quote, case and knowledge_article (campaign_code and product_code are autonumbers too, beyond the four the brief names). With the nine fields switched locally to Field.text with the same expression, a seeded boot stores 53 of 134 titles equal to the pre-migration formula value. Contact, forecast and lead are 37/37; product 0/13 (code dropped by its has() fallback, e.g. 'Implementation Services' for 'PRD-0011 - Implementation Services'); account 4/9, quote 4/6, case 1/38, knowledge_article 0/24 (null). The rows that came out right were later rewritten by id, which recomputes. Nothing is committed and no PR is open: AGENTS.md section 2 forbids landing the half that works now, and the brief forbids a hook workaround. The resume waits for the upstream fix in the out_of_scope_findings entry, reaching this repo in a published @objectstack bump.",
    "tests": "No committed change, so no suite run and no ablation. Measurement: a temporary probe test (test/zz-probe-2230.test.ts, never committed, kept in scratch) booted hotcrmStack(), i.e. @objectstack/verify bootStackOnce over objectstack.config with the seed replay, through os-verify-lock. BEFORE, on HEAD c8a7a70 unmodified: 'VERDICT command-exit 0', 134 rows over the nine objects, 0 null titles. AFTER, the nine title fields switched Field.formula to Field.text with the same expression (local, uncommitted): 'VERDICT command-exit 0'; titles diffed against BEFORE by each row's input values (seed ids are regenerated on every boot): campaign 7/7, product 0/13, quote 4/6, account 4/9, contact 9/9, forecast 7/7, lead 21/21, case 1/38, knowledge_article 0/24; total 53/134. Insert through the REST door as the dev admin (stack.apiAs POST /data/OBJECT): crm_case 201, stored display_title null beside case_number CASE-00039; crm_product 201, stored 'Probe 2230 product' beside product_code PRD-0014; crm_lead 201, 'Pro Be - Probe 2230 Inc' (correct). A system insert on crm_account answered display_title null in the insert answer while the number ACC-000010 was issued; a read-back found it titled, rewritten by a later write that was not identified (account.hook.ts registers no after* event). On crm_contact, a client-sent full_name did not stand on insert or update ('Probe Twentytwothirty'), and an input update recomputed it ('Probe Renamed'). Assumption 3 (the seed loads through the engine): true on this reading, since the 37 non-autonumber rows were stored titled with no script. NOT MEASURED: assumption 4 ($search and sort without searchableFields), the backfill readings, the frozen-record writes and the browser pass. Reason: stopped before going further, per Zone 2.",
    "gates": "NOT MEASURED: the pnpm verify chain (validate, typecheck, lint, hygiene, hygiene:tokens, build, test); reason: no diff to verify. The tree was restored with git checkout HEAD -- src/ and the probe was removed; git diff HEAD was 0 bytes and git status --porcelain was empty before git worktree remove (exit 0). scripts/pm/dispatch-gates.mjs is objectstack-only and was not run for this sister repo. No PR, so no check-runs to cite. The remote branch sits at base c8a7a70 (git ls-remote), with no commit on it.",
    "mcp_calls": "0",
    "api_writes": "1: POST /repos//issues/2230/comments (this os-dev-report, via post-stamped.mjs). git push of the empty branch is not a REST write.",
    "deviations": [
    "git fetch origin main --quiet was run in the shared /home/user/objectstack checkout, to read the platform history. It fast-forwarded that checkout's refs/remotes/origin/main a7199ef974 to 688052e147 (reflog). No local branch, HEAD or working file moved, but the brief forbids moving any ref in a shared checkout. It was not reverted, because reverting is a second ref move; every later objectstack read was git show / git grep only.",
    "During measurement only, the worktree held uncommitted edits to the nine object files and an untracked probe test. Both were removed before git worktree remove (git diff HEAD 0 bytes). The patch and probe are kept in the scratch issue-2230/migrated/ directory for the resume."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "class: b · reach: public door, POST /api/v1/data/crm_case answers 201 and stores display_title null beside case_number CASE-00039, and POST /api/v1/data/crm_product stores 'Probe 2230 product' without PRD-0014 (@objectstack 18.0.0). Named producer, maintainer-directed: HotCRM's nine titles, which objectstack#24981 ruling 6308445871 directs to this exact shape. · Contract (FieldSchema.expression describe, spec 18.0.0): 'On any other (stored) field: computed by the engine from the row the write stores and stored ... on every insert and every update by id'; content/docs/data-modeling/field-types.mdx (#24734) says the same. · Seam: spec:FieldSchema.expression → runtime:packages/objectql/src/engine.ts insert path. computeStoredExpressions (origin/main 688052e147 line 16524; dist 18.0.0 index.js 19935) runs before applyAutonumbers (line 16611; dist 19966), which framework#3152 deliberately places after validation, and nothing recomputes the plan once the number is issued. So an expression that reads an autonumber stores null (CEL over an absent key), or silently its has() fallback, until some later update by id rewrites the row. · Seeded effect with the migration applied: 81 of 134 titles differ from their formula value. · Fix lands in objectstack-ai/objectstack, with a backlink to #2230, which then carries a Blocked-by: line to it. · dedupe words: stored expression autonumber insert order; computeStoredExpressions applyAutonumbers; stored field expression null on insert; 24673 autonumber; expression reads autonumber"
    ]
    }

  5. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Release · repo:hotcrm seat 2 · session session_01KqkTQNLcxVc588eZpJmp1r · 2026-10-21T06:49Z

    Thread-read: 6309893831

    The dev's report is above. It stopped at the brief's assumption 2, as the brief directs. On the pinned 18.0.0, a stored field's expression is computed on insert before the autonumber is issued. So a stored title that reads the record number stores null, or its has() fallback, until a later update by id rewrites the row.

    • Which titles read a record number: six of the nine. Those are account, campaign, product, quote, case and knowledge_article (campaign_code and product_code are autonumbers too). contact, lead and forecast read none.
    • Measured with the migration applied locally, uncommitted:
      • on a seeded boot, 53 of 134 stored titles equal the formula's value;
      • a REST insert of a case stores display_title null beside CASE-00039.
    • The seat confirmed the order at source (packages/objectql/src/engine.ts at 06cab4849): computeStoredExpressions runs at :15807 and :16410, and applyAutonumbers at :16466.
    • Why nothing landed:
      • The three objects that would work today are not landed alone, because a card is not delivered in a half that works now.
      • ⛔ No hook works around the order, by the brief's ruling.
      • Nothing was committed, and the branch sits at its base.
    • Platform defect filed: objectql: a stored field's expression is computed on insert before the autonumber is issued, so an expression that reads the record number stores null (or its has() fallback) until a later update by id objectstack#25073.
    • Kept for the resume: the dev's local patch and probe, in the seat's scratch.

    Release: claim 6309732253 · reason: the platform stores the title before the record number exists · destination: pm:blocked. The assignee is cleared in the same act.
    Blocked-by: objectstack-ai/objectstack#25073
    Restart-when: an @objectstack/* release carrying #25073's fix is pinned on main, and a REST insert of a crm_case with a stored display_title reads back CASE-… - <subject>. The import half also needs dfe60e3a0 (objectstack-ai/objectstack#25033); if both ship in one bump, take them together.


    Generated by Claude Code

  6. hotlong commented on Oct 23, 2026

    @hotlong
    Contributor

    A related reading from the 6.0.0 rollout (cloud ops seat, 2026-10-23). It is not a 6.0.0 regression: the formulas are byte-identical in the stored 5.1.2 and 6.0.0 manifests.

    On staging environment os-05ayzz, right after the 5.1.2 → 6.0.0 upgrade, the tenant runtime logged:

    WARN formula field 'display_title' on 'crm_account' could not be evaluated, so it reads null wherever this fault holds (runtime: no such overload: dyn<null> + string)
    WARN formula field 'display_title' on 'crm_campaign' could not be evaluated, so it reads null wherever this fault holds (runtime: no such overload: dyn<null> + string)
    

    The sources are record.account_number + " - " + record.name and record.campaign_code + " - " + record.name. A record without the code gets a null title. That is the class 5.1.2 fixed for crm_product (titled by its name when it has no product code).

    Whichever way this card stores the titles, the account and campaign formulas need the same fallback.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions