Skip to content

Commit a69682b

Browse files
committed
chore(sync): cascade predicate lift + docs/claude.md/ reorg from socket-repo-template
Resolves the local fork of prefer-undefined-over-null.js — the two predicates are now upstream in the template (isAssertionLibraryArg, isNullableTypeInitializer).
1 parent 203cf44 commit a69682b

8 files changed

Lines changed: 337 additions & 128 deletions

File tree

.config/oxlint-plugin/rules/prefer-undefined-over-null.js

Lines changed: 270 additions & 115 deletions
Large diffs are not rendered by default.

CLAUDE.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ The principle: the working tree at end-of-turn should match the user's mental mo
137137

138138
### Hook bypasses require the canonical phrase
139139

140-
🚨 Reverting tracked changes or bypassing a hook (--no-verify, DISABLE*PRECOMMIT*\*, --no-gpg-sign, force-push) requires the user to type **`Allow <X> bypass`** verbatim in a recent user turn (e.g. `Allow revert bypass`, `Allow no-verify bypass`). Paraphrases don't count. Enforced by `.claude/hooks/no-revert-guard/`. Full phrase table: [`docs/references/bypass-phrases.md`](docs/references/bypass-phrases.md).
140+
🚨 Reverting tracked changes or bypassing a hook (--no-verify, DISABLE*PRECOMMIT*\*, --no-gpg-sign, force-push) requires the user to type **`Allow <X> bypass`** verbatim in a recent user turn (e.g. `Allow revert bypass`, `Allow no-verify bypass`). Paraphrases don't count. Enforced by `.claude/hooks/no-revert-guard/`. Full phrase table: [`docs/claude.md/bypass-phrases.md`](docs/claude.md/bypass-phrases.md).
141141

142142
### Variant analysis on every High/Critical finding
143143

@@ -176,6 +176,10 @@ How to check:
176176

177177
Never silently let drift sit. Either reconcile in the same PR or open a follow-up PR titled `chore(sync): cascade <thing> from <newer-repo>` and link it.
178178

179+
### Never fork fleet-canonical files locally
180+
181+
🚨 Fleet-canonical files (anything tracked by `socket-repo-template/scripts/sync-scaffolding/manifest.mts`) MUST be edited in `socket-repo-template/template/...` and cascaded out — never branched locally in a downstream fleet repo. If you spot a useful predicate / helper / test / behavior in a fleet-canonical file in a downstream repo that's NOT in the template, that's a bug — lift it up first, then re-cascade. Full canonical-surface list + lifting workflow: [`docs/claude.md/no-local-fork-canonical.md`](docs/claude.md/no-local-fork-canonical.md).
182+
179183
### Code style
180184

