Skip to content

Refactor homebrew tasks to use loop instead of with_items - #2

Closed
LoupX wants to merge 1 commit into
mainfrom
homebrew_list_loop
Closed

Refactor homebrew tasks to use loop instead of with_items#2
LoupX wants to merge 1 commit into
mainfrom
homebrew_list_loop

Conversation

@LoupX

@LoupX LoupX commented Dec 29, 2025

Copy link
Copy Markdown
Collaborator

By having loops instead all the list at once, allows to "skip" is an app already exists, instead of failing the whole task

I.E. If you already installed iTerm and after that you run osx, when it reaches Installing cask applications it will fail all with (item=iterm2) => {"ansible_loop_var": "item", "changed": false, "item": "iterm2", "msg": "Error: It seems there is already an App at '/Applications/iTerm.app'."}

With a loop, it "fails" but will continue with the next on the list.

By having loops instead all the list at once, allows to "skip" is an app already exists, instead of failing the whole task

I.E. If you already installed iTerm and after that you run _osx_, when it reaches _Installing cask applications_ it will fail all with 
`(item=iterm2) => {"ansible_loop_var": "item", "changed": false, "item": "iterm2", "msg": "Error: It seems there is already an App at '/Applications/iTerm.app'."}`

With a loop, it "fails" but will continue with the next on the list.
@inkatze

inkatze commented Feb 9, 2026

Copy link
Copy Markdown
Owner

@LoupX Sorry I missed this 😓 we use a Brewfile now so no need to loop through a yml list of items.

