Skip to content

Commit 6af0da2

Browse files
Move MSDMD orchestration state to PostgreSQL VM
Replace the SQLite prototype with a PostgreSQL job ledger, leased VM worker, exact-SHA and clean-worktree MSDMD execution, transactional receipts, visible hmmm recovery, and verified independent PostgreSQL backup/restore tooling. Preserve repository authority and keep GitHub Actions optional rather than state-owning.
1 parent 543f1f3 commit 6af0da2

19 files changed

Lines changed: 1822 additions & 414 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
__pycache__/
22
.skill-lib/
33
.stack/
4+
.venv/
5+
*.py[cod]

README.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,19 @@ EPAC is currently in this pre-graduation state.
7878

7979
### Regenerate MSDMD without depending on hosted CI
8080

81-
The first backend/CLI vertical slice keeps MSDMD regeneration state outside GitHub
82-
Actions. It queues an exact source+generator identity in SQLite, executes locally,
83-
verifies the output digest, and writes a receipt.
81+
The backend/CLI keeps MSDMD regeneration state outside GitHub Actions. PostgreSQL on
82+
the VM stores exact source+generator identities, worker leases, attempts, receipts,
83+
dependency ordering, and visible `hmmm`. A non-root VM worker executes the pinned
84+
collector locally, re-verifies identities, and atomically replaces the repository's
85+
collection artifact.
8486

8587
```bash
86-
python -m frontend.cli.stackctl msdmd refresh ucns --root ../ucns
88+
python -m frontend.cli.stackctl msdmd refresh ucns --root /srv/stack-repos/ucns
8789
python -m frontend.cli.stackctl msdmd status
8890
```
8991

90-
See [`backend/README.md`](backend/README.md) for the orchestration contract and
91-
[`frontend/cli/README.md`](frontend/cli/README.md) for operator commands.
92+
See [`backend/README.md`](backend/README.md) for the orchestration and backup contract
93+
and [`frontend/cli/README.md`](frontend/cli/README.md) for operator commands.
9294

9395
## Refreshing a canonical view
9496

@@ -115,12 +117,17 @@ source commit in the message.
115117
authority.
116118
- hosted CI may execute work, but durable stack orchestration state must not depend on
117119
hosted CI remaining available.
120+
- PostgreSQL owns orchestration state, not repository artifacts or canon.
121+
- a database backup is complete only when its independently mounted mirror is verified;
122+
a second same-disk directory is not redundancy.
118123

119124
## hmmm
120125

121126
- `skill-lib/` remains a special operational root snapshot instead of using the same
122127
`libs/` + `research/` pair.
123128
- The exact graduation automation from stack-local project to independent repo + package
124129
is not yet implemented.
125-
- VM and GitHub-hosted MSDMD executors remain unimplemented; the durable local executor
126-
is the first vertical slice.
130+
- The actual VM PostgreSQL/service-account/storage state and independent backup device
131+
remain deployment observations until inspected on the VM.
132+
- A GitHub-hosted MSDMD executor remains optional and unimplemented; VM-local execution
133+
is the resilience baseline.

backend/README.md

Lines changed: 155 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,190 @@
11
# backend — durable stack orchestration
22

33
`backend/` is the stack-level orchestration plane. It exists because repository
4-
automation must remain inspectable and recoverable when a hosted executor such as
5-
GitHub Actions is delayed, unavailable, or unreliable.
4+
automation must remain inspectable and recoverable when a hosted executor such
5+
as GitHub Actions is delayed, unavailable, or unreliable.
66

77
The first vertical slice is MSDMD regeneration.
88

9-
## Contract
10-
119
```text
1210
request
13-
-> durable SQLite job
11+
-> PostgreSQL job on the VM
1412
-> exact source + generator identities
15-
-> selected executor
16-
-> repo-local generation
17-
-> artifact verification
18-
-> SHA-256 receipt
13+
-> leased worker attempt
14+
-> bounded repo-local generation
15+
-> source/generator re-verification
16+
-> atomic artifact replacement
17+
-> PostgreSQL + JSON SHA-256 receipt
1918
-> explicit retry / hmmm
2019
```
2120

2221
GitHub Actions is not the job database and is not required by this slice. The
23-
implemented executor is `local`; VM and GitHub-hosted executors remain `hmmm`
24-
until they implement the same job contract.
22+
implemented executor is the VM-local worker; a future GitHub-hosted adapter may
23+
claim the same durable contract without becoming the state owner.
24+
25+
## Authority boundary
26+
27+
PostgreSQL owns orchestration state only:
28+
29+
- requested jobs and idempotent identities;
30+
- worker leases and attempts;
31+
- receipts;
32+
- dependency ordering;
33+
- unresolved `hmmm`.
34+
35+
Repositories continue to own their source, canon, and generated artifacts. The
36+
worker coordinates one target at an exact commit using an exact skill-lib
37+
collector digest; it acquires no semantic authority from that access.
38+
39+
## Runtime requirements
40+
41+
- Linux VM with systemd.
42+
- PostgreSQL 14+.
43+
- Python 3.11+.
44+
- `git`.
45+
- target checkouts directly under `STACK_REPO_ROOT`.
46+
- a pinned skill-lib checkout at `STACK_SKILL_LIB_ROOT`.
47+
- an independent mounted filesystem/device for the verified backup mirror.
48+
49+
The production worker is intended to use local PostgreSQL Unix-socket/peer
50+
authentication and no outbound network access.
51+
52+
## Install
53+
54+
After observing the actual VM, follow [`deploy/VM_SETUP.md`](deploy/VM_SETUP.md).
55+
The application portion is:
56+
57+
```bash
58+
cd /srv/stack
59+
python3 -m venv .venv
60+
.venv/bin/pip install --upgrade pip
61+
.venv/bin/pip install -r backend/requirements.txt
62+
```
63+
64+
Configure `/etc/stack-orchestrator.env` from
65+
`deploy/stack-orchestrator.env.example`. Keep it mode `0600`.
2566

26-
Repository authority stays with the target repository. `backend/` coordinates a
27-
regeneration against an explicit checkout and a pinned skill-lib collector; it
28-
does not become metadata authority.
67+
Initialize PostgreSQL:
68+
69+
```bash
70+
set -a
71+
. /etc/stack-orchestrator.env
72+
set +a
73+
/srv/stack/.venv/bin/python -m frontend.cli.stackctl db migrate
74+
```
2975

30-
Operational state defaults to `.stack/state/jobs.sqlite3` and is intentionally
31-
untracked.
76+
`SQLite` is no longer a production fallback. One VM PostgreSQL service owns the
77+
orchestration state so leases, concurrent claims, retries, and recovery have one
78+
transactional boundary.
3279

33-
## Usage Guidance
80+
## MSDMD usage
3481

35-
From the stack repository root:
82+
Moving branch names are not execution identities. A queued job records the full
83+
source commit plus SHA-256 of `msdmd/collect.py`.
3684

3785
```bash
38-
python -m frontend.cli.stackctl msdmd refresh ucns --root ../ucns
86+
python -m frontend.cli.stackctl msdmd refresh ucns \
87+
--root /srv/stack-repos/ucns \
88+
--source-sha <40-hex-commit>
89+
3990
python -m frontend.cli.stackctl msdmd status
4091
python -m frontend.cli.stackctl msdmd explain <job-id>
4192
python -m frontend.cli.stackctl msdmd retry <job-id>
4293
```
4394

44-
Queue without executing:
95+
Queue without running immediately:
96+
97+
```bash
98+
python -m frontend.cli.stackctl msdmd refresh ucns \
99+
--root /srv/stack-repos/ucns \
100+
--source-sha <40-hex-commit> \
101+
--queue-only
102+
```
103+
104+
The persistent worker claims queued jobs with `FOR UPDATE SKIP LOCKED` and a
105+
lease:
45106

46107
```bash
47-
python -m frontend.cli.stackctl msdmd refresh ucns --root ../ucns --queue-only
48-
python -m frontend.cli.stackctl msdmd run <job-id>
108+
python -m frontend.cli.stackctl worker once
109+
python -m frontend.cli.stackctl worker run
49110
```
50111

51-
Run the verification suite:
112+
A regeneration becomes `hmmm`, not guessed-through success, when the worker
113+
finds an operator-resolvable boundary such as:
114+
115+
- target HEAD differs from the requested commit;
116+
- target HEAD changes during generation;
117+
- skill-lib collector digest differs from the queued identity;
118+
- unrelated worktree changes are present;
119+
- target is outside `STACK_REPO_ROOT` / `STACK_ALLOWED_REPOS`;
120+
- an expired worker lease is recovered.
121+
122+
A collector non-zero exit is `failed`. Successful output is written to a temp
123+
file, re-verified, hashed, and atomically replaced at the repository root.
124+
125+
## Backups
126+
127+
`ops/backup_postgres.sh`:
128+
129+
1. runs custom-format `pg_dump`;
130+
2. validates the dump with `pg_restore --list`;
131+
3. records SHA-256;
132+
4. retains a local recovery copy;
133+
5. requires an independent mounted backup root;
134+
6. refuses a same-filesystem mirror;
135+
7. copies, re-hashes, and re-validates the independent copy;
136+
8. applies local and mirror retention windows.
137+
138+
If the independent mount is absent, the script leaves the validated local dump
139+
in place but exits non-zero with `hmmm`; that is recovery material, not a
140+
complete backup.
141+
142+
The systemd timer runs daily with a randomized delay. Install it only after one
143+
manual backup and one restore drill succeed.
144+
145+
Restore drill:
146+
147+
```bash
148+
set -a
149+
. /etc/stack-orchestrator.env
150+
set +a
151+
backend/ops/restore_test.sh
152+
```
153+
154+
The script refuses to restore into the production DSN.
155+
156+
## Tests
157+
158+
Local unit tests require no PostgreSQL installation:
52159

53160
```bash
54161
python -m unittest backend.tests.test_orchestrator
55162
```
56163

164+
A PostgreSQL integration test is enabled only when a disposable database is
165+
explicitly supplied:
166+
167+
```bash
168+
STACK_TEST_DATABASE_URL='postgresql:///stack_orchestrator_test?host=/var/run/postgresql' \
169+
python -m unittest backend.tests.test_orchestrator.PostgresIntegrationTests
170+
```
171+
172+
Shell syntax:
173+
174+
```bash
175+
bash -n backend/ops/backup_postgres.sh backend/ops/restore_test.sh
176+
```
177+
57178
## hmmm
58179

59-
- VM executor and credential boundary.
60-
- GitHub Actions executor as an optional worker, never the durable state owner.
61-
- Organization-level affected-repository discovery and dependency ordering.
62-
- Persistent service/daemon; the first slice is intentionally operator-driven.
180+
- The actual VM distribution, PostgreSQL state, service account, and filesystem
181+
ownership are not observable from this chat and must be inspected before
182+
installation.
183+
- The independent backup device/remote-backed mount is not yet identified from
184+
this environment.
185+
- GitHub Actions executor adapter remains deliberately unimplemented; VM-local
186+
execution is the resilience baseline.
187+
- Organization-level affected-repository discovery and automatic dependency
188+
scheduling are represented as a next layer, not silently inferred.
189+
- Automatic commit/PR materialization of regenerated collection points remains
190+
separate from regeneration and receipt verification.

0 commit comments

Comments
 (0)