@harperfast/template-react-ts-studio 1.12.1 → 1.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. package/.agents/skills/harper-best-practices/AGENTS.md +672 -400
  2. package/.agents/skills/harper-best-practices/rules/automatic-apis.md +131 -55
  3. package/.agents/skills/harper-best-practices/rules/checking-authentication.md +155 -61
  4. package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +78 -48
  5. package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +111 -52
  6. package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +38 -70
  7. package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +81 -69
  8. package/.agents/skills/harper-best-practices/rules/v5-upgrade.md +108 -60
  9. package/.agents/skills/harper-best-practices/rules.manifest.yaml +212 -0
  10. package/agent/skills/harper-best-practices/AGENTS.md +672 -400
  11. package/agent/skills/harper-best-practices/rules/automatic-apis.md +131 -55
  12. package/agent/skills/harper-best-practices/rules/checking-authentication.md +155 -61
  13. package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +78 -48
  14. package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +111 -52
  15. package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +38 -70
  16. package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +81 -69
  17. package/agent/skills/harper-best-practices/rules/v5-upgrade.md +108 -60
  18. package/agent/skills/harper-best-practices/rules.manifest.yaml +212 -0
  19. package/package.json +1 -1
  20. package/skills-lock.json +1 -1
@@ -7,8 +7,8 @@ metadata:
7
7
  mode: generate
8
8
  sources:
9
9
  - release-notes/v5-lincoln/v5-migration.md
10
- sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
11
- inputHash: 5ee6407370219136
10
+ sourceCommit: 677ad213d67822e109c83619e181ca23a59823db
11
+ inputHash: 01c0fafb9afa68a0
12
12
  ---
13
13
 
14
14
  # v5 Upgrade: Breaking Changes and Migration Guide
@@ -17,60 +17,53 @@ Instructions for the agent to apply when migrating a Harper application to v5, c
17
17
 
18
18
  ## When to Use
19
19
 
20
- Apply this rule when upgrading an existing Harper application to v5, when encountering runtime errors related to renamed packages, changed APIs, or security restrictions introduced in v5, or when reviewing application code for v5 compatibility before deployment.
20
+ Apply this rule when upgrading an existing Harper application to v5, when encountering runtime errors related to renamed packages, changed APIs, or security restrictions after a v5 upgrade, or when scaffolding new v5-compatible application code.
21
21
 
22
22
  ## How It Works
23
23
 
24
- 1. **Update the package import from `harperdb` to `harper`**: All application code must import from `harper` instead of `harperdb`.
24
+ 1. **Update the package import from `harperdb` to `harper`**: All application code must import from `harper`, not `harperdb`.
25
25
 
26
26
  ```javascript
27
27
  import { tables } from 'harper';
28
28
  ```
29
29
 
30
- 2. **Enable `allowInstallScripts` if packages require install scripts**: Harper v5 uses `--ignore-scripts` by default when installing packages. If your application requires installation scripts (e.g., to install additional binaries), set the `allowInstallScripts` option when deploying.
30
+ 2. **Enable `allowInstallScripts` if packages require install scripts**: Harper v5 uses `--ignore-scripts` by default when installing packages. If a package requires execution of install scripts (e.g., to install native binaries), set the `allowInstallScripts` option when deploying.
31
31
 
32
- 3. **Update `Table.get` usage — return value is now a frozen record object**: `Table.get` now returns a plain record object, not a table class instance. The record is frozen; you cannot mutate it directly.
33
- - Replace `wasLoadedFromSource()` with `target.loadedFromSource`:
32
+ 3. **Update `Table.get` usage — return value is now a frozen record object**: `Table.get` now returns a plain record object, not a table class instance. The record is frozen; you cannot add or mutate properties directly.
33
+ - Replace direct property mutation:
34
34
 
35
35
  ```javascript
36
- // Old — remove this pattern:
37
- const record = await Table.get(id);
38
- if (record.wasLoadedFromSource()) { ... }
36
+ let record = await Table.get(id);
37
+ record = { ...record, property: 'changed' };
38
+ ```
39
39
 
40
- // New — use loadedFromSource on the target:
40
+ - Replace `wasLoadedFromSource()` with `loadedFromSource` on the `target` object:
41
+
42
+ ```javascript
41
43
  const target = new RequestTarget();
42
44
  target.id = id;
43
45
  const record = await Table.get(target);
44
46
  if (target.loadedFromSource) {
45
- // record was loaded from origin (not cache)
47
+ // record was loaded from origin (not cache)
46
48
  }
47
49
  ```
48
50
 
49
- - Replace in-place mutation with object spread, since records are frozen:
51
+ The record objects still expose `getUpdatedTime` and `getExpiresAt` methods.
50
52
 
51
- ```javascript
52
- // Old — throws in v5:
53
- const record = await Table.get(id);
54
- record.property = 'changed';
53
+ 4. **Update transaction and context handling using `getContext`**: Harper v5 uses asynchronous context tracking. Context and the current transaction are automatically carried to all downstream calls — you no longer pass context explicitly. Import `getContext` and `transaction` from `harper`:
55
54
 
56
- // New — copy instead of mutate:
57
- let record = await Table.get(id);
58
- record = { ...record, property: 'changed' };
59
- ```
60
-
61
- - `getUpdatedTime` and `getExpiresAt` methods remain available on the record object.
55
+ ```javascript
56
+ import { getContext, transaction } from 'harper';
57
+ ```
62
58
 
63
- 4. **Update transaction and context handling**: Harper v5 uses asynchronous context tracking. `Table.get` and other table calls now automatically inherit the current transaction context. Code that previously omitted context to bypass a transaction will no longer work as expected. Use `getContext` (imported from `harper`) to access and commit the current transaction explicitly when you need to see updated data.
59
+ If your code previously omitted context to escape a transaction (e.g., to poll for updated data), explicitly commit the transaction and/or wrap each read in a new `transaction()` call:
64
60
 
65
61
  ```javascript
66
62
  import { setTimeout as delay } from 'node:timers/promises';
67
63
  import { getContext, transaction } from 'harper';
68
-
69
64
  class MyResource {
70
65
  static async get(target) {
71
- // Commit the current transaction to read latest data:
72
66
  await getContext().transaction.commit();
73
- // Optionally wrap each poll in a new transaction:
74
67
  while ((await transaction(() => Table.get(target))).status !== 'ready') {
75
68
  await delay(100);
76
69
  }
@@ -79,24 +72,90 @@ Apply this rule when upgrading an existing Harper application to v5, when encoun
79
72
  }
80
73
  ```
81
74
 
82
- 5. **Register allowed spawn commands via `allowedSpawnCommands`**: Any use of `spawn`, `exec`, or `execFile` from `node:child_process` must reference executables listed in `applications.allowedSpawnCommands` in `harperdb-config.yaml`. Provide a `name` property in the options argument to ensure only a single named process is started across threads.
75
+ 5. **Register allowed spawn commands via `allowedSpawnCommands`**: `spawn` and `execFile` may only launch executables listed in `applications.allowedSpawnCommands` in `harperdb-config.yaml`. Only the first token of the command is matched. `exec` is not usable through the substituted module; `execSync` always throws.
76
+
77
+ ```yaml
78
+ applications:
79
+ allowedSpawnCommands:
80
+ - npm
81
+ - node
82
+ ```
83
+
84
+ Additionally, `spawn`, `execFile`, and `fork` now require a `name` property in the `options` argument to prevent process multiplication across threads.
85
+
86
+ 6. **Use `saveBeforeCommit` instead of `blob.save()`**: The `blob.save()` method has been removed. Pass the `saveBeforeCommit` flag in the options to the `Blob` constructor instead.
87
+
88
+ 7. **Handle `headers` on returned response objects**: If you return an object from a REST method with a `headers` property, Harper v5 will use it as the response headers.
89
+
90
+ 8. **Configure the VM module loader and `lockdown` in `harperdb-config.yaml`**: v5 loads application modules through Node.js's VM module API. Control all behavior under the `applications` key:
91
+
92
+ ```yaml
93
+ applications:
94
+ lockdown: freeze-after-load
95
+ moduleLoader: vm-current-context
96
+ dependencyLoader: auto
97
+ allowedDirectory: app
98
+ allowedSpawnCommands:
99
+ - npm
100
+ - node
101
+ ```
102
+
103
+ **`moduleLoader` options:**
104
+
105
+ | Value | Behavior |
106
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
107
+ | `vm-current-context` | Default. VM loader in Harper's own context; shares intrinsics with Harper. Best compatibility. |
108
+ | `vm` | VM loader in a separate per-application context with its own intrinsics. Stronger isolation but may cause `instanceof` failures. |
109
+ | `native` | Standard Node.js `import()`. No VM loader; application-specific context (`logger`, `config`) unavailable. |
110
+ | `compartment` | SES Compartment-based loading. For specialized sandboxing only. |
111
+
112
+ **`lockdown` options:**
83
113
 
84
- 6. **Replace `blob.save()` with `saveBeforeCommit`**: The `blob.save()` method has been removed. Use the `saveBeforeCommit` flag in the options passed to the `Blob` constructor instead.
114
+ | Value | Behavior |
115
+ | ------------------- | ------------------------------------------------------- |
116
+ | `freeze-after-load` | Default. Freezes intrinsics after all components load. |
117
+ | `freeze` | Freezes intrinsics before loading any application code. |
118
+ | `ses` | Full SES lockdown via the `ses` package. Strictest. |
119
+ | `none` | No lockdown. Use as a temporary workaround only. |
85
120
 
86
- 7. **Configure the `moduleLoader` and `lockdown` settings**: Harper v5 loads application modules through Node.js's VM module API. Control this behavior in `harperdb-config.yaml` under the `applications` key.
121
+ To disable the VM loader entirely and restore pre-v5 behavior:
87
122
 
88
- | Setting | Default | Options |
89
- | ------------------ | -------------------- | --------------------------------------------------- |
90
- | `moduleLoader` | `vm-current-context` | `vm-current-context`, `vm`, `native`, `compartment` |
91
- | `lockdown` | `freeze-after-load` | `freeze-after-load`, `freeze`, `ses`, `none` |
92
- | `dependencyLoader` | `auto` | `auto`, `app`, `native` |
93
- | `allowedDirectory` | `app` | `app`, `any` |
94
- - Use `moduleLoader: native` to disable the VM loader entirely and restore pre-v5 behavior (application-specific context such as tagged logging and per-app `config` will not be available).
95
- - Use `lockdown: none` as a temporary workaround if a dependency modifies intrinsic prototypes at runtime and throws a `TypeError`.
123
+ ```yaml
124
+ applications:
125
+ moduleLoader: native
126
+ ```
96
127
 
97
128
  ## Examples
98
129
 
99
- ### Full `harperdb-config.yaml` `applications` block
130
+ **Full transaction polling pattern (v5):**
131
+
132
+ ```javascript
133
+ import { setTimeout as delay } from 'node:timers/promises';
134
+ import { getContext, transaction } from 'harper';
135
+
136
+ class MyResource {
137
+ static async get(target) {
138
+ await getContext().transaction.commit();
139
+ while ((await transaction(() => Table.get(target))).status !== 'ready') {
140
+ await delay(100);
141
+ }
142
+ return Table.get(target);
143
+ }
144
+ }
145
+ ```
146
+
147
+ **Checking `loadedFromSource` after `Table.get`:**
148
+
149
+ ```javascript
150
+ const target = new RequestTarget();
151
+ target.id = id;
152
+ const record = await Table.get(target);
153
+ if (target.loadedFromSource) {
154
+ // record was loaded from origin (not cache)
155
+ }
156
+ ```
157
+
158
+ **Full `harperdb-config.yaml` `applications` block:**
100
159
 
101
160
  ```yaml
102
161
  applications:
@@ -109,7 +168,7 @@ applications:
109
168
  - node
110
169
  ```
111
170
 
112
- ### Restricting allowed built-in modules
171
+ **Restricting allowed built-in modules:**
113
172
 
