Commit Graph
12 Commits
Author SHA1 Message Date
glm-5.3-flash faa1c9ba10 docs(lib): assembly example compiles as no_run, not ignore; convention 16
- the crate-root assembly example was a ```ignore block, which rustdoc
  renders with the untested badge docs.rs surfaces on the crate page
  (the tooltip 'This example is not tested'); ```no_run blocks are
  compile-checked by doctests and get no badge
- the example body is gated with hidden cfg lines (#[cfg(feature =
  "local")] around a hidden block): empty under default features,
  compile-checked under --all-features; the doctest now passes in both
  cargo test configurations instead of being skipped
- AGENTS.md convention 16 records the rule: doc examples are tested or
  no_run, never ignore; feature-gated bodies via hidden cfg lines

Verification: cargo test (doctest src/lib.rs line 39 now compile-... ok
in default and --all-features); cargo doc --no-deps (no untested badge
in the rendered HTML); clippy --all-targets --all-features -D warnings;
fmt --check; wasm check; fuzz/shared corpus replay (9).
2026-11-02 17:51:46 +00:00
glm-5.3-flash 62f04c6856 docs(agents): spawned subagents never commit; coordinator commits once
A subagent mid-dedash sweep read the 'commit and push when reasonable'
rule and pushed its own subset before the coordinator verified the
aggregate. State the assembly rule explicitly so spawned tasks report
instead.
2026-11-01 14:30:23 +00:00
glm-5.3-flash 58da42a021 docs: remove em dashes from repo prose and forbid them going forward
- Rewrote ~1090 em dashes across docs/ (excluding docs/reviews/
  history), README, CHANGELOG, and .opencode/agents prompts with varied
  restructures (colons, semicolons, parentheses, commas, sentence
  splits); ADR decisions, status lines, wire-shape examples, and code
  fences preserved
- Rewrote 234 em dashes in src doc comments plus a handful of existing
  inline comments and one test assert message; no code, JSON literals,
  or wire shapes touched
- Added Project Convention 15: no em dashes in prose (doc comments,
  markdown, agent prompts, commit messages); restructure instead; no
  spaced hyphens as a substitute
Verification: cargo test; cargo clippy --all-targets -- -D warnings;
cargo fmt --check; cargo doc --no-deps; cargo test --all-features;
cargo test --manifest-path fuzz/shared/Cargo.toml; cargo check and
clippy for wasm32-unknown-unknown with -D warnings; em dash grep over
src + docs + agent prompts returns no matches outside docs/reviews/
2026-11-01 13:11:32 +00:00
glm-5.3-flash e3d7f6f3f2 chore: bump to 0.8.1, changelog for the alkcall 0.10.1 adoption
- alkcall requirement 0.10.0 -> 0.10.1 (same-family version-only bump:
  the adoption-window ordering fix, private fix surface, no type alktty
  touches); lockfiles updated in both the root and fuzz workspaces
- AGENTS.md pin refreshed from the stale 0.9.0 note

Verification: cargo test 113 default / 137 all-features (unchanged from
the 0.8.0 baseline); fuzz corpus replay 9 green; clippy stable + wasm
(-D warnings); fmt; doc; wasm32-unknown-unknown check; publish dry run
(43 files)
2026-10-22 06:22:33 +00:00
glm-5.3-flash 0170897bbb feat: alkcall 0.9.0 adoption — bump to 0.7.0
The stub-sweep release changes no type alktty touches: the four
implemented stubs, the register_openable Pub-typed refusal (alktty's
op is Sub-typed), the register_imported Result return, and the removed
RelayError::PubTypedOpen are all surfaces alktty never exercises.

- alkcall requirement 0.8.1 -> 0.9.0; lockfile follows
- alktty 0.6.0 -> 0.7.0 (minor: raising the minimum alkcall requirement
  is ecosystem-coordination breaking on a 0.x crate)
- one test fix: `establisher_ok_on_valid_params` formatted a
  Result<Establishment, _> with {:?} — Establishment no longer derives
  Debug in alkcall 0.9.0; the assert now branches on Err and formats
  only the error

Verification: 113 default / 156 all-features tests, clippy
--all-targets -D warnings, fmt --check, cargo doc, fuzz corpus replay
(9 tests / 340 seeds), wasm32-unknown-unknown check + clippy,
publish --dry-run — all pass.
2026-10-14 05:15:06 +00:00
glm-5.3-flash 49f70d9efb feat(fuzz): cargo-fuzz workspace, 3 wire-surface targets; bump alkcall 0.8.1
- Bump alkcall 0.8.0 -> 0.8.1 (duplicate adopt/open channel-state
  destruction fix from alkcall's fuzz campaign; AGENTS.md stale-pin fix).
- Adopt fuzzing per docs/plans/fuzzing.md (mirrors alkcall's
  docs/research/fuzzing.md as-built layout): fuzz/ workspace with own
  [workspace] table, nightly pinned for the subtree only, invariant
  logic in a stable-toolchain shared crate.
- Targets: chunk_frame (5-byte chunk codec), negotiation_frame
  (negotiation framing + NegotiateRequest + error_response_bytes +
  the cross-codec peek-disambiguation seam), control_json
  (ControlMessage JSON + signal_from_name). src/local/ out of scope
  (not wire-attacker-shaped).
- 328 committed seeds (deterministic generator); grown corpora
  gitignored. Corpus replay on stable is the standing fuzz gate
  (cargo test --manifest-path fuzz/shared/Cargo.toml).
- Detached-runner rule (fuzz/run-detached.sh): campaigns never run in
  the foreground of an agent session - OOM in a target must cost the
  fuzzer, never the session host.
- Root Cargo.toml gained [workspace] members/exclude (MSRV vs fuzz
  nightly dev-deps footgun) and fuzz/ in the publish exclude.

Verification: cargo test (113), cargo test --all-features (156),
clippy stable + wasm32-unknown-unknown, fmt, doc, publish dry-run,
corpus replay 328 seeds - all green. 10-min detached campaigns on all
three targets: 0 crashes/hangs/OOMs/leaks (chunk_frame cov-saturated
at 710 edges; negotiation_frame 3.69M execs cov 3157; control_json
8.6M execs cov 2035). Corpus replay caught three harness-model
mismatches pre-campaign (payload-slice shape; the negotiation framing
layer is length-prefix-only - Json unreachable from read_frame;
zero-length frames admitted by the reader, rejected by the adapter's
parse). Campaigns recorded in docs/plans/fuzzing.md section 8.
2026-09-28 08:07:30 +00:00
glm-5.3-flash af9dbaedea feat: allocation moves into the channels establisher (alkcall 0.6.0 / review 007 R-01) — bump to 0.3.0
- Bump alkcall 0.5.0 -> 0.6.0 (Establishment plan payload, ADR-049
  amendment 2); alktty 0.2.0 -> 0.3.0 (breaking channels-path
  allocation-failure shape)
- make_tty_establisher runs backend.allocate; failure maps to
  EstablishmentError::DialFailed (channel:open_failed reason
  dial_failed); the TtyHandle crosses to the pump handler via a
  private per-open AllocatedHandle one-shot slot (the handle is not
  Sync — it cannot be the ChannelPlan directly)
- make_tty_open_handler gains the Option<ChannelPlan> parameter; a
  plan drives the new drive_session_pre_allocated (pumps only), a
  None plan falls back to drive_session_pre_negotiated (inline
  validate-and-allocate — defense-in-depth for no-establisher
  registrations)
- tty_open_spec's channel:open_failed ErrorDefinition declares
  dial_failed (four reachable reasons)
- Pinned in-band allocate test flipped:
  allocate_failure_fails_open_as_dial_failed (end-to-end, no channel
  survives); establisher unit gate for the plan slot + failure
  mapping
- ADR-010 amended (§2A; §2 kept as historical record), tty-adapter.md,
  session/channels/adapter docs, CHANGELOG, AGENTS.md alkcall pin
  updated

Verification: cargo test (113) + --all-features (137), clippy
-D warnings (native + wasm32, default + all-features), fmt, doc,
wasm32 check — all clean
2026-09-07 09:53:57 +00:00
glm-5.3-flash e2fa32b3c7 feat: channels-path establisher migration (alkcall 0.5.0 / ADR-049) — bump to 0.2.0
Adopt alkcall 0.5.0's channel-open establishment phase (ADR-049 —
review 006 E-01 + N-1) and migrate the channels-path semantic failures
per its §5 sequencing (alktty ADR-010).

- `register_openable` registers `channels/tty/sub` with an establisher
  (`register_openable_with_establisher`): full `NegotiateRequest`
  parse of schema-valid `input`, `carriage == "raw"`, non-empty `cmd`,
  backend lookup, and the ADR-050 ownership check run before the open
  reply; rejections are `channel:open_failed` with `details.reason`
  (`unknown_resource` / `handler_error` / `timeout`) — no phantom
  channel (the SSH contract holds consumer-visibly)
- `backend.allocate` deliberately stays in the pump handler:
  `Establishment` is payloadless so the `TtyHandle` cannot cross the
  establisher→handler boundary, and re-allocating would violate
  ADR-005's kill-on-Drop contract — `allocate_failed` remains the one
  in-band failure class on the channels path (pinned by test)
- `TtySessionError::ChannelsOpen` carries alkcall's typed
  `ChannelOpenError` (`#[from]`) instead of a flattened `String` —
  the N-1 fix at alktty's layer (breaking)
