mirror of
https://github.com/dtzp555-max/olp.git
synced 2026-07-19 09:45:07 +00:00
docs(adr-0004)+chore: D22 — defer soft triggers to v1.x (round-2 F2)
cold-audit catch from 2026-05-24
Round-2 cold-audit Finding 2 (P2 feature-surface vs data-ingestion drift).
ADR 0004 § Trigger taxonomy documented soft triggers (credit_pool_percent,
daily_request_count, five_hour_window_percent) as a live, configurable
feature category. But `evaluateSoftTriggers` in lib/fallback/engine.mjs
is functionally inert at v0.1:
- buildDefaultChain hardcodes quotaSnapshot: null on every hop
- No call site for provider.quotaStatus() in server.mjs or engine.mjs
(only definitions in the 3 provider plugins, all currently stubs)
- evaluateSoftTriggers correctly short-circuits to false on null snapshot
A user populating routing.soft_triggers in ~/.olp/config.json gets zero
runtime behavior. Round-1 cold audit + D5/D9 diff-review reviewers all
focused on evaluation correctness; nobody traced the production data
path end-to-end.
Owner decision (after considering wire-vs-defer): defer to v1.x. Wiring
quotaStatus() polling requires per-hop async I/O before each spawn
decision, error handling for providers without quota endpoints (all 3
current providers fall in this bucket: claude -p, codex exec --json,
vibe --prompt — none expose quota), a caching layer to avoid re-polling,
and a latency budget for a pre-spawn network call. Implementation cost
high; v0.1 value zero.
Strategy: defer the FEATURE (data ingestion path), not the CODE (evaluation
logic). evaluateSoftTriggers is small, well-tested via unit tests that
inject snapshots directly (test-features.mjs:3617-3665), and
architecturally correct. v1.x reactivation requires only wiring the
data path — evaluation stays untouched.
Changes (3 files, +25 / -1):
1. docs/adr/0004-fallback-engine.md +15 — new Amendment 2 block at top
of doc (after Amendment 1, before § Context, matching D11/D15/D16/
Amendment 1 placement convention):
- Finding (cold-audit round-2 F2 + 3 concrete code-state facts)
- Decision (defer; keep evaluation code inert-but-correct)
- Rationale (3-point cost/value analysis)
- Effect on § Trigger taxonomy (inline deferral note appended; design
prose preserved)
- What v1.x reactivation looks like (3 concrete steps; no rewrite needed)
- Procedural mechanism (CC 开发铁律 v1.6 § 10.x — round-2 caught it)
Plus an inline "📋 Deferred to v1.x (Amendment 2)" sub-bullet in
§ Trigger taxonomy → Soft triggers entry. The 3 threshold descriptions
are preserved verbatim — the architectural design remains the v1.x
intent.
2. lib/fallback/engine.mjs +8 / -1 — comment-only updates on the 2
`quotaSnapshot: null` lines in buildDefaultChain. Each now reads:
```
// quotaSnapshot stays null at v0.1 — soft triggers deferred to v1.x per
// ADR 0004 Amendment 2. evaluateSoftTriggers correctly short-circuits to
// false when quotaSnapshot is null. The polling path is not wired in v0.1.
```
No code logic changed. The previous misleading comment "populated at
runtime if provider.quotaStatus() is called" (which falsely implied a
live wiring) is replaced.
3. README.md +3 — two additions:
- Deferral callout immediately after the routing.soft_triggers config
example block, naming Amendment 2
- Implementation status table row: "Soft trigger data path
(quotaStatus() polling) | 📋 Planned (v1.x) | Evaluation logic
shipped + tested; data ingestion deferred per ADR 0004 Amendment 2"
Tests: 335/335 unchanged — pure docs + comment deferral, no behavior
change. Existing unit tests for evaluateSoftTriggers (which inject
snapshots directly) continue to validate the evaluation correctness
independent of the production ingestion path.
Authority:
- ADR 0004 self-amendment (Amendment 2 in-place)
- ALIGNMENT.md Rule 1 (Cite First) + CLAUDE.md § "Hard requirements"
item 1 — contract status changes require ADR amendment
- CC 开发铁律 v1.6 § 10.x — Round-2 Cold Audit caught this
Reviewer (Iron Rule v1.6 § 10.x Mode A, fresh-context opus, independent
of drafter): APPROVE. Verified all 3 framing claims independently:
(a) buildDefaultChain hardcodes null on both branches — confirmed at
engine.mjs:421 and :444; (b) zero quotaStatus() call sites in production
— `grep -rn "quotaStatus("` found only 3 definitions in provider plugins
+ JSDoc mentions; (c) evaluateSoftTriggers correctly short-circuits at
engine.mjs:139. Reactivation realism check: all 3 v1.x steps map to
existing surfaces (insertion points, hop shape, test fixtures).
Follow-up items (reviewer's non-blocking notes, NOT in this PR):
- README line 154 still reads "328-test suite"; current is 335 — pre-
existing doc-sync drift to pick up in D25 P3 batch
- v1.x ADR 0002 amendment may need to formally define authContext shape
(currently informal in the contract); pre-note as a dependency
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -415,7 +415,10 @@ export function buildDefaultChain(
|
||||
provider: hop.provider,
|
||||
model: hop.model ?? modelString,
|
||||
softTriggers: softTriggerConfig[hop.provider] ?? null,
|
||||
quotaSnapshot: null, // populated at runtime if provider.quotaStatus() is called
|
||||
// quotaSnapshot stays null at v0.1 — soft triggers deferred to v1.x per
|
||||
// ADR 0004 Amendment 2. evaluateSoftTriggers correctly short-circuits to
|
||||
// false when quotaSnapshot is null. The polling path is not wired in v0.1.
|
||||
quotaSnapshot: null,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -435,6 +438,9 @@ export function buildDefaultChain(
|
||||
provider: match.name,
|
||||
model: match.canonicalModel,
|
||||
softTriggers: softTriggerConfig[match.name] ?? null,
|
||||
// quotaSnapshot stays null at v0.1 — soft triggers deferred to v1.x per
|
||||
// ADR 0004 Amendment 2. evaluateSoftTriggers correctly short-circuits to
|
||||
// false when quotaSnapshot is null. The polling path is not wired in v0.1.
|
||||
quotaSnapshot: null,
|
||||
}];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user