Repository navigation
ci: deploy only what the box runs - #88
Merged
Merged
Conversation
* docs: record the layered backend * fix: address the backend migration review (#91) * fix: configure logging for the api process * fix: let a publisher's link claim a platform subdomain * fix: fail a link loudly on a non-numeric jev answer * docs: point stale docstrings at where the code moved --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
dimslaev
added a commit
that referenced
this pull request
Oct 19, 2026
* fix: run mypy and ty in pre-commit with the backend config * ci: enforce backend import layers * fix: name the exact claude-code-action tag in its pin comments * ci: deploy only what the box runs (#88) * docs: point the deploy README's env table at app/features * ci: deploy only what the box runs * test: check the deploy filter ships every path the units and the job use * docs: record the layered backend (#89) * docs: record the layered backend * fix: address the backend migration review (#91) * fix: configure logging for the api process * fix: let a publisher's link claim a platform subdomain * fix: fail a link loudly on a non-numeric jev answer * docs: point stale docstrings at where the code moved --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
dimslaev
added a commit
that referenced
this pull request
Oct 19, 2026
* test: colocate backend tests beside their modules * test: cover the curation tools, sign-in refusals, publisher lookups and the known-URL filter * fix: fail the daily report when its mail does not send * test: pin that the report reaches the send, and clean up the filter's publisher * ci: enforce backend import layers (#87) * fix: run mypy and ty in pre-commit with the backend config * ci: enforce backend import layers * fix: name the exact claude-code-action tag in its pin comments * ci: deploy only what the box runs (#88) * docs: point the deploy README's env table at app/features * ci: deploy only what the box runs * test: check the deploy filter ships every path the units and the job use * docs: record the layered backend (#89) * docs: record the layered backend * fix: address the backend migration review (#91) * fix: configure logging for the api process * fix: let a publisher's link claim a platform subdomain * fix: fail a link loudly on a non-numeric jev answer * docs: point stale docstrings at where the code moved --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
dimslaev
added a commit
that referenced
this pull request
Oct 19, 2026
* refactor: expose what entry needs through each feature's service * refactor: split the mcp tools into app/entry/mcp and fold the router into main * refactor: move scripts and the timer entrypoints into app/entry/cli * test: cover the mcp token gate end to end over http * test: cover the cli entrypoints' targets and exit codes * fix: fail the backup when pg_dump writes nothing * refactor: make app/entry pass strict mypy * fix: keep sentry off in development * chore: name the seed module in restore-db's hint without backticks * docs: say what tests-start.sh does with its argument * test: return the tool result's error flag and text from the gate tests' helper * fix: stop importing the email module from configuring the root logger * fix: require the alembic that reads its config from pyproject * test: check the collect run leaves the root logger alone * docs: say where command-line entrypoints live * refactor: name the newsletter service alike in every mcp tool * test: colocate backend tests beside their modules (#86) * test: colocate backend tests beside their modules * test: cover the curation tools, sign-in refusals, publisher lookups and the known-URL filter * fix: fail the daily report when its mail does not send * test: pin that the report reaches the send, and clean up the filter's publisher * ci: enforce backend import layers (#87) * fix: run mypy and ty in pre-commit with the backend config * ci: enforce backend import layers * fix: name the exact claude-code-action tag in its pin comments * ci: deploy only what the box runs (#88) * docs: point the deploy README's env table at app/features * ci: deploy only what the box runs * test: check the deploy filter ships every path the units and the job use * docs: record the layered backend (#89) * docs: record the layered backend * fix: address the backend migration review (#91) * fix: configure logging for the api process * fix: let a publisher's link claim a platform subdomain * fix: fail a link loudly on a non-numeric jev answer * docs: point stale docstrings at where the code moved --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
dimslaev
added a commit
that referenced
this pull request
Oct 19, 2026
* refactor: split backend domains into app/features * refactor: type app/features for mypy strict * fix: keep links on a shared platform's subdomains with the aggregator * fix: drop a newsletter product whose picked link is past the search results * test: cover approve and reject against the schema, and publisher resolution edges * chore: point the end-of-file exclude at the moved email templates * refactor: tidy comments and test helpers from the features split * refactor: move mcp tools and scripts into app/entry (#85) * refactor: expose what entry needs through each feature's service * refactor: split the mcp tools into app/entry/mcp and fold the router into main * refactor: move scripts and the timer entrypoints into app/entry/cli * test: cover the mcp token gate end to end over http * test: cover the cli entrypoints' targets and exit codes * fix: fail the backup when pg_dump writes nothing * refactor: make app/entry pass strict mypy * fix: keep sentry off in development * chore: name the seed module in restore-db's hint without backticks * docs: say what tests-start.sh does with its argument * test: return the tool result's error flag and text from the gate tests' helper * fix: stop importing the email module from configuring the root logger * fix: require the alembic that reads its config from pyproject * test: check the collect run leaves the root logger alone * docs: say where command-line entrypoints live * refactor: name the newsletter service alike in every mcp tool * test: colocate backend tests beside their modules (#86) * test: colocate backend tests beside their modules * test: cover the curation tools, sign-in refusals, publisher lookups and the known-URL filter * fix: fail the daily report when its mail does not send * test: pin that the report reaches the send, and clean up the filter's publisher * ci: enforce backend import layers (#87) * fix: run mypy and ty in pre-commit with the backend config * ci: enforce backend import layers * fix: name the exact claude-code-action tag in its pin comments * ci: deploy only what the box runs (#88) * docs: point the deploy README's env table at app/features * ci: deploy only what the box runs * test: check the deploy filter ships every path the units and the job use * docs: record the layered backend (#89) * docs: record the layered backend * fix: address the backend migration review (#91) * fix: configure logging for the api process * fix: let a publisher's link claim a platform subdomain * fix: fail a link loudly on a non-numeric jev answer * docs: point stale docstrings at where the code moved --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
dimslaev
added a commit
that referenced
this pull request
Oct 19, 2026
* fix: percent-encode database credentials in the dsn * fix: declare the indexes and column types the migrations built * refactor: move tables into app/core/db * test: cover the schema against migrations, the engine and ledger writes * refactor: split backend domains into app/features (#84) * refactor: split backend domains into app/features * refactor: type app/features for mypy strict * fix: keep links on a shared platform's subdomains with the aggregator * fix: drop a newsletter product whose picked link is past the search results * test: cover approve and reject against the schema, and publisher resolution edges * chore: point the end-of-file exclude at the moved email templates * refactor: tidy comments and test helpers from the features split * refactor: move mcp tools and scripts into app/entry (#85) * refactor: expose what entry needs through each feature's service * refactor: split the mcp tools into app/entry/mcp and fold the router into main * refactor: move scripts and the timer entrypoints into app/entry/cli * test: cover the mcp token gate end to end over http * test: cover the cli entrypoints' targets and exit codes * fix: fail the backup when pg_dump writes nothing * refactor: make app/entry pass strict mypy * fix: keep sentry off in development * chore: name the seed module in restore-db's hint without backticks * docs: say what tests-start.sh does with its argument * test: return the tool result's error flag and text from the gate tests' helper * fix: stop importing the email module from configuring the root logger * fix: require the alembic that reads its config from pyproject * test: check the collect run leaves the root logger alone * docs: say where command-line entrypoints live * refactor: name the newsletter service alike in every mcp tool * test: colocate backend tests beside their modules (#86) * test: colocate backend tests beside their modules * test: cover the curation tools, sign-in refusals, publisher lookups and the known-URL filter * fix: fail the daily report when its mail does not send * test: pin that the report reaches the send, and clean up the filter's publisher * ci: enforce backend import layers (#87) * fix: run mypy and ty in pre-commit with the backend config * ci: enforce backend import layers * fix: name the exact claude-code-action tag in its pin comments * ci: deploy only what the box runs (#88) * docs: point the deploy README's env table at app/features * ci: deploy only what the box runs * test: check the deploy filter ships every path the units and the job use * docs: record the layered backend (#89) * docs: record the layered backend * fix: address the backend migration review (#91) * fix: configure logging for the api process * fix: let a publisher's link claim a platform subdomain * fix: fail a link loudly on a non-numeric jev answer * docs: point stale docstrings at where the code moved --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
dimslaev
added a commit
that referenced
this pull request
Oct 19, 2026
* refactor: move shared backend mechanism into app/core * refactor: reword the check_link module docstring * fix: read a feed date with no timezone as utc * test: cover token rejection, the daily mail send and github lookups * test: spell unparsable the way typos expects * refactor: move tables into app/core/db (#83) * fix: percent-encode database credentials in the dsn * fix: declare the indexes and column types the migrations built * refactor: move tables into app/core/db * test: cover the schema against migrations, the engine and ledger writes * refactor: split backend domains into app/features (#84) * refactor: split backend domains into app/features * refactor: type app/features for mypy strict * fix: keep links on a shared platform's subdomains with the aggregator * fix: drop a newsletter product whose picked link is past the search results * test: cover approve and reject against the schema, and publisher resolution edges * chore: point the end-of-file exclude at the moved email templates * refactor: tidy comments and test helpers from the features split * refactor: move mcp tools and scripts into app/entry (#85) * refactor: expose what entry needs through each feature's service * refactor: split the mcp tools into app/entry/mcp and fold the router into main * refactor: move scripts and the timer entrypoints into app/entry/cli * test: cover the mcp token gate end to end over http * test: cover the cli entrypoints' targets and exit codes * fix: fail the backup when pg_dump writes nothing * refactor: make app/entry pass strict mypy * fix: keep sentry off in development * chore: name the seed module in restore-db's hint without backticks * docs: say what tests-start.sh does with its argument * test: return the tool result's error flag and text from the gate tests' helper * fix: stop importing the email module from configuring the root logger * fix: require the alembic that reads its config from pyproject * test: check the collect run leaves the root logger alone * docs: say where command-line entrypoints live * refactor: name the newsletter service alike in every mcp tool * test: colocate backend tests beside their modules (#86) * test: colocate backend tests beside their modules * test: cover the curation tools, sign-in refusals, publisher lookups and the known-URL filter * fix: fail the daily report when its mail does not send * test: pin that the report reaches the send, and clean up the filter's publisher * ci: enforce backend import layers (#87) * fix: run mypy and ty in pre-commit with the backend config * ci: enforce backend import layers * fix: name the exact claude-code-action tag in its pin comments * ci: deploy only what the box runs (#88) * docs: point the deploy README's env table at app/features * ci: deploy only what the box runs * test: check the deploy filter ships every path the units and the job use * docs: record the layered backend (#89) * docs: record the layered backend * fix: address the backend migration review (#91) * fix: configure logging for the api process * fix: let a publisher's link claim a platform subdomain * fix: fail a link loudly on a non-numeric jev answer * docs: point stale docstrings at where the code moved --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
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.
Stacked on #87 (step 7 of the backend migration plan).
What changed
deploy/rsync-filterlists what the box runs:backend/appwithouttest_*.py,__pycache__orapp/core/db/factories.py,backend/migrations,backend/baml_client,backend/pyproject.toml,backend/.python-version, rootpyproject.toml,uv.lock,.python-version,compose.yml,deploy/andfrontend/dist. Everything else is excluded.rsync -a --delete --delete-excluded --filter='merge deploy/rsync-filter' ./ /opt/agentique/.frontend/dist, so one sync ships it. The separate dist rsync step is gone. The job checks forfrontend/dist/index.htmlbefore syncing, so an empty or missing artifact fails the job and doesn't delete the live site.Deletion: why
--delete-excluded- *, plain--deletewould never delete excluded paths. Old files would stay on the box forever.--delete-excludeddeletes them. ThePrules protect.env,.venvand.gitfrom deletion, and rsync never scans inside them.frontend/distandfrontend-dist. Those are now shipped from the artifact. Today's--deletealready removed anything on the box that wasn't in the checkout, so files the box creates at runtime (such as__pycache__underapp/) are handled the same as before. The only new deletions are tracked files that are now outside the list..gitis protected even though the deploy never sends it. Today's excludes protected it, and keeping it costs nothing.Verified against what runs on the box
fastapi run ... app/main.py,python -m app.entry.cli.collect,python -m app.entry.cli.report,python app/entry/cli/backup_db.py, all from/opt/agentique/backend. EnvironmentFile is/opt/agentique/.env.prestart.shrunsapp.entry.cli.{wait_for_db,create_superuser,seed_tags,seed_articles}andalembic upgrade head.[tool.alembic] script_location = "%(here)s/migrations".uv sync --frozen --package appneeds the workspace root'spyproject.toml,uv.lockand every member'spyproject.toml.backup_db.pypasses-f <repo root>/compose.yml(parents[4]), so compose.yml has to be at the root.app/:sign_in.html,welcome.html,weekly_issue.html,tags.json,prestart.sh. The filter ships all of them.baml_clientimports frominlinedbaml.py. It doesn't readbaml_srcat runtime.conftest.pyimportsfactories.py, and neither ships.Simulation
These are the exact commands I ran in a scratch dir. The workspace was a copy of
git ls-files. The fake box had an old tree in it:.env,.venv/holding__pycache__andtest_x.py,.git/,pipeline/,docs/,backend/scripts/,frontend/src/, a stalefrontend/dist/old.jsandbackend/conftest.py.test -f frontend/dist/index.htmlexits 1 and nothing syncs..envis unchanged and.venvcontents are untouched.uv sync --frozen --package appsucceeds on a fresh.venv.uv run --env-file ../.env bash app/entry/cli/prestart.shwithENVIRONMENT=productionagainst a fresh Postgres 16 + pgvector db succeeds.uv.lockis unchanged afterwards.alembic checkreports no new upgrade operations.python -c "import app.main"passes, and so does importing eachapp.entry.cli.*module and all 112 modules underapp.fastapi run --workers 1 ... app/main.pyreturns 200 on the health check and/docs.alembic upgrade head --sqlfails in offline mode ona3b4c5d6e7f8_passwordless_user.py, which reads rows withconn.execute(...).all(). This was already true before this PR and doesn't affect the deploy, which runs migrations online.Tests added
backend/app/entry/cli/test_deploy_files.pytakes the rsync line from the workflow and runs it against the checkout's tracked files. Then it checks:-mmodule, and the box-owned EnvironmentFile and venvworking-directory:in the deploy job and thebashscript it runsapp/I broke the filter on purpose to check the tests catch it. Dropping
compose.yml,migrationsorbaml_clientfails them, and so does a prod module importingfactories. The test needs rsync 3 and skips without it. ubuntu-latest has 3.2.7.Bug fixes
docs: point the deploy README's env table at app/features
The newsletter env table still named
app/newsletter/broadcast.pyandapp/newsletter/routes.py. They are nowapp/features/newsletter/broadcast.pyandservice.py.Review
I ran the
code-reviewskill at high effort on the diff. Fixed:baml_client) from the checkout through the editable.pthand still pass. It now runs from the shipped tree and fails if any module came from the checkout.--delete-excludedsync meant a missing artifact would delete the live site. The job now checks forindex.htmlfirst.git ls-filesonly.-/@/+prefixes, ExecStart with no arguments and-mpackages. It handles them now.Units: installed by hand, on purpose
systemctl restart agentique-backend.cpfrom/opt/agentique/deployor the workspace. The runner user can write to both, so it could install a root unit with any ExecStart, which gives it root. This is the same reasonagentique-sqllives in/usr/local/bin. I don't propose it.Follow-ups
OnFailure=today. The pipeline reports through the 06:00 mail, so a failed report sends nothing and nobody notices. A clean fix is a smallagentique-alert@.servicethat mails throughapp.core.email, wired in withOnFailure=agentique-alert@%n.service. I left it out because it adds a unit and a CLI module.uv sync --frozen --package appinstalls the dev groups on the box (pytest, mypy, prek, zizmor).--no-devwould drop them. Check that nothing in prod needs a dev dependency first..claude/skills/curate/regression.mdhas two typos hits (syste,generat, from truncated titles). They're not in this diff, and pre-commit CI only checks changed files.test_read_endpoints_are_public[/search?q=agents]) fails because the sandbox proxy blocks the model2vec download (403). The other 699 pass.Generated by Claude Code