- channels-path semantic failures change shape from
  `NegotiationRejected` in-band frames to `channel:open_failed` call
  errors (breaking); the direct-ALPN path is unchanged
- `tty_open_spec()` gains a `description` (review 006 E-02) and an
  ErrorDefinition for `channel:open_failed` (ADR-016 — disclosed via
  services/schema)
- alkcall = "0.5.0"; version 0.2.0; ADR-010 + ADR-009 amendment +
  tty-adapter.md + CHANGELOG

Verification: cargo test (112 lib + integration), cargo test
--all-features (136), clippy --all-targets -D warnings (host + wasm),
fmt --check, cargo doc --no-deps clean; wasm32-unknown-unknown check
confirms the default crate stays wasm-clean.
2026-09-06 20:25:39 +00:00
glm-5.3-flash 3baa993edb fix: local-bridge robustness, scope-gate order, sentinel contract; packaging/docs closeout (P8-P11, P2/P3/P15)
Closes review #003 (prepublish review for v0.1.0).

- P8: StdinSink::poll_shutdown parks an inflight reserve+send on a
  full channel (waker registered) — a stdin blast followed by EOF
  delivers the EOF instead of stranding it
- P9: five poisoned-lock .expect() sites -> unwrap_or_else(into_inner)
- P10: three thread-spawn .expect() sites -> TtyError::AllocFailed
- P5: tty:open scope gate runs before carriage/cmd/backend-lookup
  checks (no backend-name enumeration differential for unscoped ids)
- P11: recv_stdout terminates on the zero-length drained sentinel;
  the sentinel is no longer yielded as an item (doc was already the
  contract); stderr has no sentinel (doc noted)
- P2: exclude AGENTS.md + docs/plans/, drop dead Cargo.lock and
  docs/research/ entries (package list: 42 files, 659.2KiB)
- P3: AGENTS.md phase status (all five landed), ADR range 001..009
  (+ alktty-native ADR-009 in the mapping), alkcall guidance
  corrected to v0.4.x / pin "0.4.0"; architecture README ADR-009 row
  + landed-phase status
- P15: backend.rs doc typo; redundant tokio-stream dev-dep removed;
  NegotiationError::Io arm logs; set_identity failure logs;
  input_pump.abort() at session end; TtySessionError::Open carries
  the accept_bi StreamError (no io::Error flattening); borrowing
  deserialize in open_via_channels (no params.clone());
  error_response_bytes guards an "error" key in fields; trivial
  inline comments promoted/removed; plan-doc test counts + doc
  front-matter refreshed; session tests that raced session teardown
  under the abort change use a GatedBackend (exit held until
  released)

Verification: cargo test 104 lib / --all-features 147; clippy
(all-targets + wasm32) -D warnings; fmt; wasm check; doc 0 warnings;
publish dry-run OK.
2026-09-05 16:47:45 +00:00
deepseek-v4-pro 99441530ab fix: address code review #001 findings (M1, M2, L2, L4, L5, N1-N3, N5)
- M1: TtySession now handles the negotiation-rejection error frame.
  from_halves peeks the first response byte (ADR-052 §5 disambiguation)
  and returns NegotiationRejected on a 0x00-prefixed error frame;
  ChunkReader gains peek_stream_type/read_chunk_after_peek.
- M2: wait() now surfaces MalformedExitChunk instead of collapsing it
  to NoExitChunk. The exit watch channel carries a cloneable
  ExitOutcome enum; MalformedExitChunk carries a String.
- L2: add EmittingBackend + recv_stdout_and_stderr_route_backend_data
  test covering the consumer read-pump stdout/stderr routing.
- L4: MockBackend/MockControl/MockStdinSink are now #[cfg(test)]
  pub(crate), removing them from the public API.
- L5: cargo fmt (the BAST drift test was unformatted).
- N1: fix all 9 rustdoc intra-doc links.
- N2: fix stale doc paths (crates/tty/ and docs/research/).
- N3: amend AGENTS.md §14 to accurately describe the local module's
  libc::kill unsafe blocks.
- N5: consolidate nanos_seed into tests/common/mod.rs.

Verification: cargo test (84), cargo test --all-features (107),
clippy clean (native + wasm), fmt clean, doc clean, wasm check clean.
Coverage: session.rs 79.71% -> 87.43%, total 90.74% -> 91.47%.
2026-08-17 12:07:44 +00:00
glm-5.2 b3f50d1836 phase 4: architecture docs + BAST schema + renumbered ADRs
Port the alknet-tty architecture docs into alktty and add the BAST
document for the alk/tty wire format. Docs-only; no Rust source
changes.

Spec docs (docs/architecture/, flat layout — single-crate repo):
- overview.md — crate purpose, two-carriage model, deps, ALPN,
  backend location map, feature gates
- tty-wire.md — 5-byte chunk codec, control channel split
  (STREAM_CTRL_IN=3 / STREAM_CTRL_OUT=4), sentinels
- tty-backend.md — TtyBackend trait, TtyHandle, TtyControl,
  REQ-TTY-01 (backends need not be natively async)
- tty-adapter.md — TtyAdapter, three-pump driver, exit-chunk
  ordering (ADR-004), cancel cleanup (ADR-005), access control
- tty-local.md — LocalTtyBackend (local feature module), PTY +
  pipe modes, REQ-TTY-02 (signal forwarding to process group)
- README.md — architecture index

ADRs (docs/architecture/decisions/, renumbered 001..008 from
alknet 052,053,054,055,056,057,077,093 in order):
- 001 wire format + two-carriage model (incl. Phase 7 control-
  channel split amendment)
- 002 TtyBackend trait + TtyHandle
- 003 local backend placement (records both the alknet sibling-
  crate decision and the alktty single-crate consolidation behind
  a local feature)
- 004 exit code on a control chunk
- 005 backend cleanup on session cancel
- 006 self-contained negotiation framing
- 007 tty inside channels (reversed by 008; kept for historical
  context with reversal notice)
- 008 channels pure channel multiplexing (reverses 007; TTY
  always uses its 5-byte format)

BAST document (docs/architecture/tty-bast.md):
- Normative JSON spec for the alk/tty wire format, conforming to
  the BAST meta-schema at https://alk.dev/bast/v1/schema
- 5-byte chunk header (struct, big-endian: stream_type uint8,
  length uint32) + StreamType enum (Stdin=0..CtrlOut=4)
- ControlMessage union (field-name discriminator on type:
  resize/signal/eof/exit) with documented deviation that on-wire
  control payloads are UTF-8 JSON, not BAST's binary union
  encoding
- NegotiationFrame (4-byte BE length + UTF-8 JSON body) +
  NegotiateRequest / TerminalParams JSON shapes
- StreamType enum deviation noted: on-wire uint8, not BAST's
  standard u32 enum index (chunk header is 5 bytes, not 8)
- alktty does not depend on alktype; the hand-rolled wire.rs is
  the runtime codec, the BAST is the human-readable contract

AGENTS.md: fixed the ADR mapping table to match the plan's 8-to-8
mapping (the previous table substituted ADR-050 for 054, relabeled
056 as control-message split, dropped 077, and added a new
control-split ADR at 006 — inconsistent with both the plan and the
prose). ADR-050 (dynamic resource ownership) is an alkcall/alknet-
core ADR, not tty-specific, and is not ported; the Phase 7 control
split stays as an amendment inside ADR-001, mirroring alknet.

Verification (all pass, no Rust source changed):
- cargo test (80 passed)
- cargo test --all-features (103 passed)
- cargo clippy --all-targets -- -D warnings (clean)
- cargo fmt --check (clean)
- cargo check --target wasm32-unknown-unknown (clean)
- cargo clippy --target wasm32-unknown-unknown -- -D warnings
  (clean)
- cargo doc --no-deps: 9 pre-existing intra-doc-link warnings in
  src/session.rs and src/channels.rs (untouched by this commit;
  not introduced here)
- BAST JSON parses; StreamType indices match wire.rs constants
  (0=Stdin..4=CtrlOut)
- all markdown cross-reference links resolve
2026-08-17 10:52:26 +00:00
glm-5.2 712e7ae071 chore: add .gitignore and AGENTS.md; fix implementation-specialist conventions
The scaffold was missing basic repo hygiene, which led to drift: the
implementation-specialist agent's Project Conventions section was a
verbatim copy from alkcall (referencing OperationEnv, EventEnvelope,
Capabilities, alktype as a dep, call.aborted, vendored core types —
none of which exist in alktty), so spawned agents got alkcall
conventions injected.

- .gitignore: target/, node_modules/, .worktrees/ (matches alkcall/alktype)
- AGENTS.md: alktty-specific operating instructions — Git Workflow,
  14 Project Conventions (5-byte chunk header wire format, TtyBackend
  trait one-way door, local feature isolation / WASM invariant,
  BAST-as-doc-not-dep, 3-arg/4-arg ownership shapes, alknet ADR→alktty
  ADR renumbering plan), Verification Commands (incl. wasm checks),
  Architecture Context (phase status, ADR index, port origin)
- .opencode/agents/implementation-specialist.md: replace stale alkcall
  Project Conventions section with alktty-appropriate rules that mirror
  AGENTS.md

Verification: cargo test (80 passed), cargo fmt --check, cargo build
--target wasm32-unknown-unknown all clean. No source changes.
2026-08-17 10:32:21 +00:00