gitoriaLog in with ident

tickets

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commit7538b0347538b034mission 011 (ticket #25 web part): short page URLs /<slug> and /<slug>/<number>; /projects/<slug>, /projects/<slug>/<n>, /projects/<slug>/tickets/<n> and /tickets/<ref> answer 301 (current slug); slug pages moved behind hl:web's own routes after construction (they answered /__hl/* and /components/*.hl); reserved slugs refused; API paths unchanged. gate 293/0, connect 60/0, live-data copy 187/0, API old vs new: only page links differmre7538b034/reports/011-short-urls.md

5.4 KB

  1. # Report 011 (w083): tickets#25 web part — short URLs /<slug> and /<slug>/<number>
  2. **Where:** one commit on main in loreana:/media/STORAGE/projects/tickets.worldapi.org (on top of 0369106).
  3. Not pushed, not deployed. No `.env` read. Ports used: 8760–8764 and 8767–8769 (8765/8766 not touched). Every server I
  4. started was stopped by its PID. Nothing of mine is still running (checked with `ss -ltn`).
  5. ## What changed
  6. - **Pages:**
  7. - a project is at `/<slug>`;
  8. - a ticket is at `/<slug>/<number>`;
  9. - every page link uses these. In the API rows, the `href` and `projectHref` values and the Markdown URL lines use them too.
  10. - **301 redirects** to the short URL, using the project's CURRENT slug:
  11. - `/projects/<slug>`;
  12. - `/projects/<slug>/<n>`;
  13. - `/projects/<slug>/tickets/<n>` (the form the conductor sent);
  14. - `/tickets/<old n|uuid>`.
  15. A URL that names nothing gets a 404 with no Location. That includes a CR/LF injection attempt.
  16. - **Unchanged:**
  17. - the API paths;
  18. - `/projects/<slug>/settings`;
  19. - the filter pages `/project/<slug>[/state/<s>]` and `/state/<s>`.
  20. - **Reserved slugs** (`lib/projects.hl reservedSlugs`):
  21. - **List:** every first path segment that a route answers (14 in project.hl, plus `__hl` and `components`), plus `my`, `me`, `assets`, `sign-in`, `sign-out`, `logout`, `settings`, `search`, `help`, `about`, `admin`, `robots.txt`, `.` and `..`.
  22. - **Refused:** when a project is created and when a slug is changed (400 `field:"slug"`, "… is reserved").
  23. - **Proposals:** a slug proposed from a title skips them (`Inbox` → `inbox-2`).
  24. - **Gate check:** every route head in project.hl must be in the list.
  25. - **Existing collisions: none.** The 11 live slugs are tickets.worldapi.org, ident.worldapi.org, gitoria.worldapi.org, antcolony, hybriel, layouts.worldapi.org, components.hybriel.worldapi.org, calendar.worldapi.org, notes.worldapi.org, termuplex and tracker.worldapi.org. No project has an old slug.
  26. ## Route order: what hl:web really does
  27. - The creator's rule holds: the FIRST matching route answers, in the order they are written (router.hl `match`).
  28. - **Moving the wildcards to the bottom of OUR table is not enough.**
  29. - `new WebFramework(…)` APPENDS hl:web's own URLs to the table: `/__hl/app.css`, `/__hl/emit`, `/__hl/sw.js`, the manifest, the runtime, and the component modules `/components/<file>.hl`.
  30. - Even at the end of our table, `/:projectSlug/:ticketNumber` answered `/__hl/app.css` and `/components/ticket.hl` with a ticket page. I measured this.
  31. - **Fix:** both slug routes stay at the end of the table in project.hl (marked `lastPage = true`). Right after `new WebFramework(…)`, project.hl moves them to the end of `server.router.routes`.
  32. - **Why they stay in the table:** hl:web only serves a component's module when a route mounts it at construction. When I added the routes only afterwards, `/components/ticket.hl` returned HTML.
  33. - **Dev watcher:** the order survives its re-analysis. I checked it with watch on and a changed component.
  34. - **Control run:** without the move, the gate ends at 35 passed, 15 failed.
  35. - **Recommendation:** a Hybriel issue saying that hl:web should match its own URLs before the app's routes. Then the move can go. I did not file it.
  36. ## Tests
  37. | test | result |
  38. |---|---|
  39. | gate `tests/browser.mjs` (`.scratch/w083/gate.sh`) | before: **249 passed, 0 failed**; after: **293 passed, 0 failed** (44 new checks: README "Test", "Mission 011 part") |
  40. | `tests/connect.mjs` (temp copy, `.scratch/w083/connect.sh`) | **60 passed, 0 failed** (before and after) |
  41. | live-data copy: new `tests/shorturls-realdata.mjs` | **187 passed, 0 failed** (see below) |
  42. | the ticket's own test, by curl on the copy | `/tracker.worldapi.org` and `/tracker.worldapi.org/31` → 200 (titles right); both old forms → 301 to them |
  43. | API, old vs new code on the same copy (`.scratch/w083/apicompare.py`) | **0 different** (see below) |
  44. | `tests/letcount.py` | never-reassigned `let` = 0 |
  45. **Live-data copy:** taken from Byrodin on 2026-10-03 around 20:20 and deleted after the runs.
  46. - **Projects:** all 11. Each `/<slug>` shows the heading with its title, and `/projects/<slug>` returns 301 to it.
  47. - **Tickets:** 20, round robin over the projects. For each:
  48. - the short URL shows the ticket page with its subject;
  49. - `/projects/<s>/<n>`, `/projects/<s>/tickets/<n>` and `/tickets/<old n>` all return 301 to it, and following the redirect gives 200;
  50. - the Markdown URL line is the short URL.
  51. **API comparison:**
  52. - 1,348 answers (JSON and Markdown).
  53. - 17 are identical.
  54. - 1,331 differ ONLY in the page links (the `href`/`projectHref` values, the Markdown URL lines). `apiHref` and `settingsHref` are unchanged.
  55. ## Found
  56. - **hl:web route order:** see above. Written into STATUS "Lessons".
  57. - **My own slip, caught:** a `setsid … &` inside a `( … )` subshell forks, so `$!` was not the server's PID.
  58. - A leftover test server kept port 8763, and my second comparison run used it.
  59. - I found it, checked by its cwd and environment that it was mine, killed it by PID, and re-ran the comparison.
  60. - This is written into STATUS "Lessons".
  61. ## Not done / open
  62. - **The API part** (`/api/tickets/<x>`, `/api/projects/<id>`), as the mission said. The creator still has to say whether `<x>` is a global id.
  63. - **Not deployed:** deploying is the architect's job (`./deploy.sh`). There is no data change.
  64. - **Not touched:**
  65. - DECISIONS.md: it belongs to the librarian. Its links use the old form and still work through the 301.
  66. - The old one-off tests `tests/browser-pre20-parked.txt` and `tests/short-id-switch.mjs`.

Branches

Latest commits

  • 7538b034mission 011 (ticket #25 web part): short page URLs /<slug> and /<slug>/<number>; /projects/<slug>, /projects/<slug>/<n>, /projects/<slug>/tickets/<n> and /tickets/<ref> answer 301 (current slug); slug pages moved behind hl:web's own routes after construction (they answered /__hl/* and /components/*.hl); reserved slugs refused; API paths unchanged. gate 293/0, connect 60/0, live-data copy 187/0, API old vs new: only page links differmre
  • 0369106emission 010 (code order) 4/4: README file map + import order + 'Same output' test, STATUS (entry, lessons, how to verify), LOG, report; tests/realdata-baseline.mjs + realdata-compare*.py (a cleanup answers the same on live data), tests/letcount.pymre
  • a75e0279mission 010 (code order) 3/4: let only where a variable is reassigned or re-bound in a loop body (456 lets → plain declarations; Hybriel refuses a plain declaration inside a loop on its 2nd pass). gate 249/0, connect 60/0, real-data reads identical, a 50-step write sequence (API + faces) identical to the old codemre
  • e9d5c618mission 010 (code order) 2/4: one lib/ file per topic — store.hl split into projects / tickets (+ relations) / events / tickets-helpers, util.hl shared helpers (env, storage dir, URLs, sorts, Vienna time), the function routes out of project.hl into lib/api.hl (thin; auth/filters/Accept in api-helpers.hl), invite + member-removal logic out of the faces/routes into invites.hl / tickets.hl; project.hl is the map. /login/callback gets req + the session store by reference. gate 249/0, connect 60/0, real-data reads identicalmre
  • 97e269b5mission 010 (code order) 1/4: .hl files out of the root — lib/ (store, users, connections, invites, migrate, markdown, mdview, import = ticketfile, util = localtime, jsoncheck, api-helpers = api), tools/import.hl, components/styles.hl; import paths only. gate 249/0, connect 60/0, real-data reads identicalmre
  • 38f9d10ftickets: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); gate 249/0, connect 60/0mre
  • d3db6139tickets: Hybriel master 190aa11d (fc838894 GC correctness, #126 closure scopes, #127); gate 249/0, connect 60/0mre
  • bce182e3tickets: Hybriel master 7eea0d32 (#126 memory, #48 lambda copies its argument); migrate.hl lambdas take &logmre
  • 4137be0fantcolony#40: mission references point to the moved missionsmre
  • 9bfba36aantcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
  • c7bd2645tickets: Hybriel master 73267707 (#122 fixed); compactNow workaround removed (#110 covered)mre
  • 2ab91ee9tickets: gate checks rows appear once (session sync); re-vendor to ff51cf46 stopped on hybriel#122, stays 837fe120mre
  • e01c2b1dtickets#24: installable app (manifest, service worker, offline list), own icon; gate waits for the hello's pongmre
  • 752fbb7fdeploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
  • 38bdd5e4deploy.sh: never send .git or .gitignore to Byrodinmre
  • f12fa1bcState of 2026-09-27, before the move to gitoriamre