feat(spec): remote-shell kickoff sign-off - #97
Merged
Conversation
The internal-hostname rule matches any dotted <label>.local-style string and cannot tell a machine name from a path this repo declares itself. config.local, config.lan (roles/ssh/files/config.lan.tpl) and planwright.local (.claude/planwright.local.yml) are files, not hosts, and every commit that so much as names them was being blocked. Anchored to the exact matched strings, so a real host called <something>-config.local still fires. Verified in both directions: the staged hook now exits 0 on the remote-shell bundle, and a negative control (Hostname my-server.local) still trips the rule.
Section-by-section walkthrough to mutual understanding, signed off; all four files flipped Draft -> Ready. Six recorded decisions. Two ambiguous terms pinned: the tailnet address rides the 1Password server_host field, in MagicDNS form. Four corrections where the spec disagreed with the repo -- REQ-D re-scoped from build to declare-and-verify after three checks proved the ~/.ssh/auth_sock indirection already exists (8990a23); Task 6 narrowed to the Linux baseline, resolving a contradiction with the macOS exclusion; D-2's mosh rejection re-grounded on port forwarding after its agent-forwarding premise fell; the Task 4 -> Task 5 dependency dropped as a leftover of the old framing. One scope addition on request: phone client access as REQ-G, D-10 and Task 8. Bundle now 27 REQs / 27 test-spec entries (one-to-one, re-derived mechanically), 10 design decisions, 8 tasks, and a 13-row risk register carrying three catalogued decision domains the spec touches but does not decide.
The kickoff sign-off is complete and anchored; only the terminal ready-flip is outstanding. Its gate requires a green CI rollup on the PR head commit, and the repo pipeline is not green for reasons outside this bundle, so PR #97 stays a draft. Re-entry is the flip alone. Recorded as a plain bullet rather than a task reference bullet: it is a bundle-level publication step, and parking a real task to express it would distort the derived status render. That tension between the refusal arm and the format-version 2 tasks.md contract is filed as a skill-drift observation.
inkatze
marked this pull request as ready for review
August 5, 2026 21:25
This was referenced Aug 6, 2026
inkatze
added a commit
that referenced
this pull request
Aug 6, 2026
…hestration observations (#99) * chore(observations): record dev-services orchestration step findings Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9 * chore(observations): record planwright worker-permission seam findings Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9 * chore(observations): record the silent stream-json recover hang Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9 * chore(observations): record worker LC_ALL=C inheritance breaking project CI Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9 * feat(tooling): gate shell scripts on shellcheck The repo lints YAML and Ansible and scans for secrets, but its 13 tracked shell scripts had no static analysis at all. Surfaced when a dev-services Task 1 worker reached for shellcheck to check the scripts it was writing and found the repo did not ship it. Pinned in mise.toml alongside the other tools, and wired into lefthook so it applies to every shell script rather than one task's. --severity=warning rather than the default: the tracked scripts carry info-level SC2015 notes (the deliberate 'A && B || C' assertion idiom in the *-test.sh harnesses) which would block every commit. Warning-level is green across the repo today, so the gate catches regressions instead of demanding a cleanup first. The one warning-level blocker was module-setup.sh, where SC2154 fires on initdir/moddir/systemdsystemunitdir. Those are dracut's module API, injected into the script by dracut itself, so the finding is a false positive and is silenced file-wide with the reason recorded inline. Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9 * chore(gitleaks): exempt mise.local.toml as a repo-owned filename Adding `mise.local.toml` to .gitignore was blocked by the internal-hostname rule, which matched the literal `mise.local` inside the filename. The rule cannot tell a repo-owned path from a machine name, which is the exact case #97 already carved out a second exemption class for; this is its fourth member, not a new precedent. Anchored like its siblings, so the backstop still catches a real host: verified that `mise.local.toml` passes clean while `buildbox-mise.local` still fires. The file itself is the machine-local mise env at the repo root, carrying this host's absolute CLAUDE_PLUGIN_DATA and CLAUDE_PLUGIN_ROOT so planwright's fleet scripts can resolve their state home. Untracked for the usual reason: every value in it is specific to one machine. Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9 * chore: gitignore planwright's per-spec orchestration runtime state Every /orchestrate dispatch writes a timestamped marker under specs/<spec>/.orchestrate/, which is runtime state by design — the tower rebuilds it from git and process evidence rather than reading it back from a commit. Untracked but unignored, it left the working tree dirty after every run and showed up as an uncommitted-change warning when opening a PR. Claude-Session: https://claude.ai/code/session_01F8oKrXASMQSXMVjSvuJpn9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Kickoff sign-off for
specs/remote-shell. Walkthrough complete, all four filesflipped Draft → Ready.
specs/remote-shellspecs/remote-shell/kickoff-brief.mdspec-validate.sh specs/remote-shell— 0 errors, 0 warnings, re-run after the Ready flip8a7b5f18fd515f08a413ff7b492cbb4c82b692c9—scripts/spec-anchor.sh specs/remote-shellLens pass
All nine Discovery-Rigor lenses walked inline (sub-agent fan-out was unavailable
this session; the substitution is declared in the brief rather than silent).
Every finding dispositioned, none declined or deferred. The kickoff altitude
check passes: a trigger fired, D-1 is the altitude record, it is cited from the
goal, and the task decomposition matches the claimed altitude.
The one finding needing its own fix was a commit blocker: this bundle's
edits tripped
internal-hostnameeleven times, every match a repo-ownedfilename rather than a machine name. Fixed with three anchored allowlist
entries in a separate commit, verified in both directions — the staged hook
passes, and a real
<host>.localstill fires.What the walkthrough changed
Four corrections where the spec disagreed with the repo:
~/.ssh/auth_sockindirection already exists — confirmed against the repo, against commit
8990a23(which postdates the observation the requirement was drafted from),and against the live host. It also resolves to the host's own 1Password
agent, so the stale-forwarded-agent failure the bundle was framed around does
not arise on this route.
its Done-when and the bundle's own macOS exclusion.
agent-forwarding premise it led with turned out to be false. Conclusion
unchanged; the reasoning is now true.
framing, shortening the critical path.
One scope addition on request: phone client access as REQ-G, D-10 and Task 8,
reusing the tailnet route and the repo's existing separate-authorized-keys-file
pattern, with the key injected from 1Password rather than committed.
Bundle now carries 27 REQs against 27 test-spec entries (one-to-one, re-derived
mechanically), 10 design decisions, 8 tasks, and a 13-row risk register — three
rows of which are catalogued decision domains the spec touches but deliberately
does not decide.
Next
Merge is the second key. Nothing dispatches until this merges;
Activeis thenderived from the first task to start.