Feature-preservation matrix¶
FP-2 review artifact, inspected at cd12d688a19f73f34995c9af6b86e72f5f6d7886 on fix/fp1-metacognition-preservation. It is an outcome inventory, not a declaration that the 11.0 migration preserves every feature. The companion machine-readable inventory is the row-level source of truth; it records the legacy trigger, observable, live owner, required wiring, exact source file, named meaningful public test (or MISSING), risk, next action, and owning FP ticket for every row.
Run the checked-in verifier from a source checkout so imports resolve to the reviewed tree:
It derives the 38 flat names from RETIRED_SETTINGS, cross-checks the selected partial rows against live cutover tables, requires all evidence fields, and derives the seven continuation contexts from RECONCILED_ROWS. Its high-risk check only detects a missing cited source anchor; the source audit, rather than a marker search, assigns the behavior class. It deliberately does not turn a passing inventory check into behavioral parity.
Reading a classification¶
| Classification | Meaning |
|---|---|
equivalent-proven |
A supported public observable has meaningful evidence. |
replacement-unverified |
A live capability/port exists, but automatic composition or old/new outcome parity is not proved. |
behavior-changed |
The replacement has a verified, intentional, or structural semantic difference. |
removed-without-equivalent |
No supported owner currently expresses the old behavior. |
legacy-inert |
The legacy input had no reachable behavior to preserve. |
admitted-but-inactive |
An admitted cutover control does not configure a reachable admitted-route consumer. This says nothing about whether legacy behavior was inert. |
unresolved |
The evidence is insufficient. |
Admission, rejection, imports, and a similarly named field are not evidence of parity. A missing proof stays visible as MISSING, with a bounded next action.
Flat retired/replaced settings (38)¶
The source column below is a readable routing label. The linked JSON carries the exact repository-relative source and test paths, along with the full legacy trigger and observable, without making this table unreasonably wide.
| Control | Classification | Live owner and required wiring | Source; evidence | Risk → action (owner) |
|---|---|---|---|---|
extraction_template_path |
unresolved | Legacy MemoryExtractionSection(template_path=...); no verified migrated consumer |
src/symfonic/agent/engine.py; MISSING public custom-directive extraction journey |
this is an HMS directive template, not a phase-12 nap setting → trace prompt and extraction result (FP-3) |
phase_12_action_type_from_tool_calls |
replacement-unverified | LearningPolicy → consolidation |
memory/policy.py; test_phase_12_tool_calls_fallback.py |
naming/semantics → compare nap (FP-3) |
phase_12_llm_max_drafts_per_run |
replacement-unverified | LearningPolicy → extractor |
memory/policy.py; MISSING public cap |
cap may not compose → boundary (FP-3) |
phase_12_llm_max_episodes_per_run |
replacement-unverified | LearningPolicy.as_kwargs() → extractor |
memory/policy.py; test_llm_procedural_extractor.py |
field alone is not end-to-end proof → candidate count (FP-3) |
phase_12_llm_model |
replacement-unverified | as_phase_kwargs().procedural_model_name → nightly_phases |
memory/policy.py; MISSING selected-model public assertion |
provider drift → capture model (FP-3) |
phase_12_promote_assistant_content |
replacement-unverified | LearningPolicy → promotion |
memory/policy.py; test_learning_policy.py |
mapping only → assistant nap (FP-3) |
phase_12_use_llm_extractor |
replacement-unverified | policy plus extractor collaborator | memory/policy.py; MISSING composed selector |
flag can be inert → both branches (FP-3) |
promotion_max_drafts_per_run |
replacement-unverified | LearningPolicy → promotion |
memory/policy.py; test_learning_policy.py |
missing output cap proof → over-cap journey (FP-3) |
promotion_min_pattern_count |
replacement-unverified | LearningPolicy → promotion |
memory/policy.py; MISSING N-1/N |
threshold drift → boundary (FP-3) |
promotion_recency_days |
replacement-unverified | LearningPolicy → promotion |
memory/policy.py; MISSING date boundary |
lookback drift → fixture (FP-3) |
synthetic_link_min_co_count |
replacement-unverified | LearningPolicy → synthetic phase |
memory/policy.py; test_synthetic_min_co_count_config.py |
composition unproved → public link boundary (FP-3) |
nightly_nap_cron |
legacy-inert | Operator scheduler metadata; engine never parsed cron | src/symfonic/agent/config.py; MISSING operator-scheduler contract |
stale retirement prose implied an engine loop → keep operator compatibility separate (FP-4) |
nightly_nap_enabled |
legacy-inert | Operator scheduler metadata; engine never started a loop | src/symfonic/agent/config.py; MISSING operator-scheduler contract |
stale retirement prose described automatic scheduling → keep operator compatibility separate (FP-4) |
quick_nap_interval |
replacement-unverified | ConsolidationSchedule + coordinator + memory capability |
memory/schedule.py; test_nap_after_the_turn.py |
native cadence is tested, legacy disable/per-scope semantics are not → old/new matrix (FP-3) |
metacognition_confidence_threshold |
behavior-changed | default SelectiveMetacognitionPolicy |
governance/stages/metacognition_policy.py; test_metacognition_preservation.py |
confidence is supplemental → migration guidance (FP-1) |
metacognition_gate |
behavior-changed | governance(trigger_policy=...) |
governance/stages/metacognition.py; test_metacognition_preservation.py |
callable signature/context changes → example (FP-1) |
metacognition_selective_gate |
behavior-changed | governance capability default policy | governance/stages/metacognition_policy.py; test_metacognition_preservation.py |
old spelling rejected → guide (FP-1) |
metacognition_sensitive_tags |
behavior-changed | sensitive_tags plus caller state evidence |
governance/stages/metacognition_policy.py; test_metacognition_preservation.py |
retrieval must actually carry tags → caller journey (FP-3) |
metacognition_trivial_ack_patterns |
replacement-unverified | explicit trivial_ack_patterns policy |
governance/stages/metacognition_policy.py; test_metacognition_preservation.py |
custom parity absent → custom test (FP-1) |
activation_log_mode |
removed-without-equivalent | No activation-log consumer | cutover/retired_settings.py; MISSING prompt comparison |
footer loss → product decision (FP-4) |
prompt_block_self_edit |
legacy-inert | None | cutover/retired_settings.py; test_retired_configuration.py |
stale docs → remove guidance (FP-4) |
dev_sqlite_checkpoint_path |
behavior-changed | human_interaction(...) plus AgentHost(continuation_factory=human_continuation(...)) |
platform/human_continuation.py; test_public_host_continues_a_durable_pause_in_a_fresh_process |
a bare path is rejected early; the supported port composition proves SQLite recovery, authenticated scope binding and single use (FP-4) |
scorer_on_hot_path |
replacement-unverified | Retrieval capability/coordinator | cutover/memory_retrieval_rows.py; test_memory_retrieval_lane.py |
rank semantics unproved → ordered recall (FP-3) |
state_class |
removed-without-equivalent | No kernel state-class seam | cutover/retired_settings.py; MISSING adopter inventory |
extension break → survey uses (FP-4) |
experimental_tool_decorator |
legacy-inert | Always-public @symfonic_tool |
cutover/retired_settings.py; test_retired_configuration.py |
stale config → remove docs (FP-4) |
ask_user_pause_ttl_seconds |
behavior-changed | TTLPolicy in human capability |
cutover/pause_surfaces.py; test_pause_policy_lane.py |
max rejects rather than clamps → expiry/restart (FP-3) |
ask_user_tool_descriptions |
equivalent-proven | InteractionToolSpec.description |
cutover/pause_surfaces.py; test_pause_policy_lane.py |
localization not scaffold-tested → scaffold check (FP-4) |
procedural_force_first_action_tool |
replacement-unverified | procedural_force_tool_choice='soft' plus live loop |
cutover/force_lever.py; test_tools_policy_lane.py |
replacement spelling may remain refused → stateful journey (FP-3) |
credential_patterns |
behavior-changed | CredentialHygieneStage |
cutover/governance_surfaces.py; test_governance_amends.py |
custom/disable semantics lost → secret matrix (FP-4) |
fabrication_refuse_min_confidence |
behavior-changed | FabricationStage grades |
cutover/governance_surfaces.py; test_egress_stages.py |
two-threshold semantics → public boundaries (FP-1) |
hms_budget_mode |
behavior-changed | PromptBudget |
cutover/prompt_assembly_policy.py; test_prompt_assembly_lane.py |
drop order differs → replay (FP-3) |
hms_system_prompt_token_budget |
behavior-changed | PromptBudget.max_total_tokens |
cutover/prompt_assembly_policy.py; test_prompt_assembly_lane.py |
region differs → prompt replay (FP-3) |
on_hms_budget_exceeded |
removed-without-equivalent | No public callback | cutover/prompt_assembly_policy.py; MISSING observer |
operational blind spot → hook decision (FP-4) |
jit_manifest_token_budget |
behavior-changed | Shared PromptBudget |
cutover/prompt_assembly_policy.py; MISSING region test |
allocation change → fixture (FP-3) |
manifest_cache_position |
behavior-changed | Derived cache-region plan | cutover/prompt_assembly_policy.py; MISSING provider capture |
marker changes → outbound capture (FP-3) |
memory_extract_cadence |
removed-without-equivalent | No prompt-cadence consumer | cutover/prompt_assembly_policy.py; MISSING contract |
prompt behavior loss → decision (FP-4) |
messages_cache_policy |
removed-without-equivalent | Prompt cache has no rolling-history equivalent | cutover/prompt_assembly_policy.py; MISSING multi-turn capture |
cost/latency risk → serialization journey (FP-3) |
system_prefix_cache_ttl |
equivalent-proven | Stable PromptContribution cache directive plus provider serializer |
prompting/assembly.py; test_public_two_turn_cache_reaches_anthropic_wire_with_ttl_marker |
Anthropic wire capture proves the 1h system marker; history is a separate, uncached contract (FP-4) |
FP-1 metacognition update and enforcement boundary¶
FP-1 changed the reviewed target from the old scalar-only stage. SelectiveMetacognitionPolicy is the default, ConfidenceOnlyMetacognitionPolicy is an explicit opt-out, and tests/platform/test_metacognition_preservation.py covers public run and drained-stream triggers for claims, mutating tools, action/ambiguous intent, fabrication findings, caller-supplied recalled tags, trivial acknowledgments, custom policy, and invalid confidence signals. The matrix therefore no longer calls sensitive tags removed merely because they are not inferred from draft text.
This proves critic invocation coverage, not every historical amendment shape. platform/governance_verdict.py now turns a STEER or ANNOTATE with no amendment content into a typed GovernanceRefused before an egress draft reaches run, stream consumers, or event sinks. A reflector outage retains the pipeline's existing fail-open policy. The public journey proves this refusal contract; it does not claim that a prompt cache is a history cache or that every legacy verdict was textually revised.
PARTIALLY MIGRATED controls (23 unique)¶
The following controls are distinct from the flat 38. They are source-enumerated from the cutover contract. “Admitted but inactive” never means the legacy control was inert.
| Control | Classification | Live owner/wiring | Source; evidence | Risk → action (owner) |
|---|---|---|---|---|
self_reflection |
admitted-but-inactive | Native reflection phase required | cutover/admission_surfaces.py; test_reflection_and_scheduler_surfaces.py |
admission only → compose/test (FP-4) |
reflection_prompt |
admitted-but-inactive | Native reflection phase required | cutover/admission_surfaces.py; test_reflection_and_scheduler_surfaces.py |
custom prompt lost → phase test (FP-4) |
domain.core_preferences |
admitted-but-inactive | Governance policy input required | cutover/admission_surfaces.py; MISSING native input |
silent inactivity → decision (FP-4) |
read_only_tools |
admitted-but-inactive | governance(read_only_tools=...); old field not mapped |
cutover/tools_surfaces.py; test_metacognition_preservation.py |
new port works but old config is inert → guide/adapter (FP-4) |
skill_auto_approve |
admitted-but-inactive | Native promotion policy required | cutover/tools_surfaces.py; MISSING native journey |
status drift → composition (FP-4) |
domain |
behavior-changed | Description reaches HmsSystemSource |
cutover/prompting_surfaces.py; test_prompt_assembly_lane.py |
nested fields omitted → bound contract (FP-4) |
domain_description_max_chars |
behavior-changed | non-JIT [0] truncation |
cutover/prompting_surfaces.py; test_continuation_cutover.py |
JIT [1] unreachable → decide (FP-4) |
hydration_min_relevance |
behavior-changed | RetrievalCoordinator._gate |
cutover/memory_retrieval_rows.py; test_memory_retrieval_lane.py |
composite score → boundary (FP-3) |
episodic_telemetry_sink |
admitted-but-inactive | Native lifecycle writer required | cutover/memory_retrieval_rows.py; MISSING sink journey |
telemetry missing → wire (FP-4) |
working_memory_recent_turns |
behavior-changed | WorkingWindow.read |
cutover/memory_retrieval_rows.py; test_memory_retrieval_lane.py |
zero refused → disabled-window contract (FP-4) |
working_layer_exclude_speakers |
behavior-changed | Working window only | cutover/memory_retrieval_rows.py; test_memory_retrieval_lane.py |
episodic quotes stay → two-source test (FP-3) |
stm_summary_mode |
admitted-but-inactive | Native summary contribution required | cutover/memory_retrieval_rows.py; MISSING contribution |
silent inactivity → define composition (FP-4) |
scope_blend_mode |
behavior-changed | Constructed retrieval engine | cutover/memory_retrieval_rows.py; test_memory_retrieval_lane.py |
injected precedence → hierarchy test (FP-3) |
enabled_layers |
behavior-changed | Constructed orchestrator config | cutover/memory_orchestrator_rows.py; test_continuation_cutover.py |
injected precedence → both paths (FP-3) |
phase1_spreading_weight |
replacement-unverified | LearningPolicy → phase factory |
memory/policy.py; test_phase1_spreading_decomposition.py |
no public composition → nap boundary (FP-3) |
enable_entity_linker |
replacement-unverified | Policy plus extractor collaborator | memory/policy.py; test_entity_linker_model_wiring.py |
flag alone insufficient → off/on (FP-3) |
entity_linker_extractor |
replacement-unverified | entity_linker_extractor_kind plus collaborator |
memory/policy.py; test_entity_linker_model_wiring.py |
runtime unproved → each-kind journey (FP-3) |
entity_linker_min_mention_count |
replacement-unverified | LearningPolicy → entity phase |
memory/policy.py; MISSING N-1/N |
threshold drift → fixture (FP-3) |
entity_linker_max_episodics_per_run |
replacement-unverified | LearningPolicy → entity phase |
memory/policy.py; MISSING over-cap |
cost cap unproved → capture (FP-3) |
entity_linker_confidence_threshold |
replacement-unverified | LearningPolicy → entity phase |
memory/policy.py; MISSING threshold |
score boundary → fixture (FP-3) |
episodic_summarization_max_entries |
replacement-unverified | LearningPolicy → quick phase |
memory/policy.py; test_phase_10_threshold_plumbing.py |
no Agent lifecycle proof → post-turn (FP-3) |
episodic_summarization_batch_size |
replacement-unverified | LearningPolicy → quick phase |
memory/policy.py; MISSING batch journey |
batch drift → exact-count (FP-3) |
enable_semantic_merge |
replacement-unverified | quick_phases collaborator composition; no LearningPolicy field |
memory/phases/quick.py; test_learning_phase_parity.py |
field absence is not capability absence → composed off/on (FP-3) |
Continuation boundary and exclusions¶
Seven continuation contexts are audited separately and are not seven additional controls: enabled_layers, domain, hydration_min_relevance, working_memory_recent_turns, domain_description_max_chars, working_layer_exclude_speakers, and scope_blend_mode. continuation_admission.RECONCILED_ROWS, tests/retirement/test_continuation_reconciliation.py, and tests/agent/cutover/test_continuation_cutover.py establish cutover context only. They do not establish durable process-restart recovery.
The inventory excludes nested agent.ask_user_pause_ttl_seconds (the same TTLPolicy behavior change), per-call is_admin (refused by governance authority), and all other nested/per-call options. This is an explicit scope boundary, not a claim that no other configuration needs review.
Derived totals and release implication¶
The validator prints totals directly from the checked-in rows. The current evidence leaves a large set of high-risk replacement-unverified, removed-without-equivalent, and behavior-changed controls. That blocks a blanket no-feature-loss claim. FP-3 owns the discriminating public journeys; FP-4 owns supported composition, explicit refusals, and deliberate product decisions. FP-1 owns the metacognition policy implementation and its remaining custom-pattern and verdict-enforcement evidence.