Repository navigation
fix: S3 streaming + Range, task heartbeat + after-commit enqueue, token rehash, scaffold fixes, QA follow-ups (#449–#472) - #463
Open
antosubash wants to merge 16 commits into
Open
antosubash wants to merge 16 commits into
antosubash wants to merge 16 commits into
Conversation
…en rehash, scaffold make kill + i18n keys - file_storage: stream S3 reads, get_range on backends, 206/416 Range support on downloads; S3 get() is awaited like filesystem (#453) - background_tasks: heartbeat() API + per-task stuck_after (#451); retries publish after commit, enqueue_after_commit helper (#452) - users: /auth/token persists the upgraded password hash (#457) - hosting/cli: regenerate i18n keys into the installed npm package in scaffolded apps, smpy host gen-i18n (#449) - cli: scaffolded make kill stops only this app's ports (#461) Closes #449 Closes #451 Closes #452 Closes #453 Closes #457 Closes #461 Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Deploying simple-module-python with
|
| Latest commit: |
f16f169
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://b978992f.simple-module-python.pages.dev |
| Branch Preview URL: | https://fix-issue-batch-449-461.simple-module-python.pages.dev |
…ag source, merged not-found handling, shared filesystem existence check Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
…mmit offload, direct aclose, defaultdict grouping Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
… no longer opens the full object Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
…y/_discard from file_body_response Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
The suite signs in ~49 times from 127.0.0.1, about 120 anonymous public-route requests a minute — the default rate_limit_public. A fast runner 429'd the last test's login page (test_user_search_treats_like_metacharacters_literally). Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
This was referenced Oct 14, 2026
Open
Columns declared sa_type=DateTime(timezone=True) bypassed SQLModel's UTCDateTime and came back naive on SQLite, so the API sent timestamps with no offset and browsers read UTC as local time. New simple_module_db.AwareDateTime (a UTCDateTime that also accepts naive-as-UTC on write) replaces it in AuditMixin/SoftDeleteMixin and the audit_log, users, permissions and tenants models. Migrations still render sa.DateTime(timezone=True): no schema change. Closes #468 Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
#467) A burst of confirm clicks sent one POST each, queuing duplicate retries (and, on SQLite, racing into 'database is locked'). retryExecution now shares the in-flight request per execution id; retrying again after it settles still works. Retrying an already-retried row on purpose stays allowed. Closes #467 Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
…all (#469) The 'executions exist outside the current search' copy showed for any empty filtered view. The index view now passes has_executions (one extra count query only for an empty filtered page) and the page uses it. Closes #469 Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
… deleted' (#470) Bulk delete compares the API's deleted count with the selection: all gone -> an info toast that the file(s) were already deleted; partial -> 'X of Y files deleted; the rest were already gone'. Closes #470 Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
…#471) A module inside the host dir gave a bare 'modules/foo', which parse_add_spec treats as a PyPI requirement. Also: env_values ignores indented comments and strips spaces around keys. Closes #471 Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
…472) Compose interpolates the password raw into SM_DATABASE_URL. The scaffolded .env.example now says it must be URL-safe, make docker-up refuses other characters with a clear message, and the installation guide documents it. Closes #472 Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
Keeps app_project.py within the 300-line cap after #472; _local_env already owns the .env/.env.example content. Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
…ord guard reads .env like compose The guard grepped raw lines, so CRLF endings, quoted values and inline comments blocked valid .env files, and it checked the first definition while compose uses the last. It now extracts the value as compose does and tests it by running make docker-up against a stubbed docker. Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
This branch has not been deployed
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.
Six bug fixes. Four of them (#451, #452, #453, #457) come from the gis-data-portal port assessment (tracking issue #460).
Changes
Range.S3Backendnow streams objects in 64 KiB reads instead of buffering the whole object. The body is closed on completion, on error and on client disconnect.get_range(key, start, end)on the backend contract (inclusive end), implemented for S3 and filesystem.Rangewith206. They return416 bytes */sizewhen the range is unsatisfiable, honourIf-Range, and fall back to a full200for multi-range or malformed headers.get_rangekeeps serving full200s.S3Backend.getwas an async generator, but callersawaitit, so S3 thumbnails and the streamed public path raisedTypeError. It is now awaited like the filesystem backend. A missing object returns 404 (was 500).from background_tasks import heartbeat; heartbeat(). Writes are throttled to one per 30 s. It is a no-op outside a task and never revives a row the sweep already marked stuck.@shared_task(..., stuck_after=<seconds>)sets a per-task threshold. The sweep reads it from the task registry, so no migration is needed.TaskExecutionrows commit. The bulk path publishes inasyncio.to_thread.enqueue_after_commit(db, task, *args, **kwargs). It returns the reserved task id and works on request sessions (on_commit) and on plain or worker sessions (SQLAlchemyafter_commit/ rollback events).POST /api/users/auth/tokennow saves the upgraded password hash, as the browser login already did. The users docs list the hash formats accepted on import: Argon2, and bcrypt$2a$/$2b$/$2y$, which is rehashed on the next sign-in.packages/i18n/srcis absent, the host writeskeys.generated.tsinto the installed@simple-module-py/i18npackage. It searches up the tree fornode_modules(hoisted or the flatclient_app/layout) and keeps the keys the package already ships. Addssmpy host gen-i18n(strict) and a scaffoldmake gen-i18n, whichmake installruns.make killpkills every uvicorn/vite on the machine (other projects included) #461:make killkilled other apps' servers. The scaffoldmake killnow only stops this app's ports:API_PORT ?= 8000, andVITE_PORTread fromSM_VITE_DEV_URLin.env(default 5050). The flat host Makefile gains the same target.Verification
make lint: green.make test-py: 4041 passed, 11 skipped, 1 xfailed.make test-js: green.StreamingBody.read;/auth/token;pkill.make -n killon a real scaffold resolves the ports fromAPI_PORTand.env.npm installed scaffold for i18n: keys.generated.ts never regenerates in scaffolded apps — app modules' t(keys.<ns>…) can't typecheck #449 (unit tests only), and the Postgres suite.Ship pipeline (optimize, review, QA)
/downloadstill opened the full object before fetching the range, which on S3 meant an extra fullget_objectper range read.FileStorageService.downloadnow takesopen_body=False, and a test proves a Range request never callsbackend.get.3c051f96:make lintpassed,make test-py4042 passed,make test-jspassed, and the e2e suite 49 passed.created_athas no timezone on SQLite..github/workflows/pr.yml): the e2e job now setsSM_RATE_LIMIT_PUBLIC=1000/minute. The suite signs in 49 times from one IP, about 120 anonymous requests a minute, which is right at the default limit. A fast runner returned a 429 login page to whichever test signed in last; this failed twice in a row on this branch. Nothing in this PR touches those routes.QA follow-ups fixed here (#467–#472)
database is locked. The cause is that the publish signal does a synchronous DB write on the event loop. Fixing that means moving Celery's publish hook off the loop, which is a design change, and Postgres is unaffected.simple_module_db.AwareDateTimereplacesDateTime(timezone=True)in the audit/soft-delete mixins and in the audit_log, users, permissions and tenants models. These columns read back timezone-aware on SQLite, so the API sends an offset. Migrations still rendersa.DateTime(timezone=True), so there is no schema change.has_executionsprop).smpyworkspace hint prints./modules/..., whichsmpy addreads as a path.env_valuesalso ignores indented comments.make docker-uprejects a non-URL-safePOSTGRES_PASSWORDwith a clear message, and the scaffolded.env.exampleand the docs say so.Second
/shippass over these fixes:make docker-uppassword guard rejected valid.envfiles with CRLF line endings, quoted values or inline comments, and checked the first definition where compose uses the last. It now reads the value the way compose does, covered by a 10-case test that runsmake docker-upagainst a stubbeddocker.Z.f16f1699:make lintpassed,make test-py4063 passed,make test-jspassed, and the e2e suite 49 passed.Closes #449
Closes #451
Closes #452
Closes #453
Closes #457
Closes #461
Closes #467
Closes #468
Closes #469
Closes #470
Closes #471
Closes #472
https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4