Skip to content

Should os build fail by default on the accidental hook-body-lowering class? — deferred until the new lint rule has produced a real population number #13838

Closed as not planned

Description

@os-steve

Filed by the domain:cli execution PM seat (#6024), session session_01UngCYXF98BVpYA9hfz6NYk, as the recorded remainder of #13651 / PR #13834. ⛔ Not work today — see the trigger.

The question

#13651 (ask 1) made the accidental hook-body-lowering class loud in os lint: a handler that is expressible as a metadata body but names a module-scope const, helper or import now fails os lint as hook-body/not-lowerable (severity error). ⛔ It deliberately did not change what os build accepts — the fallback-to-bundling catch is kept and pinned.

⇒ Should os build's default eventually fail on that same class?

A keep os build at warn-and-bundle indefinitely
B flip the default to fail after a window, once the lint rule has shown a real population
C flip it now

Implementer's recommendation and mine: B. ⛔ C is unjustifiable on today's evidence, and the reason is the sharpest reading #13651 produced.

⭐ Why the measured zero is not permission to flip

#13651 measured the silent-downgrade population at 0 — 44 callables lowered, 41 bodies extracted, 0 downgraded, across every config in this tree including the reference app.

⚠️ That zero measures avoidance, not absence:

The reference app reads zero BECAUSE IT ALREADY PAID: all 39 callables are written defensively, constants hand-copied into each handler, guarded by eight bespoke pin tests.

And the bound the implementer stated without being asked: a zero inside this tree says nothing about apps outside it, on a published CLI. ⇒ The set the flip would actually affect is precisely the set nobody has measured. Flipping a contract on a number drawn from the wrong population is guessing.

⭐ The lint rule is the instrument that will produce the real number. Deciding before it has reported is the same mistake in miniature that #13411 was dispatched to stop: choosing a repair before the measurement that sizes it.

Restart-when — a predicate, not a reminder

Restart-when: re-run #13651's census on the real build path (loadConfig → normalizeStackInput → lowerCallables, classified off the reason strings extractHookBody actually produces, ⛔ nothing re-implemented) and fire when silent_downgrade_warnings > 0 in any measured tree.

⭐ The line above was added 2026-09-11T13:0xZ by the domain:cli seat (#6024) as an H9 repair, and it encodes THIS section's own predicate — ⛔ no condition was invented, widened or narrowed. The heading below reads Restart-when followed by an em dash, which is prose: the hold-hygiene predicate and the unlock scan both need the key, a colon and a value on ONE line, so for 11 days this card's trigger existed for readers and not for the machine. See the audit comment.

Re-run #13651's own census (the real build path: loadConfig → normalizeStackInput → lowerCallables, classification read off the reason strings extractHookBody actually produced — ⛔ nothing re-implemented) across the measured configs.

This card wakes when silent_downgrade_warnings > 0 in any measured tree — i.e. the lint rule has a population to point at.

⚠️ Two things about that predicate, stated so it is not misread:

  • ⛔ It does not wake on "the rule shipped". Shipping is not reporting. The number is the trigger.
  • ⚠️ It cannot see downstream apps, which are the population that matters most. If a downstream report arrives by any other route — an issue, a support thread, a dogfood run on a tree outside this repo — that is also a wake, and is worth more than the in-tree number. ⛔ Do not treat the in-tree census as the whole instrument; it is the only half that is automatable from here.

⭐ Re-establish the instrument with the same positive control #13651 used before trusting any new zero: a fixture with three known outcomes must return exactly free-identifiers, forbidden-token and extracted. A zero from an unproven instrument is not a reading.

⛔ What this card is NOT

Refs


Generated by Claude Code

Activity

  1. claude commented on Sep 7, 2026

    @claude
    Contributor

    Population figures this card is waiting on, re-derived locally (from #16095)

    This is a measurement hand-off only. Nothing about what os build accepts is changed by the linked work, and the two cards are deliberately not merged.

    #16095 needed the same population number and could not reuse the figure in its own description: the widely quoted "39 of 39 hooks are handler-authored, 24 of 31 actions are body-authored" was measured against the reference CRM's pinned @objectstack/lint@17.3.0, which is outside the platform repository and is not reproducible in this tree.

    Re-derived against this repository's own four example apps (examples/app-crm, app-showcase, app-todo, app-multi-package), loading each real config through loadConfig and normalizeStackInput:

    app hooks handler-authored body-authored actions action body-authored
    app-crm 1 1 0 2 0
    app-showcase 4 0 4 139 125
    app-todo 1 1 0 16 0
    app-multi-package 0 0 0 0 0
    total 6 2 4 157 125

    Two readings worth carrying into this card:

    • Hook authorship in this tree is mixed, not dominated by either shape — 2 of 6 handler-authored. The reference app's ratio is much stronger, so a decision calibrated only on this repository's examples will understate the handler population that real apps carry, and one calibrated only on the reference app cannot be checked in CI here.
    • Actions are overwhelmingly body-authored — 125 of 157 — which is consistent with the standing finding that the action-body door reaches its intake and is not a defect.

    Every inline handler in the table lowers cleanly: lowerCallables produced a body.language === 'js' for all 6 hooks, so none of them is in the refused-extraction class.

    Method note, since the number is the point here: the counts come from the normalized stack rather than from source-text grepping, so a hook registered through a package manifest or an object's actions array is counted the same way the compiler counts it.

    🤖 Generated with Claude Code

    https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8


    Generated by Claude Code

  2. claude commented on Sep 11, 2026

    @claude
    Contributor

    H9 repaired — this hold's trigger existed for readers and not for the machine, for 11 days

    domain:cli execution PM seat (#6024), body edited 2026-09-11T13:00:00Z (API updated_at). ⛔ No label moved: this card stays pm:on-hold, and ⛔ no condition was invented, widened or narrowed.

    What was wrong

    This card was filed by this same seat on 2026-08-31 with a section headed ## Restart-when — a predicate, not a reminder, and the section is good — it names the instrument, the code path and the numeric threshold. But a heading is prose. The hold-hygiene check and the unlock scan both read a line whose key is followed immediately by a colon and a value, anchored at the start of the line; this card had the key followed by an em dash, inside a ## heading. Measured with the patrol's own reader before the edit: 0 values in the body, 0 in the comment channel, against a firing positive control.

    ⇒ For 11 days this was a pm:on-hold card with no machine-fireable exit — the shape the state model forbids outright («两种拼写之外的 hold ⛔ 不合法»).

    What the edit added

    The section's own predicate, on one readable line directly beneath its heading:

    Restart-when: re-run #13651's census on the real build path (`loadConfig` → `normalizeStackInput` → `lowerCallables`, classified off the reason strings `extractHookBody` actually produces, ⛔ nothing re-implemented) and fire when `silent_downgrade_warnings > 0` in any measured tree.
    

    Read back through the same reader: 1 value. Labels unchanged (domain:cli, pm:on-hold, priority:p3).

    ⛔ No trigger-file line was added, deliberately. The sibling repair on #13776 gained two, because that card's predicate is literally a file-content predicate. This card's predicate is a measured population number, not a file edit: touching packages/cli/src/hook-body.ts does not make silent_downgrade_warnings rise, and nominating it would fence every future dispatch on that file behind a hold it cannot discharge. ⇒ the one required line, and nothing beyond what this card already ruled.

    ⚠️ And the card's own warning survives the repair intact and is worth restating, because the readable line could otherwise be misread as easier to fire than it is: it does not wake on "the rule shipped" — shipping is not reporting, and the number is the trigger. The measured zero in #13651 was avoidance, not absence (the reference app reads zero because all 39 callables were already written defensively, behind eight bespoke pins), and a zero inside this tree says nothing about apps outside it on a published CLI.

    Why this is worth a comment rather than a silent fix

    This is the fourth instance of one defect class disposed in this lane today, across three different directives: a decorated key (#17680), a key written mid-line (#16613), a condition left in prose with no key at all (#15638), and now a key followed by an em dash instead of a colon. ⇒ A state whose only exit is machine-gated is only as real as the line the machine reads, and every one of these was written by a seat that believed it had recorded the condition.

    PM dispatch seat · domain:cli · session session_01TSf4DV7ziu4V5j73e46b7c · half-state patrol H9 disposition


    Generated by Claude Code

  3. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    Contributor

    关 not_planned —— 维护者逐张复核 on-hold 卡时同意关闭;推理与重开条件记录在此

    分诊席(session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T10:09Z。维护者 2026-09-23 在分诊会话里逐张复核 pm:on-hold 卡,对第七组的回复原文:「其他同意」。本卡在那一组里的建议是关闭(与 #13718 是一对,#13718 同批按「甲」关闭)。

    本卡的问题,保留原样

    os build 是否应当默认拒绝一个无法编进沙箱体的钩子 —— 今天 os lint 报错,os build 只警告、照样打包。本卡正确地拒绝在没有人口数的情况下拍板,等新的 lint 规则报出真实数量。

    为什么关

    重开条件

    任一满足即带着数据重开,回决裁批决定 os build 的默认严格度:

    • 下游应用报告:一个钩子被 os build 警告后照样打包,上线后行为与作者预期不符;
    • 在真实构建路径上重跑普查(loadConfig → normalizeStackInput → lowerCallables,按 extractHookBody 实际产出的原因字符串分类),拒绝类人口 > 0。

    关闭理由:not_planned,同时摘掉 pm:on-hold。


    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

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions