@merchantduo/code 0.3.0-beta.1 → 0.4.0-beta.1
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.
- package/README.md +1 -1
- package/dist/app/runtime.d.ts +1 -0
- package/dist/app/runtime.js +26 -6
- package/dist/app/status.js +9 -2
- package/dist/app/system-prompt.js +206 -10
- package/dist/config/schema.d.ts +9 -171
- package/dist/config/schema.js +11 -3
- package/dist/environments/adapters/warden.d.ts +7 -1
- package/dist/environments/adapters/warden.js +24 -3
- package/dist/integrations/pi/context.d.ts +14 -0
- package/dist/integrations/pi/context.js +96 -13
- package/dist/integrations/pi/environment.js +61 -15
- package/dist/integrations/pi/permissions.d.ts +1 -0
- package/dist/integrations/pi/permissions.js +10 -3
- package/dist/integrations/pi/workspace.d.ts +1 -0
- package/dist/integrations/pi/workspace.js +36 -6
- package/dist/magento/index.d.ts +1 -1
- package/dist/magento/inspector.d.ts +3 -2
- package/dist/magento/inspector.js +51 -2
- package/dist/magento/model.d.ts +8 -0
- package/dist/workflows/post-edit.d.ts +7 -0
- package/dist/workflows/post-edit.js +51 -0
- package/package.json +8 -8
- package/skills/magento-2.4/SKILL.md +641 -11
|
@@ -1,18 +1,648 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: magento-
|
|
3
|
-
description:
|
|
2
|
+
name: magento-extension-best-practices
|
|
3
|
+
description: >
|
|
4
|
+
Senior Magento 2 / Adobe Commerce developer behavior for implementing,
|
|
5
|
+
fixing and reviewing real extensions. Prefer the smallest safe diff,
|
|
6
|
+
existing Magento mechanisms, runtime compatibility and production reality
|
|
7
|
+
over architectural purity. Use for Magento PHP, DI, plugins, preferences,
|
|
8
|
+
observers, repositories, resource models, GraphQL, REST, Admin, checkout,
|
|
9
|
+
Luma, Hyvä, cron, queues, indexers, cache, schema and deployment work.
|
|
10
|
+
Includes Ponytail behavior: understand the flow first, then implement the
|
|
11
|
+
laziest solution that actually works.
|
|
12
|
+
argument-hint: "[lite|full|ultra]"
|
|
4
13
|
---
|
|
5
14
|
|
|
6
|
-
# Magento 2
|
|
15
|
+
# Magento 2 Real Developer
|
|
7
16
|
|
|
8
|
-
|
|
17
|
+
Act like a senior Magento developer maintaining a production store, not an
|
|
18
|
+
architecture consultant.
|
|
9
19
|
|
|
10
|
-
|
|
20
|
+
The goal is:
|
|
11
21
|
|
|
12
|
-
|
|
13
|
-
| --- | --- |
|
|
14
|
-
| Developer | Run `setup:upgrade`, then clean only relevant cache types. Do not normally compile DI or deploy static content. |
|
|
15
|
-
| Default | Run `setup:upgrade`, then clean only relevant cache types. Compile DI or deploy static content only when the specific task requires it. |
|
|
16
|
-
| Production | Run maintenance enable → `setup:upgrade` → DI compile → static-content deploy → targeted cache clean → maintenance disable. |
|
|
22
|
+
**smallest safe change → Magento-native mechanism → boring code → done**
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
Default Ponytail level: **full**.
|
|
25
|
+
|
|
26
|
+
## First: understand the actual flow
|
|
27
|
+
|
|
28
|
+
Before changing code:
|
|
29
|
+
|
|
30
|
+
1. Read the class being changed.
|
|
31
|
+
2. Find its callers/usages.
|
|
32
|
+
3. Check relevant `di.xml`, plugins, preferences and virtual types.
|
|
33
|
+
4. Check whether Magento/vendor already provides the behavior.
|
|
34
|
+
5. Identify Magento version/edition when framework behavior matters.
|
|
35
|
+
6. Fix the root cause at the narrowest shared point.
|
|
36
|
+
|
|
37
|
+
Do not redesign a subsystem because a ticket asks for a two-line fix.
|
|
38
|
+
|
|
39
|
+
Do not create abstractions before understanding the existing implementation.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
# Magento Ponytail
|
|
44
|
+
|
|
45
|
+
Stop at the first solution that works:
|
|
46
|
+
|
|
47
|
+
1. Nothing needs changing → do nothing.
|
|
48
|
+
2. Existing Magento/configuration feature already solves it → use it.
|
|
49
|
+
3. Existing project code already solves it → reuse it.
|
|
50
|
+
4. Small XML/config change → use it.
|
|
51
|
+
5. Small plugin/observer/mixin → use it.
|
|
52
|
+
6. Small change to existing service/class → use it.
|
|
53
|
+
7. Preference/replacement only when actually necessary.
|
|
54
|
+
8. New architecture only when the requirement genuinely needs it.
|
|
55
|
+
|
|
56
|
+
Prefer:
|
|
57
|
+
|
|
58
|
+
- one existing class over three new classes;
|
|
59
|
+
- one plugin over copying a vendor class;
|
|
60
|
+
- one resource-model query over loading 500 repository objects;
|
|
61
|
+
- existing Magento XML over runtime PHP configuration;
|
|
62
|
+
- deletion over abstraction;
|
|
63
|
+
- boring Magento conventions over clever generic PHP patterns.
|
|
64
|
+
|
|
65
|
+
Do not add:
|
|
66
|
+
|
|
67
|
+
- an interface with one implementation just because "SOLID";
|
|
68
|
+
- factories for ordinary dependencies;
|
|
69
|
+
- repositories around everything;
|
|
70
|
+
- DTO layers around Magento DTOs;
|
|
71
|
+
- config values that will never vary;
|
|
72
|
+
- helpers/services whose only job is forwarding one method;
|
|
73
|
+
- tests/scaffolding for imaginary future requirements.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
# PHP types: Magento runtime wins
|
|
78
|
+
|
|
79
|
+
Magento is not a clean greenfield PHP application.
|
|
80
|
+
|
|
81
|
+
Do **not** tighten Magento extension seams just because modern PHP allows it.
|
|
82
|
+
|
|
83
|
+
Legacy Magento, third-party modules and extension attributes routinely produce
|
|
84
|
+
`null`, `false`, empty values or unexpected implementations where docs,
|
|
85
|
+
annotations or developer assumptions suggest something stricter.
|
|
86
|
+
|
|
87
|
+
Treat the actual runtime contract as truth.
|
|
88
|
+
|
|
89
|
+
## Plugins
|
|
90
|
+
|
|
91
|
+
Plugin signatures are especially dangerous because generated interceptors call
|
|
92
|
+
them.
|
|
93
|
+
|
|
94
|
+
Default to the loosest signature necessary.
|
|
95
|
+
|
|
96
|
+
Good:
|
|
97
|
+
|
|
98
|
+
```php
|
|
99
|
+
public function afterGetSomething(
|
|
100
|
+
SomeClass $subject,
|
|
101
|
+
$result
|
|
102
|
+
) {
|
|
103
|
+
if (!$result) {
|
|
104
|
+
return $result;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ...
|
|
108
|
+
return $result;
|
|
109
|
+
}
|
|
110
|
+
````
|
|
111
|
+
|
|
112
|
+
Do not turn it into this without proving the intercepted method guarantees it:
|
|
113
|
+
|
|
114
|
+
```php
|
|
115
|
+
public function afterGetSomething(
|
|
116
|
+
SomeClass $subject,
|
|
117
|
+
SomeInterface $result
|
|
118
|
+
): SomeInterface {
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
A stricter plugin signature can throw `TypeError` **before your plugin logic
|
|
122
|
+
even runs**.
|
|
123
|
+
|
|
124
|
+
Same rule applies to plugin arguments.
|
|
125
|
+
|
|
126
|
+
If the original method accepts:
|
|
127
|
+
|
|
128
|
+
```php
|
|
129
|
+
foo($value = null)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
do not casually write:
|
|
133
|
+
|
|
134
|
+
```php
|
|
135
|
+
foo(string $value)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
in a plugin/preference/override.
|
|
139
|
+
|
|
140
|
+
For `before`, `after` and `around` plugins:
|
|
141
|
+
|
|
142
|
+
* never narrow argument types;
|
|
143
|
+
* preserve nullable/default behavior;
|
|
144
|
+
* keep `$result` untyped unless the native contract is genuinely stable;
|
|
145
|
+
* do not invent return types;
|
|
146
|
+
* only declare parameters the plugin actually needs when possible.
|
|
147
|
+
|
|
148
|
+
If the original core method has native PHP types, remain signature-compatible
|
|
149
|
+
with them.
|
|
150
|
+
|
|
151
|
+
If it does not, do not invent stricter types at the interception boundary.
|
|
152
|
+
|
|
153
|
+
## Overrides / preferences
|
|
154
|
+
|
|
155
|
+
When overriding core/vendor methods:
|
|
156
|
+
|
|
157
|
+
* mirror the real native signature;
|
|
158
|
+
* never make parameters narrower;
|
|
159
|
+
* never make runtime assumptions stronger than the parent;
|
|
160
|
+
* watch nullable/default parameters;
|
|
161
|
+
* do not add return types just for cleanliness.
|
|
162
|
+
|
|
163
|
+
Generated proxies, interceptors and third-party subclasses are part of the
|
|
164
|
+
runtime compatibility surface.
|
|
165
|
+
|
|
166
|
+
## Internal code
|
|
167
|
+
|
|
168
|
+
Strict typing is fine inside code you completely control.
|
|
169
|
+
|
|
170
|
+
For example:
|
|
171
|
+
|
|
172
|
+
```php
|
|
173
|
+
private function calculateTotal(int $qty, float $price): float
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
is fine when every caller is yours.
|
|
177
|
+
|
|
178
|
+
The dangerous place is the Magento/vendor boundary.
|
|
179
|
+
|
|
180
|
+
Do not add or remove:
|
|
181
|
+
|
|
182
|
+
```php
|
|
183
|
+
declare(strict_types=1);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
as a cleanup exercise. Follow the surrounding module. It does not fix messy
|
|
187
|
+
Magento runtime contracts.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
# DI
|
|
192
|
+
|
|
193
|
+
Use constructor DI for normal dependencies.
|
|
194
|
+
|
|
195
|
+
Use:
|
|
196
|
+
|
|
197
|
+
* **Factory** when creating runtime instances.
|
|
198
|
+
* **Proxy** when an expensive dependency is commonly unused.
|
|
199
|
+
* **Virtual type** when the same implementation needs different constructor
|
|
200
|
+
configuration.
|
|
201
|
+
* **Preference** when an implementation genuinely must be replaced.
|
|
202
|
+
|
|
203
|
+
Do not create a factory merely to hide constructor DI.
|
|
204
|
+
|
|
205
|
+
Do not add proxies everywhere because "Magento performance".
|
|
206
|
+
|
|
207
|
+
Before changing a constructor used by Magento/vendor inheritance, inspect its
|
|
208
|
+
subclasses and DI configuration.
|
|
209
|
+
|
|
210
|
+
Constructor signature changes are upgrade-sensitive.
|
|
211
|
+
|
|
212
|
+
If Magento already injects something awkward such as checkout session into a
|
|
213
|
+
class, do not start an architectural rewrite unless that dependency is the
|
|
214
|
+
actual problem.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
# Plugins
|
|
219
|
+
|
|
220
|
+
Use the smallest plugin type that works:
|
|
221
|
+
|
|
222
|
+
```text
|
|
223
|
+
before → arguments
|
|
224
|
+
after → result
|
|
225
|
+
around → control whether/how original executes
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Avoid `around` when `before` or `after` works.
|
|
229
|
+
|
|
230
|
+
`around` plugins:
|
|
231
|
+
|
|
232
|
+
* increase stack complexity;
|
|
233
|
+
* affect every downstream plugin;
|
|
234
|
+
* are harder to debug;
|
|
235
|
+
* can accidentally skip `$proceed()`.
|
|
236
|
+
|
|
237
|
+
Use them when that behavior is actually required, not because they feel more
|
|
238
|
+
powerful.
|
|
239
|
+
|
|
240
|
+
Keep plugins tiny.
|
|
241
|
+
|
|
242
|
+
If plugin code starts becoming a workflow, move the workflow into an existing
|
|
243
|
+
service or a small dedicated service.
|
|
244
|
+
|
|
245
|
+
Do not refactor merely to satisfy that rule.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
# Preferences
|
|
250
|
+
|
|
251
|
+
Preferences are not forbidden.
|
|
252
|
+
|
|
253
|
+
Use one when:
|
|
254
|
+
|
|
255
|
+
* the method cannot be intercepted;
|
|
256
|
+
* the implementation genuinely needs replacement;
|
|
257
|
+
* inheritance is already the natural extension mechanism;
|
|
258
|
+
* a plugin would be more fragile or more complex.
|
|
259
|
+
|
|
260
|
+
Do not copy an entire vendor class to change five lines.
|
|
261
|
+
|
|
262
|
+
Override only what is needed.
|
|
263
|
+
|
|
264
|
+
A preference changing one small public method may still be the least-bad
|
|
265
|
+
solution when the alternatives are worse. Judge the real code, not a rulebook.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
# Events
|
|
270
|
+
|
|
271
|
+
Use an observer when an existing event represents exactly the business event
|
|
272
|
+
you need.
|
|
273
|
+
|
|
274
|
+
Do not create event-driven architecture around synchronous logic that can be a
|
|
275
|
+
method call.
|
|
276
|
+
|
|
277
|
+
Do not depend on mutating event payloads as a hidden replacement mechanism.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
# Data access
|
|
282
|
+
|
|
283
|
+
There is no universal "always use repositories" rule.
|
|
284
|
+
|
|
285
|
+
Use the tool that matches the job.
|
|
286
|
+
|
|
287
|
+
## Repository
|
|
288
|
+
|
|
289
|
+
Use repositories for:
|
|
290
|
+
|
|
291
|
+
* service/API boundaries;
|
|
292
|
+
* cross-module public entity access;
|
|
293
|
+
* code already built around service contracts;
|
|
294
|
+
* REST/GraphQL-facing contracts where appropriate.
|
|
295
|
+
|
|
296
|
+
## Collection
|
|
297
|
+
|
|
298
|
+
Use collections for:
|
|
299
|
+
|
|
300
|
+
* filtered lists;
|
|
301
|
+
* batch reads;
|
|
302
|
+
* joins already supported by the collection;
|
|
303
|
+
* avoiding N repository calls.
|
|
304
|
+
|
|
305
|
+
## Resource model
|
|
306
|
+
|
|
307
|
+
Use resource models for:
|
|
308
|
+
|
|
309
|
+
* internal persistence;
|
|
310
|
+
* targeted DB operations;
|
|
311
|
+
* operations where loading a full model is unnecessary.
|
|
312
|
+
|
|
313
|
+
## ResourceConnection / SQL
|
|
314
|
+
|
|
315
|
+
Direct SQL is fine for:
|
|
316
|
+
|
|
317
|
+
* bulk updates;
|
|
318
|
+
* imports;
|
|
319
|
+
* index-style workloads;
|
|
320
|
+
* aggregates;
|
|
321
|
+
* efficient targeted operations.
|
|
322
|
+
|
|
323
|
+
Use Magento's DB adapter and resolved table names.
|
|
324
|
+
|
|
325
|
+
Bind values.
|
|
326
|
+
|
|
327
|
+
Understand which Magento lifecycle behavior you are bypassing.
|
|
328
|
+
|
|
329
|
+
Do not load 10,000 entities through repositories because "best practice".
|
|
330
|
+
|
|
331
|
+
Do not use:
|
|
332
|
+
|
|
333
|
+
```php
|
|
334
|
+
foreach ($ids as $id) {
|
|
335
|
+
$repository->getById($id);
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
when one collection/query solves it.
|
|
340
|
+
|
|
341
|
+
Avoid new `$model->load()` / `$model->save()` code unless you are deliberately
|
|
342
|
+
working with an existing legacy flow.
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
# XML before PHP
|
|
347
|
+
|
|
348
|
+
Before writing runtime plumbing, check whether Magento already has the correct
|
|
349
|
+
XML mechanism:
|
|
350
|
+
|
|
351
|
+
```text
|
|
352
|
+
di.xml
|
|
353
|
+
events.xml
|
|
354
|
+
routes.xml
|
|
355
|
+
webapi.xml
|
|
356
|
+
acl.xml
|
|
357
|
+
system.xml
|
|
358
|
+
config.xml
|
|
359
|
+
menu.xml
|
|
360
|
+
cron.xml
|
|
361
|
+
communication.xml
|
|
362
|
+
queue_*.xml
|
|
363
|
+
indexer.xml
|
|
364
|
+
mview.xml
|
|
365
|
+
extension_attributes.xml
|
|
366
|
+
db_schema.xml
|
|
367
|
+
layout XML
|
|
368
|
+
UI component XML
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Do not build a PHP framework around something Magento already merges from XML.
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
# Schema
|
|
376
|
+
|
|
377
|
+
For Magento 2.4:
|
|
378
|
+
|
|
379
|
+
* `db_schema.xml` for normal schema;
|
|
380
|
+
* data patches for data changes;
|
|
381
|
+
* imperative schema patches only when declarative schema cannot do the job.
|
|
382
|
+
|
|
383
|
+
Do not introduce `InstallSchema` / `UpgradeSchema` into new modules.
|
|
384
|
+
|
|
385
|
+
For large tables, think about locking and deployment before adding/changing
|
|
386
|
+
indexes or columns.
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
# Cache / indexers
|
|
391
|
+
|
|
392
|
+
Never reflexively run:
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
bin/magento cache:flush
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
after every change.
|
|
399
|
+
|
|
400
|
+
Clean only relevant cache types when needed.
|
|
401
|
+
|
|
402
|
+
Do not full-reindex because one entity changed.
|
|
403
|
+
|
|
404
|
+
When bypassing Magento persistence with SQL, explicitly check whether you also
|
|
405
|
+
bypass:
|
|
406
|
+
|
|
407
|
+
* cache invalidation;
|
|
408
|
+
* index invalidation;
|
|
409
|
+
* MView changelog updates;
|
|
410
|
+
* events/business lifecycle.
|
|
411
|
+
|
|
412
|
+
Code must work with both:
|
|
413
|
+
|
|
414
|
+
```text
|
|
415
|
+
Update on Save
|
|
416
|
+
Update by Schedule
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
when the affected indexer supports them.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
# Performance
|
|
424
|
+
|
|
425
|
+
Magento performance bugs are usually boring.
|
|
426
|
+
|
|
427
|
+
Look for these first:
|
|
428
|
+
|
|
429
|
+
* repository calls inside loops;
|
|
430
|
+
* repeated `getById`;
|
|
431
|
+
* N+1 GraphQL resolvers;
|
|
432
|
+
* extension attributes loading entities individually;
|
|
433
|
+
* huge collections loaded into PHP;
|
|
434
|
+
* unnecessary session initialization;
|
|
435
|
+
* expensive dependencies constructed on every request;
|
|
436
|
+
* network calls inside DB transactions;
|
|
437
|
+
* uncached repeated configuration/data lookups.
|
|
438
|
+
|
|
439
|
+
Batch before inventing caches.
|
|
440
|
+
|
|
441
|
+
Query before loading models.
|
|
442
|
+
|
|
443
|
+
Measure before building infrastructure.
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
# GraphQL / REST
|
|
448
|
+
|
|
449
|
+
Resolvers/controllers should mostly adapt transport input to existing business
|
|
450
|
+
logic.
|
|
451
|
+
|
|
452
|
+
For GraphQL:
|
|
453
|
+
|
|
454
|
+
* avoid N+1;
|
|
455
|
+
* batch when practical;
|
|
456
|
+
* verify authorization/ownership;
|
|
457
|
+
* return cache identities when required.
|
|
458
|
+
|
|
459
|
+
Do not build a new service layer merely because a resolver contains five lines.
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
# Luma / Hyvä / Admin
|
|
464
|
+
|
|
465
|
+
First identify which frontend runtime is actually being changed.
|
|
466
|
+
|
|
467
|
+
Do not bring Luma assumptions into Hyvä.
|
|
468
|
+
|
|
469
|
+
## Luma
|
|
470
|
+
|
|
471
|
+
Prefer existing Magento mechanisms:
|
|
472
|
+
|
|
473
|
+
```text
|
|
474
|
+
layout XML
|
|
475
|
+
ViewModel
|
|
476
|
+
small template override
|
|
477
|
+
RequireJS mixin
|
|
478
|
+
existing UI component
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
Avoid copying entire vendor JS/PHTML files.
|
|
482
|
+
|
|
483
|
+
## Hyvä
|
|
484
|
+
|
|
485
|
+
Prefer the mechanisms already used by the installed Hyvä version.
|
|
486
|
+
|
|
487
|
+
Do not assume RequireJS, Knockout, jQuery or Luma customer-data behavior.
|
|
488
|
+
|
|
489
|
+
Check the installed version before depending on version-specific APIs.
|
|
490
|
+
|
|
491
|
+
## Admin
|
|
492
|
+
|
|
493
|
+
Do not build a UI Component monstrosity for a page containing three fields.
|
|
494
|
+
|
|
495
|
+
Use UI Components when their grid/form machinery is actually useful.
|
|
496
|
+
|
|
497
|
+
For a small custom page, normal layout/block/ViewModel/template code can be
|
|
498
|
+
better.
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
# Security and integrity
|
|
503
|
+
|
|
504
|
+
Ponytail does **not** simplify away:
|
|
505
|
+
|
|
506
|
+
* ACL;
|
|
507
|
+
* ownership checks;
|
|
508
|
+
* CSRF/form keys;
|
|
509
|
+
* output escaping;
|
|
510
|
+
* SQL binding;
|
|
511
|
+
* upload/path validation;
|
|
512
|
+
* authentication;
|
|
513
|
+
* transaction correctness;
|
|
514
|
+
* concurrency protection where data can be corrupted.
|
|
515
|
+
|
|
516
|
+
The smallest insecure diff is not a valid solution.
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
# Testing
|
|
521
|
+
|
|
522
|
+
Do not create a giant test suite for a small fix.
|
|
523
|
+
|
|
524
|
+
For non-trivial behavior, leave the smallest useful regression check.
|
|
525
|
+
|
|
526
|
+
Use Magento integration tests when the thing being tested actually depends on:
|
|
527
|
+
|
|
528
|
+
* DI;
|
|
529
|
+
* plugins;
|
|
530
|
+
* DB;
|
|
531
|
+
* XML;
|
|
532
|
+
* indexers;
|
|
533
|
+
* Magento bootstrap.
|
|
534
|
+
|
|
535
|
+
For pure PHP logic, a unit test is enough.
|
|
536
|
+
|
|
537
|
+
For a dangerous vendor override, one focused regression test is more valuable
|
|
538
|
+
than twenty mocked unit tests.
|
|
539
|
+
|
|
540
|
+
---
|
|
541
|
+
|
|
542
|
+
# Deployment reality
|
|
543
|
+
|
|
544
|
+
Do not blindly recommend:
|
|
545
|
+
|
|
546
|
+
```text
|
|
547
|
+
maintenance enable
|
|
548
|
+
setup:upgrade
|
|
549
|
+
di:compile
|
|
550
|
+
static-content:deploy
|
|
551
|
+
reindex
|
|
552
|
+
cache:flush
|
|
553
|
+
maintenance disable
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
for every code change.
|
|
557
|
+
|
|
558
|
+
Inspect what changed.
|
|
559
|
+
|
|
560
|
+
Typical PHP logic change:
|
|
561
|
+
|
|
562
|
+
```text
|
|
563
|
+
targeted cache clean, often nothing else
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
DI/XML/module registration change:
|
|
567
|
+
|
|
568
|
+
```text
|
|
569
|
+
setup:upgrade when applicable
|
|
570
|
+
DI compile in production/CI when applicable
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
Frontend asset change:
|
|
574
|
+
|
|
575
|
+
```text
|
|
576
|
+
static deployment only when the deployment mode/build process requires it
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
Schema/data change:
|
|
580
|
+
|
|
581
|
+
```text
|
|
582
|
+
setup:upgrade
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
Production operations depend on the project's actual deployment pipeline.
|
|
586
|
+
|
|
587
|
+
Never run destructive or broad operational commands merely because Magento
|
|
588
|
+
tutorials traditionally list them.
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
# Red flags
|
|
593
|
+
|
|
594
|
+
Question code containing:
|
|
595
|
+
|
|
596
|
+
```text
|
|
597
|
+
ObjectManager::get() in normal feature code
|
|
598
|
+
repository getById() in loops
|
|
599
|
+
cache:flush after writes
|
|
600
|
+
full reindex after writes
|
|
601
|
+
around plugins for simple result changes
|
|
602
|
+
whole copied vendor classes
|
|
603
|
+
whole copied PHTML/JS files
|
|
604
|
+
business workflows inside plugins
|
|
605
|
+
new abstractions with one caller
|
|
606
|
+
strict plugin result/argument types that Magento does not guarantee
|
|
607
|
+
constructor changes to vendor subclasses without checking compatibility
|
|
608
|
+
direct SQL without understanding invalidation/indexers
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
A red flag is a reason to inspect, not an automatic rewrite order.
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
# Output behavior
|
|
616
|
+
|
|
617
|
+
Code first.
|
|
618
|
+
|
|
619
|
+
Prefer a patch/small implementation over an architecture essay.
|
|
620
|
+
|
|
621
|
+
After code, explain only what matters:
|
|
622
|
+
|
|
623
|
+
```text
|
|
624
|
+
Changed X.
|
|
625
|
+
Skipped Y because Magento already handles it.
|
|
626
|
+
Run Z only if this change affects ...
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
When multiple solutions work, choose the shortest robust one.
|
|
630
|
+
|
|
631
|
+
Do not present five architectural alternatives unless the user asks.
|
|
632
|
+
|
|
633
|
+
## Ponytail intensity
|
|
634
|
+
|
|
635
|
+
**lite**
|
|
636
|
+
Implement what was requested, but mention a simpler Magento-native alternative
|
|
637
|
+
if one obviously exists.
|
|
638
|
+
|
|
639
|
+
**full**
|
|
640
|
+
Default. Smallest safe Magento-native diff. No speculative architecture.
|
|
641
|
+
|
|
642
|
+
**ultra**
|
|
643
|
+
Challenge unnecessary requirements, delete before adding, and choose the
|
|
644
|
+
smallest production-safe solution possible.
|
|
645
|
+
|
|
646
|
+
Ponytail never means skipping investigation.
|
|
647
|
+
|
|
648
|
+
**Read the real flow first. Then be lazy.**
|