chore: archive old plans, add new plan docs, update submodules
NexusGuard CI / server-core-test (push) Failing after 47s
NexusGuard CI / device-agent-test (push) Failing after 35s
NexusGuard CI / dashboard-ui-build (push) Failing after 31s

This commit is contained in:
datadunia
2026-05-28 02:50:43 +07:00
parent cf6ffba404
commit 075f915a66
17 changed files with 1199 additions and 3 deletions
@@ -0,0 +1,252 @@
# Optimize update.sh — Conditional Rebuild Only When Needed
## TL;DR
> **Quick Summary**: Modify `update.sh` to skip Docker rebuild, restart, and migration when no git/submodule/`.env` changes are detected. Prevents unnecessary 2-5 minute downtime on every run.
>
> **Deliverables**:
> - `update.sh` — refactored with conditional rebuild logic
> - `.update-state` — persistent state file (gitignored)
> - `.gitignore` — add `.update-state` entry
>
> **Estimated Effort**: Quick
> **Parallel Execution**: N/A (single file)
> **Critical Path**: N/A
---
## Context
### Original Request
User noticed `./update.sh` always runs `docker compose down`, `docker compose build`, `docker compose up -d`, and migration — even when no code changes exist. This wastes time (2-5 min) and causes unnecessary downtime.
### Metis Review — Key Findings
**Critical Gap #1**: `.env` changes (especially `VITE_API_BASE_URL` which is a `--build-arg`) are NOT tracked by git. Must hash `.env` content alongside git state.
**Critical Gap #2**: State file location must be `.gitignore`'d. Use `./.update-state` with atomic write (tmp + mv).
**Critical Gap #3**: No force-rebuild mechanism. Must add `--force` flag.
**Minor Gap #4**: `md5sum` not portable to macOS. Use `openssl sha256`.
**Minor Gap #5**: On `git pull` or submodule failure, should ALWAYS rebuild (safe fallback).
---
## Work Objectives
### Core Objective
Skip Docker rebuild/restart/migration cycle when git state, submodule state, and `.env` are unchanged from last successful update.
### Concrete Deliverables
- `update.sh` — refactored with state comparison + conditional rebuild
- `.update-state` — persistent state file (auto-created, never committed)
- `.gitignore` — add `.update-state` entry
### Definition of Done
- [x] Second consecutive run with no changes prints "No changes detected. Skipping." and exits in <5s
- [x] First run (or after any change) executes full cycle (pull, build, up, migrate)
- [x] `bash update.sh --force` always executes full cycle
- [x] `.env` change (esp. `VITE_API_BASE_URL`) triggers rebuild even without git change
- [x] Git pull failure triggers rebuild (safe fallback)
- [x] Corrupted state file treated as first run → always builds
### Must Have
- Conditional rebuild: only when git HEAD, submodules, or `.env` changed
- `--force` flag to bypass state check
- `.update-state` properly gitignored
- Clean output: clear `[+]` / `[-]` indicators for skip vs rebuild paths
### Must NOT Have (Guardrails)
- Do NOT change the `down → build → up` cycle pattern when rebuild IS needed
- Do NOT add per-submodule selective build (always build all or nothing)
- Do NOT add Docker health-check polling or auto-rollback
- Do NOT modify any file other than `update.sh` and `.gitignore`
- Do NOT use `docker-compose` (v1) anywhere
---
## Verification Strategy
> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed.
### Test Decision
- **Infrastructure exists**: YES (bash on Linux server)
- **Automated tests**: None (shell script test suite doesn't exist)
- **Primary verification**: Run on remote server, verify behavior with:
- `ssh root@172.20.8.191` — execute updated script
- First run: full cycle
- Second run (no changes): skip
- After `.env` edit: rebuild
- With `--force`: rebuild
---
## Execution Strategy
Single task, no waves needed — one file change.
---
## TODOs
_All tasks completed in commit `0b943ae`_
- [x] 1. Refactor `update.sh` — Add State Comparison & Conditional Rebuild Logic
**What to do**:
- Add at top of script (after `set -e`): define `STATE_FILE=".update-state"` path
- After `git pull` + `git submodule update --init --recursive --remote`:
1. Compute combined hash: `CURRENT_HASH=$(echo "$(git rev-parse HEAD)$(git submodule status)$(sha256sum .env)" | sha256sum | cut -d' ' -f1)`
2. Read previous hash from `$STATE_FILE` (if exists)
3. If `$CURRENT_HASH` matches previous AND `--force` not passed → skip rebuild
4. Otherwise → execute full `down → build → up -d → migrate → backfill` cycle
- Write new hash atomically: `echo "$CURRENT_HASH" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"`
- Handle `--force` flag: `if [ "$1" = "--force" ]; then ...`
- Handle missing/corrupt state file (treat as first run → build)
- Handle `git pull` failure (always build as safe fallback)
- Handle `git submodule update` failure (always build as safe fallback)
- Print clear `[+]`/`[-]` output for skip vs rebuild paths
**Must NOT do**:
- Do NOT change the `down → build → up` cycle pattern (preserve existing)
- Do NOT add per-service selective build
- Do NOT modify any existing command flags or environment sourcing
**Recommended Agent Profile**:
- **Category**: `quick`
- Reason: Single file, well-defined logic, no external dependencies
- **Skills**: `[]`
**Parallelization**:
- **Can Run In Parallel**: N/A (single task)
**References**:
- `update.sh` — Current file to refactor (52 lines)
- `.gitignore:41``connect_remote.txt` already listed; add `.update-state` nearby
**Acceptance Criteria**:
- [x] Script runs full cycle on first invocation (no `.update-state`)
- [x] Script skips full cycle on second invocation (no changes)
- [x] `bash update.sh --force` always runs full cycle
- [x] `.env` change triggers rebuild (hash detects difference)
- [x] Corrupted `.update-state` treated as first run
- [x] `git pull` failure → rebuild triggered (safe fallback)
- [x] All output clear and actionable
**QA Scenarios**:
```
Scenario A: Second run skips rebuild (no changes) ✅
Tool: Bash (interactive_bash via tmux on server)
Preconditions: State file created with correct hash
Steps:
1. ssh root@172.20.8.191
2. cd /root/Nexus-Guard-Suite
3. hash=$(echo "$(git rev-parse HEAD)$(git submodule status)$(sha256sum .env)" | sha256sum | cut -d' ' -f1)
4. echo "$hash" > .update-state
5. bash update.sh
Result: "No changes detected. Skipping build and restart." in <2s, exit 0
Evidence: .sisyphus/evidence/f1-update-sh-optimization.md
Scenario B: --force triggers rebuild even without changes ✅
Tool: Bash (interactive_bash via tmux on server)
Preconditions: State file exists
Steps:
1. bash update.sh --force
Result: "--force flag detected. Will rebuild." → full cycle
Evidence: .sisyphus/evidence/f1-update-sh-optimization.md
Scenario C: .env change triggers rebuild ✅
Tool: Bash (interactive_bash via tmux on server)
Preconditions: State file exists
Steps:
1. echo "# test change" >> .env
2. bash update.sh
Result: "State hash changed. Rebuilding." → full cycle
Evidence: .sisyphus/evidence/f1-update-sh-optimization.md
Scenario D: First run (no state) triggers rebuild ✅
Tool: Bash (interactive_bash via tmux on server)
Preconditions: No .update-state
Steps:
1. rm -f .update-state
2. bash update.sh
Result: "First run (no state file found). Full cycle required." → full cycle
Evidence: .sisyphus/evidence/f1-update-sh-optimization.md
```
**Evidence to Capture**:
- [x] Task 1 — skip-rebuild output
- [x] Task 1 — force-rebuild output
- [x] Task 1 — env-change rebuild output
- [x] Task 1 — corrupt-state output
> Evidence consolidated in `.sisyphus/evidence/f1-update-sh-optimization.md`
**Commit**: YES
- Message: `chore(ops): optimize update.sh to skip rebuild when no changes detected`
- Files: `update.sh`, `.gitignore`
- Pre-commit: review diff
- [x] 2. Add `.update-state` to `.gitignore`
**What to do**:
- Edit root `.gitignore` to add `.update-state` entry (alongside `connect_remote.txt` on line 41 or nearby)
- This prevents accidental commit of machine-local build state
**Must NOT do**:
- Do NOT change any existing `.gitignore` entries
- Do NOT add `.update-state` to submodule `.gitignore` files
**Recommended Agent Profile**:
- **Category**: `quick`
- Reason: Trivial one-line addition
- **Skills**: `[]`
**Parallelization**:
- **Can Run In Parallel**: YES (independent of Task 1's logic, but logically grouped in same commit)
- **Blocked By**: Commit groups with Task 1
**References**:
- `.gitignore:41` — Current state, `connect_remote.txt` already listed there
**Acceptance Criteria**:
- [x] `git check-ignore .update-state` returns the path (file is ignored)
- [x] No existing entries modified
**Evidence to Capture**:
- [x] git check-ignore verification
**Commit**: YES (group with Task 1)
---
## Final Verification
- [x] F1. **Behavioral Verification** — Run on server across all scenarios
## Commit Strategy
- **1**: `chore(ops): optimize update.sh to skip rebuild when no changes detected`
## Success Criteria
```bash
# First run (or after changes): full cycle
bash update.sh
# Expected: git pull, down, build, up -d, migrate
# Second run (no changes): skip
bash update.sh
# Expected: "No changes detected. Skipping build and restart." in <5s
# Force rebuild
bash update.sh --force
# Expected: full cycle regardless
# After .env edit
bash update.sh
# Expected: rebuild detected (new .env hash)
```