toga-ai 1.0.586 → 1.0.587

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  | Doc | Summary | Files |
4
4
  |-----|---------|-------|
5
- | [Tools (1.0 Internal-Tools App) Architecture](architecture.md) | **Tools** is a standalone 1.0 (`App_`) application that houses many small internal tools behind simple interfaces, gated by Client_True staff persona. | tools/index.php, tools/_/app/framework.php, tools/_/app/frameworkindex.php, tools/assets/img/favicon/favicon.ico, tools/assets/img/favicon/favicon-32x32.png, tools/assets/img/favicon/favicon-16x16.png, tools/assets/img/favicon/apple-touch-icon.png, tools/_/app/auth.php, tools/_/app/nav.php, tools/common/header.php, tools/common/footer.php, tools/mvc/get.php, tools/mvc/_TEMPLATE/get.php, tools/docs/ADDING_A_TOOL.md, tools/assets/css/theme.css, tools/assets/js/theme.js |
5
+ | [Tools (1.0 Internal-Tools App) Architecture](architecture.md) | **Tools** is a standalone 1.0 (`App_`) application that houses many small internal tools behind simple interfaces, gated by Client_True staff persona. | tools/index.php, tools/.ebextensions/020_setup_git_libraries.config, tools/_/app/framework.php, tools/_/app/frameworkindex.php, tools/assets/img/favicon/favicon.ico, tools/assets/img/favicon/favicon-32x32.png, tools/assets/img/favicon/favicon-16x16.png, tools/assets/img/favicon/apple-touch-icon.png, tools/_/app/auth.php, tools/_/app/nav.php, tools/common/header.php, tools/common/footer.php, tools/mvc/get.php, tools/mvc/_TEMPLATE/get.php, tools/docs/ADDING_A_TOOL.md, tools/assets/css/theme.css, tools/assets/js/theme.js |
6
6
  | [ClickUp Sprint Dashboard (tools /clickup/react)](features/clickup-sprint-dashboard.md) | A native **ClickUp sprint dashboard** in the 1.0 `tools` app at route `/clickup/react`, built for a wall-mounted **TV display** ("TOGa IQ" internal sprint metri | tools/_/app/clickup/sprint.php, tools/v2/sprints/tile/index.php, tools/v2/sprints/current/index.php, tools/v2/sprints/status-breakdown/index.php, tools/v2/sprints/worktype-breakdown/index.php, tools/v2/sprints/points-by-dev/index.php, tools/v2/sprints/burndown/index.php, tools/assets/clickup/sprint-dashboard.html, tools/mvc/clickup/react/get.php, tools/mvc/login/get.php, tools/_/app/nav.php |
7
7
  | [CloudFront Client Setup](features/cloudfront-client-setup.md) | An SSO-gated admin tool at **`/devops/cloudfront-clients`** in the Tools 1.0 app that onboards a client onto **CloudFront + Route 53 across multiple AWS account | tools/_/app/devops/cloudfront.php, tools/mvc/devops/cloudfront-clients/get.php, tools/mvc/devops/cloudfront-clients/post.php, tools/assets/js/cloudfront-clients.js, tools/assets/css/cloudfront-clients.css, tools/_/app/nav.php, tools/_/app/frameworkindex.php, tools/config.production.ini |
8
8
  | [Design Demo Admin](features/design-demo-admin.md) | A self-serve admin UI at **`/design`** in the SSO-protected **Tools** app that lets the design team publish self-contained "Claude Design" HTML exports as **ver | tools/_/app/design/github.php, tools/mvc/design/get.php, tools/mvc/design/post.php, tools/assets/css/design.css, tools/assets/js/design.js, tools/_/app/frameworkindex.php, tools/_/app/nav.php, tools/composer.json |
@@ -16,4 +16,4 @@
16
16
  | [Talos Knowledge Base Admin UI (KB Documents + Vocabulary)](features/talos-kb-documents-admin.md) | > **PER-AI-MODEL, DATA-DRIVEN SCOPING (2026-07-29).** The KB-documents and Vocabulary admin > UIs were refactored from a single hard-coded **"development-team"* | tools/mvc/talos/kb-documents/get.php, tools/mvc/talos/kb-documents/post.php, tools/mvc/talos/knowledge-bases/get.php, tools/mvc/talos/knowledge-bases/post.php, tools/mvc/talos/vocabulary/get.php, tools/mvc/talos/vocabulary/post.php, tools/_/app/talos/s3.php, tools/_/app/talos/bedrock.php, tools/_/app/pg.php, tools/_/app/model/true/aimodels.php, tools/_/app/model/true/vectorindexes.php, tools/_/app/model/true/aimodels_vectorindexes.php, tools/_/app/worker.php, tools/_/app/nav.php, tools/config.production.ini, tools/config.alpha.ini, tools/.platform/httpd/conf.d/timeouts.conf, tools/.platform/hooks/prebuild/01-install-php-pgsql.sh, tools/.platform/hooks/postdeploy/01-restart-php.sh |
17
17
  | [Talos Pricing UI (Contracts, Pricing Dashboard, Usage, Settings + Estimator)](features/talos-pricing-ui.md) | The 1.0 (tools app) face of the **Talos Pricing Platform** — a "Talos Pricing" nav folder with four pages plus the estimate engine. | tools/_/app/nav.php, tools/_/app/talos/estimator.php, tools/_/app/talos/usage.php, tools/mvc/talos/contracts/get.php, tools/mvc/talos/contracts/post.php, tools/mvc/talos/pricing/get.php, tools/mvc/talos/usage/get.php, tools/mvc/talos/settings/get.php, tools/mvc/talos/settings/post.php, tools/assets/css/style.css |
18
18
  | [App-Wide Colour Theme (light / dark / auto)](features/theme-light-dark.md) | A **light / dark / auto** colour theme for the *entire* Tools app, built as a single semantic-token layer (`assets/css/theme.css`) rather than per-page edits. | tools/assets/css/theme.css, tools/assets/js/theme.js, tools/_/app/frameworkindex.php, tools/_/app/nav.php, tools/common/header.php, tools/mvc/login/get.php, tools/assets/css/style.css, tools/assets/css/design.css, tools/assets/css/login.css, tools/assets/css/cloudfront-clients.css, tools/assets/css/gchart.css, tools/mvc/talos/usage/get.php, tools/mvc/talos/pricing/get.php, tools/mvc/talos/contracts/get.php, tools/mvc/clickup/dashboard/get.php, tools/mvc/email-migration/notify/post.php |
19
- | [Deploying Tools to Elastic Beanstalk (PHP 8.5 / Amazon Linux 2023)](workflows/deploy-to-elastic-beanstalk-al2023.md) | How the **Tools** 1.0 app boots on Elastic Beanstalk running `PHP 8.5 on 64bit Amazon Linux 2023/4.13.1 (aarch64)`. | tools/.ebextensions/004_http_to_https.config, tools/.ebextensions/006_mount-s3fs.config, tools/.ebextensions/007_setup_export_cache_folders.config, tools/.ebextensions/008_setup_ldap.config, tools/.ebextensions/009_setup_phpini.config, tools/.ebextensions/020_setup_git_libraries.config, tools/.ebextensions/050_register_instance_to_shared_application_load_balancer.config, tools/ebs/git.json, tools/ebs/setup_export_cache_folders.php, tools/_/app/frameworkindex.php |
19
+ | [Deploying Tools to Elastic Beanstalk (PHP 8.5 / Amazon Linux 2023)](workflows/deploy-to-elastic-beanstalk-al2023.md) | How the **Tools** 1.0 app boots on Elastic Beanstalk running `PHP 8.5 on 64bit Amazon Linux 2023/4.13.1 (aarch64)`. | tools/.ebextensions/004_http_to_https.config, tools/.ebextensions/006_mount-s3fs.config, tools/.ebextensions/007_setup_export_cache_folders.config, tools/.ebextensions/008_setup_ldap.config, tools/.ebextensions/009_setup_phpini.config, tools/.ebextensions/003_pgsql_hook_optional.config, tools/.ebextensions/020_setup_git_libraries.config, tools/.ebextensions/050_register_instance_to_shared_application_load_balancer.config, tools/.platform/hooks/prebuild/01-install-php-pgsql.sh, tools/.platform/hooks/prebuild/02-install-php-redis.sh, tools/ebs/git.json, tools/ebs/setup_export_cache_folders.php, tools/_/app/framework.php, tools/_/app/frameworkindex.php |
@@ -10,6 +10,7 @@ updated: 2026-08-14
10
10
  owners: [jcardinal, kyalamarthi]
11
11
  files:
12
12
  - tools/index.php
13
+ - tools/.ebextensions/020_setup_git_libraries.config
13
14
  - tools/_/app/framework.php
14
15
  - tools/_/app/frameworkindex.php
15
16
  - tools/assets/img/favicon/favicon.ico
@@ -66,8 +67,24 @@ App_Framework_Tools::renderIndex();`. App-specific framework subclasses
66
67
  `App_Framework_Tools` / `App_FrameworkIndex_Tools` live in `_/app/`. The 1.0 folder-based MVC
67
68
  page pattern is unchanged from the library skeleton (see the library feature doc).
68
69
 
69
- `App_Framework_Tools::initialize()` sets the session cookie HttpOnly + SameSite=Lax before
70
- calling the parent initialize.
70
+ `App_Framework_Tools::initialize()` sets the session cookie HttpOnly + SameSite=Lax, then
71
+ `App_Framework_Tools::startSession()` starts the session on the **shared ElastiCache Redis
72
+ cluster** (phpredis `rediscluster` handler, cluster-mode config endpoint
73
+ `asi-session-cache…clustercfg.usw2.cache.amazonaws.com:6379`, shared with the `vision` app),
74
+ configured at runtime via `ini_set()` (`session.save_handler=rediscluster`,
75
+ `session.save_path=seed[]=<endpoint>:6379`, `session.gc_maxlifetime=345600`), guarded by
76
+ `extension_loaded('redis')`. It calls `session_start()` itself and sets
77
+ `App_Framework::$useSessions=false` so the parent's `initialize()` does not double-start the
78
+ session (verified that flag's only consumer is the parent's `session_start` guard).
79
+
80
+ **Ordering is load-bearing:** `startSession()` runs **before** `parent::initialize()` installs
81
+ App_Error's fatal handler, so a Redis failure degrades to file sessions via a graceful
82
+ `@session_start()` fallback instead of a site-wide 500. **Why this exists:** sessions used to
83
+ run on the default **file** handler on **per-instance local disk**; because prod is
84
+ multi-instance behind an ALB, every deploy / instance replacement wiped the local session
85
+ files and logged all users out. Prod-verified 2026-08-14: a redeploy no longer logs users out.
86
+ How the handler is wired at the platform level (INI-file parser drops `seed[]`, fpm overrides
87
+ `/etc/php.d`, phpredis install) is in `workflows/deploy-to-elastic-beanstalk-al2023.md`.
71
88
 
72
89
  ## Layout (single-style app)
73
90
 
@@ -133,6 +150,12 @@ Create `mvc/<folder>/<tool>/get.php` (copy `mvc/_TEMPLATE/get.php`), add one ent
133
150
  `config.*`) — see the [1.0 back-end security standard](../../standards/backend-php.md).
134
151
  **Action still owed:** rotate every secret in `config.production.ini` — the file was
135
152
  reachable, so treat all of it as compromised. (Location only — no values recorded here.)
153
+ - **Hardcoded GitHub Personal Access Token committed in plaintext (rotation owed).**
154
+ `.ebextensions/020_setup_git_libraries.config` contains a GitHub PAT in plaintext, committed
155
+ to the repo and therefore exposed in git history. **Action owed:** rotate the token and move
156
+ it to an EB environment property (read via `getenv()`/`$_SERVER`/`$_ENV` per the deploy
157
+ workflow's clear_env gotcha); a rotation does not un-expose git history. (Location only — no
158
+ value recorded here.)
136
159
  - **SSO initiation + replay defense are open items** — see `features/saml-sso-auth.md`.
137
160
  - **Unproxied third-party polling from the browser (`/clickup/react`).** The monitor column pulls
138
161
  ~250 KB from OneUptime every 5s — ~3 MB/min **per open tab** — to render about six numbers, and
@@ -147,6 +170,12 @@ Create `mvc/<folder>/<tool>/get.php` (copy `mvc/_TEMPLATE/get.php`), add one ent
147
170
  composer package must `require_once` the autoloader itself.
148
171
 
149
172
  ## Change history
173
+ - 2026-08-14 — Corrected the session model: sessions were on the file handler on per-instance
174
+ local disk (not Redis as previously assumed), so every deploy logged everyone out; moved to the
175
+ shared ElastiCache Redis `rediscluster` handler via `App_Framework_Tools::startSession()`
176
+ (runtime `ini_set()`, `$useSessions=false`, started before App_Error installs so a Redis failure
177
+ degrades gracefully). Flagged the plaintext GitHub PAT in `020_setup_git_libraries.config` for
178
+ rotation + move to an EB env property. (jcardinal)
150
179
  - 2026-08-14 — Recorded that `/clickup/react` is now an unattended wall display holding a
151
180
  full-screen colour state indefinitely, carrying the app's only cross-origin browser dependency
152
181
  (OneUptime public status-page API) plus per-iframe permission policy
@@ -6,7 +6,7 @@ project: Tools
6
6
  client: shared
7
7
  type: workflow
8
8
  status: active
9
- updated: 2026-08-03
9
+ updated: 2026-08-14
10
10
  owners: [jcardinal, bala]
11
11
  files:
12
12
  - tools/.ebextensions/004_http_to_https.config
@@ -14,10 +14,14 @@ files:
14
14
  - tools/.ebextensions/007_setup_export_cache_folders.config
15
15
  - tools/.ebextensions/008_setup_ldap.config
16
16
  - tools/.ebextensions/009_setup_phpini.config
17
+ - tools/.ebextensions/003_pgsql_hook_optional.config
17
18
  - tools/.ebextensions/020_setup_git_libraries.config
18
19
  - tools/.ebextensions/050_register_instance_to_shared_application_load_balancer.config
20
+ - tools/.platform/hooks/prebuild/01-install-php-pgsql.sh
21
+ - tools/.platform/hooks/prebuild/02-install-php-redis.sh
19
22
  - tools/ebs/git.json
20
23
  - tools/ebs/setup_export_cache_folders.php
24
+ - tools/_/app/framework.php
21
25
  - tools/_/app/frameworkindex.php
22
26
  related:
23
27
  - ../architecture.md
@@ -60,9 +64,23 @@ failed silently (it was wrapped in `ignoreErrors: true`), so `include_path` neve
60
64
  The `application.ini` sets `include_path = ".:/var/www/library"`, upload/post limits
61
65
  (`upload_max_filesize=25M` / `post_max_size=30M`, raised from 16M so multi-MB design-demo HTML
62
66
  exports up to ~25MB post through — see `features/design-demo-admin.md`),
63
- `memory_limit = 2G`, `display_errors`, the `redis.so` extension, and the rediscluster session
64
- handler (`session.save_path` points at the ElastiCache cluster cfg endpoint). Session GC
65
- maxlifetime is 4 days.
67
+ `memory_limit = 2G`, `display_errors`, and loads the `redis.so` extension.
68
+
69
+ > **Do NOT configure the rediscluster session handler in `application.ini` (or any INI file) on
70
+ > this platform — it silently fails.** See the "Redis sessions" section below. Session
71
+ > `save_handler`/`save_path` are now set at **runtime via `ini_set()` in
72
+ > `tools/_/app/framework.php`**, not in `009_setup_phpini.config`. Two INI-file facts drove this
73
+ > (both verified 2026-08-14 on EB PHP 8.5 / AL2023):
74
+ > - **The INI-file parser silently drops a `session.save_path` value of the form
75
+ > `"seed[]=host:port"`** — in *both* `/etc/php.d/*.ini` and the php-fpm pool
76
+ > (`www.conf` `php_value[...]`). `session.save_handler=rediscluster` applies but `save_path`
77
+ > stays `/tmp`, so `session_start()` fatals ("Failed to initialize storage module:
78
+ > rediscluster (path: /tmp)") on **every** request → full outage. CLI `php -d` with the same
79
+ > value works, confirming it is the INI-file parser, not the value itself.
80
+ > - **The php-fpm pool overrides `/etc/php.d/*.ini` at runtime.** `memory_limit=2G` /
81
+ > `display_errors=On` set in `application.ini` were observed running as 256M/Off because the
82
+ > fpm pool `www.conf` wins. Values that must hold have to be set where fpm cannot override
83
+ > them — for session handling, that means `ini_set()` in code.
66
84
 
67
85
  ### Cloning the libraries — bash, not the CodePipeline PHP script
68
86
 
@@ -82,6 +100,52 @@ The replacement is pure bash via a cfn-init `files:` block that writes
82
100
  `ebs/git.json` was corrected to match: branch `_production` for both repos and the resources
83
101
  path set to `/var/app/ondeck/resources`.
84
102
 
103
+ ### Native PHP extensions — prebuild hooks (phpredis, pgsql)
104
+
105
+ Native PECL extensions are installed by `.platform/hooks/prebuild/*.sh` scripts, not
106
+ `.ebextensions`. `02-install-php-redis.sh` installs phpredis (needed for the Redis sessions
107
+ below); `01-install-php-pgsql.sh` installs pgsql (needed only by the Talos "Knowledge Bases"
108
+ create flow). Both target the platform php `php-common-8.5.6`. The durable AL2023 gotchas:
109
+
110
+ - **The package is `php8.5-pecl-redis6`** (phpredis major-version suffix `6`), **not**
111
+ `php8.5-redis`.
112
+ - **A plain `dnf install php8.5-pecl-redis6` drags in the php8.1 serializers.** It pulls the
113
+ igbinary/msgpack deps built for **php8.1** → `php8.1-common`, which **conflicts with the
114
+ platform's `php-common-8.5.6`** over `/etc/php.ini` and `/usr/lib64/php/modules/*.so` (the dnf
115
+ transaction test aborts, failing the deploy). Install with
116
+ `--setopt=install_weak_deps=False --exclude=php8.1-*`.
117
+ - **The versioned package installs the `.so` into a non-platform module dir.** Even once
118
+ installed, `redis.so` (and `pgsql.so`) lands in a dir the platform php does **not** scan. The
119
+ platform php loads from its own `extension_dir` — discover it with
120
+ `php -r 'echo ini_get("extension_dir");'`. The hook copies the `.so` there, writes a scan-dir
121
+ ini enabling it, then **verifies with `php -m`** and fails the deploy on error.
122
+ - **Escape hatch env property.** `02-install-php-redis.sh` honours `REDIS_HOOK_OPTIONAL=1` (EB
123
+ env property) to skip on failure rather than block the whole deploy.
124
+
125
+ **Known-broken sibling — `01-install-php-pgsql.sh` (pgsql).** It has the *same* versioned-package
126
+ / wrong-module-dir bug and currently **fails on fresh AL2023 instances**. It is presently
127
+ **bypassed** via the EB env property `PGSQL_HOOK_OPTIONAL=1`
128
+ (`.ebextensions/003_pgsql_hook_optional.config`). This is a **temporary** measure: it leaves the
129
+ Talos "Knowledge Bases" create flow (the only pgsql consumer) broken. The fix is the same
130
+ install-and-copy-into-`extension_dir` treatment `02-install-php-redis.sh` already received; once
131
+ applied, **delete the `PGSQL_HOOK_OPTIONAL` bypass config.**
132
+
133
+ ### Redis sessions (survive deploys & load balancing)
134
+
135
+ Prod Tools runs multiple EB instances behind an ALB, so PHP sessions must live in a shared store,
136
+ not per-instance local disk. Sessions use the **shared ElastiCache Redis cluster**
137
+ (`asi-session-cache…clustercfg.usw2.cache.amazonaws.com:6379`, cluster-mode config endpoint —
138
+ also used by the `vision` app) via the phpredis `rediscluster` handler.
139
+
140
+ Because the INI-file parser silently drops the `seed[]=host:port` save_path (see the PHP ini
141
+ section above), the handler is configured at **runtime in `tools/_/app/framework.php`**
142
+ (`App_Framework_Tools::startSession()`): `ini_set()` sets
143
+ `session.save_handler=rediscluster`, `session.save_path=seed[]=<cluster cfg endpoint>:6379`, and
144
+ `session.gc_maxlifetime=345600` (4 days), guarded by `extension_loaded('redis')`, then calls
145
+ `session_start()` itself. The full outage story (sessions were previously on the file handler on
146
+ local disk, so every deploy logged everyone out) and the graceful-degrade ordering vs. App_Error
147
+ are in the [architecture doc](../architecture.md).
148
+
85
149
  ### Duplicate config neutralization
86
150
 
87
151
  EB merges every `.config` alphabetically; two configs with **identical** `container_commands`
@@ -185,6 +249,19 @@ cross-instance storage has a local-disk fallback path for dev, where the AWS SDK
185
249
  e.g. `GIT=$(which git || echo /usr/bin/git)`.
186
250
  - **cfn-init `files:` runs before `container_commands`** — the correct pattern for writing a
187
251
  script and then executing it in the same config.
252
+ - **The php-fpm pool overrides `/etc/php.d/*.ini` — never trust an INI value that fpm can
253
+ override.** `memory_limit` / `display_errors` set in `application.ini` ran as 256M/Off because
254
+ the fpm pool `www.conf` wins at runtime. Values that must hold (e.g. session handler config)
255
+ belong in code via `ini_set()`, or in the fpm pool itself.
256
+ - **The INI-file parser silently drops a `session.save_path` of the form `"seed[]=host:port"`**
257
+ (in both `/etc/php.d/*.ini` and the fpm pool). `rediscluster` handler applies but save_path
258
+ stays `/tmp` → `session_start()` fatals on every request. Set it via `ini_set()` in code (CLI
259
+ `php -d` with the same value works, so it is the INI-file parser, not the value).
260
+ - **Native PECL extensions: use `php8.5-pecl-redis6`, exclude the php8.1 serializer deps, and
261
+ copy the `.so` into the platform `extension_dir`.** A plain `dnf install` pulls `php8.1-common`
262
+ which conflicts with `php-common-8.5.6`; install with
263
+ `--setopt=install_weak_deps=False --exclude=php8.1-*`, then copy the built `.so` into
264
+ `ini_get('extension_dir')` and verify with `php -m`. Same fix owed to the pgsql sibling hook.
188
265
  - **A SAML SSO return-leg "connection timeout" is a missing HTTPS listener, not code. (CONFIRMED + RESOLVED.)**
189
266
  When the gateway's return redirect to `https://<host>/sso` times out in the browser, verify the
190
267
  **EB/ALB HTTPS (443) listener + ACM cert cover the EXACT return hostname before debugging
@@ -196,6 +273,15 @@ cross-instance storage has a local-disk fallback path for dev, where the AWS SDK
196
273
  returns `200` fast. Reusable for any TOGA app behind Elastic Beanstalk.
197
274
 
198
275
  ## Change history
276
+ - 2026-08-14 — Added the phpredis/pgsql prebuild-hook install pattern
277
+ (`.platform/hooks/prebuild/02-install-php-redis.sh`): package `php8.5-pecl-redis6`,
278
+ `--setopt=install_weak_deps=False --exclude=php8.1-*` to avoid the php8.1-common conflict, and
279
+ copy the built `.so` into the platform `extension_dir`; recorded the pgsql sibling as
280
+ known-broken and bypassed via `PGSQL_HOOK_OPTIONAL=1`
281
+ (`003_pgsql_hook_optional.config`, temporary — breaks the Talos KB create flow). Corrected the
282
+ PHP ini section: `rediscluster` session `save_path` (`seed[]=host:port`) is silently dropped by
283
+ the INI-file parser and the fpm pool overrides `/etc/php.d/*.ini`, so session handling moved to
284
+ runtime `ini_set()` in `framework.php`; added a Redis-sessions section. (jcardinal)
199
285
  - 2026-08-03 — Recorded that prod Tools is multi-instance behind an ALB, so `/var/www/cache` is
200
286
  per-instance local disk (not shared) and cross-request state must go to S3 — the root cause of a
201
287
  Preview→Send "job expired"; noted the no-composer-install deploy, `ENVIRONMENT`-based config
@@ -5,7 +5,7 @@ project: Library
5
5
  client: shared
6
6
  type: standard
7
7
  status: active
8
- updated: 2026-08-06
8
+ updated: 2026-08-14
9
9
  owners: [jcardinal, rgirish, mhammontree, ajean]
10
10
  files: []
11
11
  related:
@@ -306,6 +306,26 @@ Two sanctioned patterns, in order of preference:
306
306
 
307
307
  Never leave either one in effect beyond the block that needs it.
308
308
 
309
+ ### Start the session before App_Error's fatal handler — and set the handler in code, not INI
310
+
311
+ On EB PHP 8.5 / AL2023, the `.so` extension and cookie flags aside, two rules make Redis
312
+ sessions reliable:
313
+
314
+ 1. **Set `session.save_handler` / `session.save_path` at runtime with `ini_set()`, not in an
315
+ INI file.** The INI-file parser silently drops a `session.save_path` of the form
316
+ `"seed[]=host:port"` (in both `/etc/php.d/*.ini` and the php-fpm pool), and the fpm pool
317
+ overrides `/etc/php.d/*.ini` anyway. `session_start()` then fatals on every request. `ini_set()`
318
+ in the app framework takes the value verbatim.
319
+ 2. **Call `session_start()` before App_Error's fatal handler is installed.** Because any 1.0
320
+ warning routes through `App_Error::handleError` → `exit` (see above), a session store that is
321
+ unreachable would take the whole site down. Starting the session first lets an unreachable
322
+ store degrade to file sessions via a guarded `@session_start()` fallback (acceptable for a
323
+ graceful boot; file sessions are single-instance only). Set the framework's own
324
+ `useSessions=false` flag so the parent boot does not double-start.
325
+
326
+ Reference implementation: `App_Framework_Tools::startSession()` — see the Tools architecture and
327
+ its EB deploy workflow.
328
+
309
329
  ### Documentation
310
330
 
311
331
  * **DocBlocks:** framework (`library`) classes/methods are well documented with a description and `@param`/`@return`/`@throws`. Application code is less consistent — document new and modified methods to the framework standard.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.586",
3
+ "version": "1.0.587",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",