- chat.SanitizeHTML/SanitizePlain decoded-then-escape text runs, so HTML
entities the browser emits (e.g. for the space after a mention chip,
or & for a typed "&") no longer render as literal " "/"&".
Re-escaping keeps output XSS-safe. Adds regression tests.
- Rename ./volumes -> ./.volumes so `go build/vet/test ./...` skip the mongo
data dir (700-perm files); Makefile lint now gofmt's tracked files only.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the named volumes mongo-data and work-data with bind mounts to
./volumes/mongo and ./volumes/work so all runtime state lives under the repo
tree. Existing data was migrated; the old named volumes were removed. The
${HOME}/.claude host-credential mounts are intentionally left as-is (must not
live in the repo). Added /volumes/ to .gitignore.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- APP_INTERNAL_URL: in-network base URL for §5.2 callbacks and signed
attachment URLs handed to the external services (compose: http://app:8787)
- work-performer image runs as the node user with ~/.claude mounted into
/home/node — the claude CLI refuses --dangerously-skip-permissions as root
- scripts/acceptance.sh: re-run-safe live verification of the §13 checklist
(demo import within one poll, subdivide sum=1 + editable, extend sibling,
publish/bounty math, decline/claim/approve, changes-requested loop,
approval award in metrics, unassign, AI job through real Claude Code with
signed idempotent callback, breaker independence between the two services)
- README/DECISIONS: sudo HOME gotcha, internal URL, non-root performer
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- services/atomizer: standalone Go module implementing §5.1 — Anthropic
OpenAI-compatible chat completions by default, native /v1/messages when
LLM_API_STYLE=anthropic, strict-JSON prompting, defensive fence-stripping
parse with one retry, deterministic equal-split fallback without an API
key, exact coefficient-sum normalization, bearer auth
- services/work-performer: Node 20 http server implementing §5.2 — single
concurrency, /work/{jobId}/TASK.md preparation, attachment downloads,
optional shallow git clone, claude CLI execution with JSON output,
simulated success when the CLI is unavailable (offline demo), artifact
endpoint, idempotent HMAC-signed callbacks with retry, best-effort cancel
- compose profile 'mocks': separate builds/ports/tokens, healthchecks,
${HOME}/.claude(.json) mounted read-only into the performer
- contract tests (go test -tags=contract) for both services; Makefile
test-contract target; verified live incl. a real Claude Code job run
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- customer CRUD wizard backend: per-system credential shapes validated via
connector construction, AES-256-GCM at rest, write-only over the API
- ticketing connectors (jira/azure_devops/youtrack/demo) with test-connection
- user management: roles, disable (revokes sessions), force password reset,
delete; self-demotion/disable/delete guards
- admin-editable runtime settings ({_id:app}) incl. atomizer URL override
- audit log written on every privileged mutation + filterable list API
- service status panel: mongo/atomizer/work-performer health + latency with
late-bound breaker, sync and jobs status providers
- tabbed admin UI (customers wizard dialog, users table, settings, status, audit)
- compose: mongo nofile ulimit 64000 (1024 default crashed WiredTiger)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>