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
Filing gate: ① product defects with reach measured. Class (a), five members of one family:
@objectstack/lintrules that stay silent on a defect the same rule catches in a sibling spelling. reach: public dooros 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:hotcrmseat's re-grade of its test-retirement families (objectstack-ai/hotcrm#1582, report comment6053840674), sessionsession_012zh91QzFgePbkmuHnugLN3. Every probe was an on-disk mutation of hotcrmc529de2b(@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-fieldmiss an aliasedctx.api(the highest reach)crm_case.is_escalated, or an undeclared field, throughconst api = ctx.api; api.object('crm_case').update(…). Result:os lint --strictexit 0.ctx.api.object('crm_case').update(…). Result:hook-api-update-readonly-field(error) andhook-body-write-unknown-field(warning), exit 1.isCtxDot(…, "api")only.const api = ctx.api as HookApi | undefined). That gives 25 alias declarations and 73api.object(call sites, with 0 direct calls. So on this app these two rules never see a hook write.f6-hook-readonlyvsf6-hook-readonly-ctxdirect;f6-hook-unknown-fieldvsf6-hook-unknown-field-ctxdirect.2 · A script action body referencing an undeclared identifier
mark_primary's body with a free identifier, which throwsReferenceErrorin QuickJS on every invocation. Result: exit 0.action-body-source-unparseable(warning), exit 1.f6-act-free-identifiervsf6-act-unparseable.3 · A visibility predicate rooted in an unbound namespace
visibleOn: has(record.duplicate_of_type) && foo.duplicate_of_type == "crm_lead". Result: exit 0, while the engine throwsUnknown variable: foo.duplicate_of_type == "crm_lead"firesvisibility-bare-identifier(error ×7), exit 1.f1-unbound-namespacevsf1-bare-ident.4 ·
security-master-detail-ungrantedkeys on master_detail onlycrm_campaign_member(controlled_by_parent, bound through a lookup with no master_detail field) granted in no permission set. Result: exit 0.crm_quote_line_item(master_detail) firessecurity-master-detail-ungranted(warning), exit 1.firstMasterDetailField, socrm_event_attendeeandcrm_article_feedbackshare the blind spot.f5-nonmd-nonnav-ungrantedvsf5-md-ungranted-ctl.5 · An empty
record:detailssection (low priority){ name: 'sla', fields: [] }, which renders an empty section. Result: exit 0.{ group: 'sla_nope' }firespage-section-group-unknown(warning), exit 1.f2-page-section-emptyvsf2-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_issueson objectstack-ai/objectstack, open and closed:hooks[i].body.source— a key the author never wrote — on bothos buildandos lint#16546 is the reported key path, [lint] 零字段对象(external / 数据源自省 schema)让 hook / action write-set 规则把每一个写都误报 #4383 is zero-field objects, and the rest are runtime cards.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