Phase 7 Steps 3a-3c: config split + PUT /memories/config deprecation#18
Merged
ethanj merged 4 commits intoarchitecture2from Apr 18, 2026
Merged
Phase 7 Steps 3a-3c: config split + PUT /memories/config deprecation#18ethanj merged 4 commits intoarchitecture2from
ethanj merged 4 commits intoarchitecture2from
Conversation
Introduces the public documentation split of v2's runtime config that Phase 1A deferred. No behavior change. - src/config.ts: declare SUPPORTED_RUNTIME_CONFIG_FIELDS (39 fields — infrastructure, provider/model selection, operator runtime, major feature toggles, cost/cache ops) and INTERNAL_POLICY_CONFIG_FIELDS (66 fields — thresholds, tuning knobs, experimental toggles). Derive SupportedRuntimeConfig / InternalPolicyConfig as Pick<> slices of RuntimeConfig so the split is type-level documentation without constraining threading. - src/__tests__/config-partition.test.ts: new fence asserting the two partitions are disjoint, cover every RuntimeConfig field on the singleton, and reference no stray keys. Any new RuntimeConfig field must be tagged into one bucket or the test fails — prevents silent drift of the public contract. - src/index.ts: re-export the two arrays and four derived types from the root package so consumers can reference SUPPORTED_RUNTIME_CONFIG_FIELDS as the authoritative list of what's stable. - docs/consuming-core.md: new "Config surface: supported vs experimental" section pointing at the authoritative arrays and explaining the stability contract. 961/961 tests pass (957 before + 4 new partition tests). tsc --noEmit clean. fallow --no-cache 0 above threshold. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gates PUT /memories/config behind a startup-validated flag. Production deploys get 410 Gone; dev/test environments opt in via env var and keep v1 behavior. Follows the workspace rule "config is validated at startup, routes don't re-check at request time" — no NODE_ENV branching in the route handler. - src/config.ts: add runtimeConfigMutationEnabled to RuntimeConfig, parsed from CORE_RUNTIME_CONFIG_MUTATION_ENABLED (default false). Added to SUPPORTED_RUNTIME_CONFIG_FIELDS so the partition test keeps it honest. - src/app/runtime-container.ts: CoreRuntimeConfigRouteAdapter.current() now includes runtimeConfigMutationEnabled. Default adapter populates from config singleton at construction time — memoized, not a per- request env read. - src/routes/memories.ts: RuntimeConfigRouteSnapshot gains the field. PUT /memories/config checks configRouteAdapter.current() .runtimeConfigMutationEnabled; false → 410 Gone with a message pointing at the env var. true → existing behavior preserved. - .env.test.example: documents the flag with CORE_RUNTIME_CONFIG_MUTATION_ENABLED=true for test/dev. .env.test (gitignored) should be updated locally. - .env.example: documents the flag as opt-in; left commented out so production deploys inherit the safe default. - src/__tests__/memory-route-config-seam.test.ts: MutableRouteConfig gains the field (set true for existing tests); new test asserts PUT returns 410 when the flag is flipped to false. - docs/consuming-core.md: new "PUT /memories/config — dev/test only" section explaining the gate and dev-mode setup. - atomicmemory-research/docs/core-repo/readme/readme-migration-from-v1.md: §8 updated to reflect the deprecation path and point at the env var. 962/962 tests pass (961 + 1 new 410 test). tsc --noEmit clean. fallow --no-cache 0 above threshold. Parity audit (see v1-v2-functional-parity-audit.md §2) confirmed zero production callers of PUT /memories/config, so the deprecation is parity-preserving by definition. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes embeddingProvider, embeddingModel, llmProvider, llmModel from updateRuntimeConfig() and rejects them at the HTTP boundary with 400. This is a bug fix disguised as a deprecation: v1 accepted these fields but the embedding.ts / llm.ts provider caches are stateful and fixed at first use, so mid-flight mutation never actually took effect. Making them explicitly startup-only aligns the API contract with reality. Parity audit (v1-v2-functional-parity-audit.md §4) confirmed no caller relies on runtime provider/model mutation — both in-repo tests and the vendored prototype UI only mutated thresholds / maxSearchResults, which remain mutable in dev/test mode. - src/config.ts: narrow RuntimeConfigUpdates to 4 mutable fields (similarityThreshold, audnCandidateThreshold, clarificationConflictThreshold, maxSearchResults). Delete the four provider/model blocks from updateRuntimeConfig(). Remove the now-dead requireSupportedProvider and requireNonEmpty helpers. - src/app/runtime-container.ts: narrow CoreRuntimeConfigRouteAdapter .update() signature to match. - src/routes/memories.ts: narrow RuntimeConfigRouteUpdates; add STARTUP_ONLY_CONFIG_FIELDS = ['embedding_provider', 'embedding_model', 'llm_provider', 'llm_model'] and reject the PUT with 400 if any appear in the body, with a message pointing at the env vars. - src/__tests__/memory-route-config-seam.test.ts: new test asserts 400 rejection with rejected: ['embedding_provider']. - docs/consuming-core.md + migration doc: document the startup-only constraint with the rationale. 963/963 tests pass (962 + 1 new 400 test). tsc --noEmit clean. fallow --no-cache 0 above threshold. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex review caught two drift points between the implementation and the docs/response payload: - docs/api-reference.md §PUT /memories/config still documented the pre- Step-3b/3c contract — provider/model mutation fields and "all fields optional". Rewrote the section to: flag dev/test-only gating, list the 4 currently-mutable fields, document the 400/410 responses with example payloads, and explain the startup-only rationale. - src/routes/memories.ts: the success-response `note` contradicted the handler's own behavior. "Provider/model changes are applied in-memory for local experimentation" is no longer true (those fields are rejected earlier in the same handler). Replaced with an honest note pointing threshold-only mutation at dev use and startup restart for provider/ model. 963/963 tests pass. tsc --noEmit clean. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
ethanj
added a commit
that referenced
this pull request
Apr 19, 2026
Cuts over `main` to the Phase 1A–7 rearchitecture (composition root, explicit scope/observability contracts, store-narrowed repository access, public consumption seams, config split, leaf-module config threading, retrieval orchestration polish) plus the OSS-release-prep on top.⚠️ Breaking changes for HTTP / SDK consumers - All API endpoints are now mounted under `/v1` (e.g. `POST /v1/memories/ingest`, `PUT /v1/agents/trust`). The unversioned `/health` liveness probe is unchanged. - Workspace `GET /memories/list`, `GET /memories/:id`, and `DELETE /memories/:id` now require `agent_id` when `workspace_id` is present; missing returns 400 (no visibility-unsafe fallback). - `PUT /memories/config` returns 410 Gone in production. Provider/model fields (embedding_provider, embedding_model, llm_provider, llm_model) are rejected with 400 — they were never honored mid-flight (provider caches are fixed at first use). Set via env at process start. - npm package renamed `@atomicmemory/atomicmemory-engine` → `@atomicmemory/atomicmemory-core`. Tarball now ships `dist/` (built via `tsc`); `main`/`types`/`exports` point at compiled output. - Deep-importers of `services/embedding` and `services/llm` must call `initEmbedding(config)` / `initLlm(config)` before hot-path APIs. Consumers using `createCoreRuntime({ pool })` are auto-initialized. Rearchitecture (Phases 1A–7) - Phase 1A: composition root via `createCoreRuntime` + `createApp` (#8) - Phase 2A: canonical search scope contract (#9) - Phase 2B: explicit retrieval observability contract (#10) - Phase 3: runtime-config seam cleanup to Phase 4 boundary (#11) - Phase 4: ingest pipeline decomposition (475 → 215 lines) (#13) - Post-Phase 4: unify scope contract via `scopedSearch`/`scopedExpand`, document schema scoping gaps as deferred (#15) - Phase 5: narrow repository access behind 8 domain-facing stores; workspace ingest now flows through canonical lineage (#16) - Phase 6: publish stable consumption seams (HTTP, in-process, docker) with two-direction parity contract test (#17) - Phase 7 Steps 3a–3c: split runtime config into supported/internal partitions; deprecate `PUT /memories/config` for production (#18) - Phase 7 Step 3d: thread config through 5 leaf modules (33→28 singleton audit) (#21) - Phase 7 Item 4: retrieval polish — `memory-search.ts` reduced to pure orchestration (374 → 248 lines, -34%) (#22) - Chore: reduce fallow duplication 367 → 234 lines (#12) OSS release prep - `"private": true` removed; package renamed to `@atomicmemory/atomicmemory-core`. `files` field scopes the tarball. - `tsconfig.build.json` + `prepublishOnly` so `npm publish` always ships compiled `dist/`. Bare-import smoke test passes. - `release.yml` publishes to public npm on tag push (NPM_TOKEN secret). - SuperMem codename scrubbed from `src/`, tests, docker-compose, and `.env.example` (DB user/name/password renamed to `atomicmemory`). - Private-research-repo URLs unlinked from public docs. - README links to docs.atomicmemory.ai. - `/v1` API prefix on all routes; mount-coverage test added. - CI workflow: set `CORE_RUNTIME_CONFIG_MUTATION_ENABLED=true` to match `.env.test` (gitignored) and unblock the composed-boot-parity test on `PUT /v1/memories/config`. Verification - 966/966 tests pass (100 files) - npx tsc --noEmit clean - fallow --no-cache: 0 above threshold (maintainability 91.0) - npm publish --dry-run succeeds
3 tasks
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.
Summary
Phase 7 Steps 3a, 3b, and 3c — completes the config-split deliverable that was descoped from Phase 1A. Documents the public/internal partition of runtime config, deprecates
PUT /memories/configfor production behind a startup-validated flag, and freezes provider/model selection as startup-only to match the underlying cache contract.Gated by a v1→v2 functional-parity audit (Item 0) that confirmed zero production callers of the now-restricted routes. The audit doc lives in
atomicmemory-research/docs/core-repo/readme/v1-v2-functional-parity-audit.md.What changed
Step 3a — Partition runtime config (commit
6fe44cd)src/config.tsdeclaresSUPPORTED_RUNTIME_CONFIG_FIELDS(39 fields — infrastructure, provider/model selection, operator runtime, major feature toggles, cost/cache ops) andINTERNAL_POLICY_CONFIG_FIELDS(66 fields — tuning thresholds, experimental toggles).SupportedRuntimeConfig/InternalPolicyConfigasPick<>slices ofRuntimeConfig— documentation, not threading constraint.src/__tests__/config-partition.test.tsasserts disjointness, full coverage, no stray keys. Any newRuntimeConfigfield must be tagged into one bucket or the test fails.src/index.ts.docs/consuming-core.mdexplains the stability contract.Step 3b — Deprecate
PUT /memories/configfor production (commit056f95e)runtimeConfigMutationEnabledfield onRuntimeConfig, parsed fromCORE_RUNTIME_CONFIG_MUTATION_ENABLED(defaultfalse).CoreRuntimeConfigRouteAdapter.current()surfaces the flag. Routes read it from a memoized startup snapshot — no per-requestprocess.envreads (matches the workspace rule "config validated at startup, routes don't re-check").PUT /memories/configreturns410 Gonewhen the flag is off. Production deploys inherit the safe default..env.testand.env.test.exampleset the flag totrueso existing tests and local dev keep working..env.exampledocuments the opt-in.Step 3c — Freeze provider/model selection as startup-only (commit
d369726)embeddingProvider,embeddingModel,llmProvider,llmModelfromupdateRuntimeConfig()insrc/config.ts.400+rejectedarray if any ofembedding_provider,embedding_model,llm_provider,llm_modelappear in the body.embedding.tsandllm.tsare fixed at first use. v1 accepted these fields but mid-flight mutation never took effect. Making them explicitly startup-only aligns the API contract with reality — a bug fix disguised as a deprecation.requireSupportedProviderandrequireNonEmptyhelpers.Follow-up — Docs and live-response cleanup (commit
bac6086)docs/api-reference.md§PUT /memories/config rewritten to match the new contract (4 mutable fields, 400/410 responses with example payloads, startup-only guidance).noteupdated — the old text claimed "Provider/model changes are applied in-memory" which contradicted the new 400 rejection path.Out of scope
Test plan
npx tsc --noEmit— cleannpm test— 963/963 pass (957 pre-branch + 6 new: 4 partition + 1 410 + 1 400)fallow --no-cache— 0 above threshold, maintainability 90.9 (good)memory-route-config-seam.test.ts— mutable/immutable behavior pinnedcomposed-boot-parity.test.ts— existing PUT path unchanged in dev mode🤖 Generated with Claude Code