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.
3.9 KiB
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>$nullnot2>/dev/null. - API container
shopdb-flask-wilm-api-1(Flask, port5001). - DB container
shopdb-flask-wilm-db-1(MySQL 8, root pwroot_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.txtis 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 --failon 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:
- Frontend:
npm run build, thendocker cp frontend/dist/. shopdb-flask-wilm-api-1:/app/frontend/dist. - Backend/scripts/templates:
docker cpthe 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(), updatedowngrade()to match. - Avoid duplicate indexes:
index=Trueplus an explicitdb.Indexon the same column creates two. - Importers/seeders match by natural key and must be idempotent - prove it by
running twice (expect
updated, notcreated). 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.pyandtest_docs_versions.py- the localdocs/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.