114
173
  ```yaml
115
174
  applications:
@@ -119,25 +178,14 @@ applications:
119
178
  - http
120
179
  ```
121
180
 
122
- ### Disabling the VM loader for package compatibility
123
-
124
- ```yaml
125
- applications:
126
- moduleLoader: native
127
- ```
128
-
129
- ### Accessing context and committing a transaction
130
-
131
- ```javascript
132
- import { getContext } from 'harper';
133
-
134
- await getContext().transaction.commit();
135
- ```
136
-
137
181
  ## Notes
138
182
 
139
- - The `lockdown: freeze-after-load` default freezes `Object`, `Array`, `Promise`, `Map`, `Set`, and other intrinsics after all application code loads. Any code or dependency that mutates intrinsic prototypes after startup will throw a `TypeError`.
140
- - Under `lockdown: ses`, the constrained `fetch` (https-only) is applied only in `vm` mode. In `vm-current-context` and `native` modes, application code uses the standard global `fetch`.
141
- - In production, `allowedDirectory: app` prevents loading modules from outside the application's own directory tree. Set `allowedDirectory: any` only if your application legitimately requires it.
142
- - `dependencyLoader: native` is a narrower alternative to `moduleLoader: native` — it uses native loading only for npm packages while keeping the VM loader for first-party application source files.
143
- - Access Harper functions and APIs through the `harper` package rather than through global variables. Use `getContext` from `harper` to access request context without passing it explicitly through every call.
183
+ - Always import Harper APIs from `'harper'`, not from global variables or `'harperdb'`.
184
+ - `getContext` is exported from `'harper'` and provides access to the current transaction without passing context explicitly.
185
+ - Record objects returned by `Table.get` are frozen — spread into a new object before modifying.
186
+ - `loadedFromSource` is a property on the `target` object, replacing the removed `wasLoadedFromSource()` instance method.
187
+ - `saveBeforeCommit` replaces the removed `blob.save()` method.
188
+ - The `headers` property on a returned REST response object is used as response headers.
189
+ - Under `lockdown: ses`, the constrained `fetch` applies only in `vm` mode. In `vm-current-context` and `native` modes, application code uses the standard global `fetch`.
190
+ - In production, `allowedDirectory: app` is the default; modules outside the application directory tree will throw. Set `allowedDirectory: any` only if legitimately required.
191
+ - `dependencyLoader: native` is a narrower option than `moduleLoader: native` — it uses native loading only for npm packages while keeping the VM loader for first-party application source files.
@@ -149,14 +149,61 @@ rules:
149
149
  order: 1
150
150
  mode: generate
151
151
  sources:
152
+ # overview.md is sourced section-by-section rather than whole-file: at
153
+ # ~15KB it was the largest single input in the skill, and the compression
154
+ # dropped conditional requests, content negotiation, and the `GET`
155
+ # caveats outright. Listing sections narrows the input and makes a docs
156
+ # rename fail loudly in sliceSection. The dropped headings are the
157
+ # `# REST Overview` preamble (marketing + a version badge) and
158
+ # `## See Also` (link list); `## OpenAPI` is kept because the rule
159
+ # documents `GET /openapi`.
152
160
  - path: reference/v5/rest/overview.md
161
+ section: 'How the REST Interface Works'
153
162
  role: primary
163
+ - path: reference/v5/rest/overview.md
164
+ section: 'Configuration'
165
+ role: primary
166
+ - path: reference/v5/rest/overview.md
167
+ section: 'Tables and Their Automatic Endpoints'
168
+ role: primary
169
+ - path: reference/v5/rest/overview.md
170
+ section: 'URL Structure'
171
+ role: primary
172
+ - path: reference/v5/rest/overview.md
173
+ section: 'HTTP Methods'
174
+ role: primary
175
+ - path: reference/v5/rest/overview.md
176
+ section: 'Content Types'
177
+ role: primary
178
+ - path: reference/v5/rest/overview.md
179
+ section: 'OpenAPI'
180
+ role: supplemental
154
181
  - path: reference/v5/rest/websockets.md
155
182
  role: supplemental
156
183
  must_cover:
157
184
  - 'rest: true'
158
185
  - '@export'
159
186
  - 'WebSocket'
187
+ # Each of the following occurs exactly once across the sourced sections,
188
+ # so each pins one previously-dropped section:
189
+ # If-None-Match / 304 Not Modified → `#### Conditional Requests and Caching`
190
+ # `Accept` → `## Content Types` (bare `Accept`
191
+ # would be satisfied by the SSE `Accept: text/event-stream` mention
192
+ # under `## Tables and Their Automatic Endpoints`, which gates nothing)
193
+ # .msgpack → the reserved content-type selector
194
+ # suffixes and the undeclared-property caveat in `### GET`
195
+ - 'If-None-Match'
196
+ - '304 Not Modified'
197
+ - 'ETag'
198
+ - '`Accept`'
199
+ - '.msgpack'
200
+ # Pinned after the first regen dropped them while restoring the three
201
+ # sections above — an unanchored fact is only ever one regen from being
202
+ # compressed away, whichever fact it is:
203
+ # Location (2×) → the primary key POST returns in that header
204
+ # @updatedTime (1×) → the three exceptions PUT always applies
205
+ - 'Location'
206
+ - '@updatedTime'
160
207
  cross_links:
161
208
  - querying-rest-apis
162
209
  - real-time-apps
@@ -207,13 +254,123 @@ rules:
207
254
  - path: reference/v5/resources/resource-api.md
208
255
  section: 'Session and Login from a Resource'
209
256
  role: primary
257
+ # JWT half. Sectioned *and* anchored deliberately.
258
+ #
259
+ # The generator concatenates every resolved source into one unlabeled
260
+ # blob (lib/sources.mjs `resolveSources`) and the system prompt tells the
261
+ # model to "keep it tight" and omit tangential detail. So whatever no
262
+ # `must_cover` anchor requires is exactly what gets compressed away —
263
+ # anchor starvation, not source ordering or size. As a whole-file source
264
+ # with no JWT anchors, this half collapsed to a single "use JWT instead"
265
+ # pointer and lost the token issue/refresh flow entirely.
266
+ #
267
+ # `must_cover` is the actual gate: it is enforced verbatim
268
+ # (validate-generated.mjs, `body.includes(must)`) and is echoed to the
269
+ # model as a hard requirement. `section:` only narrows what gets fed in —
270
+ # it helps because it tends to come with anchors, not on its own. Prefer
271
+ # identifier-shaped anchors that occur in exactly one sourced section; an
272
+ # anchor matching many sections gates nothing in particular.
273
+ #
274
+ # `role:` is a human-facing annotation only — the generator never reads
275
+ # it (it is enum-checked by the validator and otherwise unused).
276
+ - path: reference/v5/security/jwt-authentication.md
277
+ section: 'Create Authentication Tokens'
278
+ role: primary
210
279
  - path: reference/v5/security/jwt-authentication.md
280
+ section: 'Using the Operation Token'
281
+ role: supplemental
282
+ - path: reference/v5/security/jwt-authentication.md
283
+ section: 'Refreshing the Operation Token'
284
+ role: primary
285
+ - path: reference/v5/security/jwt-authentication.md
286
+ section: 'Scoped Tokens (Inline Role)'
287
+ role: primary
288
+ - path: reference/v5/security/jwt-authentication.md
289
+ section: 'Issuing Tokens from a Custom Resource'
290
+ role: primary
291
+ - path: reference/v5/security/jwt-authentication.md
292
+ section: 'Token Expiry Configuration'
293
+ role: supplemental
294
+ # Sourced so the rule carries the *negative* recommendation too. Without
295
+ # it the generated body pushed JWT at every non-browser client, while the
296
+ # source actually points simple and server-to-server callers at Basic
297
+ # Authentication — i.e. the rule was inviting token lifecycle complexity
298
+ # the docs tell you to avoid.
299
+ - path: reference/v5/security/jwt-authentication.md
300
+ section: 'When to Use JWT Auth'
301
+ role: primary
302
+ - path: reference/v5/security/jwt-authentication.md
303
+ section: 'Security Notes'
211
304
  role: supplemental
