Commit Graph
47 Commits
Author SHA1 Message Date
weichen a5f0ca107d Only count remote-unreachable commits as local work in finish guard
ci / test (pull_request) Successful in 2m19s
Why: 本地 main 停在 origin/main 顶端(克隆默认态)在 pin 为 feature 顶端时不在 pin
历史内,--branches 直判仍会误阻(本 worktree 自身收尾实测踩到)。
Evidence: 第五例回归(本地默认分支+克隆 reflog 不阻)全绿;五例套件+全套治理回归
GOVERNANCE-SUITE-OK;worktree 实际 finish 通过即端到端自证。
Impact: local_work_outside 候选提交先过 --not --remotes 过滤(远端可达即已保全);
stash 仍恒算本地独有。
2026-10-05 15:05:54 +00:00
weichen 91d25a3ed1 Fix two finish-guard false positives: IDE locks and remote-only refs
ci / test (pull_request) Successful in 2m21s
Why: 2026-10-05 两次实测踩到——①rglob("*.lock") 把 .git/cursor/ IDE 产物当 Git 锁
(五天陈锁阻断 worktree 回收);②pinned-history 用 --all --reflog 把 refs/remotes
计入,pin 在 feature 顶端的子仓永远无法 finish(被迫删远端引用+清 reflog 损害现场)。
Evidence: FinishGuardFixTests 四例全绿(误报修复+真实锁仍拦+独有提交仍保);
全套治理回归 91 例 OK;make test 全链证据入卡。
Impact: 仅 finish 模式两处判定;IDE 产物与远端引用不再误伤,本地独有工作保全语义不变。
Refs: 本仓 governance 收尾实录(EXT-1 与 governance-reliability 两轮)。
2026-10-05 15:00:20 +00:00
weichen c1fdf0141c Merge current main while preserving governance repairs
Why: main advanced with merged-task-name and legacy evidence guards during this task.

Evidence: SELF 44 lifecycle regressions pass after resolving both hunks; independent review repairs are recorded in the task card.

Impact: retains both task-start protections and the stronger JSON/legacy receipt reader, without rewriting either branch history.

Refs: Dev PR #211 and #212; .task/feature-governance-reliability.md
2026-10-05 13:11:50 +00:00
weichen b84667a697 Close review gaps in cleanup and evidence handling
Why: independent review found shared submodule metadata risk, quoted header leakage, stale JSON receipt blindness and missing abandon coverage.

Evidence: SELF 92 governance regressions pass; the original review receipt and replay output are recorded in the task card.

Impact: preserves external component worktrees, handles both evidence formats and adds targeted failure-path coverage; no product behavior changes.

Refs: .task/feature-governance-reliability.md; .task/reviews/governance-reliability.json
2026-10-05 13:07:10 +00:00
weichen 8af945a1d5 Make development gates preserve work and verifiable evidence
Why: cleanup, component synchronization, receipt recording and credential handling could contradict the documented development boundaries.

Evidence: SELF 75 isolated governance tests and source checks are captured in .task/feature-governance-reliability.md; combination and CI verification follow.

Impact: hardens local task and CI tooling, aligns policy and component documentation, and adds continuous regression tests without changing product behavior.

Refs: .task/feature-governance-reliability.md; policy/governance.md; policy/platform-admission.md
2026-10-05 12:36:02 +00:00
weichen 1e0508e8a7 Skip non-hex cells in the sync evidence scan
Why: 证据命令含 || 时 evidence.sh 把表格单元格里的管道转义为 \|\|,cmd_sync 按裸 |
切行把碎片当 HEAD 传给 git diff,fatal 128 在 set -e 下杀死 sync(本卡功能负例行实测触发,
task-sync 门禁被卡死)。
Evidence: bash -n 通过;含转义管道行的本卡上 bash scripts/task.sh sync 正常完成(WARN 照发、
exit 0);修复后 make test 全链重跑。
Impact: 仅 cmd_sync 证据扫描加十六进制过滤;WARN 语义不变。
Refs: 本卡 12:30-12:32 五次 sync 中毒复现记录。
2026-10-05 12:33:06 +00:00
weichen e58035a8e4 Guard task-start against reusing a merged branch name
Why: 合入后再 task-start 同名分支会从新 main 长出第二段历史并覆盖已合入任务卡
(2026-10-05 EXT-1 复核轮实测,两轮证据差点丢失);原校验只看本地分支能否创建。
Evidence: bash -n 通过;功能负例——start feature/ext-1-inproc-handler 被拒且无
worktree 副作用;make test 全链 exit 0;task-sync 基线 43d33aa。
Impact: 仅 scripts/task.sh cmd_start 增加已合入同名分支检查,其余子命令行为不变。
Refs: EXT-1 任务卡复核轮记录(.task/archive/feature-ext-1-inproc-handler.md)。
2026-10-05 12:30:25 +00:00
weichen 0123cec450 Sharpen the sync evidence warning to non-card changes only
Why: evidence rows are written before their containing card commit, so a naive
HEAD-diff would flag every task's evidence as stale and train people to ignore
the warning.

Evidence: bash -n clean; the live task-sync for this task exercises the new
path (warning fires only when a non-.task diff follows an evidence row's HEAD).

Impact: scripts/task.sh cmd_sync now excludes .task from the staleness diff;
AGENTS.md wording aligned (three-output evidence via make evidence).

Refs: task card evidence table; guidelines verification.md tool-written rule.
2026-10-05 10:51:39 +00:00
weichen efa701279f Fix evidence CMD quoting and record first tool self-tests
Why: the make-variable pass-through re-quoted CMD and broke any command
containing quotes (caught by the redaction self-test before it could run).

Evidence: redaction self-test now records 'token <redacted> hello' with quoting
intact (row sha256 aae6a895); negative 'false' case earlier recorded exit=1
row and propagated rc — both in the task card evidence table.

Impact: CMD now travels via environment (CMD="..." make evidence); SRC/TAIL
stay make variables; usage strings updated in Makefile/AGENTS.md/task.sh
template comment.

Refs: task card evidence table; guidelines draft.10 tool-written-evidence rule.
2026-10-05 10:48:31 +00:00
weichen ba83a17c11 Add evidence gates: facts registry, evidence tooling, and precheck checks
Why: declarations were passing as capability; hand-transcribed outputs flowed
through cards and PR bodies as if they were execution evidence, and stale
external facts (e.g. the dead git-panel host) kept being trusted until burned.

Evidence: guidelines draft.10 (PR Development-Guidelines#4, merged af199ee)
pinned here; policy/facts.md F1-F4 each re-verified on 2026-10-05 before
registration (endpoint version, token HTTP 200 via header only, SSH ls-remote,
dead-host negative probe); scripts syntax-checked (bash -n); tool self-tests
and make test recorded in the task card via the new make evidence.

Impact: new AGENTS.md section (SELF/REPLAY/GATE, tool-written evidence,
replay-on-review, zero-trust facts, honest-empty); make evidence/facts-verify;
precheck gains [hooks]/[facts], task-sync gains stale-evidence-HEAD warning;
task-start cards now embed the evidence table; gitlink advances to draft.10.

Refs: task card .task/feature-evidence-driven-gates.md; guidelines CHANGELOG
0.1.0-draft.10.
2026-10-05 10:47:27 +00:00
weichen 421ee87d04 Normalize the rebuild args comparison to stop spurious drop warnings
Why: adjust_args_for_bin strips the leading space of its return while the
rebuilt args keep it, so every rebuild carrying --dsn/--auth compared
unequal and warned that the legacy binary had the flags dropped even when
nothing was dropped — misleading during incident triage.

Evidence: bash -n clean; against the real dev binary the normalized
comparison reports no drop and the flags survive intact; make test green.

Impact: warning now fires only when flags are actually filtered; no
behavioral change to start/deploy.

Refs: PR #188
2026-10-05 02:23:32 +00:00
weichen 4215107126 Keep the DB binding and fail closed on svc.sh start rebuilds
Why: the 2026-10-05 dev outage — a restart with an explicit --addr rebuilt
the start args, and the rebuild branch dropped the persisted --dsn for the
dev env, so the binary resolved auth=auto to off on 0.0.0.0 and the new
listen guard refused to spawn; record_state then persisted the broken exec=
before the health probe, so bare starts kept failing.

Evidence: bash -n clean; sandbox registry with stub binaries — dbref DSN is
re-derived on rebuild (priority CLI > env > dbref), the pre-flight blocks
non-loopback without auth with actionable remedies, immediate-death starts
leave the previous exec= intact, and DSN masking covers all start-path log
lines; make test green.

Impact: dev/prod agent starts keep their DB binding across explicit-arg
rebuilds; failed starts no longer corrupt the registry; static/pg paths get
the same persist-after-probe ordering (pg already had it); no change to
deploy materialization or the binary guard semantics.

Refs: backend 8eda35f (listen guard), runtime/dev history.jsonl 01:23 fail
2026-10-05 02:16:20 +00:00
weichenandCursor f8e06090e6 Pin the SillyTavern borrow across the linked repositories
Why: The research record, HTML cleaning, listen guard, secret store, and context controls land together, and the parent pointers have to name those commits.
Evidence: Child commits are core bd63223, agent-native 3a110a7, ui d76a8e6, frontend 36b92ed, documents f3f823e, backend 42cca8f. svc.sh forwards the listen switches and info prints them.
Impact: A reverse proxy or a LAN hostname needs allowedHosts or an unauthenticated host check returns 403. Startup moves raw API keys into the secret table after a settings snapshot.
Refs: .task/feature-sillytavern-review.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-04 18:21:17 +00:00
weichen ecfed7be31 Add service config-file switching with schema validation to svc.sh
Why: beyond database binding, services needed a way to switch the JSON config
file they run with and have the new config take effect promptly; hand-editing
exec= risks restarting a service into an invalid config.

Evidence: in the task worktree with a real agent binary -- a config with an
unknown key is rejected by the binary's strict schema check before any state
change; a valid file binds via --config in exec= + conffile= (survives
record_state rewrites), restarts the running service, and the config's dsn
verifiably drives the process (wrong-password variant failed PG auth in the
log; correct variant connected and created 21 tables); editing the file and
re-running 'config <same file>' re-validates and restarts (pid changes);
'--clear' removes both the flag and conffile; db and config coexist in exec=;
view mode shows masked JSON content plus 'config explain' effective values
with masked dsn; list DB column also resolves dsns that live only inside the
config file. Full log in the task card.

Impact: new service-level action 'svc.sh <name> config [file | --clear]
[--no-restart]' for agent services; config-file content snapshots (masked,
--reveal to show) in info; a config-file line in status; conffile persisted
in svc.env. No agent binary changes.

Refs: task card .task/feature-svc-db-bind.md (same doc as PR #182);
docs/svc.md sections 2/4.5/4.6/6/10.1
2026-10-04 13:42:51 +00:00
weichen 843495e0d0 Add per-service database binding and fix single-dash flag detection in svc.sh
Why: info showed services and postgres instances but no service-to-database
correspondence, and switching an agent service to another database required
redeploying with a hand-built DSN. While wiring this up, adjust_args_for_bin
was found matching Go flag help with '--dsn' although Go prints '-dsn', so
deploy-built --dsn/--auth args were silently dropped on current binaries.

Evidence: full E2E in the task worktree with a real agent binary and a real
PostgreSQL 18 instance -- 't-app db bpg' persisted exec=/dbref, auto-restarted
(dbref survives record_state rewrites), and the agent created 21 tables in the
bound database; 'db bpg --db t2' auto-created and switched databases (21
tables in t2); '--clear' returned the service to embedded SQLite; --no-restart
and error paths behave; list gains a DB column, status a database line, info a
reverse bound-services line; legacy deployments without dbref resolve by DSN
host:port; single-dash detection proven with positive and negative cases;
regressions list/db dsn/db ls/info/history/--help pass; make test exit 0.
Full log in the task card.

Impact: new service-level action 'svc.sh <name> db [pg [--db X] | --clear]
[--no-restart]' for agent services (bind/switch/unbind/view), DB column in
list, binding lines in status/info, dbref persisted in svc.env, auto database
creation when the instance runs, and the adjust_args_for_bin fix restoring
deploy --dsn/--auth on current binaries. No agent binary changes.

Refs: task card .task/feature-svc-db-bind.md (same doc as the PR); docs/svc.md
sections 4.5/6.1/6.2/10.1
2026-10-04 13:30:50 +00:00
weichen 106ef07ef0 Add read-only svc.sh info report for services, databases, and config snapshots
Why: svc.sh could show a service table (list), per-instance DB names one at a
time (db ls), and per-service status, but had no single view answering "what
is running, which databases exist, and what is configured" -- the questions
asked when inspecting or handing over a machine.

Evidence: exercised in the task worktree runtime -- empty-state report; fake
agent/static/postgres registrations proving masking (exec DSN password,
password=, SVC_TAVILY_KEYS -> ***, non-secret values verbatim; --reveal shows
plaintext); a real postgres instance (db create r-pg --port 18901, start,
extra orders db, one backup) whose info section lists inner databases with
sizes, pgdata size and backup stats; regressions list/history/--help/help
lifecycle/make svc-info; info stdout carries the full report (stderr 0 bytes)
so it can be redirected as a snapshot. Full log in the task card.

Impact: new read-only `scripts/svc.sh info [name] [--tag T] [--reveal]`
command (also `make svc-info`): service table + running summary, postgres
instances incl. inner databases, per-service svc.env content snapshots plus
global .svc.env / --config / exported SVC_* vars, and recent events. Secrets
are masked by default. No deploy/lifecycle/db-ops behavior changes; `info`
becomes a reserved service name; docs/svc.md gains section 6.2 (former
6.2-6.4 shifted to 6.3-6.5).

Refs: task card .task/feature-svc-info.md (same doc as the PR); docs/svc.md
2026-10-04 12:42:49 +00:00
weichenandCursor 937152a563 Add an architecture edge ratchet and waiting-state tokens
Why: New cross-layer imports and unused exports could land unnoticed, and confirm-waiting reused the success color.
Evidence: bash scripts/lint-boundaries.sh passed, including a probe that a new edge fails. Both design-guard tests passed. Knip counts stay at the baselines.
Impact: make test-boundaries now checks architecture edges. Frontend and ui test targets also run the knip ratchet.
Refs: feature/architecture-baseline
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-03 16:02:57 +00:00
weichenandCursor 10bff94a6a Pin the D1 heads and cover the adapter modules
Why: Dev has to test the split modules and refuse a core import of a sibling library.
Evidence: bash scripts/lint-boundaries.sh printed boundaries ok. Full make test follows on this pin.
Impact: test-libs runs the intent, native, sqlite, and command modules. The sibling allowlist is empty.
Refs: D1
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-03 13:47:02 +00:00
weichenandCursor 88d5787f29 Compare pin trees offline and archive finished task cards
ci / test (pull_request) Failing after 1m0s
Why: Merge commits share a tree with the pinned feature commit, the import ratchet downloaded modules during CI, and task sync wrote the checkpoint onto the wrong card.
Evidence: check-pins accepts 6c0f1e8 (same tree as Backend squad 8e987bf) and rejects empty-tree 8db069d; both objects stayed local. An empty GOMODCACHE run of lint-boundaries matches the cached go list, 14 pairs. bash -n scripts/task.sh.
Impact: make pin no longer checks out Backend nested core or agent-command, and a failing pin check does not fail the target. task sync writes the branch card or warns. precheck reports completed-but-unarchived cards and card-close branches older than 24 hours.
Refs: feature/agent-stack-r0-r1
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-03 10:19:06 +00:00
weichenandCursor 978bf8bdae Check nested library pins and test the three agent libraries
Why: Dev could ship a combination whose nested gitlinks differed from the top-level pins, and make test never ran the three agent libraries.
Evidence: A go.work was measured and not adopted: workspace MVS selected newer golang.org/x crypto, exp, net, term, and text than backend with GOWORK=off. check-pins passes on the new pins and fails when backend's squad pin is 5cbac00.
Impact: make test adds pin checks and GOWORK=off vet/test for intent, native, and squad. make build still compiles inside backend; the pin check requires those gitlinks to match Dev.
Refs: R0
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-03 02:10:00 +00:00
weichenandCursor 09964e522b Pin the extension roadmap and downstream spike
Why: Downstream products need a published extension surface, contract checks, and a sample plugin that does not modify the base.
Evidence: scripts/lint-boundaries.sh printed boundaries ok. examples/downstream-rdm go test passed. Submodule pointers record the core, documents, backend, ui, and frontend commits for this roadmap.
Impact: make test runs the boundary lint first. make plugin-new scaffolds a declaration plugin. Version tags and remote downstream repositories are not created.
Refs: .task/feature-base-extension-roadmap.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-01 10:35:15 +00:00
weichen a42fff69e4 Deploy svc updates from an isolated remote source clone
Why: svc.sh update skipped services with a local@<sha> source whenever the
main checkout was dirty, and bare deploy built the current workspace. The
owner requires updates/deploys to be independent of the working tree
state, defaulting to the latest remote commit built outside the checkout.

Evidence: bash -n passes; commits dev lists from the source clone; bare
deploy --dry-run plans dev@<origin/main>; end-to-end "svc.sh update
svc-selftest" with a dirty tree updated a local@d64742c service to
dev@0be23f9 (built in runtime/.worktrees from
~/.cache/agent-system-svc/src, started healthy), then stopped and purged.
Full make test output recorded on the task card.

Impact: deploy now defaults to dev@<origin/main> resolved in the
script-owned clone (SVC_SRC_DIR, default ~/.cache/agent-system-svc/src);
--from local stays the only workspace-dependent source; update no longer
pulls the main checkout - local@/dev@ services redeploy from remote
latest, ahead/diverged/missing-on-remote still decline to act.
docs/svc.md and in-script help updated to match.

Refs: .task/svc-remote-source.md
2026-09-30 18:39:25 +00:00
weichen aeb9a6a8ea Harden task.sh materialization check and close push retry
Why: two recurring papercuts from 2026-09-30 sessions — (1) task-start treated a zero-exit submodule update as complete, but a worktree could still carry 12 drifted/uninitialized nested submodules that only surfaced at build time; (2) close ran a single git push, so a tunnel hiccup left the card-close branch unpushed and the auto-PR never created (hand-patched twice that day).
Evidence: bash -n clean; smoke start of a throwaway task measured nested drift count explicitly and abandon-path finish recycled worktree and branch cleanly (both PASS); fresh-clone commit identity probe also PASS after setting the global identity outside this repo.
Impact: scripts/task.sh cmd_start (+3-line status check) and cmd_close (one retry on push); no interface change.
Refs: .task/fix-followup-hardening.md
2026-09-30 17:11:40 +00:00
weichen 888aa9471c Retry card-close PR creation instead of failing silently
Why: cmd_close posted the PR with a single curl wrapped in
2>/dev/null || true, so any transient TLS/timeout on the git-home
HTTPS surface left the card-close branch pushed with no PR and no
diagnostics; this hit three times on 2026-09-30 and each needed a
manual API call to recover.

Evidence: bash -n clean; stub-server harness running the block
verbatim (sed-extracted from this file, executed inside the worktree
branch context): ok mode recovers the PR URL on first POST; exists
mode (POST always 500) retries 4x with visible stderr then recovers
the pre-existing open PR via GET ?state=open matching head ref;
fail mode against the retired git-panel host shows four visible
retry notices and falls through to the existing [next] hint.

Impact: scripts/task.sh cmd_close only; precheck/start/sync/finish
untouched; card-close merge authority unchanged (owner merges).
post-merge hook and task-finish auto-close inherit the fix through
the same function.

Refs: task card fix-close-pr-retry
2026-09-30 16:47:53 +00:00
weichen b46d890529 Merge remote-tracking branch 'origin/main' into fix/task-finish-close-followups 2026-09-30 16:01:38 +00:00
weichen c61920a8dc Stop task-finish from uninitializing shared submodule config
Why: cmd_finish ran git submodule deinit --all, but submodule.<name>.url entries live in the shared .git/config — finishing any task silently marked every other checkout and worktree uninitialized (observed twice on 2026-09-30: main checkout uninit=12 after each finish; a parallel session hit it minutes before this fix landed). The deinit serves no purpose: worktree removal with gitlinks is refused regardless, so cleanup already goes through rm -rf + prune. Also aligns AGENTS.md with observed hook behavior (post-merge fires on ff-only pulls too, and its inline close cannot see cards merged remotely until they are pulled), and ignores the ZCode-generated .zcodeignore that tripped the BUSY gate in every session.
Evidence: bash -n clean; abandon-path smoke of the patched script — start + FORCE_ABANDON=1 finish of a throwaway branch left shared submodule url config at 12 entries (pre-fix: 0), main checkout submodule status uninit=0, smoke worktree and branch fully recycled; the smoke close also backfilled a parallel session card left open (gitea-access-facts) via a card-close branch, proving the fallback path.
Impact: scripts/task.sh cmd_finish only (removes one line, updates comment), AGENTS.md card-close paragraph, .gitignore one entry. No product or gitlink change; make test not applicable (repo-level tooling/docs only). web_base default fix intentionally withdrawn from this PR — landed via parallel PR #73.
Refs: .task/fix-task-finish-close-followups.md
2026-09-30 16:00:31 +00:00
weichen 80cddd82d4 Fix stale Gitea host and record access facts in AGENTS.md
Why: the TASK_CARD_WEB_BASE default in scripts/task.sh still pointed at
git-panel.u1680832.nyat.app:30319, which now fails the TLS handshake
(curl exit 35), breaking card-close PR links and API calls; agents also
kept rediscovering hosts and credential locations from scratch each
session.

Evidence: curl https://git-panel...:30319/api/v1/version -> exit 35; curl
https://git-home...:30319/api/v1/version with token from ~/.secrets/gitea
-> {"version":"1.27.3"}; ssh -p 31411 git@git-ssh... -> 'Hi there,
weichen!' with key ~/.ssh/home_gitea (ED25519, fingerprint
SHA256:GYXaOXIMeloQ1fKSfdJ/ndgPQzs/Ix7Hk62ekfkfQ20, key name GMKtec).

Impact: task.sh default web base now resolves to the live host; AGENTS.md
gains a Gitea access-facts section recording hosts plus credential
locations only (no secret values, per baseline hard boundary 2). Follow-up
PRs propagate the same section to the other project repos.

Refs: task card feature-gitea-access-facts
2026-09-30 15:45:22 +00:00
weichen aecaa52e6b Merge remote-tracking branch 'origin/main' into feature/task-start-rootfix 2026-09-30 15:28:27 +00:00
weichen d3893609b7 Fix task worktree path derivation to anchor on the main checkout
Why: cmd_start derived the worktree location from $PWD, so running task.sh start from a repository subdirectory (or inside a task worktree) placed the new worktree at the wrong spot — e.g. scripts-wt-<slug> nested inside the repo.
Evidence: bash -n clean; functional smoke of the patched script from both the main checkout scripts/ subdir and the repo root created ../Agent-System-Dev-wt-<slug> as a sibling of the main checkout (paths asserted; pre-fix subdir run would nest inside the repo); git rev-parse --git-common-dir resolves to the main checkout from both locations (relative ../.git vs absolute).
Impact: scripts/task.sh cmd_start only; from the main checkout root the derived path is identical to before; new worktrees now always land as siblings of the main checkout regardless of invocation directory.
Refs: .task/feature-task-start-rootfix.md
2026-09-30 15:28:14 +00:00
weichen ac8db54ecb Add svc.sh update command: auto-detect repo advances and refresh services
Why:
After the repository moves forward, updating a running service meant
manually figuring out the new commit, rebuilding and redeploying by hand;
the user asked for the tool to detect and update automatically.

Evidence:
- "update [name...] [--check] [--all] [--no-fetch]": fetches origin,
  compares each service's registered source against the latest (Dev repo
  origin/main for local@/dev@ sources, newest Releases version for
  release@), prints a per-service table (current / latest / state), and
  without --check refreshes outdated running services by reusing the full
  deploy pipeline (stop → build/verify → start → health check; persisted
  exec= config and tags survive; update events appended to history).
- local@ services: auto git pull --ff-only origin main + make sync before
  rebuilding, guarded three ways (current branch == main, clean worktree,
  ff-only) — dirty trees or non-main branches are skipped with a warning,
  never touching uncommitted work.
- dev@ sources go straight to the remote main commit via an isolated
  worktree; release@ sources deploy the newest Releases version with
  sha256 verification; postgres and static --dir services are reported as
  not applicable; sources that diverged from or lead the remote are never
  force-updated.
- Verified end to end with five test services: dev@73b2802 → dev@ffda6d3
  (real isolated build, HTTP 200, tag/port preserved, worktree recycled),
  non-main-branch skip, stopped-service warning vs --all, release
  sha256-verified update, --check read-only (svc.env checksums unchanged),
  unregistered name exits 2.
- Fixed en route: a latent bug from the v2 refactor — materialize_dev_commit
  leaked submodule/make stdout into the captured worktree path, breaking
  every real dev@sha deploy since (cp: File name too long); build output
  now goes to stderr. Also fixed an unbound-variable crash in the update
  loop (local statement self-reference under set -u).

Impact:
New read-mostly operational command; no behavior change to existing
commands except dev@sha deploys now actually working end to end.
Makefile gains svc-update; --help and docs/svc.md document the command.

Refs: .task/feature-svc-auto-update.md(任务卡=PR 描述)
2026-09-30 15:22:33 +00:00
weichen 2c7f55bfe8 Document svc.sh comprehensively and layer its help system
Why:
svc.sh grew into a three-kind service manager with database operations,
but its only documentation was a flat --help wall of text; the user asked
for a complete usage document and a better help experience.

Evidence:
- docs/svc.md: 14-section manual (prerequisites, quick start, concepts
  and directory layout, per-command reference for service/global/db
  commands, deploy sources, database operations handbook, configuration
  layering, registry fields and event types, safety boundaries, exit
  codes, troubleshooting table, recipe index) — every claim cross-checked
  against the implementation from the previous two rounds.
- Help layering: no-args and -h print a one-screen overview; --help
  renders the header comment reorganized into 7 labeled sections; the new
  "help [topic]" command deep-dives eight topics (model, deploy,
  lifecycle, db, dbops, config, examples, safety); usage errors now show
  the short overview plus a pointer to --help / help / docs/svc.md.
  All topics verified to render; unknown topic exits 2.
- No runtime behavior changed: end-to-end db lifecycle regression
  (create → start → backup → status → stop → rm --purge) passes after the
  refactor.
- Makefile help and README's documentation section point to docs/svc.md.

Impact:
Documentation-only plus display-layer changes; command semantics,
exit codes and file formats are untouched. Maintenance note: behavior
changes must now update both --help and docs/svc.md.

Refs: .task/feature-svc-docs-help.md(任务卡=PR 描述)
2026-09-30 14:29:39 +00:00
weichen 69871136e5 Add db ops to svc.sh: port change, backup, restore, clone, cross-instance copy
Why:
The service manager could create and run postgres instances but had no
way to retarget a port explicitly, back data up, clone an instance to
another port, or move a database between instances — the user asked for
exactly these operations.

Evidence:
- "set <name> [--port N] [--host H] [--apply] [--tag T...]": explicit
  registration change; running postgres requires --apply (stop → rewrite
  registration → start); port availability checked against both
  registrations and live listeners. Verified: 8890→8895 with data intact
  and DSN updated, old port freed; refusal without --apply.
- "db backup <name> [--db X] [--out F]": pg_dump -Fc into
  runtime/<name>/backups/ (0600) with pg_restore --list self-check;
  "db backups" lists them.
- "db restore <name> --file F [--db X] [--force]": restores into a new db
  or refuses on a non-empty target unless --force (drop with FORCE +
  recreate + restore), reporting table counts afterwards. Verified all
  three paths.
- "db clone <src> <dst> [--port P] [--password PW] [--tag] [--online]":
  default physical clone (brief source stop, cp -a of pgdata minus
  postmaster files, new registration, source restarted on its own port);
  --online copies via dump/restore without stopping the source (verified
  source pid unchanged). Clone lands on the requested or derived port.
- "db copy <src> <dst> [--db X] [--force]": single-database logical move
  between two running instances with the same non-empty-target guard.
  "db ls <name>" lists databases.
- Fixed during verification: clone/copy leaked the CLI --port into the
  source restart path (source briefly came up on the clone's port); the
  address overrides are now cleared inside those commands.

Impact:
All operations stay inside runtime/<name>/, append to history.jsonl, and
reuse the existing safety constraints (own-process stop, port conflicts
reported not seized, secrets in 0600 files). Overwriting a non-empty
database requires an explicit --force everywhere. Makefile help line
mentions the new db subcommands.

Refs: .task/feature-svc-db-ops.md(任务卡=PR 描述)
2026-09-30 14:11:30 +00:00
weichen 60261a835a Generalize svc.sh into a multi-kind service manager with tags and persistence
Why:
svc.sh only managed agent-system environments; databases, standalone
frontend serving, per-service tags and reusable start configs were out of
scope, and the user asked for a unified service lifecycle on this host.

Evidence:
- Service model v2: kind=agent|static|postgres registered in
  runtime/<name>/svc.env (dotenv, mode 600); legacy entries without kind=
  are adopted as agent.
- postgres: "db create <name> --port/--user/--password/--db/--auth-mode/
  --tag" runs initdb (scram-sha-256, pwfile 0600), start/stop/restart use
  pg_ctl (-m fast, never SIGKILL on postmaster) with pg_isready checks and
  first-start database creation; "db dsn <name> [--reveal]" prints a
  composable DSN (password masked by default). Verified end to end against
  a real postgresql@18 instance: data survives restart, wrong passwords
  rejected, stop/restart clean.
- static: "deploy --kind static --from dev[@sha]|local" builds frontend
  dist into htdocs/ in an isolated worktree, or "--dir PATH" serves an
  existing directory; verified serving HTTP 200, restart, stop, dry-run
  plan, and explicit rejection of release sources.
- agent: unchanged three deploy sources plus --tag; bare start/restart now
  reuses the persisted exec= from svc.env (verified: same custom port and
  args across restart); old binaries lacking --dsn/--auth get those flags
  auto-omitted with a warning.
- "list|status [--tag]" shows NAME/KIND/STATE/PID/ADDR/SOURCE/TAGS for all
  registered services; "<name> status" gives per-kind detail; "rm <name>
  [--purge]" unregisters (and optionally deletes) only runtime/<name>/.
- Fixed during verification: psql arg mangling (-c -c), tags lost because
  record_state read svc.env inside its own redirect block, postgres
  --version field parsing, unbound vars for unregistered names.

Impact:
Same invariants as before: writes stay under runtime/<name>/ and
runtime/.worktrees/ (only --from local also writes main-checkout build
outputs, all gitignored), stops only own pidfile+cmdline-verified
processes, port conflicts reported not seized. Prompt output moved to
stderr so stdout (tables, DSNs) stays pipeable. Makefile gains svc-list.

Refs: .task/feature-svc-services-registry.md(任务卡=PR 描述)
2026-09-30 13:44:58 +00:00
weichen 8ba1b0e715 Add commit-picked deploys and a service registry to svc.sh
Why:
svc.sh only knew two hardcoded environments (dev/prod) and always built
the current workspace, so there was no way to deploy a specific Dev- repo
commit or a Releases artifact, and no record of what was actually started.

Evidence:
- scripts/svc.sh commits dev|release lists deployable commits (release
  entries annotated with version + devCommit; both mark HEAD and the
  environments already running them).
- deploy --from local|dev@<sha>|release@<version|sha> materializes the
  chosen source: dev commits build in an isolated worktree
  (runtime/.worktrees/<sha>, submodule pins verified to land exactly),
  release artifacts are sha256-verified against versions/<v>/manifest.json
  (a forged manifest is refused); --pick offers an interactive numbered
  choice and --dry-run prints the plan.
- Environment names are generalized (^[a-z][a-z0-9-]{0,15}$, derived port
  8800-9099 on collision-free scan); each env is self-contained under
  runtime/<env>/{bin,plugins,data} with svc.env (current state) and
  history.jsonl (append-only deploy/start/stop events). status scans all
  registered envs and history [env] [N] merges the event stream.
- Old artifacts that predate --dsn/--auth have those flags auto-omitted
  (probed via serve usage); legacy svc.env files still render in status.
- Verified end to end in the task worktree: stub-binary lifecycle, a real
  release@0.1.0 deploy (HTTP 200, source shown in status, commits marked),
  failure paths (sha mismatch, immediate exit, non-TTY --pick).

Impact:
scripts/svc.sh users gain multi-version side-by-side environments and
rollback by redeploying an older source; existing dev/prod defaults and
safety constraints (own-pidfile-only stop, port-occupancy check) are
unchanged. Environments deployed by the previous script need one fresh
deploy before start/restart works again. Makefile gains svc-commits and
svc-history targets.

Refs: .task/feature-svc-deploy-source-registry.md(任务卡=PR 描述)
2026-09-30 13:20:32 +00:00
weichen 2460e49157 Support --env config files with CLI override
Why: per-environment bring-up needs a persistent file for the SVC_*
knobs (model keys, addresses, tavily pool) instead of relying on shell
history or the single global .svc.env; CLI flags must still win for
one-off overrides like a different port.

Evidence: live matrix - .env.dev parsed (comments, paired quotes,
export prefix) with its address and model values applied and seeded;
--port 8831 overrode the file's port while keeping its 0.0.0.0 host;
missing file fails fast; .svc.env and --env layer correctly (overlap
keys resolve to --env, disjoint keys merge).

Impact: --env FILE / --env=FILE anywhere on the command line; dotenv
parsed safely line-by-line (valid identifiers only, never sourced);
precedence CLI > --env file > .svc.env > OS env > defaults; help and
make svc ARGS examples updated.

Refs: feature/svc-envfile task card.
2026-09-30 12:00:25 +00:00
weichen 81ac0ca5c2 Seed model and search settings on service start
Why: a freshly deployed environment boots with an empty settings store,
so the first run dies with "main model unconfigured" and the user has
to open the settings UI before anything works - the opposite of
one-command bring-up.

Evidence: live matrix - full seed (chat+lightweight+tavily) lands in
the settings store (API view shows baseUrl/model with the key masked),
restart without flags does not re-seed and the settings persist,
.svc.env sourcing seeds a fresh environment from the one-time config
file, and a no-flag start stays silent. Also wrapped a /proc read race
in pid_alive that printed tr noise during stop.

Impact: --model-base/--model-key/--model-name, --light-base/-key/
-name, --tavily-keys on start/deploy (idempotent, only provided
fields); SVC_MODEL_*/SVC_LIGHT_*/SVC_TAVILY_KEYS env vars; <repo>/
.svc.env one-time config file (gitignored) makes every future deploy
self-configuring; auth-protected instances fall back to a clear hint.

Refs: feature/svc-auto-seed task card.
2026-09-30 11:56:41 +00:00
weichen 8a494e87c7 Add CLI flags to svc.sh (addr/host/port/data/dsn/auth/mock/passthrough)
Why: the manager only took configuration from SVC_* environment
variables; binding a public interface or pointing at a database meant
exporting vars first, which is awkward for one-off deploys and
invisible in shell history review.

Evidence: live matrix on the worktree - --port (8801), --host 0.0.0.0
(bind verified via ss, health probe auto-maps to 127.0.0.1), --addr
whole-form, CLI-over-env precedence (--port beats SVC_DEV_ADDR),
--mock reaching the server cmdline, --dsn passthrough proven by the
postgres connect attempt in the log, -- passthrough (--artifacts), and
make svc ARGS passthrough. A set -e silent-exit trap in env_config was
caught by the first run and fixed (condition-as-last-statement).

Impact: scripts/svc.sh <env> [action] [--addr|--host|--port|--data|
--dsn|--auth|--mock|--plugins| -- <extra>]; precedence CLI > env vars >
defaults; help rewritten with examples; make svc gains ARGS; logs keeps
the positional line-count form. The real-world port guard held: a dev
instance started from the main checkout was refused with owner info,
untouched.

Refs: feature/svc-cli-args task card.
2026-09-30 11:50:24 +00:00
weichen 35d114307d Add the svc.sh environment service manager
Why: deploying a new build meant manually finding and killing the old
process, rebuilding and re-launching with the right flags; dev and prod
instances could collide on ports, data dirs or kill each other.

Evidence: live matrix on the worktree - dev deploy (stop -> make build
-> start with health check), redeploy swaps the pid and keeps seeded
data, prod deploys alongside dev on separate port/data with fully
isolated /api/projects, port takeover is refused with the owning
process named while the running env stays up, stop clears pidfile and
frees the port. A pid-capture bug (compound-background subshell wrote
the wrapper pid instead of the server) was caught and fixed during the
first live run.

Impact: scripts/svc.sh <dev|prod> [deploy|stop|start|restart|status|
logs]; runtime/<env>/{data,svc.pid,svc.log,svc.env} isolation; defaults
dev 127.0.0.1:8788 / prod 127.0.0.1:8787 overridable via SVC_* env
vars (incl. SVC_PROD_DSN for the PG tier); make svc ENV=... shortcut;
runtime/ gitignored. Safety: only processes started by the script are
stopped (pidfile + /proc cmdline double check).

Refs: feature/svc-env-script task card.
2026-09-30 11:38:43 +00:00
weichen dfcf8e4555 Ship the post-merge hook with its executable bit
ci / test (pull_request) Failing after 1m37s
Why: the hook landed as 100644, so `make setup` chmod left a mode-only diff that makes the main checkout permanently dirty and blocks task.sh close (dirty-tree guard).
Evidence: git status showed " M scripts/hooks/post-merge" with 0 insertions/deletions after make setup; task-finish tail reported the dirty-tree refusal.
Impact: mode 100644 -> 100755 only; no content change.
Refs: task card feature/card-autoclose-r1 (PR #16 follow-up)
2026-09-30 07:22:14 +00:00
weichen beaefb7549 Add task-card autoclose wiring: close subcommand, post-merge hook, gate reports
Why: 11 merged branches had left their task cards open (bookkeeping debt found on 2026-09-30); closure was manual and never triggered, so card status rotted after each merge.
Evidence: dogfood run of `task.sh close --fold` closed and archived the 11 cards (previous commit); temp-repo matrix 33/33 PASS covering detection, pending-branch idempotence, dirty/no-fold refusals, post-merge auto-close on merge-type pulls, worktree guard, and the full lifecycle (closure PR merge archives cards on main).
Impact: scripts/task.sh (+close, precheck [cards] report, finish-tail trigger), scripts/hooks/post-merge (new), Makefile (+task-close target, setup chmod), AGENTS.md rule; archive fixes correct PR links missed by the first dogfood run; no module or gitlink change.
Refs: task card feature/card-autoclose-r1
2026-09-30 07:12:54 +00:00
weichen 51543046e1 Pin T1 contracts combo and guard task-finish against wrong cwd
Why: Provider repos merged for T1 (core PR#2, agent-command PR#2, frontend
  PR#3, ui PR#3, documents PR#9); gitlinks pinned to those mains. The
  task-finish guard prevents a repeat of the T0 incident where running
  finish from the main checkout deleted it (scripts/task.sh treated $PWD as
  the worktree to remove).

Evidence: make test green on the pinned combo — core, backend 13 pkgs,
  frontend 9, ui 6, agent-command (vet + tests incl. conformance); make build
  produces the binary; combo version string now includes agentcmd SHA.

Impact: combo grows its version traceability; AGENTS.md documents the
  worktree-cwd requirement for finish.

Refs: modules/documents docs/records/2026-09-30-t1-core-cards-commands-verification.md
2026-09-30 06:29:11 +00:00
weichen 7c9c1e7b22 Align task-start guards with precheck and soften uninitialized to warning
Why: the pin-documents flow exposed guard divergence — precheck counted
submodule drift while task-start checked porcelain only, letting a task
start despite a BUSY verdict; and PR#8 overcorrected by treating
uninitialized (-) submodules as BUSY when they only block builds, not
writes.
Evidence: bash -n clean; precheck on this checkout prints tree line with
drift/uninit split and READY verdict; negative path exercised by the
real divergence that started this task.
Impact: precheck warns on uninitialized, BUSY only on +/U; task-start now
refuses on porcelain dirt and +/U drift, matching precheck.
Refs: PR#8; policy/tool-adaptation-matrix.md A1
2026-09-30 03:50:46 +00:00
weichen c2da46e4d2 Harden the gate: uninitialized-submodule detection and platform protection registration
Why: precheck missed uninitialized submodules (git submodule status '-'
prefix), and the branch protection configured today plus the second live
probe outcome must be recorded honestly in the matrices.
Evidence: platform negative: direct push to protected main rejected
(pre-receive hook declined, Logging-System probe); second write-guard probe
confirmed session-start config loading (no hook run in the pre-config
session log).
Impact: precheck sub_dirty now counts '-' prefixed entries; A3 registered
enforced at platform layer across 11 repos; zcode matrix pending-live
annotated with the loading-timing proof.
Refs: policy/tool-adaptation-matrix.md; policy/tool-adaptation-zcode.md
2026-09-30 03:47:24 +00:00
weichen ccddcc2b2b Add the zcode write-path guard instance with its adaptation matrix
Why: zcode lacks a rules feature (AGENTS.md is the resident layer) but
supports PreToolUse hooks that can block Edit/Write before the write lands,
upgrading A1/A3 from commit-time to write-time enforcement; the two block
shapes (integration branch, detached submodule) mirror the real incidents.
Evidence: script-level suite 8/8 (N1-N3 blocks with exit 2 and remediation
hints, P1-P5 allows incl. fail-open degradation paths); config JSON valid;
client-side live-fire interception marked pending-live in the matrix.
Impact: .zcode/config.json enables the hook runner for this workspace;
.zcode/plans/ ignored (client state); no product code change.
Refs: Development-Guidelines 0.1.0-draft.8; policy/tool-adaptation-zcode.md
2026-09-30 03:43:26 +00:00
weichen fdf63e3fc8 Fall back to prune-based removal for submodule-bearing worktrees
Why: git unconditionally refuses worktree remove when the tree contains
gitlinks (index-level check; deinit does not bypass it), so the PR#4 fix
path still failed on the second real task.
Evidence: after deinit the worktree was clean and submodule dirs empty, yet
remove refused; rm -rf + worktree prune is the documented workaround and
was proven manually on the empty-list task worktree.
Impact: task-finish now completes the recycle path automatically after its
merge verification; no guard weakened.
Refs: Agent-System-Dev PR#4; policy/tool-adaptation-matrix.md A5
2026-09-30 03:37:01 +00:00
weichen a073b8712c Teach task-finish to recycle submodule-bearing worktrees
Why: git refuses to remove a worktree with initialized submodules; the first
real dogfood run of task-finish hit this on the empty-list fix task.
Evidence: the fix task's worktree recycled only after manual force-remove;
deinit-then-remove path exercised on the same state afterwards.
Impact: finish deinitializes submodules, removes, prunes, and deletes the
remote branch; unmerged-result guard unchanged.
Refs: .task/fix-empty-list-json.md
2026-09-30 03:27:06 +00:00
weichen f31fd5f62d Add the task-startup gate scripts and local hooks
Why: agents skipped triggered reading and wrote into shared checkouts holding
other tasks' in-flight changes; the 2026-09-30 empty-list incident session
found 24 overlapping in-flight files only by accident at first write.
Evidence: positive/negative suite in a real scratch repo passed 19/19
(precheck READY/BUSY/SYNC_REQUIRED, start refuse/establish, hook main/badname/
longsubject refusals, sync checkpoint, finish recycle and abandon double-
confirm); the suite caught three real defects (pipefail empty-grep abort,
worktree gitdir COMMIT_EDITMSG resolution, message checks in the wrong hook
phase).
Impact: make setup enables pre-commit/commit-msg hooks; make precheck/task-
start/task-sync/task-finish provide the governed path; no existing workflow
removed. AGENTS.md carries the resident gate rules.
Refs: Development-Guidelines 0.1.0-draft.7; task card .task/delivery-mechanism.md
2026-09-30 03:11:58 +00:00