Files
shopdb-flask/.github/agent-workflow.md
benjamin.baker af133372b4 Gate endpoint UI refresh on fresh telemetry and land endpoint agent
A command reaching 'succeeded' only proves the agent ran the action, not that it posted a new telemetry snapshot. Reloading panels on command success alone re-rendered stale service/process rows, so a stopped process could still show running right after Refresh Status.

Add a lightweight telemetrymeta probe exposing lastreportedat and gate both the header Refresh Status action and inline row Start/Stop on that stamp advancing past a pre-action baseline. Polling is bounded so an offline or idle agent never hangs the button, and messaging distinguishes a confirmed refresh from a queued one.

Bring the .NET endpoint agent source (service, tray, installer) into the repo so Cameron can merge and test, with an agent/.gitignore keeping bin/obj/publish out. Includes the DncMain launch-path fix, tray single-file host env scrub, and best-effort file logger.
2026-08-28 15:07:20 -04:00

3.9 KiB

Agent workflow rules

Companion to copilot-instructions.md (which owns naming/style/architecture). These cut wasted turns. All are lessons from real sessions.

Environment - know these, do not rediscover

  • Shell is PowerShell: use ; not &&, 2>$null not 2>/dev/null.
  • API container shopdb-flask-wilm-api-1 (Flask, port 5001).
  • DB container shopdb-flask-wilm-db-1 (MySQL 8, root pw root_password_123).
  • SPA is baked into the image (not bind-mounted). Plugin code is bind-mounted read-only.
  • docs/ is stripped to a public wiki mirror - keep working docs out of it.
  • requirements.txt is hash-checked - never hand-edit.

Verify, don't react

  • The terminal "Command failed" banner fires on any non-zero exit or stderr output and is usually a false negative (curl --fail on a 400, pytest/npm/git writing to stderr). Judge success from real output.
  • Read container health via docker inspect --format '{{.State.Health.Status}}' plus a probe without --fail - never eyeball the exit code.

Container runs the image, not your edits

Before running anything in the container that must reflect a change:

  1. Frontend: npm run build, then docker cp frontend/dist/. shopdb-flask-wilm-api-1:/app/frontend/dist.
  2. Backend/scripts/templates: docker cp the files (or rebuild) first.

If a result contradicts a change you just made, suspect stale container code before re-deriving the fix.

Testing

  • Confirm the working directory once, up front.
  • Run the smallest test that proves the point; find the minimal polluter for isolation bugs. Run the full suite only at the end.
  • Clear stale local state before plugin/migration tests: if (Test-Path instance/plugins.json) { Remove-Item instance/plugins.json -Force }.
  • Naming-gate hits inside local venvs (.ci-venv/, env/) are not repo code - do not "fix" vendored libraries.
  • Final gates, exactly as CI: python -m pytest tests/ -q; cd frontend; npx vitest run; npm run build; cd ..; bash scripts/check-naming-and-style.sh.

Migrations and imports

  • Every migration: idempotent guard + real downgrade; must run clean on strict MySQL 8. If you rename indexes in upgrade(), update downgrade() to match.
  • Avoid duplicate indexes: index=True plus an explicit db.Index on the same column creates two.
  • Importers/seeders match by natural key and must be idempotent - prove it by running twice (expect updated, not created). Watch all-or-nothing writes.

Don't offer rollbacks you don't need

State current state plainly; surface a rollback path only for a real regression.

Wilmington (wilm) local-run known failures - do not re-investigate

Running the full python -m pytest tests/ -q on a Windows dev box (not CI) produces a stable set of environmental failures that are NOT code regressions. Treat these as expected locally; judge your change against CI/Linux instead:

  • test_core/test_security_headers.py::test_a_served_upload_is_sandboxed - PermissionError [WinError 32] (served upload file still locked by another process). Windows file-lock timing, not a headers bug.
  • test_plugin_contract.py::test_import_scan_covers_symlinked_plugins - OSError [WinError 1314] (symlink privilege not held). Needs admin/Developer Mode to create symlinks; irrelevant to plugin logic.
  • test_plugin_importguard.py::test_verified_source_signed_ok_tampered_raises - CRLF vs LF (b'# plugin\r\n' == b'# plugin\n'). Git autocrlf checkout, not a signing bug.
  • test_docs_publishable.py and test_docs_versions.py - the local docs/ tree is not the stripped public wiki mirror, so doc-count / PROJECT-MAP assertions fail. Expected off-CI.
  • test_core/test_public_read_surface.py::test_every_get_route_is_gated_or_named_public
    • pre-existing ungated-GET inventory drift; only act on it if YOUR change added a new GET route.

If a run shows ONLY these, the suite is green for our purposes. Anything outside this list is real - investigate it.