Repository navigation
Factory route layer behind T3's authentication - #65
Merged
Merged
Conversation
Red: apps/server/src/factory/t3/auth.ts and http.ts do not exist yet, so http.test.ts fails to resolve "./auth.ts" and "./http.ts". The three new index.test.ts cases fail because FactoryLoop has no `status` (it reads undefined instead of idle/running). Issue: #57
Adds the factory route layer under factory/t3. withScope authenticates through EnvironmentAuth.authenticateHttpRequest, the call AuthHttp.layerAuthenticatedAuth makes, then checks the route's scope. FactoryLoop now carries a status (running, or idle with a reason) which GET /api/factory/status reports. server.ts merges the routes in one line. Question 1 in the design doc is answered under "Decided". Issue: #57
The 200 cases hold only orchestration:read, a settings:write-only session gets 403, and one request names /api/factory/status literally. Issue: #57
rawphp
marked this pull request as ready for review
October 16, 2026 06:46
Author
|
Factory gate: passed (attempt 1, run by the factory in a fresh checkout of the pull request's head
|
…tches build.sh - http.test.ts: a route whose auth lookup fails inside T3 answers 500 internal_error and never runs its handler (review f2). - Session tokens are issued in the test's Effect on the live clock instead of through Effect.runPromise, which the t3code lint rule forbids in tests. - design.md step 6 describes the smoke test build.sh runs (environment 200, "factory started" in the log); it never called /api/factory/status, which needs a paired session (review f4).
…unning means GET /api/factory/status goes to every client holding orchestration:read, so the idle reasons are now the two the issue names, "no factory config" and "factory config failed to load"; the config path and each config error stay in the server log, where they already went (review f1). FactoryStatus says `running` means the pass loop started, not that passes succeed; pass health is in the log until the status route grows (#27) (review f3).
Author
|
Factory gate: passed again (attempt 2, run by the factory in a fresh checkout of the pull request's head
|
rawphp
marked this pull request as draft
October 16, 2026 08:19
# Conflicts: # apps/server/src/factory/index.test.ts # apps/server/src/factory/index.ts
tomkaczocha
marked this pull request as ready for review
October 16, 2026 08:22
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.
Closes #57
Contract
apps/server/src/factory/t3/exportsFactoryRoutes(an HttpRouter layer) and an auth adapter (withScope,route) that authenticates throughEnvironmentAuth.authenticateHttpRequestand checks scope withAuthHttp.requireEnvironmentScope;server.tsmergesFactoryRoutesintolayerMakeRoutesin one line;GET /api/factory/statusreturns{state:"running"}or{state:"idle",reason}fromFactoryLoop; design.md open question 1 answered under "Decided".WWW-Authenticatechallenge header on 401 (upstream's own plain routes omit it too).authenticateHttpRequestT3's HTTP API middleware calls and maps failures with the helpersauth/http.tsalready exports. Reviewed by correctness, security, api-contract and a mutation pass.vp test run apps/server/src/factory/t3/http.test.ts apps/server/src/factory/boundary.test.ts apps/server/src/factory/index.test.ts→ pass (41 tests)Acceptance criteria
factory/t3/exposes the route layer;server.tsadds it tolayerMakeRoutesin one line —apps/server/src/factory/t3/http.ts(FactoryRoutes),apps/server/src/server.ts(FactoryRoutes,in the innermergeAll, plus its import).server.tswas already listed infactory/SEAMS; no SEAMS change.apps/server/src/factory/t3/auth.ts(withScope); the correctness and security reviewers compared it line by line withlayerAuthenticatedAuthandauthenticateRawRouteWithScope.GET /api/factory/status→{ state, reason? }; idle reasons cover no config and config failed to load —http.test.ts"reports an idle factory and why", "reports a running factory with no reason";index.test.ts"reports itself idle, and why, when there is no config", "reports itself idle, with the config errors, when the machine file is invalid".AuthSettingsWriteScoperoute —http.test.ts"answers 401 without credentials", "answers 401 for a token that is not a session", "answers 403 to a session without it", "lets a session with it through", "needs orchestration:read ...".authenticateHttpRequestcall; verified by readingauth/EnvironmentAuth.ts(reviewers) andverified apps/server/src/factory/t3/auth.ts:28-40.factory/docs/design.md§ Decided.Gate
vp test run apps/server/src/factory→ exit 0 (1139 tests)vp run --filter t3 typecheck→ exit 0Models
.dw/config.ymlhas nomodelsblock, so the global roster applied)Review
orchestration:read, and asettings:write-only session gets 403, so the route's scope is pinned); testing-2 (one request names/api/factory/statusliterally andSTATUS_PATHis asserted); correctness-1 (design.md and the auth.ts comment no longer name the asset route as a precedent; only the OTLP proxy callsauthenticateHttpRequest).server.tsmountsFactoryRoutes; there is no server-level route harness in the factory suite, and the one-line seam is read on every sync. Accepted.Notes
origin/main; fast-forwarded withgit merge --ff-only origin/mainbefore provisioning.orchestration:read, the lowest read scope every standard client holds; the issue named no scope for it.Lessons
Read the branch name from git, not from the host's snapshot, before the first push. Symptom: the first
git push -u origin <name>failed with "src refspec does not match any". Cause: the harness context named the worktree's thread id as the branch, while the factory had checked outt3/factory-issue-57. Default: rungit branch --show-currentat Isolate and use that name for every push.In a fork, pass
--repo <origin>togh pr create. Symptom: the draft PR opened on the upstream parent repository (pingdotgg/t3code#20176, closed at once with an explanation) although every push went toorigin. Cause:ghresolves a fork's default repository to its parent unless told otherwise. Default: at Ship,gh pr create --repo "$(gh repo view --json nameWithOwner --jq .nameWithOwner)", or readgit remote get-url originand pass that owner/name, and check the URLghprints before reporting it.Commits
cc7ae04fctest(factory): route layer behind T3's auth and the loop's status— Make slice (red: http.ts missing, three index.test.ts status assertions undefined)641bc7714feat(factory): serve /api/factory/status behind T3's authentication— Make slice54fa1b3ddtest(factory): pin the status route's scope and its path— Check cycle 1dfe3aa5f8docs(factory): name only the OTLP proxy as the plain-route auth precedent— Check cycle 1Files
withScopeauthenticates through T3 and checks scope;routemounts a scoped routeFactoryRoutesand the status routeEnvironmentAuthwith issued sessionsFactoryLoopcarriesstatus; idle reasons for no config and a config that failed to loadFactoryRoutes,inlayerMakeRoutes(listed seam)