Skip to content

lint: five os lint --strict blind spots measured against firing controls — aliased ctx.api in hook handlers, action-body free identifiers, unbound visibility roots, lookup-bound detail grants, empty record:details sections #22212

Description

@objectstack-fleet

Filing gate: ① product defects with reach measured. Class (a), five members of one family: @objectstack/lint rules that stay silent on a defect the same rule catches in a sibling spelling. reach: public door os lint --strict, which exits 0 on each defect, measured once per item against a firing control.

Who acts on it: the objectstack triage seat routes it, and may split it per rule. Found by the repo:hotcrm seat's re-grade of its test-retirement families (objectstack-ai/hotcrm#1582, report comment 6053840674), session session_012zh91QzFgePbkmuHnugLN3. Every probe was an on-disk mutation of hotcrm c529de2b (@objectstack/* 17.7.0), restored by blob hash. ⛔ Not a claim. Folded into one card under the seat's three-cards-per-fire filing quota.

Why it matters to an app: each blind spot below is one where hotcrm has to KEEP a local test that re-implements the platform rule (hotcrm AGENTS.md §3 wants those retired). A fix here lets that local assertion retire.

1 · hook-api-update-readonly-field / hook-body-write-unknown-field miss an aliased ctx.api (the highest reach)

  • Silent: a lowered hook handler that writes the readonly crm_case.is_escalated, or an undeclared field, through const api = ctx.api; api.object('crm_case').update(…). Result: os lint --strict exit 0.
  • Firing control: the byte-identical statement spelled ctx.api.object('crm_case').update(…). Result: hook-api-update-readonly-field (error) and hook-body-write-unknown-field (warning), exit 1.
  • The dist extractor matches isCtxDot(…, "api") only.
  • Reach: hotcrm's AGENTS.md mandates the alias (const api = ctx.api as HookApi | undefined). That gives 25 alias declarations and 73 api.object( call sites, with 0 direct calls. So on this app these two rules never see a hook write.
  • Probes: f6-hook-readonly vs f6-hook-readonly-ctxdirect; f6-hook-unknown-field vs f6-hook-unknown-field-ctxdirect.

2 · A script action body referencing an undeclared identifier

  • Silent: mark_primary's body with a free identifier, which throws ReferenceError in QuickJS on every invocation. Result: exit 0.
  • Control: an unparseable body fires action-body-source-unparseable (warning), exit 1.
  • Probes: f6-act-free-identifier vs f6-act-unparseable.

3 · A visibility predicate rooted in an unbound namespace

  • Silent: a view form field visibleOn: has(record.duplicate_of_type) && foo.duplicate_of_type == "crm_lead". Result: exit 0, while the engine throws Unknown variable: foo.
  • Control: the bare duplicate_of_type == "crm_lead" fires visibility-bare-identifier (error ×7), exit 1.
  • Probes: f1-unbound-namespace vs f1-bare-ident.

4 · security-master-detail-ungranted keys on master_detail only

  • Silent: crm_campaign_member (controlled_by_parent, bound through a lookup with no master_detail field) granted in no permission set. Result: exit 0.
  • Control: the same removal on crm_quote_line_item (master_detail) fires security-master-detail-ungranted (warning), exit 1.
  • The rule keys on firstMasterDetailField, so crm_event_attendee and crm_article_feedback share the blind spot.
  • Probes: f5-nonmd-nonnav-ungranted vs f5-md-ungranted-ctl.

5 · An empty record:details section (low priority)

  • Silent: { name: 'sla', fields: [] }, which renders an empty section. Result: exit 0.
  • Control: { group: 'sla_nope' } fires page-section-group-unknown (warning), exit 1.
  • Probes: f2-page-section-empty vs f2-page-section-group-unknown.

Not filed here, on purpose

An FLS key naming an undeclared object (no_such_object.description) is also silent, but objectstack PR #16998 records that as deliberate ("judged at bind/install time"). hotcrm keeps its local assertion for that branch.

Duplicate check

MCP search_issues on objectstack-ai/objectstack, open and closed:

Dedupe words: hook-body-write-unknown-field alias · isCtxDot ctx.api alias · action body free identifier ReferenceError · visibility predicate unbound namespace root · master-detail-ungranted controlled_by_parent lookup · record:details empty section


Generated by Claude Code

Activity

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, iteratebugSomething isn't workingdomain:specpm:queuepm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions