# Release v0.15.15 - Changelog

Released: 2026-02-19

## Overview

Plan cleanup and documentation reorganization.

## Fixes

### CI: Release date placeholder not substituted
- **Fixed `2026-02-19` never replaced** in release notes -- the `release.yml` workflow substituted version placeholders but not the date placeholder
- **Added date substitution** to both the release body generation and the archived changelog file
- **Backfilled 4 releases** (v0.11.17, v0.12.48, v0.13.20, v0.14.21) with correct dates

### CI: Recurring changelog merge conflicts on every release
- **Fixed cherry-pick divergence** in `release.yml` -- the workflow was archiving the changelog on `dev` then cherry-picking to `main`, creating parallel commit histories that caused merge conflicts on the next PR
- **Changed to archive on `main` first**, then merge main into dev -- this creates a shared commit ancestor, eliminating the divergent histories

### Hardening: Safe JSON parsing & output redaction
- **Replaced raw `JSON.parse` with `readJSONFile`** in `apps.js`, `socialAccounts.js`, `scriptRunner.js` -- corrupted data files no longer crash the server
- **Added null guard** on `data?.apps?.[id]` in `apps.js` to prevent undefined access
- **Added `.catch()` handler** on fire-and-forget `cloneRepoInBackground()` in `brain.js` to prevent unhandled promise rejections
- **Added sensitive output redaction** in `scriptRunner.js` -- env vars containing keys, tokens, passwords, and secrets are now `[REDACTED]` before persisting to `scripts-state.json`

### Bugs Fixed
- **Fixed index out of bounds** in `agents.js` Windows process parsing -- checked `parts.length >= 6` but accessed `parts[6]` (needs `>= 7`)
- **Fixed non-unique React keys** in `UpcomingTasksWidget` -- `task.taskType` isn't unique, now uses compound keys
- **Fixed missing optional chaining** in `agentTools.js` -- `commentsResponse.comments` would throw if null
- **Fixed falsy value bug** in `apps.js` routes -- used `||` instead of `??` for PM2 process fallback
- **Fixed unsafe `JSON.parse`** in `pm2.js` `listProcesses` -- now uses `safeJSONParse` with fallback
- **Fixed silent error swallowing** in `cos.js` actionable insights -- `Promise.all` catches now log errors
- **Fixed missing date validation** in `formatters.js` -- `formatTime()` now guards against null/invalid timestamps
- **Fixed hardcoded localhost** in `vite.config.js` proxy -- now configurable via `VITE_API_HOST` env var
- **Fixed dependency version mismatches** -- aligned Express, PM2, and portos-ai-toolkit between root and server `package.json`
- **Removed forbidden `pm2:kill`** npm script that violated project rules

### DRY Refactors
- **Extracted `spawnPm2Cli` helper** in `pm2.js` -- eliminated 3x duplicated spawn+stderr+close blocks for stop/restart/delete
- **Extracted `loadApp` middleware** in `apps.js` routes -- eliminated 11 repeated `getAppById` + null check patterns
- **Used existing `extractJSONArray`/`safeJSONParse`** in `pm2.js` -- removed duplicated JSON extraction logic
- **Created `useAutoRefetch` hook** -- consolidated identical fetch+interval `useEffect` pattern across 4 dashboard widgets
- **Extracted `pickScheduleSettings`** in `cos.js` -- eliminated duplicated `if (X !== undefined)` settings pattern
- **Removed duplicate `.pm2` entry** from `.gitignore`

### YAGNI Cleanup
- **Deleted 3 dead `.old.js` route files** -- `prompts.old.js`, `providers.old.js`, `runs.old.js`
- **Removed unused `addAllowedCommand`/`removeAllowedCommand`** from `commands.js` -- never called from any route

## Improvements

### Plan & Documentation Cleanup
- **Extracted M42 spec** to `docs/features/identity-system.md` -- removed ~600 lines from PLAN.md
- **Extracted M40 summary** to `docs/features/agent-skills.md` -- completed milestone moved to feature docs
- **Moved M40 to Completed** -- all 4 phases (skill templates, context compaction, negative routing, deterministic workflows) were done
- **Removed external project content** (M44) -- belongs in its own repo, not PortOS
- **Removed orphaned research docs** -- external project docs were for other projects
- **Added Scope Boundary rule** to CLAUDE.md -- CoS agents must write research/plans/docs for managed apps in those apps' repos, not PortOS
- **Updated Next Actions** -- focused on M42 Identity System, M7 App Templates, M34 behavioral feedback
