deploy foundation: push-based deploy.sh, spec-007, v3.0.0
This commit is contained in:
@@ -54,6 +54,11 @@ Decisions inside the set architecture. D-NNN, never renumbered.
|
||||
fact-level erasure ships with FDB-007 structured memory — stated in
|
||||
the user-facing confirmation, not hidden. (Superseded by D-014:
|
||||
erasure now covers facts, observations and episode traces.)
|
||||
- **D-015** — Deploys are push-based from the dev machine
|
||||
(`git archive <tag> | ssh`), not pull-based: no deploy keys or git
|
||||
state on the hosts, the artifact is exactly the tag tree, untracked
|
||||
live config survives in-place extraction. Trade-off: deploys need
|
||||
the dev machine; acceptable for a one-operator project.
|
||||
- **D-014** — Structured memory (FDB-007): observations are the only
|
||||
consolidation feed (independent of history trimming); consolidation
|
||||
returns NEW facts only (no wholesale rewrite — the lossiness of the
|
||||
|
||||
@@ -79,3 +79,7 @@ build: clean ## Build distribution packages
|
||||
|
||||
# CI targets
|
||||
ci: install-dev all-checks ## Full CI pipeline (install deps and run all checks)
|
||||
|
||||
# Deploy targets (SPEC-007)
|
||||
deploy: ## Deploy a tag to a host: make deploy HOST=ggg TAG=v3.0.0
|
||||
bash deploy/deploy.sh $(HOST) $(TAG)
|
||||
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy.sh <host> <tag> — push-based deploy from the dev machine (SPEC-007).
|
||||
# Rollback = run again with the previous tag (DEP-06); restore the
|
||||
# bot.db.pre-<tag> backup first when the schema version moved (PER-06).
|
||||
set -euo pipefail
|
||||
|
||||
HOST="${1:?usage: deploy.sh <fjerkroa|ggg> <tag>}"
|
||||
TAG="${2:?usage: deploy.sh <fjerkroa|ggg> <tag>}"
|
||||
|
||||
case "$HOST" in
|
||||
fjerkroa) SERVICE=kroa CONFIG=kroa.toml ;;
|
||||
ggg) SERVICE=luma CONFIG=ggg.toml ;;
|
||||
*) echo "unknown host: $HOST (known: fjerkroa, ggg)" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
# Tags only — no branch/commit deploys (DEP-01)
|
||||
git rev-parse -q --verify "refs/tags/$TAG" >/dev/null || { echo "not a tag: $TAG" >&2; exit 1; }
|
||||
|
||||
# Restaurant service window (DEP-05)
|
||||
if [ "$HOST" = fjerkroa ] && [ "${DEPLOY_FORCE:-0}" != 1 ]; then
|
||||
HOUR=$(TZ=Europe/Oslo date +%H)
|
||||
if [ "$HOUR" -ge 11 ] && [ "$HOUR" -lt 22 ]; then
|
||||
echo "refusing kroa deploy during service hours (11-22 Europe/Oslo); DEPLOY_FORCE=1 overrides (DEP-05)" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "== deploy $TAG -> $HOST (service $SERVICE, config $CONFIG) =="
|
||||
|
||||
# Code push: tag tree over ~/fjerkroa_bot; untracked config/state survives (DEP-01)
|
||||
git archive "$TAG" | ssh "$HOST" 'mkdir -p ~/fjerkroa_bot && tar -x -C ~/fjerkroa_bot'
|
||||
|
||||
ssh "$HOST" "set -e
|
||||
[ -x ~/venv-bot/bin/python ] || python3.11 -m venv ~/venv-bot
|
||||
~/venv-bot/bin/pip install -q --upgrade pip
|
||||
~/venv-bot/bin/pip install -q ~/fjerkroa_bot
|
||||
printf '#!/bin/sh\ncd %s/fjerkroa_bot || exit 1\nexec %s/venv-bot/bin/python -m fjerkroa_bot --config $CONFIG\n' \"\$HOME\" \"\$HOME\" > ~/fjerkroa_bot/start.sh
|
||||
chmod +x ~/fjerkroa_bot/start.sh
|
||||
~/venv-bot/bin/python -c 'import fjerkroa_bot'
|
||||
find ~/fjerkroa_bot -maxdepth 3 -name bot.db | while read -r db; do cp \"\$db\" \"\$db.pre-$TAG\"; done # DEP-03
|
||||
supervisorctl restart $SERVICE"
|
||||
|
||||
echo "== waiting for startsecs =="
|
||||
sleep 35
|
||||
|
||||
# Smoke (DEP-04)
|
||||
ssh "$HOST" "supervisorctl status $SERVICE | grep -q RUNNING" \
|
||||
|| { echo "SMOKE FAIL: $SERVICE not RUNNING on $HOST — rollback: deploy.sh $HOST <previous-tag> (DEP-06)" >&2; exit 1; }
|
||||
ssh "$HOST" "tail -80 ~/logs/supervisord.log | grep -q 'We have logged in as'" \
|
||||
|| { echo "SMOKE FAIL: no fresh Discord login line on $HOST — check logs, consider rollback (DEP-06)" >&2; exit 1; }
|
||||
|
||||
echo "== OK: $HOST runs $TAG — RUNNING + logged in (DEP-04) =="
|
||||
@@ -6,6 +6,9 @@ with date + result.
|
||||
|
||||
| ID | Date | Result |
|
||||
| --- | --- | --- |
|
||||
|
||||
_No manual-coverage requirements declared yet — DEP-NN arrives with
|
||||
FDB-017._
|
||||
| DEP-01 | 2026-07-13 | Verified with the v3.0.0 ggg deploy: tag-only refusal + untracked config/state survived. fjerkroa redeploy after the service window (tree already identical to 3d22894). |
|
||||
| DEP-02 | 2026-07-13 | Service map exercised: luma restart via script (v3.0.0); kroa mapping code-reviewed, exercised on its next deploy. |
|
||||
| DEP-03 | 2026-07-13 | bot.db.pre-v3.0.0 backup confirmed on ggg after deploy. |
|
||||
| DEP-04 | 2026-07-13 | Smoke gate exercised on ggg: RUNNING + fresh login line. |
|
||||
| DEP-05 | 2026-07-13 | Live-verified: kroa deploy attempt ~15h Oslo refused without DEPLOY_FORCE=1. |
|
||||
| DEP-06 | 2026-07-13 | Rollback documented (older tag + db backup restore); live drill pending — next release. |
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "fjerkroa-bot"
|
||||
version = "2.0"
|
||||
version = "3.0.0"
|
||||
description = "Discord bot with OpenAI responder for Fjærkroa and GGG"
|
||||
authors = [{ name = "Oleksandr Kozachuk", email = "ddeus.lp@mailnull.com" }]
|
||||
requires-python = ">=3.11"
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# SPEC-007 — Deploy + hosts
|
||||
|
||||
Two uberspace hosts, one release: **fjerkroa** (service `kroa`,
|
||||
config `kroa.toml`) and **ggg** (service `luma`, config `ggg.toml`).
|
||||
Deploys are push-based from the dev machine — `git archive <tag>`
|
||||
over ssh, no repo credentials on the hosts (D-015). Coverage here is
|
||||
`manual`: rows in `manual-verification.md` with date + result.
|
||||
|
||||
### DEP-01 — Deploys go by tag, in place, configs survive (coverage: manual)
|
||||
|
||||
`deploy/deploy.sh <host> <tag>` refuses unknown hosts and refs that
|
||||
are not tags. The tag's tree is extracted over `~/fjerkroa_bot` —
|
||||
untracked files (live TOML config, `history/`, news snapshot) are
|
||||
never touched. Dev-on-host drift ends here: hosts run tag content
|
||||
only.
|
||||
|
||||
### DEP-02 — Per-host service map (coverage: manual)
|
||||
|
||||
fjerkroa → supervisord program `kroa`, config `kroa.toml`; ggg →
|
||||
program `luma`, config `ggg.toml`. The script owns this map; restart
|
||||
via `supervisorctl restart <service>`.
|
||||
|
||||
### DEP-03 — Pre-deploy state backup (coverage: manual)
|
||||
|
||||
Before the restart, every `bot.db` under `~/fjerkroa_bot` is copied
|
||||
to `bot.db.pre-<tag>` on the host. Schema migrations are
|
||||
forward-only (PER-06) — rolling back past a schema bump means
|
||||
restoring this backup.
|
||||
|
||||
### DEP-04 — Smoke test gates the deploy (coverage: manual)
|
||||
|
||||
After restart the script fails loudly unless the service reports
|
||||
RUNNING and the log shows a fresh Discord login line. On failure the
|
||||
operator instruction is printed: deploy the previous tag (DEP-06).
|
||||
|
||||
### DEP-05 — No kroa deploys during service hours (coverage: manual)
|
||||
|
||||
Deploys to fjerkroa between 11:00 and 22:00 Europe/Oslo are refused
|
||||
unless `DEPLOY_FORCE=1` is set. The restaurant does not beta-test
|
||||
during dinner.
|
||||
|
||||
### DEP-06 — Rollback is a deploy of an older tag (coverage: manual)
|
||||
|
||||
`deploy.sh <host> <previous-tag>` is the rollback path; when the
|
||||
schema version moved, restore the DEP-03 backup first. Venv is
|
||||
rebuilt from the tag's pyproject either way.
|
||||
Reference in New Issue
Block a user