workdir: promote from hint to authoritative-with-confidence + aggressive cwd-binding heuristics #4

Open
opened 2026-05-23 20:53:52 +00:00 by coilysiren · 0 comments
Owner

Originally filed by @coilysiren on 2026-05-14T22:28:24Z - https://github.com/coilysiren/cli-guard/issues/59

Problem

Today workdir.Detect is described as a hint and scope.Resolve is authoritative, but the gap between them gets crossed constantly: cwd-keyed views in downstream consumers (session-lattice's planned cwd_sessions view, repo-recall, dispatch routing) want a specific-repo answer, and most active Claude Code sessions live at a parent path like ~/projects/coilysiren/ rather than a specific repo. The current signal chain (env → nearest .git → first-segment-under-coilysiren → cwd) bottoms out at the parent for those sessions and there is no notion of confidence to gate consumers.

Origin: session-lattice docs/decisions.md (CLIguard side-issue), recorded as the precondition for the cwd_sessions view.

Proposed change

Promote workdir from hint to authoritative-with-confidence. Keep scope as the audit-row binder, but make workdir something downstream views can trust by tagging the answer with a confidence band and adding more aggressive signals above the current chain.

Shape

type Confidence string

const (
    ConfidenceHigh   Confidence = "high"   // env override, explicit binding, manifest match
    ConfidenceMedium Confidence = "medium" // git root, longest-prefix repo-recall match
    ConfidenceLow    Confidence = "low"    // recent-touch only, first-segment-under-coilysiren
    ConfidenceNone   Confidence = "none"   // cwd fallback
)

type Result struct {
    Path       string
    Source     Source
    Confidence Confidence
}

New signals (in precedence order, above current chain)

  1. Explicit binding command. A coily bind <repo> (or equivalent) verb that pins the binding for the current shell session via $COILY_PRIMARY_DIR or a session state file under ~/.coily/session/<pid-tree-key>. ConfidenceHigh.
  2. Last-binding / recent-touch sticky. Remember the last specific-repo binding observed in this session (or in the last N minutes from this shell ancestor) and reuse it when cwd is a parent path. ConfidenceMedium if from session state, ConfidenceLow if reconstructed from recent-touch heuristic.
  3. Longest-prefix match against repo-recall's known paths. Read repo-recall's repo registry (already an HTTP-accessible list) and longest-prefix-match cwd against it. When cwd is a parent, take the most-recently-active repo under that parent rather than stopping at the parent itself. ConfidenceMedium.
  4. Package-manager manifest gate. For package-manager invocations (npm, uv, pip, cargo, go, dotnet, brew), require that the resolved repo carry a matching language manifest (package.json, pyproject.toml, Cargo.toml, go.mod, *.csproj, etc.). If the resolved repo does not match the package manager, downgrade to ConfidenceNone and surface a recovery message naming the manifest mismatch. This is a gate, not a separate signal: it post-filters the answer the other signals produced.

Existing signals remain, with confidence tags

  • SourceEnvConfidenceHigh
  • SourceGitConfidenceMedium
  • SourceCoilysirenConfidenceLow (this is exactly the case session-lattice flagged as gutting the cwd-keyed view)
  • SourceCWDConfidenceNone

Boundary considerations

  • repo-recall coupling: workdir grows a new external dependency. Options: (a) static read from a registry file repo-recall writes, (b) HTTP call with TTL cache via ttlcache, (c) optional dependency that degrades to current behavior when unavailable. Lean toward (c) so the package stays usable in environments without repo-recall.
  • Session state file shape: needs to survive across coily invocations from the same shell but expire when the shell exits. Candidate key: parent shell PID + hostname. ~/.coily/session/<key>.yaml with a short TTL.
  • Consumers should not silently use ConfidenceLow or ConfidenceNone answers without acknowledging the downgrade. Document this in the package doc.
  • Test surface: each new signal needs its own test fixture. Manifest gate needs a fixture per package manager.

Acceptance

  • workdir.Result carries a Confidence field.
  • The four new signals land with tests.
  • Package doc is rewritten to describe authoritative-with-confidence, not hint.
  • At least one downstream consumer (session-lattice cwd_sessions view spec, or repo-recall dispatch routing) is updated to branch on confidence.
  • Adjacent but separate: #58 (lockdown segment-splitter cd <path> no-op). Both touch cd-shaped behavior but the code paths do not overlap.
  • Downstream: session-lattice cwd_sessions view (blocked on this).
_Originally filed by @coilysiren on 2026-05-14T22:28:24Z - [https://github.com/coilysiren/cli-guard/issues/59](https://github.com/coilysiren/cli-guard/issues/59)_ ## Problem Today `workdir.Detect` is described as a hint and `scope.Resolve` is authoritative, but the gap between them gets crossed constantly: cwd-keyed views in downstream consumers (session-lattice's planned `cwd_sessions` view, repo-recall, dispatch routing) want a specific-repo answer, and most active Claude Code sessions live at a parent path like `~/projects/coilysiren/` rather than a specific repo. The current signal chain (env → nearest `.git` → first-segment-under-coilysiren → cwd) bottoms out at the parent for those sessions and there is no notion of confidence to gate consumers. Origin: session-lattice [docs/decisions.md](https://github.com/coilysiren/session-lattice/blob/main/docs/decisions.md) (CLIguard side-issue), recorded as the precondition for the `cwd_sessions` view. ## Proposed change Promote `workdir` from hint to authoritative-with-confidence. Keep `scope` as the audit-row binder, but make `workdir` something downstream views can trust by tagging the answer with a confidence band and adding more aggressive signals above the current chain. ### Shape ```go type Confidence string const ( ConfidenceHigh Confidence = "high" // env override, explicit binding, manifest match ConfidenceMedium Confidence = "medium" // git root, longest-prefix repo-recall match ConfidenceLow Confidence = "low" // recent-touch only, first-segment-under-coilysiren ConfidenceNone Confidence = "none" // cwd fallback ) type Result struct { Path string Source Source Confidence Confidence } ``` ### New signals (in precedence order, above current chain) 1. **Explicit binding command.** A `coily bind <repo>` (or equivalent) verb that pins the binding for the current shell session via `$COILY_PRIMARY_DIR` or a session state file under `~/.coily/session/<pid-tree-key>`. `ConfidenceHigh`. 2. **Last-binding / recent-touch sticky.** Remember the last specific-repo binding observed in this session (or in the last N minutes from this shell ancestor) and reuse it when cwd is a parent path. `ConfidenceMedium` if from session state, `ConfidenceLow` if reconstructed from recent-touch heuristic. 3. **Longest-prefix match against repo-recall's known paths.** Read repo-recall's repo registry (already an HTTP-accessible list) and longest-prefix-match cwd against it. When cwd is a parent, take the most-recently-active repo *under* that parent rather than stopping at the parent itself. `ConfidenceMedium`. 4. **Package-manager manifest gate.** For package-manager invocations (`npm`, `uv`, `pip`, `cargo`, `go`, `dotnet`, `brew`), require that the resolved repo carry a matching language manifest (`package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `*.csproj`, etc.). If the resolved repo does not match the package manager, downgrade to `ConfidenceNone` and surface a recovery message naming the manifest mismatch. This is a gate, not a separate signal: it post-filters the answer the other signals produced. ### Existing signals remain, with confidence tags - `SourceEnv` → `ConfidenceHigh` - `SourceGit` → `ConfidenceMedium` - `SourceCoilysiren` → `ConfidenceLow` (this is exactly the case session-lattice flagged as gutting the cwd-keyed view) - `SourceCWD` → `ConfidenceNone` ## Boundary considerations - repo-recall coupling: workdir grows a new external dependency. Options: (a) static read from a registry file repo-recall writes, (b) HTTP call with TTL cache via `ttlcache`, (c) optional dependency that degrades to current behavior when unavailable. Lean toward (c) so the package stays usable in environments without repo-recall. - Session state file shape: needs to survive across coily invocations from the same shell but expire when the shell exits. Candidate key: parent shell PID + hostname. `~/.coily/session/<key>.yaml` with a short TTL. - Consumers should not silently use `ConfidenceLow` or `ConfidenceNone` answers without acknowledging the downgrade. Document this in the package doc. - Test surface: each new signal needs its own test fixture. Manifest gate needs a fixture per package manager. ## Acceptance - `workdir.Result` carries a `Confidence` field. - The four new signals land with tests. - Package doc is rewritten to describe authoritative-with-confidence, not hint. - At least one downstream consumer (session-lattice cwd_sessions view spec, or repo-recall dispatch routing) is updated to branch on confidence. ## Related - Adjacent but separate: #58 (lockdown segment-splitter `cd <path>` no-op). Both touch `cd`-shaped behavior but the code paths do not overlap. - Downstream: session-lattice `cwd_sessions` view (blocked on this).
coilysiren added
P2
and removed
P1
labels 2026-05-31 07:00:16 +00:00
Sign in to join this conversation.
No labels
P0
P1
P2
P3
P4
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/cli-guard#4
No description provided.