Skip to content

docs(tui): govern agent process interfaces#683

Closed
huangzesen wants to merge 16 commits into
mainfrom
dev4/windows-tui-native-20260718
Closed

docs(tui): govern agent process interfaces#683
huangzesen wants to merge 16 commits into
mainfrom
dev4/windows-tui-native-20260718

Conversation

@huangzesen

@huangzesen huangzesen commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add the first two root-governed, co-located TUI interface contracts:
    • tui/internal/process/CONTRACT.md for agent launch/observe/terminate lifecycle behavior;
    • tui/internal/processscan/CONTRACT.md for advisory Unix/Windows process observation;
  • add/route the paired Anatomy graph without creating one umbrella Contract;
  • add focused first-child graph validation and an exact argv test proving a Windows agent path with spaces remains one argument.

Scope

This is the first real vertical slice of the Windows-native TUI contract tree requested by the maintainer. It freezes the existing TUI process boundary before the backend is implemented.

Out of scope:

  • Python kernel/backend implementation or readiness changes;
  • Windows installer/runtime packaging;
  • shared .lingtai/ disk-protocol changes;
  • Postman/UDP restoration (PR refactor(tui): retire Postman relay #681 remains intact);
  • claiming that cross-compilation is Windows real-machine execution.

Contract map

root CONTRACT.md
├── tui/internal/process/CONTRACT.md
│   ├── launcher.go
│   ├── check.go
│   └── kill_{unix,windows}.go
└── tui/internal/processscan/CONTRACT.md
    └── check.go + cross-platform parser/scan tests

Each Contract is paired with its nearby ANATOMY.md; the root/TUI/neighbor links are reciprocal and checked mechanically.

Validation

Base: 19f0d61272413524daaa5d402597c2e65bd334f1 (merged PR #681; live main at candidate lock)

Passed:

cd tui
go test ./internal/process ./internal/processscan -count=1
go test . -run 'TestArchitecture|TestGovernedProcessContractGraph' -count=1
GOOS=windows GOARCH=amd64 go test -c ./internal/process
GOOS=windows GOARCH=amd64 go test -c ./internal/processscan
GOOS=windows GOARCH=amd64 go build -o /private/tmp/dev4-windows-tui-contracts/lingtai-tui.exe .
git diff --check

The built artifact is identified as PE32+ executable (console) x86-64, for MS Windows.

Post-open evidence

Passed at the same exact head after opening the review surface:

cd tui
go test ./... -count=1
go vet ./...
Anatomy citation scan: PASS (58 citations)
worktree cleanliness: PASS
  • No real Windows 11 execution evidence is claimed by this PR.
  • Runtime discovery, shared disk protocol, and future preflight/plan/apply/rebind interfaces each require their own nearby Contract rather than expansion of these two files.

@huangzesen

Copy link
Copy Markdown
Collaborator Author

Independent post-open review

Review was locked to base 19f0d61272413524daaa5d402597c2e65bd334f1 and original head c51321139f244fe521c064d688fd3f7122a50a26.

The read-only review found two P2 documentation blockers: stale migration-ownership statements in the new process and processscan Anatomy files. Commit 0cca1ded27db2cbfd227b8399c139667aecfcc08 corrects only those two statements.

Focused re-review of c5132113... → 0cca1ded... returned PASS:

  • both original blockers resolved;
  • no new findings in the two-file delta;
  • stale-claim absence check and git diff --check passed;
  • TestArchitectureEntryLinks and TestGovernedProcessContractGraph passed;
  • independent snapshot remained clean at the exact reviewed head.

This records review evidence only; it is not a GitHub approval or merge authorization.

huangzesen and others added 13 commits July 18, 2026 19:09
Add internal/duplaunch, the DuplicateLaunchCheck policy interface: it
returns allow/block/unknown from a private, non-creating probe of the
kernel's .agent.lock lease (POSIX non-blocking flock; Windows
fail-immediately LockFileEx on the msvcrt-locked byte). Unknown blocks.

The LaunchAgent launch gate now consults this check instead of process
observation; ForceLaunchAgent still bypasses it for /refresh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New internal/spawnprocess owns exactly one authority: creating at most
one child from a typed Spec (executable/args/env/dir/stdio), returning a
Child identity or a typed Error (invalid_spec/not_found/start). Success
implies no readiness, ownership, or duplicate-launch safety; POSIX and
Windows creation live in private build-tag adapters (CONTRACT.md).

The one low-level launch seam (launchAgentUnsafe) now creates the child
via spawnprocess.Spawn; LaunchAgent/ForceLaunchAgent return
*spawnprocess.Child, with type-only follow-through in
waitForLaunchHeartbeat and headless RunSpawn (PID/Release).

Validation: go test ./internal/spawnprocess ./internal/process
./internal/headless (ok); go build ./... and go test -run '^$'
-exec=/usr/bin/true for windows/amd64 and windows/arm64 (ok); gofmt
clean on touched files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deliver one native stop request to an immediately identity-verified
target, with distinct stale-identity / access-denied / already-absent /
unsupported / unknown outcomes. POSIX verifies the kernel command name
then signals; Windows verifies image name and liveness and terminates on
the same held handle. Caller: the Windows stopTUIProcess stub no longer
fakes success.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Own Contract/Port with private POSIX (procfs/sysctl start-token) and
Windows (query+wait rights, creation-time token) adapters; observation
only — never signals, stops, or escalates, and Unknown/Error are never
converted into Exited. Minimal caller seam: stopTUIProcess's existing
bounded exit polls now observe the pinned incarnation instead of the
ad-hoc signal-0 probe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add internal/actionstate: a read-only policy that computes start/restart/
refresh enablement from its own heartbeat observation. Running, Stopped,
and Unknown stay distinct; malformed, unreadable, or future heartbeats
are Unknown and never enable an action. Absence proof is classified in
private POSIX/Windows adapter files. The /cpr seam now revives only on a
Stopped verdict and surfaces Unknown with its reason instead of treating
it as dead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Independent Query interface over one project .lingtai root: one record per
agent directory with explicit running/absent/unknown/conflict presence from
the directory's own manifest/status record checked against a private native
PID existence probe (kill(0) on POSIX, query-only OpenProcess on Windows).
Whole-query failure is a typed *QueryError, never a silent empty list.
Minimal caller seam: the list command's shared warnings section prints
unresolved (unknown/conflict) records and typed query failures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MigrationGuard answers allow/block/unknown for one offline
migration/destructive action on an agent working directory, using only a
non-creating probe of the kernel's .agent.lock (POSIX flock; Windows
one-byte LockFileEx range probe). Unknown blocks, and the zero-value
verdict is Unknown so an uninitialized decision can never permit.

The m036 SQLite backfill migration now gates candidate discovery on this
verdict instead of process-table observation, and rechecks the lock
immediately before each rebuild since the user confirmation prompt can
stay open indefinitely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…evidence

Replace the ps/WMIC process-count startup counter with a self-contained
AgentCounter query (internal/agentcounter): registry.jsonl + .agent.json
+ .agent.heartbeat are the only authority, with explicit Known/Unknown
state and Issues so failure never passes silently as zero. Private
POSIX/Windows adapter files; minimal caller adapter in main.go.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TUIInstanceGuard: internal/tuiinstance acquires/releases the one TUI
singleton ownership token per project scope. Only Acquired permits the
protected interactive startup in runPreparedApp; Contended and Unknown
refuse distinctly. POSIX flock and Windows share-mode-0 handle locks are
private to this interface; no process scan, PID hint, record age, or
file-deletion bypass exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-ports-20260718

feat(tui): isolate nine Windows process interfaces
…slim-20260718

fix(windows): honor lifecycle locks and add an amd64 preview
@huangzesen huangzesen closed this Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant