096-01: orientation reports work in flight (open PRs + unmerged branches)#122
Open
Kyarha wants to merge 2 commits into
Open
096-01: orientation reports work in flight (open PRs + unmerged branches)#122Kyarha wants to merge 2 commits into
Kyarha wants to merge 2 commits into
Conversation
Both orientation layers read only the project's own files, so work that is *finished* but parked — in an open PR, or on a branch nobody merged — is invisible to every artifact they consult, and orientation confidently reports the project as unblocked. The sharper half: unattended workers put their questions for the owner in the **PR description**, not in any file. So an agent asked "what's next" never sees them, re-derives the question set from raw review artifacts, and puts a worse-framed subset to the owner as if it were new. That happened in a downstream project (spec 096 Overview records it): four of five questions re-derived, the fifth missed entirely. Deterministic layer — `workflow.py orient` gains one optional segment: · in flight: 3 commits ahead of main on claude/night-prep Silent in every degraded case, so the pre-096 headline stays byte- identical: not a git repo, no git binary, no resolvable trunk, detached HEAD, level with or behind trunk, or any git failure. All git work shares one 1.5 s wall-clock deadline — a per-call timeout is not a bound when nine calls are possible, and overrunning the SessionStart hook's 4 s ceiling would leave the session with *no* headline at all, strictly worse than before. `origin/HEAD` is verified like any other candidate rather than trusted, so a stale one cannot silence the segment or produce a count against the wrong trunk. Both ref names are sanitised and capped before reaching the injected headline — git permits `·`, the headline's own field separator, in a ref name. Judgment layer — `skills/orient/SKILL.md` gains open PRs as its first survey item (`gh pr list` + `gh pr view` to read the *body*), a "Waiting on you" output section flagging stale / unmerged-no-PR / superseded, a cross-check so a question already put to the owner is not re-derived, and the generalising rule: "what's next" means what is blocked on a human, not what the repo contains. Three review passes, all of which found real defects: - compliance r1: the per-call timeout was not a bound; three tests passed with the feature deleted - compliance r2: UnicodeDecodeError escaped `orient()`; ref names reached the injected headline unsanitised (AC9 added rather than fixed silently) - reconciliation: a fourth vacuous test, plus four places where the written record disagreed with the tree All findings applied. 3527 tests, pyright clean, host packages in sync. The pinned pre-096 headline test is provably unedited — zero deletion lines in its diff. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
The problem
Both orientation layers — the deterministic
workflow.py orientheadline (088-01) and the/jig:orientjudgment briefing (088-02) — read only the project's own files. Neither looks at the collaboration layer.A status board describes the default branch. Work that is finished but parked — in an open PR awaiting the owner, or on a branch nobody merged — is invisible to every artifact orientation reads, so it reports the project as unblocked.
The sharper half is what unattended workers do: a night/cron worker that finishes a run opens a PR and writes its questions for the owner in the PR description — not into any file in the repo. Orientation never opens that description.
This is a field report, not a hypothesis. In a downstream project an overnight worker left a PR titled "(5 decisions need you)" whose body posed five questions in plain language with recommendations. A "what's next" pass surveyed specs, ADRs, refinement-todo, the inbox, the bug board, commits and branches — every local source — and never ran
gh pr list. It found the same work as an unmerged branch, concluded it was uncommitted drafts, re-derived the questions from the review files, got four of five, missed the fifth entirely, and put worse-framed versions to the owner, who had to answer them twice. Recorded in the spec's Overview.What this changes
Deterministic —
workflow.py orientgains one optional trailing segment:Absent — and the headline byte-identical to its pre-096 form — in every degraded case: not a git repo, no
giton PATH, no resolvable trunk, detached HEAD, level with or behind trunk, or any git failure.Judgment —
skills/orient/SKILL.mdgains open PRs as its first survey item (gh pr list+gh pr viewto read the body), a "Waiting on you" output section, a cross-check against re-deriving decisions, and the generalising rule in Judgment.Design notes worth reviewing
_in_flight_summarycan issue nine git calls. A per-call timeout × 9 blows the SessionStart hook's 4 s ceiling, and the hook swallows a timeout as no orientation at all — strictly worse than before this slice. All calls share one 1.5 s wall-clock deadline; once spent, the rest return without spawning.origin/HEADis verified, not trusted. A stale one (default-branch rename, pruned target) would otherwise silence the segment permanently, or produce a confidently wrong count against an old trunk.·— the headline's own field separator — in a ref name, so an unsanitised branch could forge a field. Reuses the existing claim whitelist at a cap that fits real branch names.ghin the CLI. It needs network and auth; the PR survey lives in the judgment layer only.Review record
Three independent passes, each of which found real defects — all applied:
UnicodeDecodeErrorescapedorient()(aValueError, uncaught); ref names unsanitised into the injected headline — AC9 added rather than fixed silently< 400chars passed with the cap deleted); four places where the written record disagreed with the treeThe deviation log carries 12 entries, including the ones nobody asked for: the per-call timeout dropping 2.0 s → 0.75 s can make the segment vanish on a cold repo (AC2-compliant, but a real behaviour change), AC4's
origin/<trunk>phrasing not literally describing the code, and the first-resolvable-candidate heuristic reporting againstmainin adevelop-trunk repo with a stale localmain.Honest limitation, stated in the log: all three reviewer subagents had read-only tools, so every executable claim was verified by the implementer. The independent checks are of the code and the record, not of the test run.
Verification
python3 scripts/run_tests.py→Ran 3527 tests … OK (skipped=4),pyright: cleanpython3 scripts/build_host_packages.py --check→ in syncpython3 scripts/spec_lint.py→ no contradictions across 95 specstest_scaffolded_headline_compacts_active_specs) is provably unedited — zero deletion lines in its diff🤖 Generated with Claude Code