Prd 1 agentforge monigarr#11
Closed
monigarr wants to merge 85 commits into
Closed
Conversation
…: review audit the test coverage relevance accuracy
…d openai responses, formatted token usage on the visual card
…ment. todo: manual visual tests
AgentForge PRD1 new module created and manually visually tested. todo: review... See merge request monicapeters/openemr!1
#### Short description of what this changes or resolves: While working on openemr#11805 I came across a bug when running a SQL upgrade. Invalid syntax! Since the block was conditional, you wouldn't always hit it. The Inferno data did. #### Changes proposed in this pull request: Splits the index additions into a syntactically-legal version without changing the results. Well, technically the new conditionals could change the results, but the intent of what it did before was clear. #### Was an AI assistant used? Yes / No No
Correction from openemr#11866, which was incorrectly extracted from openemr#11805.
…nemr#11857) Refs openemr#11725. ## Summary Diagnostics-only change motivated by the research in openemr#11725. The Selenium standalone-chromium container occasionally returns `invalid session id: session deleted as the browser has closed the connection` mid-test, but the existing post-test `dc logs selenium` step has shown no OOM kill, no tab-crashed event, and no supervisord restart at the moment of failure. We can't pin down the silent Chrome death without more evidence, so this PR makes the next failure leave a usable trace. Adds a failure-only step in the e2e job in `.github/workflows/test.yml` that writes the following to a `selenium-diagnostics/` directory and uploads it as a separate artifact: - `dmesg | tail -200` from the runner (OOM-killer / segfault lines) - `docker compose top selenium` (process tree inside the container at teardown) - `docker stats --no-stream selenium` (memory/CPU at teardown) - Full `docker compose logs selenium` written to a file (also still echoed to the job log by the existing step, but the file is downloadable alongside the rest) No test behavior change. No image bumps, no `shm_size`, no restart policies. The new steps are gated on `failure() && matrix.suite == 'e2e'` so green builds are unaffected. ## Test plan - [ ] Merge and wait for the next e2e flake on master - [ ] On failure, download the `selenium-diagnostics-<docker_dir>` artifact from the run - [ ] Inspect `dmesg.tail.txt`, `docker-compose-top.txt`, `docker-stats.txt`, and `selenium.log` for OOM-killer / segfault / resource-pressure signals around the failure timestamp - [ ] Feed findings back into openemr#11725 to choose the actual fix
…ker/development-insane in the openemr-images group across 1 directory (openemr#11870) Bumps the openemr-images group with 1 update in the /docker/development-insane directory: openemr/openemr. Updates `openemr/openemr` from flex-3.17 to flex-3.17 [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
….notFound (openemr#11859) Drain `class.notFound` and `method.notFound` baseline entries originating in the Carecoordination zend module. Fourth phase-4 module batch following the eRx drain (openemr#11825). ## Source changes **Controller property native types.** Convert PHPDoc-typed properties on `CarecoordinationController` and `CcdController` to native types (constructor property promotion applied via Rector). PHPStan was resolving docblocks like `@var Documents\Controller\DocumentsController` relative to the `Carecoordination\Controller` namespace, producing `class.notFound` for nonexistent paths. **`@method` tags for Laminas MVC plugins.** `$this->CommonPlugin()` and `$this->Documents()` resolve through Laminas' plugin manager via `__call`. Add explicit `@method` declarations on the controllers that invoke them, plus `@method \Laminas\Http\Request getRequest()` to narrow the request type so `getPost()`/`getQuery()` resolve. **Fix `CcdController::uploadAction()` bug.** The method was calling `$this->updateDocumentCategoryUsingCatname()` on itself, which does not exist on the controller. The sibling `CarecoordinationController::uploadAction()` calls it correctly via `$this->documentsController->getDocumentsTable()->updateDocumentCategoryUsingCatname()` — apply the same call here. Dead since at least 2014; PHPStan would have caught it as `method.notFound` if the entry hadn't been baselined. **Remove dead `CarecoordinationTable::getIssues()`.** Body called `DocumentsTable::getIssues()` which does not exist. Author left an inline `Method not used` TODO; grep confirms no callers. **Remove dead try/catch in `EncounterccdadispatchController::indexAction()`.** The block wrapped only `echo`/`exit` calls that cannot throw. **`getCarecoordinationTable()` / `getDocumentsTable()` return types.** Changing the docblock from `@return object` to a real return type collapses several `method.notFound` entries that were `Cannot call method ... on object`. **DOM narrowing.** `CcdaUserPreferencesTransformer` and `CcdaServiceDocumentRequestorTest` iterate `\DOMNodeList` results and call element-only methods (`insertBefore`, `setAttribute`, `getAttribute`). Add `instanceof \DOMElement` and `instanceof \DOMNode` guards plus a null-check on `lastElementChild` so the type system sees the narrowing. **Content type narrowing in `EncounterccdadispatchController::indexAction()`.** Initialize `$content = ''` up front and call `strval($content)` before substring operations to avoid Rector flip-flop between `RecastingRemovalRector` (full-codebase) and `NullToStrictStringFuncCallArgRector` (single-file). ## Tests Adds `CcdaUserPreferencesTransformerTest` covering `transform()` (sort, truncate, default-fallback) and the getter/setter round-trip. Lifts patch coverage on this PR. ## Counts | Identifier | Before | After | Delta | |---|---:|---:|---:| | `class.notFound` | 237 | 229 | -8 | | `method.notFound` | 184 | 160 | -24 | | `method.nonObject` | 1995 | 1991 | -4 | | `argument.type` | 14973 | 14972 | -1 | | `assign.propertyType` | 388 | 384 | -4 | | `cast.string` | 807 | 806 | -1 | | `missingType.parameter` | 9488 | 9487 | -1 | | `missingType.property` | 6198 | 6195 | -3 | | `missingType.return` | 5913 | 5912 | -1 | | `offsetAccess.nonOffsetAccessible` | 10757 | 10756 | -1 | | `preDec.type` | 9 | 8 | -1 | | `property.notFound` | 135 | 132 | -3 | | `return.type` | 2167 | 2164 | -3 | | `variable.undefined` | 3075 | 3074 | -1 | Caps in `.phpstan/fatal-baseline-caps.php` updated to match. Refs openemr#11792. ## Test plan - [x] `composer phpstan-baseline` regenerates cleanly - [x] `composer phpunit-isolated -- --filter=FatalBaselineCaps` passes - [x] `composer phpcs` clean on edited files - [x] Pre-commit hooks (rector, phpcs, phpstan, codespell, composer-require-checker) all pass
…_id (openemr#11618) ## Summary - Replace `die("Site ID is missing from session data!")` in `globals.php` with `throw new MissingSiteIdException()` - Introduce `MissingSiteIdException` extending the existing `MissingSiteException`, so callers can catch either the specific session case or the broader "site not identified" family - This allows callers like `BackgroundServiceRunner` that wrap `globals.php` inclusion in `try`/`catch` to handle the failure gracefully and release DB locks, instead of having the process killed mid-execution ## Notes `portal/patient/scripts/app.js:30` checks for the string "Site ID is missing from session data" in AJAX responses. That handler relies on parsing the raw `die()` output, which is already fragile. With this change, uncaught exceptions in production won't produce that exact string in the response body (PHP returns a 500 with no body when `display_errors` is off). The JS handler should be updated separately to use a proper error response format. ## Test plan - [ ] Verify web requests without a session site_id still get a 400 response (the `http_response_code(400)` call is preserved before the throw) - [ ] Verify CLI callers (e.g. `BackgroundServiceRunner`) can catch `MissingSiteIdException` and clean up gracefully - [ ] Verify the patient portal session expiry flow still redirects correctly (may need follow-up for `app.js`) Closes openemr#11616 --------- Co-authored-by: Eric Stern <eric@ericstern.com>
…10387) ## Summary Fixes openemr#10386 PHPStan's container cache (Nette DI) validates against file modification times. Git doesn't preserve mtimes, so a freshly checked out file always looks newer than its cached metadata, invalidating the entire container and forcing a full re-analysis of all ~4000 files even when the result cache restored cleanly. ## Approach The expensive parts of fixing this are (1) a full-history clone, which `git-restore-mtime` needs to walk, and (2) installing the tool itself. Both are pure waste on a cold cache miss. So this PR makes them conditional on whether a cache was actually restored: - Replace `actions/cache@v5` with `actions/cache/restore@v5` + `actions/cache/save@v5` so the restore step exposes a `cache-hit` / `cache-matched-key` output. - When (and only when) a cache was restored: install `git-restore-mtime` from apt, `git fetch --unshallow`, and walk the history to restore mtimes. - Save the cache on `always()` so partial results from a failed analyze still seed the next run. Cold misses pay zero new overhead vs. before this PR. Warm hits pay an unshallow + mtime walk to make the restored cache validate. ## Testing The first run after merge is still cold-cache (no savings). Compare runtime on the second and third runs of the same branch to confirm the cache is now effective.
…undefined) (openemr#11878) ## Summary Refs openemr#11792. Drains 19 `method.notFound` and 10 `variable.undefined` baseline entries in `library/edihistory/` without changing runtime behavior. - Type `csv_check_x12_obj()` return as `edih_x12_file|false` so PHPStan can narrow callers across the 11 sibling html/error/segments files. Replace the now-redundant `'edih_x12_file' == \$obj::class` checks with `\$obj !== false`. - Pre-initialize accumulator variables in the 271 and 277 segment loops (`\$cls`, `\$loopid`, plus segment-specific scalars). Limited to files where the variables are pure accumulators — `edih_997_error.php` etc. use `isset()` as a "did this segment appear?" check, so pre-initializing would alter behavior. - Decrement caps in `.phpstan/fatal-baseline-caps.php`: - `method.notFound.php`: 160 → 141 - `variable.undefined.php`: 3074 → 3064 - Regenerate `.phpstan/baseline/*.php` (side-effect drains in `argument.type`, `booleanAnd.leftAlwaysTrue`, `encapsedStringPart.nonString`, etc.). ## Test plan - [x] `composer phpstan` passes (via pre-commit hook) - [x] `composer phpunit-isolated -- --filter FatalBaselineCapsIsolatedTest` — 19/19 pass - [ ] CI green
…openemr#11877) ## Summary Drains 45 entries from the PHPStan `class.notFound` fatal-category baseline by correcting bogus PHPDoc `@var` and `@param` tokens in portal/patient files. The cap is lowered from 237 to 192 in the same commit. Most fixes replace SQL types (`date`, `longtext`, `datetime`, `char`, `blob`), English description words, and `unknown` with correct PHP types. Editing `IDaoMap2::AddMap` / `SetFetchingStrategy` propagates via `{@inheritdoc}` to every implementing Map class. In `GlobalConfig::GetRenderEngine`, the dynamically instantiated render engine is now narrowed via `assert($engine instanceof IRenderEngine)` so the subsequent `assign()` / `display()` calls resolve against the interface instead of plain `object` (avoiding new `method.notFound` entries). Refs openemr#11792. Non-overlapping with the WIP in openemr#11859 (Carecoordination zend module). ## Test plan - [x] `composer phpstan-baseline` regenerates clean - [x] Pre-commit hooks pass (phpcs, phpstan, rector, composer-require-checker) - [ ] CI green, including `FatalBaselineCapsIsolatedTest`
…rm (openemr#11883) ## Summary `C_EncounterVisitForm::render()` calls `UuidRegistry::uuidToString($result['uuid'])` immediately after `sqlQuery("SELECT * FROM form_encounter WHERE id = ?", [$id])` without checking whether the row was found, or whether the `uuid` column was populated. When the request carries a stale or invalid encounter id (e.g. a deleted encounter via a bookmarked URL), or the row exists but predates uuid backfill, `$result['uuid']` is `null` and `Ramsey\Uuid\Uuid::fromBytes(null)` throws: ``` PHP Notice: TypeError: Ramsey\Uuid\Uuid::fromBytes(): Argument #1 ($bytes) must be of type string, null given, called in src/Common/Uuid/UuidRegistry.php on line 287 Stack trace: #0 src/Common/Uuid/UuidRegistry.php(287): Ramsey\Uuid\Uuid::fromBytes(NULL) #1 interface/forms/newpatient/C_EncounterVisitForm.class.php(504): UuidRegistry::uuidToString(NULL) #2 interface/forms/newpatient/common.php(43): C_EncounterVisitForm->render(2) ``` This change: - Throws `RuntimeException` when no row matches, instead of silently continuing with `$encounter = false` and crashing several lines later in an unrelated stack frame. - Passes `''` through to `$encounter['uuid']` when the row exists but `uuid` is `null` (the comment on the original line notes this field is set so the array JSON-encodes — empty string preserves that intent). - Drops the `offsetAccess.nonOffsetAccessible` baseline entry that covered the old unsafe access. ## Test plan - [ ] View an existing encounter — renders normally - [ ] Visit `view_form.php` with a deleted/invalid encounter id — surfaces the explicit "Encounter not found" error rather than a `fromBytes(null)` TypeError - [ ] PHPStan passes (`composer phpstan`) Assisted-by: Claude Code
#### Short description of what this changes or resolves: The older-style `HelpfulDie` does not particularly live up to its name. Fixing it the right way is removal in favor of everything using exceptions, which is an ongoing but massive task. Debugging is overly complex. This logs the function and full stack trace any time the legacy global-namespace SQL functions catch/suppress/crash any sort of query failure. Yes, `HelpfulDie` makes an attempt to do this, but it's rather limited in how it works and doesn't go through the SystemLogger. I was hoping this would help with diagnosing some Inferno test issues. It doesn't seem to, but I think it's still a worthwhile addition. #### Changes proposed in this pull request: Add an error-level log to all of the `catch` paths inside the older SQL functions, going to the system logger. #### Was an AI assistant used? Yes / No No
…y\X12File (openemr#11879) ## Summary Refs openemr#11792. Lifts the procedural `edih_x12_file` class from `library/edihistory/edih_x12file_class.php` into the modern PSR-4 namespace `OpenEMR\Billing\EdiHistory\X12File`, leaving a `class_alias` shim so all existing legacy callers keep working. This PR is **behavior-preserving** — no type tightening beyond what the lift requires. Future PRs will tighten types and drain more baseline entries on the lifted class. ## Changes - Moves `edih_x12_file` class body into `src/Billing/EdiHistory/X12File.php` - Replaces `library/edihistory/edih_x12file_class.php` with a `class_alias` shim - Adds `.phpstan/phpstan_legacy_aliases.php` bootstrap so PHPStan resolves the legacy `edih_x12_file` symbol (it does not follow runtime `class_alias`) - Adds fixture-based isolated tests under `tests/Tests/Isolated/Billing/EdiHistory/X12FileIsolatedTest.php` (24 tests covering happy path, scan/delimiter/type/envelope error paths, no-mk_segs path, and unknown-GS warning) - Removes 81 bare `//` line comments inherited from the original procedural class - Regenerates the PHPStan baseline (fatal-cap counts unchanged) ## Test plan - [x] `composer phpunit-isolated` passes - [x] `composer phpstan` passes - [x] CI green
…ity (openemr#11876) ## Summary Follow-up to openemr#10762, which renamed the misspelled `declne_to_specfy` race value to `decline_to_specify`. Brady's review on that PR flagged two issues in `sql/8_0_0-to-8_1_0_upgrade.sql` (originally `8_0_0-to-8_0_1_upgrade.sql`) that were never addressed before merge: - The `patient_data.race` UPDATE was guarded by `#IfColumn patient_data race`, which is always true — the UPDATE ran on every upgrade even when there was nothing to convert. Switch to `#IfRow patient_data race declne_to_specfy` so it's skipped when no rows match. - The same misspelled value can also appear in `patient_data.language` and `patient_data.ethnicity`. The `list_options` side already covers all three list_ids; this PR mirrors that on the patient row side. Refs openemr#10385, follow-up to openemr#10762. ## Test plan - [ ] Fresh install of 8.0.0 → upgrade to current master succeeds - [ ] Tenant with `declne_to_specfy` in `patient_data.race` / `language` / `ethnicity` is migrated to `decline_to_specify` - [ ] Tenant with no matching rows skips all three `#IfRow` blocks
…ad (openemr#11888) ## Summary Loading `interface/main/main_screen.php` unconditionally regenerated the per-session CSRF private key, silently invalidating CSRF tokens already embedded in pages and iframes rendered before that load. Long-lived widgets that bake their token in at render time and poll on a fixed interval — most visibly `interface/main/dated_reminders/dated_reminders.php` (60s poll) — then logged `OpenEMR CSRF token authentication error` on every poll following any in-app reload of the top frame. The rotation looks like it was meant only for the new-login path. This PR moves `CsrfUtils::setupCsrfKey($session)` inside the new-login branch so the key is generated once at login and not rotated on subsequent top-frame loads. The `else` branch is reached only after a successful CSRF check, which already requires an existing private key, so no key setup is needed there. Fixes openemr#11865. ## Test plan - [ ] Log in, capture the CSRF token rendered into `dated_reminders.php`, reload `main_screen.php`, then re-POST the same token to `dated_reminders.php` — should now return 200 instead of 403. - [ ] Confirm fresh login still works (the new-login branch still runs `setupCsrfKey`). - [ ] Confirm `OpenEMR CSRF token authentication error` log entries no longer appear at the 60s polling cadence after navigating between top frames.
… string functions (openemr#11884) Closes openemr#11880. Convert `preg_match` calls that only match a literal prefix or suffix to `str_starts_with()` / `str_ends_with()`, or `pathinfo()` for file-extension checks. Skip cases that use capture groups, character classes, or alternation that can't be expressed cleanly without a regex. In `SQLUpgradeService::clickOptionsMigrate()`, guard against `fgets()` returning `false` explicitly rather than letting it coerce silently into `preg_match`. The matching baseline ignore is dropped. ## Test plan - [x] `composer phpcs` - [x] `composer phpstan` (baseline shrinks by one entry) - [x] `composer php-syntax-check` - [ ] CI green
…emr#11887) Drains 137 entries from the `variable.undefined.php` PHPStan baseline (openemr#11792, Phase 5). Scope expanded beyond the original `interface/batchcom` to include: - `interface/batchcom` - `interface/therapy_groups` - `interface/usergroup` - `interface/super` - `interface/orders` ## Fix patterns applied - Hoist init of array accumulators / scalars before conditional blocks - Use `?? ''` / `??=` defaults at use sites (template-style includes) - Replace legacy globals (`$srcdir`, `$webroot`, `$webserver_root`, `$rootdir`, `$OE_SITE_DIR`) with `OEGlobalsBag::getInstance()` typed getters - Replace stale `$pid` reads with `SessionWrapperFactory::getInstance()->getActiveSession()->get('pid')` - File-level `@var` annotations for globals provided by required files (gacl/admin precedent openemr#11826) - Convert `for ($i = 0, $j = $k; ...; ...)` comma-init loops to explicit `while` (PHPStan can't follow comma expressions in for-init) ## Real bug fix `interface/super/layout_service_codes.php` was calling `fclose($eres)` on the wrong handle. Should be `fclose($fhcsv)`. ## Follow-up Filed openemr#11892 to track replacing the manual loop-counter pattern (`$i = 0; while (...) { ...; ++$i; }`) with `foreach` indices and `\Generator`s.
…ker/development-insane in the openemr-images group across 1 directory (openemr#11899)
…penemr#11895) ## Summary Drain 341 entries from `.phpstan/baseline/variable.undefined.php` by initializing previously-undefined variables across `interface/billing/`. Where the offending variable was a legacy global (`$srcdir`, `$webroot`, `$web_root`, `$webserver_root`) or a `$GLOBALS` lookup, replace it with the typed `OEGlobalsBag` accessor (`getSrcDir()`, `getWebRoot()`, `getString()`, `getBoolean()`). Cap in `.phpstan/fatal-baseline-caps.php` lowered from 2927 → 2586 to match. Refs openemr#11792. ## Files touched `interface/billing/`: billing_report, billing_tracker, edi_270, edi_271, edih_main, edih_view, edit_payment, era_payments, get_claim_file, indigent_patients_report, new_payment, payment_master.inc, payment_pat_sel.inc, print_billing_report, print_daysheet_report_num1/2/3, search_payments, sl_eob_invoice, sl_eob_search, sl_receipts_report, ub04_dispose, ub04_form, ub04_helpers. ## Test plan - [x] `composer phpstan-baseline` regenerates with no new entries outside `variable.undefined.php` reductions - [x] `composer phpstan` passes (pre-commit) - [x] `composer rector-check` clean - [x] `composer phpcs` clean - [ ] CI green
…ules, reports, services (openemr#11903) Continues openemr#11792. ## Summary Drives `variable.undefined` to **zero** in the four target directories and lowers the cap from **3064 → 2261** (-803 entries): | Directory | Before | After | |---|---|---| | `library/edihistory` | 101 | **0** | | `interface/modules` | 95 | **0** | | `interface/reports` | 83 | **0** | | `src/Services` | 46 | **0** | ## Patterns applied - Hoist initialization before conditional/loop assignment - Replace ad-hoc globals with `OEGlobalsBag` typed getters (added `getIncludeRoot()` helper) - Replace direct `$_SESSION` access with `SessionWrapperFactory` - Add file-level/standalone `@var` docblocks for include-injected vars - Convert while-not-comma-for patterns to explicit init - Delete dead `test_edih_835_accounting.php` (~120 entries removed; function had no callers and contained syntactically broken trailing code) ## Real bugs caught while draining - `text($invnumber)` → `text($irnumber)` in `receipts_by_method_report.php` - Empty `$ids` left `$p` undefined in `PrescriptionTemplates` Controller - `xl()` return discarded in faxsms `NotificationEventListener` - `$value['reaction_text']` wrong scope in `CarecoordinationTable` - `$combination` undefined in `EncounterccdadispatchController` - `$status` undefined return path in `InstallerController::InstallModule()` - Several `edihistory` variable typos (`$rtp`/`$ft`, `$tp`/`$ft`, `$file_type`/`$from_type`, `$err .=` on first use) ## Cleanups bundled with the drain - `OEGlobalsBag::getIncludeRoot()` typed accessor (replaces 7 callsites of `getString('include_root')`) - Collapse 4-branch if/elseif over claim filetypes in `edih_csv_data.php` into a single foreach using `http_build_query` and `sprintf` - `match` expression with destructuring in `DecisionSupportInterventionService::getEmptyService` - Replace `intval($_POST[...] ?? 0)` with `filter_input(..., FILTER_VALIDATE_INT) ?: 0` in EHI exporter - Type guard (`is_string` / `is_int`) instead of cast in `EncounterccdadispatchTable::getDetails` - `http_build_query` + `js_escape` for the redirect URL in weno `indexrx.php` - Replace `empty()` with explicit `=== ''` / `=== null` comparisons where touched - Delete commented-out and vestigial `?> <?php` blocks - Fix bootstrap docblocks: `Symfony\Contracts\EventDispatcher\EventDispatcherInterface` → `Symfony\Component\EventDispatcher\EventDispatcherInterface` (matches what `ModulesApplication` actually injects; drops 3 `argument.type` baseline entries) ## Net baseline impact Across all touched identifiers, hundreds of additional baseline entries dropped beyond the variable.undefined target. A small number of identifiers picked up entries when initialization changes widened downstream array element types: - `nullCoalesce.variable.php` +1 error - `offsetAccess.invalidOffset.php` +21 errors (5 in `interface/reports/appt_encounter_report.php`, 17 in `library/edihistory/edih_csv_parse.php`) - `offsetAssign.dimType.php` +1 entry / +17 errors in `library/edihistory/edih_csv_parse.php` These are downstream of the hoisted-init pattern and can be cleaned up in a follow-up. ## Test plan - [x] `composer phpstan-baseline` clean (cap = 2261, matches actual count exactly per FatalBaselineCapsIsolatedTest) - [x] `composer phpcs` clean - [x] Pre-commit hooks pass (phpstan, phpcs, rector, codespell, require-checker)
#### Short description of what this changes or resolves: Fixes some of the setup process used during the Inferno suite, which should upgrade some of its tests from "crashing, errors suppressed" to "failing, errors suppressed". On master, CI shows this: ``` Tests: 40, Assertions: 7, Errors: 34, Failures: 6, PHPUnit Warnings: 1, Warnings: 1. ``` This improves the situation significantly: ``` Tests: 41, Assertions: 965, Errors: 1, Failures: 3, PHPUnit Warnings: 1, Skipped: 1. ``` Extracted from openemr#11805 #### Changes proposed in this pull request: - Adjust the tear-down process to not stop the containers (GHA will do this automatically), so we can dump the logs to aid in debgging; removes some steps that GHA will do automatically but just slow things down for us - Dump the logs to aid in debugging - Run the SQL upgrade script, since apparently the data fixture is from 7.0.3 - Fix redis permissions _before_ redis is needed - Update a timer on an expired password so it doesn't cause failures - ~Fixes a place in the test API client to actually throw the error that it constructs, rather than fail silently~ removes some dead code in test setup that was a red herring in earlier work #### Was an AI assistant used? Yes / No Yes, Claude did most of the work on the original PR --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…1882) ## Summary The eRx branch in `interface/patient_file/summary/demographics.php` sets `btnLink` but never sets `linkMethod`, so `card_base.html.twig` renders a dead `href=\"#\"` instead of linking to `eRx.php?page=compose`. The non-eRx branch at the same call site sets both fields. Add `linkMethod = 'html'` to match. This is a small one-line fix to the Add (+) button on the Prescription History card when Ensora eRx is enabled (`erx_enable = 1`). ## Test plan - [ ] Enable Ensora eRx (`erx_enable = 1`) in Admin → Globals → Connectors - [ ] Open a patient's demographics summary - [ ] Verify the + button on the Prescription History card navigates to the eRx compose page (`eRx.php?page=compose`) - [ ] Disable eRx and verify the non-eRx branch still works (Edit button via `editScripts(...)`) ## Notes - Affects `master` and `rel-810` (verified `rel-810` has the same code path at `demographics.php:1219-1227`). - Discovered while preparing an OpenCoreEMR fork upgrade; fix originally landed in our internal branch as openCoreEMR/openemr-internal#243.
Fix Dockerfile cache mount ids and remove unsupported VOLUME
…OpenERM branding on the Medical Record Dashboard
…ocs. todo: improve LangFuse ingestion metadata and env wiring
Fix cache mount id format with cacheKey prefix
Remove unsupported BuildKit cache mounts for Railpack compatibility
Assisted-by: Cursor
Assisted-by: Cursor
|
|
||
| # Flex is Alpine-based; root required for package installs (matches flex runtime expectations). | ||
| # hadolint ignore=DL3002 | ||
| USER root |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Short description of what this changes or resolves:
Changes proposed in this pull request:
Was an AI assistant used? Yes / No