Skip to content

Routing: ingest module configs/routes.ini centrally (fix the dead module-route config) - #129

Merged
WebTigers merged 1 commit into
mainfrom
feat/module-routes-ingest
Aug 17, 2026
Merged

Routing: ingest module configs/routes.ini centrally (fix the dead module-route config)#129
WebTigers merged 1 commit into
mainfrom
feat/module-routes-ingest

Conversation

@WebTigers

Copy link
Copy Markdown
Owner

The bug

Module configs/routes.ini had no consumer. Tiger_Application::buildConfig() merges only the core and app routes.ini into resources.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/skills and register's .well-known/tiger-verify.txt were both dead (proven by dumping the live router — neither route present).

The fix — the missing per-type consumer

Every other module .ini already 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's configs/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 → honors type, preserves newest-first order).
  • Tiger_Application_Bootstrap::_initModuleRoutes() — the seam: runs after the kernel /api + /auth routes (they keep priority), reads the active set from the DB (graceful pre-DB → all active). Works under the reserved /admin prefix — a native router route is matched before dispatch, so it wins over the default MVC resolution, which Tiger_Routing_Overrides can't (it refuses reserved prefixes).
  • Cleanup: blog moves from _initBlogRoutes ($router->addRoute() ×5) to a declarative modules/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, /admin all intact.

Tests

  • Unit ModuleRoutesTest: namespacing, inactive-skip, app-overrides-core, no-routes-ini-skip.
  • Integration BlogBootstrapTest: blog's real routes.ini contract + the blogAdmin-ordered-last shadowing rule.
  • Full unit (821) + integration green locally; CAPABILITIES regenerated; ROUTING.md documents the three route homes.

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

…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
WebTigers merged commit 5fe94e6 into main Aug 17, 2026
18 of 19 checks passed
@WebTigers
WebTigers deleted the feat/module-routes-ingest branch August 17, 2026 08:26
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant