You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7362ce1
Browse filesBrowse the repository at this point in the historyBrowse files
fix(lint): 18 more author-time rule ids print a `fix:` line of one remedy sentence, and `os explain RULE_ID` carries what those lines used to explain
6
+
7
+
Clause-②: no
8
+
9
+
-**Shorter fix lines.** Each finding of these 18 rule ids now carries a `hint` (the CLI's `fix:` line, the runtime issue's `hint`) of one remedy sentence of at most 200 characters on every variant the lint suite fires (the lengths here are the `hint` alone; the CLI prints it after `fix: `). The longest of each, before → after:
-**One line, one remedy.** Where a fix line explained its remedy, the explanation moved: why `runAs: 'system'` is the channel for a static readonly field and why a `beforeInsert` stamp survives the strip; why a hook-derived value lands on a `readonlyWhen`-locked record, the drop-the-field alternative and that the warning never blocks a build; how to pick between the two bulk contracts; the controlled-by-parent tier precedence and what each sharing baseline means; how to tell which half of a sharing rule on a public object is wrong; why `sourceView` is an interface page's one binding channel; the descriptor's optional keys and the schedule's default; the api trigger's signature format; the connector's `provider`, the Basic auth variant, where `credentialRef` resolves and that a `{variable}` template draws nothing.
19
+
-**A list becomes a nearest name.**`security-fls-unknown-field` no longer lists up to twelve of the object's fields; it names the nearest declared or registry-injected column when one is close (`'crm_account.description' is the nearest`), and none otherwise. `page/visualization-without-binding` names the field TYPE the derivation looks for and no longer repeats the name pattern it also tries.
20
+
-**`os explain RULE_ID` carries the rest.** What the fix lines stopped saying is each id's `RULE_EXPLANATIONS` entry in `@objectstack/lint`, which `os explain RULE_ID` prints. Two ids had no entry and gain one, so their `rule:` line now ends with the `os explain` pointer: `security-wildcard-vama` ("why the '*' entry cannot carry View All / Modify All") and `flow-trigger-unknown-object` ("why an unknown trigger object only warns"). The other 16 entries gain paragraphs. The auth variants and the descriptor keys the lines and entries spell out are held to the spec's `ConnectorInstanceAuthSchema` and `TimeRelativeTriggerSchema` by the rules' tests.
21
+
-**At the runtime publish gate** (Studio, REST `PUT /api/v1/meta`, and the MCP and AI authors that write through that door), 13 of the 18 fire; the `hint` FROM → TO, measured at the door:
Studio's save-advisory toast prints an advisory's `hint` after its message, so the credential, readonlyWhen, unknown-object and ungranted-detail toasts shorten, and Studio's draft-changes panel shows the `hint` in place of the message for the two controlled-by-parent errors its in-browser security check finds on object drafts. No Studio, REST or MCP reader in this repository or in objectui matches on `hint` text; a tool that did should match on `rule` and `path` instead.
27
+
-**Never at the runtime gate:**`action-dispatch-contract-mismatch`, `page/visualization-without-binding`, `action-api-update-readonly-when-field` and the two `sharing-rule-object-*` ids run on the CLI only.
28
+
-**Unchanged:** every `message` (the verdict), rule id, severity and `path`, and what each rule accepts or refuses.
**BREAKING**: an accept-set narrowing on a published authoring surface, shipped as `minor` under the launch-window convention for breaking changes.
12
+
13
+
Functions are one flat namespace resolved by name: a hook's `handler`, an action's `target` and a flow `script` node's `config.function` all look a function up by its name. The `functions`**array** form could author one name twice, and nothing refused it. Measured on `main` at this change's base with `functions: [{ name: 'kc_a', handler: first }, { name: 'kc_a', handler: second }]`:
14
+
15
+
-`objectstack validate` exited 0 (`valid: true`);
16
+
-`objectstack build` exited 0 and shipped `[{ name: 'kc_a' }, { name: 'kc_a__2' }]`: the second entry went out under a suffixed internal ref the author never wrote and nothing references, and `kc_a` ran `first`;
17
+
- a source boot (`objectstack serve`, no build) registered `kc_a` as `second` and dropped `first`, with no notice.
18
+
19
+
So the same stack ran different code under `kc_a` depending on whether it was built. `composeStacks` already refused one name defined by two stacks (`STACK_COMPOSE_FUNCTION_CONFLICT`); this is the one-stack case.
20
+
21
+
**What is refused.**`defineStack`'s cross-reference pass refuses the stack with its existing envelope (`STACK_CROSS_REFERENCE_INVALID`, status 422, `defineStack cross-reference validation failed (N issues):`), one finding per colliding name, naming the name and every index:
22
+
23
+
```text
24
+
✗ Function 'kc_a' is declared twice in the `functions` array: stack.functions[0] and stack.functions[1]. …
25
+
```
26
+
27
+
It runs in an object-less stack too, and every entry counts, byte-identical twins included. `objectstack validate`, `objectstack build` and a source boot all load the config through `defineStack`, so all three refuse it at load, printing that line: `objectstack validate --json` answers `valid: false` with `code: 'STACK_CROSS_REFERENCE_INVALID'` (exit 1), `objectstack build` exits 2, and `objectstack serve` exits 1 before the kernel boots. Like every cross-reference check it is skipped under `defineStack(…, { strict: false })`.
28
+
29
+
**Unchanged.** The map form, which cannot author one name twice; an array whose names are distinct; the suffixed refs a build emits for an internal slot (`kc_a__2` beside `kc_a` is two names); and the cross-stack refusal in `composeStacks`.
30
+
31
+
## FROM → TO
32
+
33
+
| you wrote | write instead |
34
+
|:--|:--|
35
+
|`functions: [{ name: 'sync', handler: a }, { name: 'sync', handler: b }]`|`functions: [{ name: 'sync', handler: a }, { name: 'sync_backup', handler: b }]`, and point each hook, action or script node that meant `b` at `sync_backup`|
36
+
| two entries that are the same function under one name | one entry: delete the other |
37
+
38
+
**The one-line fix: give each `functions` array entry its own `name`, or merge the duplicates into one entry.**
39
+
40
+
No D2 conversion rewrites it: which entry keeps the name, and what every caller of the other one should name instead, is the author's call. Its D3 record is the semantic entry `stack-functions-array-duplicate-name-refused` (protocol 18).
41
+
42
+
**Who is affected, measured.** On `main` at this change's base, no example app, fixture or test authors one name twice in a `functions` array: the four example apps author the map form or none, and every array-form fixture under `packages/` names distinct entries. `objectstack validate --json` on `examples/app-crm`, `app-todo`, `app-showcase` and `app-multi-package` answers byte-for-byte as it did without the check, apart from the `duration` value. Deployed metadata and other repositories were not measured.
0 commit comments