Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-4167Done

(motir-core) The rail's `Docs` row is a DEAD link — it still hard-codes `/docs` after MOTIR-3932 moved that surface to motir-marketing, while the `Legal` row beside it got the configured-url treatment

Found by motir run MOTIR-4130 while drawing the rail's bottom section (2026-09-02). It holds nothing up and is filed forward. Not absorbed into MOTIR-4130, whose Boundary is explicit that no .tsx is edited.

The defect

app/(authed)/_components/SidebarNav.tsx's bottom section, on origin/main 8d80ac8db:

{
  // The documentation area's front door (MOTIR-2570) — `/docs`, not
  // `/docs/api`: the index IS the area …
  icon: <BookOpen />,
  label: t('nav.docs'),
  href: '/docs',
},

Nothing in this repository serves /docs. Measured at 8d80ac8db:

checkcommandresult
a routegit ls-tree -r --name-only HEAD app | grep -i docsonly ApiDocsLinkPanel.tsxno page
a redirectgrep -n "source: '/docs'" next.config.tsno match (DOCS_REDIRECTS maps /api-docs/*/docs/*, i.e. /docs is a DESTINATION, never a source)
a rewritegrep -n "rewrites" next.config.tsnone defined — only async redirects()
middlewaregrep -n docs middleware.tsno match

So a signed-in user who clicks Docs in the rail gets a 404. The public reading surface moved to motir-marketing under MOTIR-3932; the row that points at it did not move with it.

Independent corroboration, from a guard that already knew. tests/design-asset-addresses.test.ts's KNOWN table carries eight /docs entries, every one reasoned "The public reading surface moved to motir-marketing (MOTIR-3932); this asset is a point-in-time record of the route as it was on app.motir.co." The guard has been recording that /docs is dead for every design asset that names it — while the shipped rail row kept pointing there, because no guard reads a .tsx href against the route tree.

Why the row beside it is the answer

The Legal row had exactly this problem and was fixed three hours before this was found. MOTIR-3909 / MOTIR-4010 moved the legal documents out of the repository and gave the row a resolver — lib/legal/links.ts's legalIndexUrl() — which returns the operator's configured absolute url, or null, and the row does not render at all when it is null:

...(legalIndexUrl
  ? [{ icon: <Scale />, label: t('nav.legal'), href: legalIndexUrl }]
  : []),

That is the shape this row wants, for the same reason: "a door pointing nowhere is worse than no door" (lib/legal/links.ts's own docstring). The two rows are adjacent in the same section, they lost their destination to the same architectural split, and only one of them was repaired.

Boundary

  • It does not move the docs surface. That already happened (MOTIR-3932).
  • It does not decide the hosting arrangement. Where motir-marketing publishes the docs is settled; this card reads it, it does not choose it.

Acceptance criteria

  • The rail's Docs row resolves to a page a signed-in user can reach, or it does not render — never a link to a 404. Which of the two is a function of configuration, exactly as the Legal row's is.
  • The mechanism matches the Legal row's unless there is a stated reason to differ: a server-side resolver returning string | null, resolved in app/(authed)/layout.tsx and passed to the client component as a prop, with the row spread-conditional on it. Do not invent a second pattern for the same problem in the same section.
  • Whatever the resolver reads is named in docs/decisions/public-surface-hosts.md, beside the legal manifest it sits next to.
  • A test asserts the row is absent when the resolver returns null, mirroring tests/components/SidebarNav-legal-door.test.tsx.
  • design/shell/rail-bottom-section.mock.html is updated to draw the Docs row's two arms, and its KNOWN entry in tests/design-asset-addresses.test.ts is removed — that entry exists only to record this defect, and it is asserted tight in both directions, so leaving it fails the suite once the address stops being drawn.
  • The other seven /docs KNOWN entries are left alone: they are point-in-time records of assets drawn before the move, which is a different thing from a live row.

Context refs

  • motir-core/app/(authed)/_components/SidebarNav.tsx — the dead row
  • motir-core/lib/legal/links.tslegalIndexUrl(), the pattern to mirror
  • motir-core/app/(authed)/layout.tsx — where the sibling resolver is called and threaded
  • motir-core/tests/components/SidebarNav-legal-door.test.tsx — the test to mirror
  • motir-core/tests/design-asset-addresses.test.ts — the KNOWN table, and the entry this card removes
  • motir-core/design/shell/rail-bottom-section.mock.html — the asset to update
  • MOTIR-3932 — the move that stranded the row
  • MOTIR-4130 — the card that found it; relates_to

Advisory dispositions

  • No blocked_by is owed to MOTIR-4130, and here is the command that settles it rather than the assertion alone: this card edits SidebarNav.tsx, lib/, app/(authed)/layout.tsx and tests/, none of which MOTIR-4130 touches (git show --stat on its branch is design/** plus one tests/design-asset-addresses.test.ts entry). The one file both name is that guard's KNOWN table, where MOTIR-4130 ADDS the entry this card REMOVES — a dependency in the ordering sense, which is what relates_to plus the criterion above records. If this card runs first, the entry is simply never added.