start-vibing-stacks 2.16.0 → 2.18.0

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.
@@ -1,12 +1,91 @@
1
1
  ---
2
2
  name: mariadb-octane
3
- version: 1.0.0
3
+ version: 2.0.0
4
+ description: "MariaDB patterns for Laravel Octane (long-lived workers) targeting MariaDB 11.8 LTS (released 2025, supported until June 2028). Octane-safe connection config (PERSISTENT + EMULATE_PREPARES off + STRICT_TRANS_TABLES + utf8mb4 default in 11.8), automatic flush on request boundary, Octane::tick health probes, MariaDB 11.8 features (VECTOR data type + VEC_DISTANCE_*, JSON Schema validation, system-versioned temporal tables, TIMESTAMP range to 2106, PARSEC auth plugin, parallel mariadb-dump), strict migrations with explicit lengths, composite/covering indexes, cursor pagination, transaction safety in workers, immutable_datetime casts. Invoke for any query, migration, model, or DB config in Laravel Octane."
4
5
  ---
5
6
 
6
- # MariaDB + Octane — Database Patterns for Persistent Workers
7
+ # MariaDB + Octane — Database Patterns (MariaDB 11.8 LTS, 2026)
7
8
 
8
9
  **ALWAYS invoke when writing queries, migrations, models, or DB config in Laravel Octane.**
9
10
 
11
+ ## MariaDB 11.8 LTS — what changed (release Jun 2025; LTS until Jun 2028)
12
+
13
+ MariaDB 11.8 supersedes 11.4 LTS. Adopt for new projects; plan migration for existing.
14
+
15
+ | Feature | Why it matters |
16
+ |---|---|
17
+ | **Default charset is now `utf8mb4`** (was `latin1` for ~20 years) | New tables don't need explicit charset; old tables stay as-is until ALTERed |
18
+ | **Native `VECTOR` type + `VEC_DISTANCE_COSINE` / `VEC_DISTANCE_EUCLIDEAN`** | Embeddings + similarity search in the same DB — RAG without a separate vector store. SIMD on AVX2/AVX512/ARM/PowerPC |
19
+ | **JSON Schema validation** at column level | Constrain `JSON` columns instead of validating only in PHP |
20
+ | **System-versioned (temporal) tables** | Native row history, point-in-time queries — replaces hand-rolled audit tables |
21
+ | **`TIMESTAMP` range extended to 2106** | The 2038 problem is fixed for new schemas |
22
+ | **PARSEC auth plugin** (Password Auth Response Signed by Elliptic Curves) | Stronger than `mysql_native_password`; safer than `caching_sha2_password` for SSL-less internal hops |
23
+ | **Parallel `mariadb-dump` / `mariadb-import`** | Backup/restore minutes instead of hours on multi-GB DBs |
24
+
25
+ ### Vector search example (RAG-style)
26
+
27
+ ```sql
28
+ -- MariaDB 11.7+
29
+ CREATE TABLE doc_chunks (
30
+ id INT AUTO_INCREMENT PRIMARY KEY,
31
+ text TEXT NOT NULL,
32
+ embedding VECTOR(1536) NOT NULL, -- e.g. text-embedding-3-small
33
+ VECTOR INDEX (embedding) USING HNSW -- approximate nearest neighbor
34
+ );
35
+
36
+ -- Similarity search
37
+ SELECT id, text, VEC_DISTANCE_COSINE(embedding, VEC_FromText(?)) AS distance
38
+ FROM doc_chunks
39
+ ORDER BY distance
40
+ LIMIT 5;
41
+ ```
42
+
43
+ ```php
44
+ // Eloquent — bind embedding as a JSON-encoded array of floats; MariaDB driver coerces
45
+ $results = DB::select(
46
+ 'SELECT id, text, VEC_DISTANCE_COSINE(embedding, VEC_FromText(?)) AS distance
47
+ FROM doc_chunks ORDER BY distance LIMIT 5',
48
+ [json_encode($queryEmbedding)],
49
+ );
50
+ ```
51
+
52
+ ### System-versioned tables (audit history without triggers)
53
+
54
+ ```sql
55
+ CREATE TABLE accounts (
56
+ id INT PRIMARY KEY,
57
+ balance DECIMAL(12,2) NOT NULL,
58
+ PERIOD FOR system_time(start_ts, end_ts),
59
+ start_ts TIMESTAMP(6) GENERATED ALWAYS AS ROW START,
60
+ end_ts TIMESTAMP(6) GENERATED ALWAYS AS ROW END
61
+ ) WITH SYSTEM VERSIONING;
62
+
63
+ -- Query historical state
64
+ SELECT * FROM accounts FOR SYSTEM_TIME AS OF '2026-04-01 12:00:00';
65
+ SELECT * FROM accounts FOR SYSTEM_TIME BETWEEN '2026-04-01' AND '2026-05-01';
66
+ ```
67
+
68
+ Replaces hand-rolled `accounts_history` tables fed by triggers — MariaDB does it natively, including `pg_dump`-style point-in-time queries.
69
+
70
+ ### JSON Schema column constraint
71
+
72
+ ```sql
73
+ ALTER TABLE leads
74
+ MODIFY metadata JSON
75
+ CHECK (JSON_SCHEMA_VALID('{
76
+ "type": "object",
77
+ "required": ["source", "campaign"],
78
+ "properties": {
79
+ "source": { "type": "string" },
80
+ "campaign": { "type": "string" }
81
+ }
82
+ }', metadata));
83
+ ```
84
+
85
+ Bad payloads now fail at INSERT time, not at the next time PHP tries to read them.
86
+
87
+ ---
88
+
10
89
  ## Why Octane Changes Everything
11
90
 
12
91
  ```
@@ -39,8 +118,9 @@ Problems in Octane:
39
118
  'database' => env('DB_DATABASE'),
40
119
  'username' => env('DB_USERNAME'),
41
120
  'password' => env('DB_PASSWORD'),
42
- 'charset' => 'utf8mb4',
43
- 'collation' => 'utf8mb4_unicode_ci',
121
+ 'charset' => 'utf8mb4', // default in MariaDB 11.8 — keep explicit for older servers
122
+ 'collation' => 'utf8mb4_uca1400_ai_ci', // 11.x — Unicode 14, accent-insensitive, case-insensitive
123
+ // (use utf8mb4_unicode_ci on MariaDB ≤ 10.11 / MySQL)
44
124
  'prefix' => '',
45
125
  'strict' => true, // ← MANDATORY
46
126
  'engine' => 'InnoDB',
@@ -388,3 +468,15 @@ Route::get('/health', function () {
388
468
  | `Lead::count()` on millions of rows | Cached count or approximate count |
389
469
  | `'metadata' => 'json'` cast | `'metadata' => 'array'` (auto decode) |
390
470
  | `datetime` cast | `immutable_datetime` (Octane-safe, no mutation) |
471
+ | Hand-rolled `*_history` tables fed by triggers | System-versioned (`WITH SYSTEM VERSIONING`) — MariaDB 11.x |
472
+ | Storing embeddings as `LONGTEXT` JSON | Native `VECTOR(N)` + `VEC_DISTANCE_*` (MariaDB 11.7+) |
473
+ | Validating JSON only in PHP | Add `JSON_SCHEMA_VALID` CHECK constraint on the column |
474
+
475
+ ## See Also
476
+
477
+ - `_shared/skills/postgres-patterns` — analogous skill on the Postgres side (PG 18 features); MariaDB-specific equivalents documented here
478
+ - `_shared/skills/database-migrations` — universal parallel-change / backfill rules
479
+ - `laravel-octane` — worker safety rules this skill plugs into
480
+ - `php-patterns` — `readonly`, enums, immutable_datetime that pair with Eloquent casts
481
+ - `phpstan-analysis` (Larastan) — model PHPDoc generation makes Eloquent type-safe
482
+ - `api-design` — pagination shape that backend cursor pagination feeds
@@ -1,15 +1,108 @@
1
1
  ---
2
2
  name: php-patterns
3
- version: 1.0.0
3
+ version: 2.0.0
4
+ description: "Modern PHP idioms for Laravel apps targeting PHP 8.3 and 8.4 (Nov 2024). Covers property hooks (replace boilerplate getters/setters), asymmetric visibility (public read / private write), lazy objects via Reflection, typed class constants (8.3), readonly classes, enums, match, named args, null-safe, first-class callable syntax, constructor promotion, Octane-safe DI patterns. Invoke for any new PHP class, refactor of an old one, or when reviewing OOP code."
4
5
  ---
5
6
 
6
- # PHP 8.3+ Patterns for Laravel
7
+ # PHP 8.3 / 8.4 Patterns for Laravel
7
8
 
8
9
  ## Version Requirements
9
10
 
10
- - **PHP >= 8.3** — MANDATORY. Use all modern features.
11
- - **Composer >= 2.0** — For dependency management.
12
- - Use strict types: `declare(strict_types=1);` in EVERY file.
11
+ - **PHP 8.3** — minimum supported (Laravel 12 supports 8.2–8.5; we target 8.3+).
12
+ - **PHP 8.4 strongly recommended** for new projects (released **Nov 21, 2024**) adds property hooks + asymmetric visibility + lazy objects.
13
+ - **Composer 2.8** see `composer-workflow`.
14
+ - `declare(strict_types=1);` in EVERY file. No exceptions.
15
+
16
+ ## PHP 8.4 Highlights — adopt for new code
17
+
18
+ ### Property Hooks — replace getter/setter boilerplate
19
+
20
+ The single most consequential 8.4 feature. Replaces hand-rolled `get`/`set` methods that exist solely to wrap a stored value.
21
+
22
+ ```php
23
+ class User
24
+ {
25
+ public function __construct(
26
+ public string $firstName,
27
+ public string $lastName,
28
+ ) {}
29
+
30
+ // Computed property — no method call, no boilerplate
31
+ public string $fullName {
32
+ get => trim("{$this->firstName} {$this->lastName}");
33
+ }
34
+
35
+ // Validation on assignment
36
+ public string $email {
37
+ set (string $value) {
38
+ if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
39
+ throw new \InvalidArgumentException("Invalid email: {$value}");
40
+ }
41
+ $this->email = strtolower($value);
42
+ }
43
+ }
44
+ }
45
+
46
+ $u = new User('John', 'Doe');
47
+ echo $u->fullName; // "John Doe" — read like a field
48
+ $u->email = 'JOHN@DOE.COM'; // validated + lowercased on assign
49
+ ```
50
+
51
+ Use property hooks when the field has computation or validation. **Don't** wrap a plain value just because old code did.
52
+
53
+ ### Asymmetric Visibility — read public, write protected
54
+
55
+ ```php
56
+ final class Order
57
+ {
58
+ public function __construct(
59
+ public private(set) string $id, // readable everywhere; writable only inside Order
60
+ public protected(set) string $status, // writable in Order + subclasses
61
+ ) {}
62
+
63
+ public function markPaid(): void { $this->status = 'paid'; }
64
+ }
65
+
66
+ $o = new Order('ord_123', 'pending');
67
+ echo $o->id; // OK
68
+ $o->status = 'paid'; // ERROR — only Order/subclasses can write
69
+ $o->markPaid(); // OK
70
+ ```
71
+
72
+ Replaces the `private $id; public function id() { return $this->id; }` pattern entirely.
73
+
74
+ ### Lazy Objects — defer expensive init
75
+
76
+ ```php
77
+ $reflector = new \ReflectionClass(ExpensiveService::class);
78
+ $service = $reflector->newLazyGhost(function (ExpensiveService $svc): void {
79
+ // Runs only on first real access — bootstraps DB conn, loads cache, etc.
80
+ $svc->__construct(/* ... */);
81
+ });
82
+
83
+ // $service behaves like ExpensiveService but does nothing until used:
84
+ $service->doSomething(); // <-- init runs here, exactly once
85
+ ```
86
+
87
+ Mostly relevant for ORM-style proxies / DI containers. Day-to-day app code rarely needs it.
88
+
89
+ ### New JIT (IR Framework)
90
+
91
+ Enabled by default in PHP 8.4. No app code change needed; just verify your `opcache.ini` enables JIT in production:
92
+
93
+ ```ini
94
+ opcache.jit_buffer_size=128M
95
+ opcache.jit=tracing
96
+ ```
97
+
98
+ ### Other 8.4 deltas worth knowing
99
+
100
+ - HTML5-aware `Dom\HTMLDocument` (replaces the legacy quirks-mode parser)
101
+ - `array_find()`, `array_find_key()`, `array_any()`, `array_all()` — finally
102
+ - Object API for `BCMath\Number` — chainable arbitrary-precision math
103
+ - 4-year support lifecycle (active + security)
104
+
105
+ ## Modern PHP Features (USE THESE)
13
106
 
14
107
  ## Modern PHP Features (USE THESE)
15
108
 
@@ -1,73 +1,179 @@
1
1
  ---
2
2
  name: phpstan-analysis
3
- version: 1.0.0
3
+ version: 2.0.0
4
+ description: "PHPStan 2.x (released Nov 11, 2024) static analysis for PHP 8.3-8.5 / Laravel 12. Covers Level 10 (strict mixed even from inferred types — new in 2.0), the list<T> array type for sequential int-keyed arrays, baseline workflow for legacy code, generics + array shapes annotations, larastan extension for Laravel-specific rules (Eloquent magic, facades, container resolution), 50-70% memory reduction in 2.0, CI integration with --error-format. Invoke when configuring PHPStan, raising the level, fixing reported issues, or onboarding a legacy codebase."
4
5
  ---
5
6
 
6
- # PHPStan Static Analysis
7
+ # PHPStan Static Analysis (2.x, Nov 2024)
8
+
9
+ **Invoke when configuring PHPStan, raising the level, fixing reports, or wiring it into CI.**
10
+
11
+ > PHPStan 2.0 (Nov 11, 2024) added **Level 10** and the **`list<T>`** type, dropped 50-70% memory usage, and tightened reference-parameter analysis. It's a transparent upgrade from 1.x — same config keys, stricter inferences. Update as part of any project refresh.
7
12
 
8
13
  ## Setup
9
14
 
10
15
  ```bash
11
- composer require --dev phpstan/phpstan
16
+ composer require --dev phpstan/phpstan "^2.0"
17
+
18
+ # Laravel projects — add Larastan for framework awareness
19
+ composer require --dev larastan/larastan "^3.0"
12
20
  ```
13
21
 
14
- ## Configuration (phpstan.neon)
22
+ ## Configuration (`phpstan.neon` / `phpstan.neon.dist`)
15
23
 
16
24
  ```neon
25
+ # Plain PHP project
17
26
  parameters:
18
- level: 6
27
+ level: 8 # Target. Raise toward 10.
19
28
  paths:
20
29
  - src
21
- - app
30
+ - tests
22
31
  excludePaths:
23
32
  - vendor
24
33
  - storage
25
34
  - bootstrap/cache
26
- checkMissingIterableValueType: false
35
+ treatPhpDocTypesAsCertain: false # Pragmatic for first month at high level
36
+ reportUnmatchedIgnoredErrors: true
37
+ parallel:
38
+ maximumNumberOfProcesses: 4
39
+
40
+ # Laravel project (Larastan)
41
+ includes:
42
+ - vendor/larastan/larastan/extension.neon
43
+ parameters:
44
+ level: 8
45
+ paths:
46
+ - app
47
+ - bootstrap
48
+ - config
49
+ - database
50
+ - routes
51
+ excludePaths:
52
+ - storage
53
+ - bootstrap/cache
27
54
  ```
28
55
 
29
- ## Levels
56
+ ## Levels — what each one adds
30
57
 
31
- | Level | What it checks |
32
- |-------|---------------|
33
- | 0 | Basic checks (unknown classes, functions) |
34
- | 1 | Possibly undefined variables, return types |
35
- | 2 | Unknown methods on all expressions |
58
+ | Level | Catches |
59
+ |---|---|
60
+ | 0 | Unknown classes / functions / methods on `$this` |
61
+ | 1 | Possibly undefined variables, undefined params on `$this`, unreachable code |
62
+ | 2 | Unknown methods on **all** expressions (not just `$this`) |
36
63
  | 3 | Return types, property types |
37
- | 4 | Dead code, always true/false |
38
- | 5 | Argument types |
39
- | **6** | **MINIMUM for this project** strict types |
40
- | 7 | Union types |
41
- | 8 | Nullable types everywhere |
42
- | 9 | Mixed type restrictions |
64
+ | 4 | Dead code, always-true/always-false branches |
65
+ | 5 | Argument types in function/method calls |
66
+ | 6 | Missing typehints (params + returns) |
67
+ | 7 | Partially-wrong union types |
68
+ | 8 | Calling methods / accessing props on nullable types |
69
+ | 9 | `mixed` is treated strictly when **explicitly typed** |
70
+ | **10 (NEW in 2.0)** | `mixed` strict even when **implicitly inferred** (any unknown type) |
71
+
72
+ **Recommended target:** Level 8 for new projects (achievable with Larastan + readonly DTOs); raise to 9 once stable; 10 only after eliminating all `mixed` from your own code.
73
+
74
+ ## `list<T>` — the new sequential array type *(2.0)*
75
+
76
+ Use when you have a 0-indexed contiguous array. PHPStan can then narrow types far more precisely than with `array<int, T>`.
77
+
78
+ ```php
79
+ /**
80
+ * @param list<int> $ids sequential 0,1,2,... no gaps
81
+ * @return list<User> same shape on the way out
82
+ */
83
+ public function findManyById(array $ids): array
84
+ {
85
+ return User::whereIn('id', $ids)->get()->all();
86
+ }
87
+ ```
88
+
89
+ Other useful array types:
90
+
91
+ | PHPDoc | Meaning |
92
+ |---|---|
93
+ | `array<int>` | Any-shape array of ints |
94
+ | `list<int>` | Sequential, 0-indexed, no gaps |
95
+ | `non-empty-array<string, int>` | At least one entry; string keys, int values |
96
+ | `non-empty-list<User>` | Sequential AND non-empty |
97
+ | `array{name: string, age: int}` | Array shape (object-like) |
98
+ | `array{name: string, age?: int}` | Optional key |
43
99
 
44
100
  ## Running
45
101
 
46
102
  ```bash
47
- vendor/bin/phpstan analyse # Default config
48
- vendor/bin/phpstan analyse --level=6 src/ # Specific level & path
49
- vendor/bin/phpstan analyse --generate-baseline # Generate baseline for legacy code
103
+ vendor/bin/phpstan analyse # Use config
104
+ vendor/bin/phpstan analyse --level=8 src/ # Override level + path
105
+ vendor/bin/phpstan analyse --memory-limit=1G # Bigger projects (still ~50% less than 1.x)
106
+ vendor/bin/phpstan analyse --generate-baseline # Snapshot legacy errors → unblocks CI
107
+ vendor/bin/phpstan analyse --error-format=github # CI annotations on PRs
50
108
  ```
51
109
 
110
+ ## Baseline workflow (legacy adoption)
111
+
112
+ ```bash
113
+ # Day 1: ratchet to a level that's mostly clean, baseline the rest
114
+ vendor/bin/phpstan analyse --level=6 --generate-baseline
115
+
116
+ # Day 2+: every new file/edit cannot ADD baseline entries
117
+ # Periodically: chip away at the baseline (delete entries, fix code)
118
+ vendor/bin/phpstan analyse --level=6 # must pass
119
+ vendor/bin/phpstan analyse --level=6 --error-format=github
120
+ ```
121
+
122
+ `reportUnmatchedIgnoredErrors: true` ensures the baseline shrinks (or fails CI) instead of growing silently.
123
+
52
124
  ## Common Fixes
53
125
 
54
126
  ```php
55
- // ❌ PHPStan error: Parameter $data has no type hint
127
+ // ❌ Parameter $data has no type hint
56
128
  function process($data) {}
57
129
 
58
- // ✅ Fixed
130
+ // ✅
59
131
  function process(array $data): void {}
60
132
 
61
- // ❌ PHPStan error: Method returns mixed
133
+
134
+ // ❌ Method returns mixed
62
135
  function getData() { return $this->db->query(); }
63
136
 
64
- // ✅ Fixed
65
- /** @return array<string, mixed> */
137
+ // ✅ — PHPDoc + native return type
138
+ /** @return list<array<string, mixed>> */
66
139
  function getData(): array { return $this->db->query(); }
140
+
141
+
142
+ // ❌ "Cannot access property $name on User|null"
143
+ echo $request->user()->name;
144
+
145
+ // ✅ — assert or null-coalesce
146
+ echo $request->user()?->name ?? 'guest';
147
+
148
+
149
+ // ❌ "Property User::$email is never written, only read"
150
+ class User {
151
+ public function __construct(public readonly string $email) {}
152
+ // PHPStan now reports if you typo-shadow the property elsewhere
153
+ }
67
154
  ```
68
155
 
156
+ ## CI integration
157
+
158
+ ```yaml
159
+ # .github/workflows/ci.yml
160
+ - name: PHPStan
161
+ run: vendor/bin/phpstan analyse --error-format=github --memory-limit=1G
162
+ ```
163
+
164
+ GitHub annotations show inline diff comments on the PR — much higher signal than the textual report.
165
+
69
166
  ## Rules
70
167
 
71
- 1. **Level 6 minimum** no exceptions
72
- 2. **Fix errors, don't ignore** use baseline only for legacy code
73
- 3. **Run before commit** — part of quality gates
168
+ 1. **Target level 8 minimum** for new code; raise to 9/10 incrementally
169
+ 2. **Larastan is mandatory** on Laravel projects (Eloquent magic methods, facades, container)
170
+ 3. **Baseline only legacy code** — new files must be clean
171
+ 4. **Run before every commit** — wired into the quality gate
172
+ 5. **`reportUnmatchedIgnoredErrors: true`** — baseline shrinks, never grows silently
173
+ 6. **No `@phpstan-ignore` without a comment** explaining why and a link to the issue if upstream
174
+
175
+ ## See Also
176
+
177
+ - `quality-gate` — typecheck step ordering
178
+ - `composer-workflow` — `--memory-limit` and CI script wiring
179
+ - `phpunit-testing` — Pest 4 + PHPUnit 12 typing patterns that benefit from PHPStan