212
305
  must_cover:
306
+ # Session half.
213
307
  - 'getCurrentUser()'
214
308
  - 'getContext()'
215
309
  - 'context.login'
216
310
  - 'enableSessions'
311
+ # JWT half. One anchor per sourced section wherever an identifier is
312
+ # unique to it: `server.operation` pins the custom-resource section,
313
+ # `add_role`/`expires_in` the scoped-token section, `HTTPS` the security
314
+ # notes (`operationTokenTimeout` alone no longer distinguishes those two,
315
+ # since it occurs in both). `create_authentication_tokens` is the one
316
+ # unavoidably broad anchor — it is the subject of its own section but is
317
+ # back-referenced by three others, so it gates presence, not depth.
318
+ - 'create_authentication_tokens'
319
+ - 'refresh_operation_token'
320
+ - 'server.operation'
321
+ - 'add_role'
322
+ - 'expires_in'
323
+ - 'operationTokenTimeout'
324
+ - 'HTTPS'
325
+ # Scoped tokens are rejected with a 401 by nodes too old to understand
326
+ # them. Unanchored, that bullet was dropped the first time this rule was
327
+ # regenerated after the section was added — a rollout hazard, so it gets
328
+ # its own anchor rather than relying on the section being sourced.
329
+ - 'mixed-version'
330
+ # Operation names alone gate vocabulary, not mechanics: a regeneration
331
+ # could keep `create_authentication_tokens`/`refresh_operation_token` and
332
+ # still drop the token exchange, the refresh timeout, or what the third
333
+ # `server.operation` argument does. The anchors below pin those specific
334
+ # semantics. Each occurs exactly once in the doc and in exactly one
335
+ # sourced section, so it forces depth in that section rather than a
336
+ # passing mention anywhere.
337
+ #
338
+ # Two caveats this list is deliberately built around:
339
+ #
340
+ # 1. `must_cover` is a substring test (`body.includes(must)`), so an
341
+ # anchor contained in another anchor gates nothing extra.
342
+ # `operation_token` is already implied by `refresh_operation_token`,
343
+ # and `refresh_token` by `Bearer <refresh_token>` — listing either
344
+ # separately would be noise, not coverage.
345
+ # 2. A bare-fragment anchor invites literal satisfaction. Anchoring the
346
+ # exchange as `Bearer <refresh_token>` — rather than `refresh_token`,
347
+ # which occurs in three sourced sections — requires the body to show
348
+ # the refresh token actually being presented as the Bearer credential.
349
+ #
350
+ # `third argument` + `current authenticated user` pin the authorize
351
+ # behavior together. `authorize: true` is the doc's prose name for it but
352
+ # is rejected as an anchor: the code passes `true` positionally, so
353
+ # forcing that string risks a body an agent transcribes as an options
354
+ # object.
355
+ - 'Bearer <refresh_token>'
356
+ - 'refreshTokenTimeout'
357
+ - 'third argument'
358
+ - 'current authenticated user'
359
+ # When to Use JWT Auth. `Basic Authentication` is a superstring of the
360
+ # plain `Basic Auth` the section also contains — which is the better
361
+ # anchor, since `Basic Auth` additionally appears in a code comment in
362
+ # the custom-resource section and could be satisfied from there while the
363
+ # recommendation itself stayed compressed away. `server-to-server` pins
364
+ # the scenario the source actually steers away from JWT.
365
+ #
366
+ # `preferred over Basic Auth` carries the source's *conditional* framing.
367
+ # It is anchored because sourcing the section alone was not enough: the
368
+ # body kept a flat "for non-browser clients, use JWT" directive and filed
369
+ # the Basic Auth alternative under Notes, which reads as a contradiction.
370
+ # Anchoring the conditional forces the choice to be stated as a tradeoff.
371
+ - 'Basic Authentication'
372
+ - 'server-to-server'
373
+ - 'preferred over Basic Auth'
217
374
  cross_links:
218
375
  - custom-resources
219
376
 
@@ -293,6 +450,36 @@ rules:
293
450
  - 'search('
