ReviewOS
@if (!pullRequest)

No such pull request

stacks/reportshq has no pull request numbered 36.

@else

also looking at this

stacks/reportshq

fix(auth): point the action registry at this app's Auth actions

#36
Merged glennmichael123 wants to merge fix/reportshq-auth-actions-registry into main
4 files +22 -7
@if (tab === 'conversation')
8 days ago

main has been red since 2026-09-22. Because ci.yml's deploy job has needs: [lint, typecheck, test, test-postgres, build], nothing has deployed since - production is still serving 50be0ca, the last green commit, so the auth rework in 437970e has never been live.

Seven tests were failing in both test and test-postgres. Four of them were one bug.

The bug: the app's Auth actions were shadowed by the framework defaults

storage/framework/auto-imports/actions.ts is tracked, and was last regenerated at 2dc1c68 - before 437970e added app/Actions/Auth/. So the four names that commit introduced were still mapped to the framework's own actions:

'Actions/Auth/LoginAction': '../defaults/app/Actions/Auth/LoginAction.ts',
'Actions/Auth/RegisterAction': '../defaults/app/Actions/Auth/RegisterAction.ts',

The router's string-handler resolver consults that map first and does not check whether an app file of the same name exists, so every route.post('/login', 'Actions/Auth/LoginAction') in routes/auth.ts resolved to the framework default. The entire auth rework was dead code at runtime:

Behaviour the app's action implementsWhat actually happened
10-character password policya 9-character password registered fine, 200
email lowercased before lookupUSER@x.test refused 401
email-taken pre-check, 409422 from a unique-constraint path
the app's own sign-in rate limitingnot applied at all
201 on register200

The generator already prefers app/Actions over the defaults - generatePathIndex scans path.appPath("Actions") before frameworkDefaultsDir("app/Actions") and keeps the first key it sees - which is why statushq's registry is correct. This file was simply never regenerated after the actions were added. Regenerated here on the locked 0.74.5; it changes only those four lines.

Worth knowing for next time: autoImportsAreStale() decides by mtime. A fresh CI checkout stamps every file at checkout time, so a stale committed registry is used as though it were current. The resulting failure is silent, because the name still resolves to a real action - just not yours.

The three stale assertions

All three were written against the client pre-paint guard that 437970e deleted along with resources/partials/AuthGuard.stx.

  • marketing-links scanned resources/partials/AuthGuard.stx, which no longer exists, so the test died in readFileSync rather than failing an assertion.
  • reports-surface required /var/www/reviewos-reviewos/releases/3e057f9/resources/views/layouts/app.stx:3620:2492: include error: Error loading include file AuthGuard: ENOENT: no such file or directory, open '/var/www/reviewos-reviewos/releases/3e057f9/resources/views/partials/AuthGuard.stx' ╭──────────────────────────────────────────────────────────────╮ │  ERROR  Include Error │ ╰──────────────────────────────────────────────────────────────╯ File: app.stx (line 3620, col 2492) Message: Error loading include file AuthGuard: ENOENT: no such file or directory, open '/var/www/reviewos-reviewos/releases/3e057f9/resources/views/partials/AuthGuard.stx' Context:  3618: 3619:

    main has been red since 2026-09-22. Because ci.yml's deploy job has needs: [lint, typecheck, test, test-postgres, build], nothing has deployed since - production is still serving 50be0ca, the last green commit, so the auth rework in 437970e has never been live.

    Seven tests were failing in both test and test-postgres. Four of them were one bug.

    The bug: the app's Auth actions were shadowed by the framework defaults

    storage/framework/auto-imports/actions.ts is tracked, and was last regenerated at 2dc1c68 - before 437970e added app/Actions/Auth/. So the four names that commit introduced were still mapped to the framework's own actions:

    'Actions/Auth/LoginAction': '../defaults/app/Actions/Auth/LoginAction.ts',
    > 3620: 'Actions/Auth/RegisterAction': '../defaults/app/Actions/Auth/RegisterAction.ts',

    The router's string-handler resolver consults that map first and does not check whether an app file of the same name exists, so every route.post('/login', 'Actions/Auth/LoginAction') in routes/auth.ts resolved to the framework default. The entire auth rework was dead code at runtime:

    Behaviour the app's action implementsWhat actually happened
    10-character password policya 9-character password registered fine, 200
    email lowercased before lookupUSER@x.test refused 401
    email-taken pre-check, 409422 from a unique-constraint path
    the app's own sign-in rate limitingnot applied at all
    201 on register200

    The generator already prefers app/Actions over the defaults - generatePathIndex scans path.appPath("Actions") before frameworkDefaultsDir("app/Actions") and keeps the first key it sees - which is why statushq's registry is correct. This file was simply never regenerated after the actions were added. Regenerated here on the locked 0.74.5; it changes only those four lines.

    Worth knowing for next time: autoImportsAreStale() decides by mtime. A fresh CI checkout stamps every file at checkout time, so a stale committed registry is used as though it were current. The resulting failure is silent, because the name still resolves to a real action - just not yours.

    The three stale assertions

    All three were written against the client pre-paint guard that 437970e deleted along with resources/partials/AuthGuard.stx.

    • marketing-links scanned resources/partials/AuthGuard.stx, which no longer exists, so the test died in readFileSync rather than failing an assertion.
    • reports-surface required /var/www/reviewos-reviewos/releases/3e057f9/resources/views/layouts/app.stx:3724:31: include error: Error loading include file AuthGuard: ENOENT: no such file or directory, open '/var/www/reviewos-reviewos/releases/3e057f9/resources/views/partials/AuthGuard.stx' ╭──────────────────────────────────────────────────────────────╮ │  ERROR  Include Error │ ╰──────────────────────────────────────────────────────────────╯ File: app.stx (line 3724, col 31) Message: Error loading include file AuthGuard: ENOENT: no such file or directory, open '/var/www/reviewos-reviewos/releases/3e057f9/resources/views/partials/AuthGuard.stx' Context:  3722: 3723:

      > 3724: Sign in to comment on this pull request. 3725:

      3726: @else
      and an #auth-required element on both report pages - that is, it asserted the browser guard was still there. Inverted to assert what the test's own name claims: the server reads the session, data is withheld from an unidentified visitor, and nothing gates in the browser. Matched as the directive and the element rather than the bare word, since both pages mention AuthGuard in a comment explaining its removal. Mutation-checked: re-adding /var/www/reviewos-reviewos/releases/3e057f9/resources/views/layouts/app.stx:3752:1: include error: Error loading include file AuthGuard: ENOENT: no such file or directory, open '/var/www/reviewos-reviewos/releases/3e057f9/resources/views/partials/AuthGuard.stx' ╭──────────────────────────────────────────────────────────────╮ │  ERROR  Include Error │ ╰──────────────────────────────────────────────────────────────╯ File: app.stx (line 3752, col 1) Message: Error loading include file AuthGuard: ENOENT: no such file or directory, open '/var/www/reviewos-reviewos/releases/3e057f9/resources/views/partials/AuthGuard.stx' Context:  3750: