Why: The login recovery contract leftovers and KTD12/KTD14 require:
concurrent same-name account creation must not overwrite the winner,
first-admin bootstrap must serialize across processes, the redeem
endpoint backoff must be shared across instances, revoked API keys
must close established SSE streams, and CLI credentials need an
env-DSN path plus a non-interactive 0600 file delivery mode.
Evidence: go test ./... green; new tests cover 16-way concurrent
create (1 win/15 conflict, winner credentials intact), 8-way
concurrent bootstrap (single admin, refuse takeover after), redeem
guard shared across two store handles on one DB, SSE stream closed
after key revocation within the recheck window, and HTTP 429 after
the failure cap (SELF worktree run; CI is the GATE, PG via test-pg).
Impact: Migration v29 (redeem_attempts); CreateAccount becomes a
single-row INSERT with unique-violation conflict; BootstrapFirstAdmin
advisory-locks (PG) / rechecks (SQLite) and commits admin+key+audit in
one transaction; SSE revalidation covers API-key streams; redeem
backoff moves to the shared DB; CLI gains AGENT_SYSTEM_DSN fallback
and --out file delivery for create/reset-password/issue-login-key/
bootstrap-admin.
Refs: docs/svc-deploy/2026-10-13-login-recovery-contract.md leftovers;
proposal r2 KTD12/KTD14/R5/R11.
Why: Since the system-managed settings change (#188), runtime.* writes
at the user scope are rejected, so the mock startup flag failed with
"system-managed settings require admin" and the serve process never
became healthy - the Dev multi-instance integration regression.
Evidence: go build ok; internal/app and internal/settings suites green
(SELF); the Dev composite CI on the follow-up PR re-runs
make test-multi-instance against this fix (GATE).
Impact: The mock startup flag now seeds runtime.mock via MergeSystem
(trusted operator input, effective for every tenant through the
Effective merge chain); no HTTP surface changes.
Refs: Dev PR #508; backend #188.
Why: The 2026-10-13 login recovery contract (Dev docs/svc-deploy/
2026-10-13-login-recovery-contract.md, plan item 6.7) requires that
established SSE connections stop receiving private events once a
password write destroys their session.
Evidence: go test ./... green; TestSSESessionInvalidationClosesStream
streams over a real HTTP server, invalidates the session via
AdminResetUserPassword, and asserts the stream terminates with the
session-expired marker within the recheck window (SELF, worktree run).
Impact: Session-authenticated event streams revalidate at a 15s
heartbeat cadence (package var, shortened in tests) and terminate on
invalidation; API-key streams are unchanged (key revocation is separate).
EventSource reconnects are rejected by the auth middleware.
Refs: Dev PR #504; login recovery contract section 6.7.
Why: The login recovery contract (2026-10-13) requires admin-issued
one-time keys, in-transaction revalidation of restricted sessions, a
login race guard, and audited password writes; the previous
implementation validated sessions outside the change-password
transaction and let stale password verifications create sessions.
Evidence: go test ./... green (SQLite); store tests switch to
openTestStore so the CI test-pg job covers real PostgreSQL, including
100-way concurrent redeem single-winner and auth-version race cases
(SELF, local run).
Impact: New migration v28 (users/sessions.auth_version,
account_events). New admin endpoints POST/GET
/api/admin/users/{owner}/login-keys and DELETE
.../login-keys/{id}. Login binds session creation to the verified
auth version and creates restricted sessions for must-change accounts;
redeem gains per-IP backoff; cookies gain Secure under TLS; active
change-password and admin/CLI resets become single transactions that
bump auth_version, revoke keys and sessions, and write audit events.
Refs: modules/documents/docs/proposals/2026-10-12-svc-unified-deploy-and-login-key.md r2; Dev task feature/svc-login-recovery-flow
Why: an unset object-storage endpoint passed a typed nil into the store and artifact upload panicked.
Evidence: GATE vet-and-test run 2783 job 4031 success on 46073d30a5. Independent review approved with no blockers.
Impact: unconfigured stores fall back to the local artifacts directory. Configured S3 is unchanged.
Refs: #186
Why: an unset S3 client passed through the Store interface is not a nil interface, so uploads panic instead of using the local artifact directory.
Evidence: TestIsNil and TestFinishOpenTypedNilS3UsesLocalArtifacts failed before this change and pass after it. The PostgreSQL case skips unless AGENT_PG_TEST_DSN is set.
Impact: only an unset blob store falls back; a constructed S3 or local store is unchanged.
Refs: internal/blobstore/blobstore.go internal/store/store.go
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: identity probes must open an existing database without creating or migrating it, and DSN must stay out of argv.
Evidence: GATE ci / vet-and-test success on 0f192a4813, run 2625 job 3782.
Impact: version --json carries schema target and compat floor; unknown top-level commands exit 2.
Refs: #184
Why: main gained AGENT_SYSTEM_DSN fallback in #182 after this branch
was cut. Both changes touch identity DSN parsing.
Evidence: go test ./pkg/identity/ ./internal/store/ ./cmd/agent-system/ for the identity, schema, and unknown-subcommand cases passed after the resolution.
Impact: keeps open-existing identity mode and the 0600 dsn file. Environment
DSN still wins when --dsn is absent, via ResolveDSN.
Refs: Backend #182; recovery plan r3.1 D1
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: a rollback can only be safe when the candidate says which schema it
will migrate to and whether older binaries can still read that schema.
A new migration that forgets to register that fact must fail the test.
Evidence: go test ./internal/store/ ./pkg/identity/ -run 'TestMigrationCompat|TestCapabilities' passed.
Impact: version --json and identity capabilities include schema.target and
schema.compatFloor. Every migration version is listed in
migrationBreaksOldReaders. Current versions do not break old readers, so
the floor stays 0.
Refs: recovery plan r3.1 D2
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: identity ensure/verify went through the normal store open, which
creates a database and runs migrations. A deploy gate that calls the
candidate before stopping the old service could migrate production
ahead of the switch, and a missing database was turned into an empty one.
Evidence: go test ./pkg/identity/ ./internal/store/ ./cmd/agent-system/ -run 'TestCapabilities|TestEnsure|TestVerify|TestDSN|TestUsage|TestSystemIdentity|TestOpenIdentity|TestUnknownSubcommand' passed in this worktree.
Impact: identity CLI refuses a missing file or a missing agent_system_identity table, does not migrate, reads DSN from the environment or a 0600 file, and version --json plus identity capabilities emit one capability document. Unknown top-level commands exit 2.
Refs: recovery plan r3.1 D1; Dev feature/svc-d1-identity-flow
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: svc.sh delivers database credentials via environment per G1-7
(command lines are visible to every process on the host), but identity
ensure/verify only accepted --dsn on the command line for pg-bound
instances.
Evidence: go test ./pkg/identity/... ok; build ok.
Impact: --dsn remains highest priority, then AGENT_SYSTEM_DSN, then
embedded SQLite; no storage changes.
Refs: Dev U3 (real-combination CI gates); G1-7 credential discipline.
Why: runIdentity lived in cmd/agent-system package main, so downstream
combination binaries (Agent-System-RDM) cannot reuse it and their unknown
subcommands fall into the serve path; the 2026-10-12 rdm1/rdmcand batch
update failures traced back to that capability gap.
Evidence: go test ./pkg/identity/... ok; CGO_ENABLED=0 go build ok;
behavioral probes (usage rc=2, capabilities v1, ensure/verify roundtrip)
recorded in the PR.
Impact: identity semantics unchanged for the base binary; adds
identity capabilities (v1) and usage-on-unknown contract shared by all
products; no storage changes.
Refs: Dev PR #474 (svc.sh candidate gate); user root-cause report
2026-10-12 U1 (shared identity interface).
Why: Stop showing raw task text as progress and stop lighting the
done lamp on failed background runs (U1 whitelist).
Evidence: go test ./internal/runmgr/ -count=1
Impact: create/promote/finish card bodies; material queue status text.
Refs: fast-slow-channel-display-u1-plan W2; Core ba289e7
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: TestMaterialIntakeAttachmentOnlyLifecycle flaked when waiting on
systemTexts; deliverNotices runs before defer materialKeyRelease, so
done-dedup still saw the in-memory key and returned pending.
Evidence: go test ./internal/runmgr/ -run TestMaterialIntakeAttachmentOnlyLifecycle -count=20
Impact: Aligns the wait with materialExisting gates; no production change.
Refs: fix/material-intake-lifecycle-flake
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: main #171 claimed migration v26; rebase conflict required
bumping the U1 I3 table and completing copyOrder for both new tables.
Evidence: go test ./internal/store/ ./cmd/storage-migrate/ -run
'SystemIdentity|CopyOrder'
Impact: migrate v27; copyOrder += login_keys + agent_system_identity.
Refs: Backend PR #170; conflict with main 1d9e8f4
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: TestCopyOrderCoversAllFixtureTables fails when new schema tables
are omitted from the migrate tool inventory.
Evidence: go test ./cmd/storage-migrate/ -run CopyOrder
Impact: copyOrder gains agent_system_identity (no FK deps).
Refs: U1 I3; Backend PR #170
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: U1 I3 needs a DB-side instance identity anchor matching
manifest.instance_id so wrong/missing DB blocks startup (I4).
Evidence: go test ./internal/store/ ./internal/app/; CLI smoke
ensure/verify on SQLite temp dir.
Impact: migration v26; store Ensure/Verify; identity subcommand;
serve checks AGENT_SYSTEM_INSTANCE_ID when set.
Refs: docs/recovery/u1-identity-manifest.md §5.2; Dev feature/recovery-u1-db-identity
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: system.intent ParamsSchema requires top-level text, but
SubmitAction only nested values under data, so button intent always
rejected missing text during prod acceptance.
Evidence: go test ./internal/surfacesvc/ -run TestSubmitActionFlattensDataIntoParams
Impact: B-class intent and other schema-required params work via actions;
submit still receives nested data.
Refs: GenUI prod deploy acceptance; fix track
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Async notice-run delivery raced with test teardown and in-flight
conversation runs (database closed / material lifecycle flakes).
Evidence: go test ./internal/runmgr/ -run Material
Impact: Reminders append as system messages only; material path still
inlines into startNoticeRun.
Refs: Dev PR #425 CI test-pg failure
Co-authored-by: Cursor <cursoragent@cursor.com>