294
451
  - 'addTo'
295
452
  - 'select'
453
+ # Query Object options that were covered before the transaction material
454
+ # was pinned, and that the regen then compressed out to make room. They
455
+ # are anchored now rather than left to survive on luck; each occurs only
456
+ # in § Query Object. `sort` also carries the `@indexed`-or-`conditions`
457
+ # requirement and `allowFullScan`, which have no meaning without it.
458
+ - 'sort'
459
+ - '@indexed'
460
+ - 'explain'
461
+ - 'enforceExecutionOrder'
462
+ # The `transaction(context?, callback)` source was already declared with a
463
+ # `section:` and was still dropped in full — proof that sectioning narrows
464
+ # the input but does not hold content in. Only an anchor does. Each of
465
+ # these occurs in exactly one sourced section:
466
+ # transaction() (2×) → § `transaction(context?, callback)`
467
+ # resetReadSnapshot() (1×) → its `### Transaction Object` member table
468
+ # atomicity (1×) → `### Transaction Scope and Atomicity`
469
+ # limit / offset (1× each) → § Query Object, the pagination pair
470
+ # Balanced parens deliberately: anchoring the bare `transaction(` also
471
+ # gates the section, but the model satisfies it literally and writes
472
+ # prose like "wrap background work in `transaction(`". `transaction()`
473
+ # contains `transaction(`, so it is the stricter anchor as well.
474
+ - 'transaction()'
475
+ - 'resetReadSnapshot()'
476
+ - 'atomicity'
477
+ - 'limit'
478
+ - 'offset'
479
+ # § Module Loading's one piece of actionable build guidance: keep `harper`
480
+ # external when bundling for SSR, or it is bundled instead of resolving
481
+ # to the runtime. Only occurrence of `vite.config` in the sources.
482
+ - 'vite.config'
296
483
 
297
484
  - rule: typescript-type-stripping
298
485
  description: How to run TypeScript files directly in Harper without a build step.
@@ -347,6 +534,28 @@ rules:
347
534
  must_cover:
348
535
  - 'harper deploy'
349
536
  - 'harper login'
537
+ # `### Provisioning a Deploy Credential` is already inside the sourced
538
+ # `## Remote Management` slice, and its security guidance was compressed
539
+ # away anyway. These anchors pin it; each occurs only in that slice:
540
+ # fine-grained (2×) → prefer a fine-grained PAT over the `gh` CLI token
541
+ # read:org (1×) → the account-wide scopes the `gh` token carries
542
+ # enc:v1: (1×) → the client-side-encryption envelope
543
+ # They double as the rename detector for that subheading: if it is
544
+ # retitled or removed, the content goes and these anchors fail.
545
+ - 'fine-grained'
546
+ - 'Contents: Read-only'
547
+ - 'read:org'
548
+ - 'enc:v1:'
549
+ # Pinned after the first regen dropped it while restoring the credential
550
+ # guidance: `refs/heads/*` and `refs/tags/*` (or a bare branch/tag) are
551
+ # the only refs a `by_ref` deploy can fetch.
552
+ - 'refs/tags'
553
+ # Also pinned after a regen dropped it: `setup=true` calls
554
+ # `get_secrets_public_key` / `set_secret` / `grant_secret`, so it must be
555
+ # run with an administrative credential, not the CI identity it
556
+ # provisions for. The source escapes it as `super\_user`; every generated
557
+ # body so far unescapes, so the anchor is the unescaped form.
558
+ - 'super_user'
350
559
  cross_links:
351
560
  - creating-a-fabric-account-and-cluster
352
561
 
@@ -422,6 +631,9 @@ rules:
422
631
  - 'moduleLoader'
423
632
  - 'lockdown'
424
633
  - 'Table.get'
634
+ # `## Response Objects` had no anchor and was dropped in full. Every
635
+ # occurrence of `headers` in the whole-file source is in that section.
636
+ - 'headers'
425
637
 
426
638
  - rule: delegating-to-the-built-in-agent
427
639
  description: How to delegate tasks to Harper's built-in agent via the CLI and the agent operations API.