Routing: ingest module configs/routes.ini centrally (fix the dead module-route config) - #129
Merged
Merged
Conversation
…umer)
Module configs/routes.ini had NO consumer — buildConfig() merges only core + app
routes.ini, so a module's pretty URL only worked if it called $router->addRoute()
from its Bootstrap (config-as-code). That left agent's /admin/settings/agent/skills
route (and register's .well-known/tiger-verify.txt) dead.
Add the missing per-type consumer, mirroring how acl.ini/navigation.ini/schedule.ini
are already discovered:
- Tiger_Routing_ModuleRoutes::collect()/apply() — scan every ACTIVE module's
configs/routes.ini, namespace each route <slug>__<name> (collision-proof; a module
can't stomp core or a peer; app-dir overrides same-slug core-dir), and register via
ZF1's native route factory (honors type, preserves newest-first order).
- Tiger_Application_Bootstrap::_initModuleRoutes() — the seam: runs after the kernel
(/api,/auth) routes, reads the active set from the DB (graceful pre-DB), applies.
Works under the reserved /admin prefix (a native router route is matched before
dispatch), which Tiger_Routing_Overrides cannot claim.
- Convert blog from _initBlogRoutes ($router->addRoute × 5) to a declarative
modules/blog/configs/routes.ini — no more route code in a Bootstrap.
- Now live-registered at boot (verified on dev): agent__agentSkillsAdmin,
blog__blog{Single,Category,Tag,Feed,Admin}, register__tigerVerify.
/admin/settings/agent/skills resolves (was 404); /blog/post, /api, /admin intact.
- Tests: collect() namespacing/inactive-skip/app-override (unit); blog routes.ini
contract + ordering (integration). ROUTING.md documents the three route homes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WebTigers
added a commit
that referenced
this pull request
Aug 17, 2026
…ake class) (#130) Tiger_Uuid::v7() filled the sub-ms bits with pure randomness, so two IDs minted in the same millisecond had no deterministic order. Any v7-keyed append log that sorts by id (or falls back to id as a created_at tiebreak) could therefore re-order two rows written in the same tick — the AgentServiceTest transcript flake (expected 'user', got 'assistant'), which has recurred across #68/#125/#129. Fix at the root (RFC 9562 §6.2 "monotonic random", method 2): rand_a becomes a 12-bit counter that increments for each same-ms mint (seeded randomly per ms so it doesn't leak a mint count; rolls into the next ms if it exhausts 4096). rand_b stays fully random, so uniqueness and index locality are unchanged, and the ID is still a valid v7 whose embedded timestamp timeOf() reads. `ORDER BY id` is now a stable insertion order for same-process appends — the case that matters (a conversation's turns are appended within one request). - UuidTest: assert STRICT full-string monotonicity over 5000 tight-loop mints (forces same-ms collisions) — the direct regression guard, replacing the old "full-string order NOT guaranteed within a ms" assertion. - Verified: the previously ~1/20-flaky transcript test now passes 40/40; full unit (821) + integration (1094) green; v7 still unique over 20k and version/variant-valid. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.
The bug
Module
configs/routes.inihad no consumer.Tiger_Application::buildConfig()merges only the core and approutes.iniintoresources.router.routes— module route files were never read. So a module's pretty URL only worked if it called$router->addRoute()from its Bootstrap (config-as-code, à la blog).agent's/admin/settings/agent/skillsandregister's.well-known/tiger-verify.txtwere both dead (proven by dumping the live router — neither route present).The fix — the missing per-type consumer
Every other module
.inialready has a central discoverer (Tiger_Acl_Acl→acl.ini,Tiger_Admin_Nav→navigation.ini,Tiger_Schedule→schedule.ini). Routes were the orphan. This adds the mirror:Tiger_Routing_ModuleRoutes::collect()/apply()— scans every active module'sconfigs/routes.ini, namespaces each route<slug>__<name>(collision-proof: a module can't stomp a core or peer route; an app-dir module overrides a same-slug core-dir one), and registers via ZF1's native route factory (addConfig→ honorstype, preserves newest-first order).Tiger_Application_Bootstrap::_initModuleRoutes()— the seam: runs after the kernel/api+/authroutes (they keep priority), reads the active set from the DB (graceful pre-DB → all active). Works under the reserved/adminprefix — a native router route is matched before dispatch, so it wins over the default MVC resolution, whichTiger_Routing_Overridescan't (it refuses reserved prefixes).blogmoves from_initBlogRoutes($router->addRoute()×5) to a declarativemodules/blog/configs/routes.ini— no route code in a Bootstrap.Verified at boot on tiger-dev
Router now contains
agent__agentSkillsAdmin,blog__blog{Single,Category,Tag,Feed,Admin},register__tigerVerify. Live:/admin/settings/agent/skills→ 302→login (was 404);/blog/post→ the admin list (not an article);/blog/:slug,/api,/adminall intact.Tests
ModuleRoutesTest: namespacing, inactive-skip, app-overrides-core, no-routes-ini-skip.BlogBootstrapTest: blog's realroutes.inicontract + the blogAdmin-ordered-last shadowing rule.Follow-on (separate): the general
/[module]/admin/*→/admin/[module]/*+/admin/settings/[module]/*normalization now has a clean declarative substrate to build on.🤖 Generated with Claude Code