The @tdd_expected_fail tag was already absent from the tag lines of both
features/tdd_context_tier_runtime.feature (bug #821) and
features/tdd_plan_apply_yes_flag.feature (bug #932). However, the feature
description and step-definition docstring for bug #821 still referenced the
@tdd_expected_fail tag and described the bug as unfixed.
Updated the feature description in tdd_context_tier_runtime.feature and the
module docstring in tdd_context_tier_runtime_steps.py to reflect that bug #821
has been fixed and these tests now serve as permanent regression guards. No
changes were needed for bug #932 as its files had no stale references.
Permanent tags @tdd_issue / @tdd_issue_821 and @tdd_issue / @tdd_issue_932
remain in place per the CONTRIBUTING.md TDD Issue Test Tags convention.
ISSUES CLOSED: #1206
Co-authored-by: Brent E. Edwards <brent.edwards@cleverthis.com>
Co-committed-by: Brent E. Edwards <brent.edwards@cleverthis.com>
Rename the TDD tag system from tdd_bug/tdd_bug_<N> to tdd_issue/tdd_issue_<N>
across the entire codebase. The tdd_expected_fail tag is unchanged.
The TDD expected-failure workflow is not limited to bug fixes — it applies
equally to any issue type (features, tasks, refactors). The _bug suffix was
misleading and narrowed the perceived scope. The new _issue suffix accurately
reflects that the TDD tagging system applies to any Forgejo issue.
Changes span 92 files:
- features/environment.py: validate_tdd_tags(), should_invert_result(), and
apply_tdd_inversion() updated — regex, variables, error messages
- robot/tdd_expected_fail_listener.py: _validate_tdd_tags(), _should_invert_result(),
start_test(), end_test() updated consistently
- 33 Behave .feature files: all @tdd_bug/@tdd_bug_<N> tags renamed
- 29 Robot .robot files: all tdd_bug/tdd_bug_<N> tags renamed
- 3 Robot fixture files renamed (tdd_bug_alone, tdd_missing_tdd_bug,
tdd_expected_fail_missing_bug_n) with content and references updated
- Tag validation tests and helpers updated (function names, command dispatch
keys, output strings, fixture references)
- CONTRIBUTING.md: section renamed from 'TDD Bug Test Tags' to
'TDD Issue Test Tags', all tag references and examples updated
- noxfile.py: comment references updated
- Step definition files, mock helpers, and benchmark files: docstring
references updated
ISSUES CLOSED: #965
Implement the missing runtime logic for the ACMS context tier service.
Previously only data models and manual promote()/demote()/evict_lru()
methods existed. This commit adds:
- Auto-promotion on access: get() now promotes fragments one tier up
when access_count reaches the configurable promotion_threshold
(default: 5 accesses). The access counter resets after each
successful promotion so fragments must accumulate fresh accesses
before the next tier transition.
- Staleness enforcement: new enforce_staleness() method demotes hot
fragments older than hot_ttl (default: 24h) to warm, and warm
fragments older than warm_ttl to cold. A snapshot of existing
warm-tier IDs prevents double-demotion in a single pass.
- Budget enforcement on store and promote: store() and promote()
now enforce TierBudget.max_tokens_hot by evicting LRU hot-tier
fragments until the token budget is met. The eviction loop uses
incremental token tracking to avoid recomputing the sum.
- Event emission: Added TIER_PROMOTED, TIER_DEMOTED, TIER_EVICTED
event types to EventType enum. All tier transitions emit
DomainEvent instances through the optional EventBus.
- Configuration: Added context_tier_promotion_threshold,
context_tier_hot_ttl_hours, context_tier_warm_ttl_hours settings.
The warm TTL setting also accepts the spec-defined env var
CLEVERAGENTS_CTX_WARM_HOURS as an alias.
- DI wiring: container.py now injects event_bus into
context_tier_service.
Review fixes applied (code review on PR #1150):
- C1: Reset access_count to 0 after each auto-promotion to prevent
chain promotion that bypassed the warm tier.
- C2: Call _enforce_hot_budget() inside promote() warm-to-hot path
so auto-promoted fragments respect the token budget.
- H1: Corrected _enforce_hot_budget() docstring: actual complexity
is O(n + n*k) not O(n), since min() scans remaining entries on
each eviction.
- M1: Added CLEVERAGENTS_CTX_WARM_HOURS as an additional env var
alias for context_tier_warm_ttl_hours per specification line 30555.
Review fixes applied (second code review on PR #1150):
- B-CRIT-1: Fixed data loss in promote() warm-to-hot: emit
TIER_PROMOTED before _enforce_hot_budget(), and if the promoted
fragment is evicted by budget, restore it to the warm tier instead
of silently losing it.
- B-HIGH-1: Fixed self-eviction on store(): fragments whose
token_count exceeds the entire hot-tier budget are now redirected
to the warm tier with a warning log.
- B-MED-1: Wrapped _emit_tier_event() in try/except so a failing
event bus does not break tier operations (best-effort emission).
- B-MED-2: Fixed event ordering so TIER_PROMOTED fires before any
budget-triggered TIER_EVICTED events.
- D-LOW-1: Fixed type hint in Robot helper (dict[str, Callable]).
- D-LOW-2: Added __all__ export to context_tiers.py.
- S-LOW-1: Added thread-safety docstring note to ContextTierService.
Review fixes applied (third code review on PR #1150):
- B-MED-1: Added TIER_DEMOTED event emission for oversized fragment
redirect in store(), closing the observability gap where the only
tier transition without event emission was the hot-to-warm redirect
for fragments exceeding the entire hot-tier budget.
- S-LOW-1: Added CLEVERAGENTS_CTX_HOT_HOURS as an additional env var
alias for context_tier_hot_ttl_hours, for consistency with the
warm-tier alias CLEVERAGENTS_CTX_WARM_HOURS.
- S-LOW-2: Added docstring note to enforce_staleness() reconciling
the hot-tier TTL with the specification statement that hot-tier
retention is "Until resource removed" (TTL controls tier placement,
not data retention).
Review fixes applied (fourth code review on PR #1150):
- B-HIGH-1: Reset access_count to 0 on demotion so that demoted
fragments must accumulate fresh accesses before re-promotion.
Without this reset, a previously popular fragment whose
access_count already exceeded the promotion threshold would be
re-promoted on the very next get() call, making staleness
enforcement ineffective.
Review fixes applied (freemo APPROVED review on PR #1150):
- #1: Removed all # type: ignore annotations from test files.
Fixed _EventCollector, _FailingBus, and _NullBus subscribe()
signatures to use Callable[[DomainEvent], None] matching the
EventBus protocol. Replaced dict-spread TieredFragment construction
with explicit keyword arguments and post-construction assignment.
- #2: Extracted runtime policy logic (enforce_staleness,
_maybe_auto_promote, _re_fetch_after_promotion, _enforce_hot_budget,
_emit_tier_event) into TierRuntimeMixin in tier_runtime.py to
reduce context_tiers.py toward the 500-line guideline.
- #3: Added fragment_id non-empty validation guard to promote() and
demote() per CONTRIBUTING.md argument validation policy.
- #8: Renamed _resolve to _re_fetch_after_promotion for clarity.
Removed @tdd_expected_fail from TDD tests (Behave + Robot) as the
bug is now fixed. All 3 TDD scenarios pass normally.
Tests: 27 Behave scenarios (24 feature + 3 TDD), 4 Robot integration
tests, 4 ASV benchmark suites.
ISSUES CLOSED: #821