@inkatze inkatze closed this Feb 9, 2026
inkatze added a commit that referenced this pull request Jun 4, 2026
Fallback-2 matched the digit in a redirection (e.g. 'gh pr merge
2>/dev/null' extracted PR #2), short-circuiting the reliable
'gh pr view' fallback and writing a wrong PR number into tasks.md.
Tighten the pattern to a bare numeric argument only.
inkatze added a commit that referenced this pull request Jun 5, 2026
* docs(spec): add pair-flow spec bundle

Spec-driven pipeline that pairs human and agent from comprehension
through execution and orchestration. Defines /spec-draft, /spec-kickoff,
/execute-task, /orchestrate, /resume, the new Agent-resolvable finding
bucket, and the inbox + tmux dashboard substrate.

Status: Draft. 14 tasks in dependency order; 10 open questions and 7
deferred items captured for follow-up discussion before implementation.

* docs(spec): resolve pair-flow open questions, add D-19 through D-30

Encodes the decisions from the 2026-05-22 review pass:

- D-19/D-20: two-file config model (~/.claude/pair-flow.yml tracked
  defaults + ~/.claude/pair-flow.local.yml agent-maintained), with
  discovery flow that never silently writes. Replaces the spec-config.yml
  proposal that would have leaked personal workflow into shared repos.
- D-21: PRs are always drafts; no auto-merge at any tier. Removes the
  v3 auto-merge from Deferred and moves to Out of scope as permanent.
- D-22/D-23: dashboard visual language (red/orange/blue/yellow/green/grey)
  with sort order, plus inbox heartbeat (30s tick, 2-minute stale sweep,
  24h legacy fallback).
- D-24 through D-30: bundle sizing, CI retry, path-guard scope, brief
  invalidation scope, validator reuse, PR-merge detection, telemetry
  layout.

Adds Task 3.5 for the pair-flow config helper. Resolves nine of the ten
open questions; only codex availability on personal/alt remains, gated
on Task 1's investigation.

* docs(spec): pair-flow second-pass clarifications (D-31 through D-48)

Resolves the second round of clarifications surfaced after the initial
spec was committed:

- D-31: Spec status lifecycle (Draft -> Active -> Done) with explicit
  ownership of each transition.
- D-32: Branch naming convention for orchestrator-created branches.
- D-33: No bypass mode for /spec-kickoff; manual work remains available.
- D-34: Inbox keyed per Claude Code session UUID, presented per worktree.
- D-35 through D-48: kickoff walkthrough on partial invalidation,
  orchestrator behavior on unkickoffed specs, cross-spec concurrency,
  measurement plan convention, in-session skill composition,
  Last-reviewed auto-update, incremental brief writing, spec-looks-wrong
  escalation, gh auth failure handling, worktree ownership split,
  validator status-aware enforcement, brief retention, uncommitted
  changes on /resume, and no separate audit log.

Adds Task 3.6 for the validator port + extension (a precondition for
/spec-draft and /spec-kickoff). Extends /spec-kickoff and /orchestrate
tasks with status-flipping responsibilities. Documents the spec-status
and measurement-plan conventions in specs/README.md.

The codex availability question (last remaining open question after the
first clarification pass) is also resolved: codex is available on both
work and personal profiles.

* docs(spec): pair-flow D-49 through D-51 (brief commits, validator scope, rewrite threshold)

- D-49: Kickoff briefs are committed to git as part of the spec bundle,
  not gitignored. They're decisions, not secrets.
- D-50: Validator v1 enforces structural fields only (stable ID,
  Done-when, Dependencies, Citations). Measurement plan and Last
  reviewed are recommended but not blocking.
- D-51: Wholesale-brief invalidation fires when both requirements.md
  and design.md change in the same commit, or when >50% of REQ-IDs
  or D-IDs change in a single commit. Otherwise section-scoped.

Adds REQ-A2.11 and REQ-A2.12 to anchor the requirements.

* docs(spec): pair-flow D-52, D-53 plus lock-timing clarification

Final consistency pass surfaced two gaps and two adjacent fixes:

- D-52: One task per /orchestrate invocation; intra-spec parallelism
  comes from multiple invocations (manual via parallel tmux panes, or
  the scheduled runner picking up successive ready tasks). Matches the
  user's existing "different workstreams in parallel" workflow.
- D-53: /execute-task weighs performance, security, and system-wide
  implications during research and records tradeoffs in the kickoff
  brief's risk register. CI is the hard gate; performance regressions
  that pass CI are still user-observable and excluded from
  Agent-resolvable by D-3.
- D-17 fix: reconcile lock path with D-37 (per-spec, not repo-wide) and
  pin lock-release timing (released before /execute-task runs, not held
  for its full duration).
- D-37 wording: clarify that "same-spec concurrency blocked" applies
  only to state-changing moves, not to concurrent task execution.

REQ-B1.5 expanded with explicit "industry standards, popular projects"
language and the performance/security/system-wide weighing instruction.
REQ-D2.2 added with the parallelism contract.

* docs(spec): pair-flow Task 1 — panel-* underuse diagnosis

Diagnosis: /panel-* shipped 2026-05-15, mid 30-day window. /copilot-* count
(42) all pre-release; /panel-* count (14) all post-release; zero copilot
invocations after panel landed. Not underuse, just availability.

Recommendation: keep panel as default. Confirms D-6 (codex-only default,
drop "provisional") and D-12 (panel-pairing demoted to escalation, /polish
as default convergence). One LAN-Ollama auto-mode classifier denial logged
as follow-up.

* feat(claude): pair-flow Task 3.6 — spec-validate.sh

Structural validator for spec bundles. Checks four-file presence, Status:
declaration, and per-task fields (stable ID, Done when, Dependencies,
Citations). Status-aware: Draft warns (exit 0), Active errors (exit 1).
Also flags prose-only REQs (the tecpan/specs/org counter-example pattern).

Self-tests pass on the three target fixtures:
- tecpan/specs/settings (Active): 0 errors, 0 warnings
- tecpan/specs/org (no status, prose REQs, bare tasks): 0 errors, 27 warnings
- specs/pair-flow (Draft, this bundle): 0 errors, 0 warnings

The REQ-G7.1 Gherkin scenarios verified via synthetic fixture: same gap
warns on Draft (exit 0), errors on Active (exit 1). Materializes through
the existing roles/osx/tasks/osx.yml scripts/ directory symlink; no
per-file symlink task added.

* feat(claude): pair-flow Task 3.5 — config helper + defaults file

Adds roles/osx/files/claude/pair-flow.yml (tracked defaults: codex-only panel
backend, 1h stale-lock threshold, 30s inbox heartbeat) plus a per-file
symlink task in osx.yml materializing it to ~/.claude/pair-flow.yml.

Adds roles/osx/files/claude/scripts/pair-flow-config.sh with five
subcommands: repo, defaults, repo-class, confirm-repo-class <value>, show.
Per D-20 the helper never silently writes — repo-class on an unknown repo
exits 2 with `needs-confirmation:<inferred>`; only confirm-repo-class
persists. Inference reads gh pr list and filters known bot logins
(*[bot], copilot-*, dependabot*, renovate*, github-actions*) plus
PR-author self-reviews so a solo repo with copilot review history is
not misclassified as multi-reviewer.

Smoke-tested end-to-end on this dotfiles repo. spec-validate.sh still
emits zero errors and zero warnings on specs/pair-flow.

* feat(claude): pair-flow Task 2 — file-path PreToolUse guard

Adds roles/osx/files/claude/scripts/path-guard.sh wired from settings.json
as a PreToolUse hook with matcher Read|Edit|Write (Bash and NotebookEdit
out of scope per D-26). The hook denies via the PreToolUse JSON envelope
with permissionDecision=deny and a structured reason so the model gets
useful context, not a stderr blob.

Blocks: Read/Edit on missing file or directory path; Write on missing
parent directory. Allows everything else. Smoke-tested seven cases via
direct stdin; the hook returns the correct deny envelope or silent allow
in each. End-to-end behavior needs a fresh session because PreToolUse
hooks load at session start; the materialized settings.json is updated
for the next session to pick up.

The 82/month file-path-mistake baseline (April-May 2026 friction analysis)
will be re-measured in the next 30-day window per Task 2's Measurement
plan.

* feat(claude): pair-flow Task 6 — /spec-kickoff skill

Adds roles/osx/files/claude/commands/spec-kickoff.md, the didactic
walkthrough that produces signed-off kickoff briefs. Seven sections
(Goal+glossary, Requirements, Design, Verification, Task graph, Risk
register, Sign-off) walked per a read → restate → surface implicit
terms → Socratic checks → D-42 inconsistency gate → wait-for-sign-off
→ incremental-append pattern (D-41). Retrofit mode patches tasks.md
at the Task-graph step with per-patch red-line. Partial-invalidation
re-walk uses D-27 section scope plus D-51 wholesale-rewrite triggers.
Sign-off flips all four spec files Draft → Active via Edit and bumps
Last reviewed: (REQ-A2.9, D-40); validator failure post-flip reverts
and halts. Repo-class discovery via pair-flow-config.sh with the
needs-confirmation semantics from REQ-D9.1 / D-20; never silently
writes.

Pre-flight stages traced cleanly against specs/pair-flow/: validator
0/0, repo-class solo, no prior brief. The interactive bootstrap-test
per REQ-A2.7 is the user's move and the D-7 quality gate.

* feat(claude): pair-flow Task 3 — inbox + tmux dashboard substrate

Cross-session awareness layer (REQ-F). Six inbox-*.sh scripts in
roles/osx/files/claude/scripts/ (materialized via the existing
directory symlink): write/heartbeat/sweep/session-start/status/
dashboard. Hooks wired in settings.json: SessionStart spawns the
heartbeat in the background, Stop transitions to idle, Notification
(permission_prompt | idle_prompt) transitions to awaiting-input
alongside the existing notify-event.sh chain. tmux.conf gains a
`prefix + i` popup binding for the dashboard plus a second dracula
custom plugin for the status-bar triplet (⚠N ●N ◆N).

Display-only v1 (no row-jump) and triplet status segment per user
pick on PR #28. macOS notifications reuse notify-event.sh's
tnotify-send chain rather than duplicating it. Heartbeat self-exits
when its claude PID dies (walks up to 6 ancestors looking for
claude/claude-code) or when the inbox file is removed, so no Stop
cleanup hook is required and orphan processes do not accumulate.
The sweeper combines the spec's 2-min heartbeat threshold (D-23)
with a same-host PID-liveness backstop for kill -9 leaks.

Sync mechanism (iCloud vs Syncthing) stays Awaiting input; entries
are single-writer atomic-rename sub-1KB JSON so either works.

Smoke-tested end-to-end: hook init + tick + transition + sweep all
behave; dashboard renders 6 mixed states with correct colours, sort
weights, column truncation; status segment computes correct counts;
heartbeat self-exits within 30s of its inbox file being removed.
v1 verification's two-concurrent-sessions + kill-9 + macOS-notify
checks are deferred to the user (require fresh-session hook load).

* feat(claude): pair-flow Task 8 — Agent-resolvable bucket

Add the four-bucket Finding Categorization to user-global CLAUDE.md
(Auto-applicable / Agent-resolvable / Needs sign-off / Needs human
judgment). The new Agent-resolvable bucket carries the REQ-C1.2 five-
condition predicate (failing regression test, test passes after fix,
full project CI passes, kickoff alignment, no hard disqualifier), with
a repo-class behavior split (solo auto-applies, multi-reviewer surfaces
for review with evidence) routed through ~/.claude/scripts/pair-flow-
config.sh repo-class.

/polish and /panel-pairing gain a pre-flight step that resolves repo-
class and locates the active kickoff brief, a 4-bucket categorize/
loop-fate path, and a new step (d-AR) Agent-resolvable application
flow (write failing test → confirm failure mode matches finding → fix
→ test passes → wider CI → verify kickoff alignment → record
evidence). Iteration summaries now log repo-class, brief path, all
four bucket counts, and per-item Agent-resolvable evidence. Auto-
execution invariants extended.

/peer-review updated to four tables with an Agent-resolvable thread
table and matching option semantics. /code-review's descriptive
reference updated to four-bucket. /copilot-pairing left untouched; it
inherits by reference from CLAUDE.md.

specs/pair-flow/tasks.md: Task 8 moved to Completed.

* feat(claude): pair-flow Task 9 — /polish standalone-mode PR creation

Add an "Invocation mode" section to polish.md that splits behavior on
the literal --nested flag in $ARGUMENTS. Standalone (default) pushes
and opens or updates a draft PR after a normal exit; nested mode (used
by /execute-task in the pair-flow design) hands back to the parent for
PR creation.

The new "Standalone-mode PR creation" section mirrors /self-review's
shape: push, check for an existing PR via gh pr view and reuse it,
otherwise template / convention discovery then gh pr create --draft
with a body listing the Polish notes (per-iteration Auto-applicable
and Agent-resolvable items, test paths and kickoff-brief citations,
plus any unresolved Needs sign-off / Needs human judgment items).

Auto-execution invariants split into in-loop (no push, no PR ever)
and post-loop (standalone may push and open a draft PR, nested may
not). Force-push, amend, squash, and rebase remain forbidden at all
times. Safety stops suppress PR creation in both modes.

specs/pair-flow/tasks.md: Task 9 moved to Completed.

* feat(claude): pair-flow Task 4 — tasks.md state conventions + auto-update hook

Document the canonical tasks.md state sections (Completed, In progress,
Awaiting input, Deferred, Out of scope) and the In progress annotation
format in specs/README.md. Phase values: implementing, polish iter N,
PR #M draft. Bullet shape for Completed pinned.

Add roles/osx/files/claude/scripts/tasks-pr-sync.sh wired from settings
.json under hooks.PostToolUse with matcher "Bash". The script filters
`gh pr (create|merge)` from the tool call, parses the D-32 branch
(pair-flow/<spec>/task-<ids>, including bundles and dotted IDs),
extracts the PR number from tool_response.stdout via URL match, then
`#N` literal, then argv, then `gh pr view` fallback, and rewrites
specs/<spec>/tasks.md.

On open: move task block(s) Forward plan → In progress, insert the
two annotation lines right after the H3; strip existing Status /
Last-activity bullets first so the hook is idempotent. On merge:
replace the block with a one-line Completed bullet referencing the
PR. Bundle order preserved. Silent on no-op cases; python failures
log to stderr and leave tasks.md untouched.

Smoke-tested seven scenarios via synthetic stdin against ephemeral
fixtures (single-task open, gh pr merge with realistic #N stdout,
bundle open with correct order, non-pair-flow branch no-op, non-Bash
tool no-op, idempotent re-open). Out-of-session merge reconciliation
remains Task 12's scheduled-runner job.

* feat(claude): pair-flow Task 5 — /resume context-load skill

* feat(claude): pair-flow Task 10 — /execute-task skill

* feat(claude): pair-flow Task 11 — /orchestrate v1 skill

* feat(claude): pair-flow Task 12 — scheduled runner documentation

* feat(claude): pair-flow Task 7 — /spec-draft skill

* docs(spec): pair-flow kickoff-brief; status Draft -> Active

* feat(claude): pair-flow Task 13 — spec amendments, contract checker, observation convention

Apply kickoff-brief amendments: D-6 profile-aware panel backends (codex
on work, gemini on personal/alt), D-17 stale-lock threshold reduced from
1h to 15m, D-24 effort-based fallback for low-data repos.

Add skill-contracts.sh contract-consistency checker wired as a lefthook
pre-commit job. Checks cross-file invariants (D-32 branch naming,
four-bucket presentation, --nested flag, pair-flow-config.sh, D-21
always-draft, D-33 Active gate, D-36 kickoff gate) across skill files.

Add observation convention to /execute-task and /polish (Risk 6 Layers
1/1b: passive record of opportunities for future /spec-draft seeds).

* chore(polish): iter 1, expand pair-flow-config.sh invariant coverage

Add execute-task.md and peer-review.md to the pair-flow-config.sh
check list in skill-contracts.sh. Both make load-bearing calls to
pair-flow-config.sh repo-class in their pre-flight.

* docs(spec): update Task 13 status to PR #28 draft

* feat(claude): interaction style for spec skills, composability principle, Task 15

- Add interaction style sections to /spec-draft and /spec-kickoff:
  progress indicator, progressive disclosure, visual aids, selectors
  over open-ended questions, smart defaults, running summary
- Add composability-by-default design principle to user-global CLAUDE.md
- Add Task 15 (work project e2e validation) to pair-flow tasks
- Add standalone project extraction to Deferred with gate conditions

* feat(claude): polish handoff presentation with clustered decisions

Add explicit handoff presentation rules to /polish post-loop flow.
Items sharing a decision axis (e.g., test coverage gaps) cluster into
one question instead of individual confirmations. Reduces human
interaction count without losing granularity.

* feat(claude): panel-pairing handoff presentation with clustered decisions

Same fix as polish: when the autonomous loop hands off residual items,
cluster shared-axis findings and use batched decisions instead of
defaulting to one-by-one confirmation.

* fix(claude): orchestrate worktree context switch via EnterWorktree

/orchestrate said "navigate to the worktree" but didn't specify how,
so /execute-task ran in the wrong directory. Now explicitly uses
EnterWorktree/ExitWorktree. Also documents /loop wrapping for
multi-task autopilot.

* docs(spec): defer four-file format meta-spec until extraction gate

Gated on the standalone extraction goal — current sources
(specs/README.md, validator, /spec-draft) are sufficient for personal
use, and a meta-spec would add a sync burden without immediate value.

* docs(spec): defer Dynamic Workflows integration investigation

Two integration surfaces identified (discovery rigor fan-out across
review skills, /execute-task conditional fan-out for multi-file
mechanical work). Gated on Anthropic publishing the API.

* fix(claude): self-review base diff uses origin/main, not stale local

A stale local main in a long-lived worktree inflates the diff with
already-merged commits. Fetch first and diff against the remote-tracking
base; fall back to local main only when no remote is configured.

* fix(claude): four findings tables in self-review and panel-review

CLAUDE.md Finding Categorization defines four buckets (added
Agent-resolvable), but /self-review and /panel-review still said
'three findings tables'. Aligned to the canonical four.

* docs(spec): pair-flow v1 retrospective

Task 13 deliverable. Captures e2e validation findings across dotfiles,
STEAI-748 work project, and tecpan kickoffs. Sections: what worked,
what needed iteration during the run, concrete tunings per Task 13's
Done-when, personal-preference vs generalizable for the
standalone-extraction gate, and what v1 did not validate.

Recommends holding the extraction gate until at least one tecpan
/orchestrate -> draft PR cycle closes the orchestration validation gap.

* feat(claude): gemini panel backend on personal/alt per D-6

- Brewfile: install gemini-cli
- scripts/claude-gemini-auth-sync.sh: read GEMINI_API_KEY from 1Password
  (item hvscsuq25owvgrqt235xwlfmgy), write ~/.gemini/.api-key mode 0600
- roles/fish/files/gemini.fish + symlink task: export GEMINI_API_KEY
  from that file into the shell environment
- roles/osx/tasks/homebrew.yml: call the sync script on non-work hosts
  (skipped on CI and inventory_hostname == 'work')
- pair-flow-config.sh: merge top-level keys from pair-flow.local.yml
  (not just repo-class), so panel-backends: [gemini] on personal/alt
  resolves correctly per D-6 amendment
- panel-review.md + panel-pairing.md: add gemini to supported backends,
  with setup check (auth via env var) and invocation pattern
  (gemini -p "<prompt>" -o text); update default tables to D-6
  (work=codex, personal/alt=gemini)
- CLAUDE.md: align /panel-review and /panel-pairing default tables

* fix(claude): polish + panel-pairing kickoff-brief resolution with multiple Active specs

Previous heuristic ('single Active spec or D-32 branch pattern, else
disable Agent-resolvable') gave up too early when multiple specs are
Active. Walk five steps in order: D-32 branch -> single Active spec ->
branch-name token match -> diff-scope >=80% under one spec -> ask the
user. Only disable the bucket when no Active spec exists at all.

* docs(spec): close out Task 13 (tecpan /orchestrate PR #161 merged)

tecpan PR #161 (settings Tasks 3, 4, 5 via /orchestrate, merged
2026-06-04) is the missing piece for Task 13's 'at least one tecpan
task shipped via the full pipeline' Done-when. Moves Task 13 to
Completed, updates the retrospective to reflect the orchestration
validation evidence, and flips the extraction-gate recommendation to
'gate has enough evidence to fire.'

* feat(claude): orchestrate worktree reuse + claude --worktree interop (D-54); autonomy-pipeline docs (Task 14)

* docs(spec): re-sign kickoff brief Section 3 for D-54 worktree reuse + D-44 amendment

* chore(polish): iter 1, fix shellcheck SC2004/SC1010 in inbox scripts

* fix(claude): guard inbox writes against empty jq output (N1) and skip malformed dashboard blob parts (N2)

* fix(claude): escape notify JSON + host-scope inbox stale sweep

- inbox-write.sh: build notify-event payloads via jq --arg so a branch or
  path containing a double-quote can't emit malformed JSON (N1).
- inbox-sweep.sh: host-scope the heartbeat-staleness/legacy deletion so a
  synced inbox can't have one host sweep another host's live entry by local
  clock when sync lag exceeds the stale threshold (J2).
- inbox-write.sh: document the accepted tick/hook-event read-modify-write
  race (self-heals within one heartbeat; flock absent on macOS) (J1).

* docs(spec): pin 5 unpinned REQs in test-spec; de-em-dash CLAUDE.md skill list

- test-spec.md: add verification entries for REQ-A2.9/A2.11/A2.12/B1.10/B1.11
  so every REQ is pinned per REQ-A1.5 (N2).
- CLAUDE.md: replace em-dashes with colons in the pipeline skill list to
  honor the repo's own Writing Style rule (N3).

* docs(claude): gate /polish observations on pair-flow adoption

/polish can run in any repo; only write specs/_observations/opportunities.md
when the repo has adopted pair-flow (a specs/<feature>/requirements.md exists).
/execute-task always runs against an Active spec, so it notes the premise is
guaranteed there.

* docs(claude): scope panel Backend-failure stop to non-recovered failures

Clarify in /panel-review and /panel-pairing that the Backend failure stop
condition fires only on a non-recovered failure (final non-zero exit, empty or
unparseable output, auth lost with no successful retry), not on transient
quota/rate-limit/retry notices the CLI prints while retrying internally and
then still returning a valid result. Judge by final outcome, not stderr.

* docs(observations): seed note to decouple review tooling from pair-flow

Capture scope for a future separate branch: panel-backends config mis-homed in
pair-flow.yml, employer org names leaked in panel-review.md:23, CLAUDE.md
over-couples the review workflows. Includes the leak surface map and the
work-detection mechanism decision.

* fix(claude): tasks-pr-sync PR-number regex ignores shell redirections

Fallback-2 matched the digit in a redirection (e.g. 'gh pr merge
2>/dev/null' extracted PR #2), short-circuiting the reliable
'gh pr view' fallback and writing a wrong PR number into tasks.md.
Tighten the pattern to a bare numeric argument only.

* docs(spec): sync pair-flow status and stale-lock threshold across docs

- specs/README.md: pair-flow row Draft -> Active; cold-start points at
  kickoff-brief + tasks.md state (was stale 'begins at Task 1/2').
- requirements.md: drop stale 'Implementation begins at Task 1/2'.
- design.md D-9: 'webhook-triggered hook' contradicted D-29 (no webhook);
  reword to PostToolUse (in-session) or scheduled runner (out-of-session).
- tasks.md: stale-lock threshold 1h -> 15m to match pair-flow.yml/D-17;
  annotate Task 3.5 record with the D-52 reduction.

* chore(copilot): iter 1, address portability and PAIR_FLOW_HOST findings

- spec-validate.sh: replace non-POSIX \b (grep) and \y (BSD awk) regex
  boundaries with portable equivalents; \y silently failed on BSD awk,
  causing a latent false 'lacks stable numeric ID' on EOL-number headings.
- tasks-pr-sync.sh: match gh pr create/merge as an anchored command
  invocation, not a raw substring, so unrelated commands mentioning the
  string no longer rewrite tasks.md.
- inbox-heartbeat/sweep/dashboard.sh: honor PAIR_FLOW_HOST like
  inbox-write.sh's host_name(), so an overridden host name no longer
  desyncs the entry filename (heartbeat never ticking, entries mislabeled
  remote, host-scoped sweep skipped).

* chore(copilot): iter 2, portability, dep guard, and doc-vs-code alignment

- skill-contracts.sh: use grep -E for alternations instead of non-POSIX \|.
- pair-flow-config.sh: guard python3 + PyYAML before YAML read/write so a
  fresh machine fails with an actionable message, not ModuleNotFoundError.
- requirements.md REQ-F1.2: filename contract is {host}-{session}.json with
  repo/branch as JSON fields, matching the implementation.
- inbox-dashboard.sh: clarify the aggregation key is host|worktree|branch.
- panel-review.md / panel-pairing.md: reference pair-flow-config.sh show as
  the canonical config merger for panel-backends.
- homebrew.yml: correct the Gemini-sync comment (when: gates non-work+non-CI;
  the script itself requires an authenticated 1Password session).

* chore(copilot): iter 3, redact employer data + dashboard/sweep/perms fixes

Confidentiality (public repo): redact employer org names and work-project
details from files new/changed in this branch.
- panel-review.md: profile detection reads PANEL_REVIEW_PROFILE env var
  instead of a hardcoded work-org allowlist.
- peer-review.md: genericize a work-repo war-story reference.
- v1-retrospective.md: generalize the work-project evidence (ticket ids,
  teammate name, internal identifiers, production figures, repo names).
- decouple-review-tooling.md, design.md, requirements.md, test-spec.md,
  tasks.md: replace employer/work-project names with generic descriptions.
Org names also exist in main history and out-of-diff files (tm.fish,
copilot-*.md, metrics-baseline); the user handles those separately.

Findings:
- inbox-dashboard.sh: document weight 1 as error/blocked (a session dashboard
  has no stale-lock state); skip fs_epoch=0 parts so malformed entries don't
  dominate the sort.
- inbox-sweep.sh: list filters stale entries from display regardless of host
  (D-23); deletion stays host-scoped.
- inbox-write.sh / inbox-sweep.sh: best-effort chmod 700 on the inbox dir.

* chore(copilot): iter 4, fix spec-bundle contract drift + stale comment

- requirements.md REQ-G3.1: profile-aware default (work: codex; personal/alt:
  gemini) per D-6, replacing the stale 'codex on all profiles' text that
  contradicted the rest of the bundle.
- kickoff-brief.md Task Graph Reconstruction: mark it a sign-off-time snapshot
  (tasks.md is canonical) and correct the 15->16 task count.
- claude-gemini-auth-sync.sh: the default ITEM_UUID is the real 1Password item,
  not a placeholder; fix the stale comment (no behavior change).

* chore(copilot): iter 5, explicit jq dependency guards in hooks

Add an early 'command -v jq || exit 0' to path-guard.sh, inbox-session-start.sh,
and inbox-write.sh so they degrade cleanly on a machine without jq, consistent
with tasks-pr-sync.sh. The existing 2>/dev/null already suppresses the shell's
command-not-found under bash, but inbox-write.sh has write-side jq calls that
are not 2>/dev/null-guarded, and the explicit check makes the degrade-to-safe
behavior intentional rather than incidental. Verified: with jq absent all three
exit 0 silently; with jq present, path-guard still denies and inbox tick still
writes.

* chore(copilot): iter 6, tmux status wrapper guard + repo-class comment fix

- roles/tmux/files/scripts/inbox-status.sh: guard the exec so the dracula
  status slot degrades to 'inbox?' if the Claude script is not yet
  materialized (tmux role applied before osx role), instead of erroring.
- pair-flow-config.sh: fix the misleading infer_repo_class comment. The no-gh
  fallback keeps suggesting solo (the common case), but the comment no longer
  claims that 'surfaces for review' (it doesn't; solo enables auto-apply). The
  value is only a needs-confirmation suggestion the human confirms (exit 2).

(A third Copilot thread flagging the gh_pr regex '\$' as a bug was a false
positive: bash double-quote processing converts it to the '$' end anchor
before grep sees it; bare 'gh pr merge' is detected. Verified, dismissed.)

* chore(copilot): iter 7, fix inbox notify payload + orchestrate flag parsing

- inbox-write.sh maybe_notify: pass the real cwd to notify-event.sh instead of
  a pre-built 'project · branch' string. notify-event derives project+branch
  itself (basename + git -C) and prepends that context; the old code broke
  branch detection (a non-path cwd failed the git lookup in the draft-pr-ready
  case) and duplicated the context in the awaiting-input permission body.
  Verified: done -> {cwd: <real path>}, permission -> {cwd, message:'awaiting
  input'}.
- orchestrate.md: clarify that flags (e.g. --bookkeeping) are ignored when
  resolving the spec path, so '/orchestrate --bookkeeping specs/<spec>' is not
  misread as treating --bookkeeping as the path.

* chore(copilot): iter 8, refresh branch on update + jq guards + README wording

- inbox-write.sh: the existing-entry update path now refreshes .branch (guarded
  to skip empty, e.g. detached HEAD), so switching branches in the same session
  no longer leaves a stale branch in the dashboard/status forever.
- inbox-sweep.sh: add the early 'command -v jq || exit 0' guard (degrade to
  no-sweep/empty-list), consistent with the other inbox scripts.
- inbox-dashboard.sh: same jq guard (message + exit 1, matching its missing-
  SWEEPER handling) so a fresh host degrades cleanly. (Proactively drained the
  same class Copilot flagged on inbox-sweep.sh.)
- specs/README.md: clarify that status controls task-structure-check severity
  only; the four-file presence check always errors regardless of status.
Verified: stale branch refreshes on next hook-event; sweep/dashboard degrade
cleanly with jq absent.

* chore(copilot): iter 9, harden ~/.gemini perms + tmux fallback throttle

- ~/.gemini directory perms: add an Ansible 'file' task (state: directory,
  mode: 0700) in homebrew.yml before the sync task, mirroring the
  ~/.claude/inbox precedent in osx.yml, plus a best-effort 'chmod 700' in
  claude-gemini-auth-sync.sh as defense-in-depth. The dir holds the API key
  file (only the file was chmod 600 before; the dir used the umask).
- roles/tmux/files/scripts/inbox-status.sh: the iter-6 placeholder fallback
  returned immediately, which lets dracula re-invoke the custom: slot in a
  tight loop. Sleep for status-interval (default 5s) in the fallback too,
  matching the real inbox-status.sh and gpu-usage.sh siblings.

* chore(copilot): iter 10, correct host_name .local comment

The comment claimed host_name() strips a .local suffix, but only 'hostname -s'
does that (the bare-hostname fallback, used only if -s fails, may keep the
suffix). Reword the comment to describe the actual behavior; no behavior change,
and the derivation stays consistent with the other inbox scripts.

* chore(copilot): iter 10, de-duplicate awaiting-input notification

Per the chosen resolution: keep the rich direct notify-event.sh permission/idle
hooks in settings.json (they carry the actual permission message) and stop
inbox-write.sh from emitting its own generic 'awaiting input' notification on
the same transition. inbox-write still records the awaiting-input state for the
dashboard, and still owns the draft-pr-ready notification (which has no direct
hook). Removes the duplicate macOS notification on permission_prompt/idle_prompt.
Verified: awaiting-input updates state with no notification; draft-pr-ready
still fires 'done'.
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.

2 participants