181185
- **Comments** — default to none. Write one only when the WHY is non-obvious to a senior engineer. **When you do write a comment, the audience is a junior dev**: explain the constraint, the hidden invariant, the "why this and not the obvious thing." Don't label it ("for junior devs:", "intuition:", etc.) — just write in that voice. No teacher-tone, no condescension, no flattering the reader.
@@ -189,8 +193,8 @@ Never silently let drift sit. Either reconcile in the same PR or open a follow-u
189193
- **File deletion** — route every delete through `safeDelete()` / `safeDeleteSync()` from `@socketsecurity/lib/fs`. Never `fs.rm` / `fs.unlink` / `fs.rmdir` / `rm -rf` directly — even for one known file. Prefer the async `safeDelete()` over `safeDeleteSync()` when the surrounding code is already async (test bodies, request handlers, build scripts that await elsewhere) — sync I/O blocks the event loop and there's no benefit when the caller is awaiting anyway. Reserve `safeDeleteSync()` for top-level scripts whose entire flow is sync.
190194
- **Edits** — Edit tool, never `sed` / `awk`.
191195
- **Generated reports** — quality scans, security audits, perf snapshots, anything an automated tool emits — write to `.claude/reports/` (naturally gitignored as part of `.claude/*`, no separate rule needed). Never commit reports to a tracked `reports/`, `docs/reports/`, or similarly-named tracked directory: dated reports rot the moment they land and the directory becomes a graveyard. The current state of the repo is the report; tools regenerate findings on demand. If a finding is genuinely worth keeping past one run, fix it or open an issue — don't pickle it as a markdown file.
192-
- **Inclusive language** — see [`docs/references/inclusive-language.md`](docs/references/inclusive-language.md) for the substitution table.
193-
- **Sorting** — sort alphanumerically (literal byte order, ASCII before letters). Applies to: object property keys (config + return shapes + internal state — `__proto__: null` first); named imports inside a single statement (`import { a, b, c }`); `Set` / `SafeSet` constructor arguments; allowlists / denylists / config arrays / interface members. Position-bearing arrays (where index matters) keep their meaningful order. Full details in [`docs/references/sorting.md`](docs/references/sorting.md). When in doubt, sort.
196+
- **Inclusive language** — see [`docs/claude.md/inclusive-language.md`](docs/claude.md/inclusive-language.md) for the substitution table.
197+
- **Sorting** — sort alphanumerically (literal byte order, ASCII before letters). Applies to: object property keys (config + return shapes + internal state — `__proto__: null` first); named imports inside a single statement (`import { a, b, c }`); `Set` / `SafeSet` constructor arguments; allowlists / denylists / config arrays / interface members. Position-bearing arrays (where index matters) keep their meaningful order. Full details in [`docs/claude.md/sorting.md`](docs/claude.md/sorting.md). When in doubt, sort.
194198
- **`Promise.race` / `Promise.any` in loops** — never re-race a pool that survives across iterations (the handlers stack). See `.claude/skills/plug-leaking-promise-race/SKILL.md`.
195199
- **`Safe` suffix** — non-throwing wrappers end in `Safe` (`safeDelete`, `safeDeleteSync`, `applySafe`, `weakRefSafe`). Read it as "X, but safe from throwing." The wrapper traps the thrown value internally and returns `undefined` (or the documented fallback). Don't invent alternative suffixes (`Try`, `OrUndefined`, `Maybe`) — pick `Safe`.
196200
- **`node:smol-*` modules** — feature-detect, then require. From outside socket-btm (socket-lib, socket-cli, anywhere else): `import { isBuiltin } from 'node:module'; if (isBuiltin('node:smol-X')) { const mod = require('node:smol-X') }`. The `node:smol-*` namespace is provided by socket-btm's smol Node binary; on stock Node `isBuiltin` returns false and the require would throw. Wrap the loader in a `/*@__NO_SIDE_EFFECTS__*/` lazy-load that caches the result — see `socket-lib/src/smol/util.ts` and `socket-lib/src/smol/primordial.ts` for canonical shape. **Inside** socket-btm's `additions/source-patched/` JS (the smol binary's own bootstrap code), use `internalBinding('smol_X')` directly — that's the C++-binding access path and it's guaranteed available there.
@@ -260,7 +264,7 @@ An error message is UI. The reader should fix the problem from the message alone
260264
3. **Saw vs. wanted** — the bad value and the allowed shape or set.
261265
4. **Fix** — one imperative action (`rename the key to …`).
262266

263-
Use `isError` / `isErrnoException` / `errorMessage` / `errorStack` from `@socketsecurity/lib/errors` over hand-rolled checks. Use `joinAnd` / `joinOr` from `@socketsecurity/lib/arrays` for allowed-set lists. Full guidance in [`docs/references/error-messages.md`](docs/references/error-messages.md).
267+
Use `isError` / `isErrnoException` / `errorMessage` / `errorStack` from `@socketsecurity/lib/errors` over hand-rolled checks. Use `joinAnd` / `joinOr` from `@socketsecurity/lib/arrays` for allowed-set lists. Full guidance in [`docs/claude.md/error-messages.md`](docs/claude.md/error-messages.md).
264268

265269
### Token hygiene
266270

@@ -281,7 +285,7 @@ Full hook spec in [`.claude/hooks/token-guard/README.md`](.claude/hooks/token-gu
281285
- `/scanning-security` — AgentShield + zizmor audit
282286
- `/scanning-quality` — quality analysis
283287
- Shared subskills in `.claude/skills/_shared/`
284-
- **Handing off to another agent** — see [`docs/references/agent-delegation.md`](docs/references/agent-delegation.md) for when to reach for `codex:codex-rescue`, the `delegate` subagent (OpenCode → Fireworks/Synthetic/Kimi), `Explore`, `Plan`, vs. driving the skill CLIs directly. The CLI-subprocess contract used by skills lives in [`_shared/multi-agent-backends.md`](.claude/skills/_shared/multi-agent-backends.md).
288+
- **Handing off to another agent** — see [`docs/claude.md/agent-delegation.md`](docs/claude.md/agent-delegation.md) for when to reach for `codex:codex-rescue`, the `delegate` subagent (OpenCode → Fireworks/Synthetic/Kimi), `Explore`, `Plan`, vs. driving the skill CLIs directly. The CLI-subprocess contract used by skills lives in [`_shared/multi-agent-backends.md`](.claude/skills/_shared/multi-agent-backends.md).
285289

286290
#### Skill scope: fleet vs partial vs unique
287291

File renamed without changes.
File renamed without changes.
Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ Every message needs, in order:
1818
Callers may match on the message text, so stability matters. Aim for one
1919
sentence.
2020

21-
| ✗ / ✓ | Message | Notes |
22-
| ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
23-
|| `Error: invalid component` | No rule, no saw, no where. |
24-
|| `The "name" component of type "npm" failed validation because the provided value "" is empty, which is not allowed because names are required; please provide a non-empty name.` | Restates the rule three times. |
25-
|| `npm "name" component is required` | Rule + where + implied saw (missing). Six words. |
26-
|| `Error: bad name` | No rule. |
27-
|| `name "__proto__" cannot start with an underscore` | Rule, where (`name`), saw (`__proto__`), fix implied. |
21+
| ✗ / ✓ | Message | Notes |
22+
| --- | --- | --- |
23+
|| `Error: invalid component` | No rule, no saw, no where. |
24+
|| `The "name" component of type "npm" failed validation because the provided value "" is empty, which is not allowed because names are required; please provide a non-empty name.` | Restates the rule three times. |
25+
|| `npm "name" component is required` | Rule + where + implied saw (missing). Six words. |
26+
|| `Error: bad name` | No rule. |
27+
|| `name "__proto__" cannot start with an underscore` | Rule, where (`name`), saw (`__proto__`), fix implied. |
28+
|| `Error: invalid argument` | No where, no rule, no fix. |
29+
|| `orgSlug is required` | Rule + where (`orgSlug`), saw (missing), implies fix. |
30+
|| `Error: request failed` | No status, no hint what to check. |
31+
|| `Socket API rejected the token (401); check SOCKET_API_TOKEN` | Rule (401), where (token), fix (check env var). |
2832

2933
## Validator / config / build-tool errors (verbose)
3034

@@ -42,7 +46,7 @@ Breakdown:
4246
- **Saw vs. wanted**: saw = missing; wanted = a single-word lowercase filename, with `"parsing"` as a concrete model.
4347
- **Fix**: `Add … to this part` — imperative, specific.
4448

45-
The trailing `to route /<slug>/part/3 at publish time` is optional. Include a _why_ clause only when the rule is non-obvious; skip it for rules the reader already knows (e.g. "names can't start with an underscore").
49+
The trailing `to route /<slug>/part/3 at publish time` is optional. Include a *why* clause only when the rule is non-obvious; skip it for rules the reader already knows (e.g. "names can't start with an underscore").
4650

4751
## Programmatic errors (terse, rule only)
4852

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Never fork fleet-canonical files locally
2+
3+
Fleet-canonical files (anything tracked by `socket-repo-template/scripts/sync-scaffolding/manifest.mts`) MUST be edited in `socket-repo-template/template/...` and cascaded out — never branched locally in a downstream fleet repo.
4+
5+
## Canonical surfaces
6+
7+
These directories and files cascade fleet-wide. They are **not** repo-local:
8+
9+
- `.config/oxlint-plugin/` — plugin index + rules
10+
- `.git-hooks/` — commit-msg / pre-commit / pre-push hooks + helpers
11+
- `.claude/hooks/` — PreToolUse / PostToolUse hooks
12+
- `.claude/skills/_shared/` — shared skill helpers
13+
- `CLAUDE.md` fleet block (between `BEGIN/END FLEET-CANONICAL` markers)
14+
- `docs/claude.md/` — CLAUDE.md offshoot references (this file lives here)
15+
- `.husky/` — Husky entry shims
16+
- Anything else listed in the sync manifest
17+
18+
If unsure, check `socket-repo-template/scripts/sync-scaffolding/manifest.mts`. Tracked = canonical.
19+
20+
## How to apply
21+
22+
If a downstream repo needs a behavior change in one of these files:
23+
24+
1. Edit the file in `socket-repo-template/template/...`.
25+
2. Commit the template change.
26+
3. Run `node scripts/sync-scaffolding/main.mts --target <downstream-repo> --fix` to cascade.
27+
28+
Do NOT edit the local copy in the downstream repo and rely on cascades to "preserve" your edits via `git checkout HEAD --` workarounds. That creates drift the sync mechanism then has to dance around, blocking other improvements from reaching that file in that repo.
29+
30+
## Spotting drift to lift
31+
32+
If you spot a useful predicate / helper / test / behavior in a fleet-canonical file in a downstream repo that is **not** in the template, that is a bug. Lift it up first, then re-cascade.
33+
34+
The fix is mechanical:
35+
36+
1. Diff the downstream version vs the template version.
37+
2. Identify the additions (if there are any subtractions, those are also drift — usually they need to be added back to the downstream repo via a cascade).
38+
3. Add the additions to the template.
39+
4. Commit + push the template.
40+
5. Re-cascade the downstream repo (overwrites its local copy with the now-superset canonical version).
41+
42+
## Why this matters
43+
44+
Local forks turn into "drift to preserve" hacks. Every cascade subagent has to be told to skip the locally-forked file, which makes the cascade fragile. Worse, those forks block fleet-wide improvements from reaching the forked repo: when the template's version of the file gets a real upgrade (e.g. a new fix predicate, a new exception case), the downstream repo's local copy never gets it.
45+
46+
The fleet's value is the shared canon. Branching locally splits the canon and erodes the value.
File renamed without changes.

0 commit comments

Comments
 (0)