-
Notifications
You must be signed in to change notification settings - Fork 2
plat 060
| Coordination | Value |
|---|---|
| Assigned agent | Claude Code |
| Ticket state | implemented; runtime reverify deferred |
| Last synchronized | 2026-08-09 |
- Priority: P2
-
Owner:
update_step_configwrite path ·llm_ops_review→ Fixer handoff -
Related: PLAT-059 (
lock_learnings_reason) established the pattern.
llm_ops_review already owns tier, model and execution-mode selection, is
explicitly read-only, and already produces "current state, exact suggestion,
expected benefit, risk, and evidence" for every recommendation — including a
strict tier-downgrade policy ending "missing evidence means keep the tier."
That rationale never reached the config:
- Ops writes the evidence into the Pulse finding.
- The Fixer applies it with
update_step_config(execution_tier=…)— no reason parameter. -
planning/step_config.json, which is what the next reviewer reads, records the change with no trace of why. - The Fixer had no guidance at all for this class of change:
execution_tier,declared_execution_mode, andtierreturned nothing frompulse-review-fixer.mdorpulse-fixer-practices.md.
Two consequences were invisible at the call site:
- Setting
execution_tierpermanently disables adaptive tiering for the step (shouldUseAdaptiveExecutionTiering), so it stops promoting high→medium after 3 stable runs. -
execution_llmoutranks tier entirely and does not follow provider-profile updates.
Three validators alongside validateLockLearningsChange
(controller_learning_helpers.go), called from the update_step_config handler:
| Field | Reason | Consequence named in the rejection |
|---|---|---|
execution_tier |
execution_tier_reason (new) |
disables adaptive tiering |
execution_llm |
execution_llm_reason (new) |
outranks tier; ignores profile updates |
declared_execution_mode |
declared_execution_mode_reason (existed, now required) |
scripted freezes behaviour into main.py
|
- Reasons are read before their fields in the handler, so a reason supplied in the same call satisfies its own validator.
- Clearing a field clears its reason; clearing never requires one.
- Guidance:
ops-review.md(write recommendations so they can be stored verbatim as the reason),pulse-fixer-practices.md(net-new "Applying an Ops config recommendation" playbook),step-config.md. - UI: the
execution_tierdropdown inStepEditPanel.tsxwas removed, as thelock_learningstoggle was in PLAT-059. Current tier stays visible.
A required field invites a confabulated answer from an agent that has already
decided to act, and an invented justification is harder to challenge later
than a missing one. Every rejection therefore names the sanctioned
alternative: raise a decision with create_human_input_request and park the
finding awaiting_user. That path is already enforced —
RecordPulseFindingDispositionsTx rejects awaiting_user when the decision does
not exist or is no longer pending. Uncertainty is a legitimate terminal state.
learning_objective and knowledgebase_contribution take no reason field.
They are meant to be refined continuously as evidence accumulates, and a
write-time gate would suppress exactly that iteration. Instead the Fixer's skill
playbook gained a yield check (step 5b) reading the already-recorded
detection_history[].has_new_learning in .learning_metadata.json: repeated
no-yield means sharpen the objective or drop to learnings_access="read".
Reflection turns measured 20.1% of all LLM time on Social Media's run, so an
objective that never yields is pure overhead — ops-review.md now names that a
first-class cost line.
ops_config_reason_test.go — five tests: each field rejected without a reason,
accepted with one, not gated when unset; clearing clears the reason; reasons
survive MergeAgentConfigFields. Each rejection is asserted to name its hidden
consequence and create_human_input_request.
Full run reproduced the known 22-failure baseline exactly; no new failures.
Runtime reverify is deferred and cannot be claimed yet: llm_ops_review is
currently disabled at the Gate for the core-system verification phase, so the
lens that supplies these reasons does not run. The enforcement is live; the
loop it serves resumes when that block is removed from pulse-gate.md.
Removed runtime High-to-Medium promotion based on description_hash_runs and
all tier state updates from execution. Those counters were learning-reflection
records, not consecutive successful executions, and a description reset could
reuse the old count. Model selection now follows explicit model/tier/caller
settings; absent an override, execution defaults to High and evaluation to Medium.
Existing explicit pins are preserved. Legacy adaptive metadata remains historical
only and does not migrate into a persistent pin or affect execution.
Pulse Architecture now owns evidence-based tier/model proposals. It compares actual execution/evaluation quality, retries, duration and workflow cost evidence, proposes bounded trials through the existing impact/approval contract, and assesses them at a checkpoint with rollback settings. It must respect user pins, avoid per-run switching and not infer cheaper-model quality from a success count. QA retains concrete provider failures and attribution defects. Tool descriptions, configuration reason validation, reviewer guidance and step UI describe this same ownership. No additional reviewer or reporting ledger was introduced.
Regression checks cover unchanged default and explicit-tier selection across repeated calls, evaluation defaults, model/one-run override precedence, absence of history-derived runtime overrides, reason requirements and the Architect contract.
Auto-synced from docs/ on main. Edit there, not here.