Skip to content

Pedroro/release scout - #457

Draft
pedro romero vargas (p3dr0rv) wants to merge 161 commits into
masterfrom
pedroro/release-scout
Draft

Pedroro/release scout#457
pedro romero vargas (p3dr0rv) wants to merge 161 commits into
masterfrom
pedroro/release-scout

Conversation

@p3dr0rv

Copy link
Copy Markdown
Contributor

No description provided.

… projects

- Introduced `checks.py` in the `release-agent/tools` directory, implementing various readiness checks including Azure DevOps build definition access, HTTP reachability, and pipeline variable management.
- Updated `settings.gradle` to comment out several project inclusions, including `AcaPlugin`, `LinuxBroker`, `java-linux-test-app`, `LinuxBrokerPackage`, and `NativeAuthSample`, to streamline the build configuration.
…e conditions and ensure safe parallel execution; enhance error messaging for Azure DevOps authentication issues.
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

❌ Work item link check failed. Description does not contain AB#{ID}.

Click here to Learn more.

Engine (gate integrity):
- sign: remove blanket --all; CLI now requires explicit --item ids + refuses
  a bare sign, and records each attestation individually with an evidence
  --note. Closes the hole where sign --all attested every human item in one
  blind call (a release reached Phase 0 without real confirmation).
- readiness.sign() carries a per-item evidence note.

Readiness config/UX:
- silent_perms.required_servers now includes kusto + icm (the MCP servers the
  adx_access / oncall_now checks call) so they don't prompt on first run.

Skill (A: dedupe, B: modular split):
- Split the 48KB monolith SKILL.md into a lean 7KB core (golden rules +
  behaviour dispatch + reference routing table) plus skill/reference/*.md read
  on demand (readiness-gate, starting-and-scheduling, presenting-status,
  commands, phases/preflight, phases/_TEMPLATE). Core is now well under Scout's
  inline limit, so it no longer spills / gets skimmed.
- Fix regression where the readiness table was suppressed: render the checklist
  table FIRST, then handle silent-runs (was "before showing the checklist").
- Anti-assumption rule: never attest/approve on an echoed m_ask_user result.
- Scale convention: add a phase = phases.yaml + phases/agents/<id>.py +
  reference/phases/<id>.md + one routing-table row.

bootstrap.ps1: auto-install Python via winget + silent pyyaml; verify Scout
present + skill copy; restart Scout by default (guarded when run inside a Scout
session); UTF-8 + detached-launch fixes; clearer folder/run instructions.

Tests: 101/101 (added regressions for bare-sign refusal, no --all, evidence note).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Recurring regression: the model ran checklist (which auto-logs) but did not
paste the table into its reply, then asked for attestations in a table-less
message — losing the context the user needs.

- Core golden rule #2: running a command != showing it; the user only sees what
  you paste.
- New golden rule #2b: NEVER ask for a gate decision or attestation in a message
  that doesn't contain the freshly-rendered table (in the SAME message).
- readiness-gate.md step 3b: paste the table verbatim into the same message as
  the attestation question.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ecks

Two UX nits from testing:

1. Table rendered twice (once mid-auto-checks, once after). Restructured the
   readiness flow to render the checklist table ONCE, in step 3b, right before
   the attestations — steps 1-3a are now quiet setup (verify + silent-runs +
   scout checks) with no half-done table. Step 1 uses �erify (terse pass/fail)
   instead of checklist --verify (big table).

2. Model asked the user permission to run the ADX/Kusto query even though the
   kusto MCP server is auto-approved (verified: the query runs silently). The
   prompt was the model asking, not Scout. Step 3a now explicitly forbids asking
   permission to run the scout-assisted auto checks — they're auto-approved and
   must run silently.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…uctural fix)

Prompt-level 'render the table then ask' instructions were fragile — the model
would run checklist (auto-logged) but not paste it, then ask attestations in a
table-less message. Fix structurally in the engine instead:

- render.readiness_table now appends a '✋ Your confirmation needed' section
  listing the outstanding attest items, but ONLY once every auto item is
  satisfied. The table and the attestation prompt are now a single deterministic
  output — you can't show one without the other, and the prompt can't appear
  before the auto checks are done. Engine controls the ordering, not the model.

Skill readiness flow simplified to match: run all auto checks silently first
(never ask permission to run the ADX/on-call MCP calls — they're auto-approved),
then render checklist ONCE (its output carries the confirmation section) and
fire m_ask_user in the same message. Fixes both nits: single table render, and
no spurious 'can I run the query?' prompt.

Tests: 102/102 (added test_attest_prompt_welded_only_after_auto_done).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…plays)

Root-cause of the recurring 'no table, just a list' regression: it's controlled
by WHERE the checklist render sits in the tool-call sequence, not by wording.

- A checklist table render that is the model's FIRST action is pasted verbatim.
- A render placed AFTER a chain of silent tool calls (verify/record-check/
  m_get_settings) gets summarized into a plain list (model switches to wrap-up
  mode). The first render also primes verbatim-pasting for the second.

So the double-render is the control mechanism, not waste. Codified as a DESIGN
INVARIANT in readiness-gate.md so future edits don't collapse to a single
end-of-flow render and reintroduce the regression.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…wo-render flow)

Now that we understand the render-first mechanism, re-apply the engine welded
prompt WITHOUT the flow reorder that broke display:

- render.readiness_table appends '✋ Your confirmation needed' only once all auto
  items are satisfied. In the working two-render flow this means render #1
  (checklist --verify, scout items still pending) stays a clean table with NO
  prompt, and render #2 (after the silent scout checks) carries the welded
  attestation list. Verified: render1 no prompt, render2 has prompt.
- Keeps the proven display-first two-render flow (render #1 primes verbatim
  paste); adds deterministic attestation context to render #2 from the CLI so
  the model doesn't hand-build the list.
- step 3b notes the confirmation section comes from the CLI.

Tests: 102/102.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lock

User wants the table shown once, not twice. The two outputs are inherent (one
before the silent auto-checks, one after) — the fix is to make the SECOND output
a compact confirmation block, not the full table again.

- render.py: full table no longer carries the welded prompt; new public
  render.attest_prompt(chk) returns just the '✋ Your confirmation needed' block
  (or a status line if auto checks aren't done / gate cleared).
- new CLI mode: checklist --attest-prompt emits ONLY that block (no table).
- Flow: render #1 = full table (display-first, primes verbatim paste); silent
  auto checks; render #2 = checklist --attest-prompt = block only. One table
  total. Verified E2E: render1 has table/no block, render2 has block/no table.
- Invariant doc + step 3b updated to the single-table design.

Tests: 102/102.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…mplete table once + deterministic attestation card

Fixes the recurring readiness-display problems with a two-part approach:

1. Deterministic attestation card (removes the LLM from the critical path).
   - render.attest_prompt_payload(chk, release) builds the exact m_ask_user
     payload the engine owns: question + answer cards (1 confirm_all + one
     decline per outstanding attest item) + confirm_items + recommendedIndex.
     ready:false until all auto checks pass. On-call window dates surfaced in
     the confirm_all description.
   - `checklist --attest-prompt --json` returns that payload; the skill passes
     it straight to m_ask_user. The always-rendered Scout card is the guaranteed
     source of truth even if the markdown table doesn't render.

2. Table shown ONCE, AFTER full evaluation (the requested UX).
   - Skill flow reordered: steps 1-3 run all auto checks SILENTLY (Python
     verifiers, silent_perms, on-call, ADX) with no table/partial renders; step
     4 renders the complete checklist table (all [auto] items resolved to the
     final state) with explicit "paste verbatim, do not summarize" framing;
     step 5 presents the deterministic card; steps 6-8 map the answer to
     sign/decline. No more early/incomplete table, no spurious ADX permission
     prompt.

Gate integrity preserved throughout: no --all, explicit per-item sign, never
attest on assumption.

Tests: 103/103 (added test_attest_prompt_payload_is_deterministic_card,
test_attest_prompt_is_separate_render_never_in_table).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The phase map and current-phase steps tables used an empty-header first column
just for the status icon (| | # | Phase | Done |). Scout's table renderer gives
that empty column a huge width, leaving a big gap before the # column.

Fix: drop the standalone icon column and prefix the icon onto the Phase/Step
name — '| 0 | 🗓 Pre-flight … |' instead of '| 🗓 | 0 | Pre-flight … |'. Clean
3-/2-column tables, no empty gap. (Readiness table left as-is — user-validated.)

Tests: 103/103.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Give every Phase-0 step ONE home under steps/<phase>/ authoring a single
build(state) -> Outcome, replacing the split where scout steps were scattered
across phases.yaml + stub_runner + commands/*.py + templates + skill md.

Outcomes (orchestrator/outcomes.py): Done | Blocked | NeedsHuman | NeedsSkill.
Generic dispatcher `step-action` serializes a migrated step's outcome as JSON so
the skill reacts uniformly (needs_skill -> run tool + record-step; needs_human ->
show prompt + done). Agent steps run in-process during `next` (step-action
refuses them).

Migrated (steps/preflight/):
  scout : notice, flight_reminder, lockdown (gather-then-decide via check-lockdown)
  attest: confirm_reminders, vitals (NeedsHuman prompts)
  agent : breaking, cg, cron, wiki (Done/Blocked, engine-run)

Shared libs: steps/lib/{context,templating,agent}. Legacy homes
(phases/agents/preflight.py, commands/notice.py, commands/lockdown.py) reduced to
thin compatibility/recorder shims so the engine + 103 tests are unchanged.

Also fixes:
- render.py: phase-map legend was glued into the table as a one-column row
  (missing blank line) -> now a separate italic caption.
- skill docs: render the status table ONCE per advance pass (after the work),
  not an interim table before running the scout steps.

103/103 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ils + knowledge

Replace the dry-run boolean with a real-by-default model plus a personal,
gitignored mocks.local.yaml overlay for safe testing:

- Remove dry_run entirely (state/engine/render/cli/steps). Every run makes real
  calls; the fake "[dry-run] Would…" branches are gone.
- Mock overlay (orchestrator/mocks.py + steps/lib/mockctx.py): mocks.local.yaml
  can, per step, force outcome (done|blocked), redirect a real send (send_to),
  or inject inputs so the step's REAL logic runs on your data (cg alerts,
  breaking changelog, cron run, wiki page_name/name_suffix, notice variant).
  Readiness entry-gate auto checks are mockable too (readiness.<item>).
- Each step DECLARES its mockable knobs (MOCKABLE); `mock-spec` lists exactly
  what every step exposes (steps + readiness), with typo detection.

Status "Details" column (render): a third column captures each step's execution
outcome from its stored note — where a lockdown clashed, the breaking change, CG
alerts found, the created wiki link — generic for all current/future steps, with
rich multi-line notes expanding below. Durable refs are now first-class:
StepState.links [{name,url}] (wiki page, CG alerts page + per-alert deep links),
threaded Done/Blocked -> StepResult -> StepState -> render.

Step knowledge base (config/knowledge.yaml + orchestrator/knowledge.py +
`step-info`): curated per-step help (what/where/how/links/faqs) so the skill
answers step questions accurately instead of guessing. Fixes the Play Console
vitals navigation. SKILL.md consults step-info for step questions.

Also: readiness table groups auto items before attest (oncall_now before
play_console_access); breaking-change entries no longer double their bullet.

106/106 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…registries

Make a step a single self-contained module so adding one touches ~2 files and can
never silently drift:

- Auto-discover step modules: steps/__init__.discover() scans steps/<phase>/*.py.
  Remove the hand-maintained _STEPS list.
- Engine resolves agent steps via steps.get_step() (module.run when KIND==agent),
  stub fallback otherwise. DELETE phases/agents/ (package + REGISTRY) and the dead
  `agent:` field from config/phases.yaml — no runner registry, no agent-id indirection.
- Co-locate step CONFIG into each module (CONFIG constant); remove config/preflight.yaml
  and orchestrator/phase_config.py. The module is now the single home for a step's
  logic + mock knobs + config.
- Structural guardrail test: every discovered module maps to a phases.yaml step and
  its KIND matches the config flags — drift fails LOUDLY.

config/phases.yaml is now pure COMPOSITION (which steps, order, deps, flags); a
step's logic/config lives in its module; knowledge stays in config/knowledge.yaml
(a module may override via KNOWLEDGE). README documents the 2-file "adding a step"
contract. Tests point at steps.preflight.* directly; block-path tests use the mock
overlay instead of registry patching.

107/107 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Correct the Component Governance alerts link to the real One/AD-MFA
  phonefactor-phoneApp-android componentGovernance page (in the cg module
  CONFIG and knowledge.yaml).
- Pending scout steps (e.g. lockdown) now render as 'Scout runs this'
  instead of 'Your action' and are no longer flagged as needing the user;
  they only escalate to a blocked user action when a scout step records an
  attention/overlap.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The knowledge base had no ownership fact for the CG step, so 'who fixes
this?' was answered by guessing (wrongly deferring to the component owner).
Record the real rule: the RELEASE OWNER remediates Component Governance
alerts, including authoring and landing the fix PR. Add a 'who' field to
the knowledge schema/renderer and populate it (plus a matching FAQ) for
preflight.cg.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Free-form step questions (what/why/who/how about a step) are exactly the
'interaction' the event log is meant to capture, but nothing journaled
them, so surfacing missing/inaccurate knowledge (e.g. CG ownership) left
no trace. Add a thin two-sided 'step_qa' event: EventLog.qa(), a
'journal --kind qa --question ... --answer ...' path, log-viewer rendering,
and a questions_answered rollup in summarize(). Wire the skill so that,
during an active release, answering a step question from step-info silently
journals the pair (skipped when no release run exists).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ocalization

Build out the first three CCD steps as self-contained scout modules under
steps/ccd/ (auto-discovered), each doing the real work idempotently:

- final_reminder  (email)  — CCD-day 'code complete is TODAY' notice to the
  Android DL (the 'update' variant of the Phase-0 notice template).
- pr_reminder     (Teams)  — NEW step; posts to the 'Code reviews' chat: merge
  every required PR before the 11 PM auto branch-cut; a CCD delay or post-CCD
  cherry-pick both need Moumita Ghosh's (moghosh@) approval; merge string PRs
  before the noon localization run.
- localization    (trigger)— fires pipeline 405133 (msazure/One) with
  isCreatePrSelected=true; PR created => strings to merge, no PR => none.

Each module carries CONFIG (incl. fire_at_local timing), MOCKABLE knobs,
knowledge.yaml entries, and tests. phases.yaml marks the three source: scout
and inserts pr_reminder (P1-1b); branch_cut stays the human gate. Timing is
encoded per-step (09:00 / 12:00) for a per-release CCD automation to drive;
the engine stays date-based. EXTERNAL-REFERENCES catalogs the new chat,
pipeline, and approver. Test harness gains _clear_ccd_scout so flow tests
reach the branch_cut gate. 114/114.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wire the timed Phase-1 automations into release-start provisioning, and close
the traceability gap: the registry knew an automation's id/release/purpose but
not WHICH STEPS it drives.

- config/automations.yaml: declarative source of truth mapping each per-release
  automation to the steps it drives. Timing is DERIVED from each step module's
  fire_at_local (no duplication).
- orchestrator/automations.py: plan(release, ccd) emits concrete specs
  (name/schedule/steps/prompt/registration) for the skill to create; validate()
  enforces every fire_at_local step is owned by exactly one automation and each
  automation's steps exist + share one fire time.
- registry: entries now carry steps[]; list(step=...) is the reverse lookup
  (which automation owns a step). �utomation plan CLI action + --step /
  --step-filter flags.
- Guardrail test test_automations_cover_every_scheduled_step makes the mapping
  self-enforcing; plus registry-linkage and plan tests.
- SKILL/commands/scheduling docs: provision timed automations at start
  (register WITH --step), reverse/forward lookup, runtime journaling. 117/117.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
'Release push reminders' drives no steps — it advances the whole release via
hourly tick. An empty steps[] read the same as 'not filled in', so label the
category explicitly. Registry entries now carry a 'kind': step-driving (owns
steps) or release-level (whole-release, no steps), auto-derived from whether
steps are present, with a guard that the two can't contradict. kind_of()
derives it for legacy entries. CLI: --kind on register (override) and list
(filter); list shows [kind] and '(release-level - no steps)'. Docs note push
reminders is release-level. 118/118.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Code Complete Day is now three scout steps (final_reminder, pr_reminder,
localization) with NO gate:
- branch_cut: removed — the release branch is cut AUTOMATICALLY at 11 PM,
  there is no manual cut action, so a human 'cut the branch' gate was wrong.
- precheck_prs: removed — there's no reliable signal for which PRs are
  'required' for a release, so an automated pre-check can't be built honestly.
- verify_trigger: removed from Phase 1 — verifying the overnight/auto build
  fits Phase 2 (Build & Lib Verification), not Code Complete Day.

Consequence: the first human gate is now go_test (Phase 2). Updated the flow
tests (first gate go_test, second stop the bug-bash ui_failures hold), the
phase-shape test, the mocks example, and stale comments. 118/118.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make localization a small state machine instead of fire-and-describe:
- TRIGGER: build() runs pipeline 405133 (isCreatePrSelected=true); the runner
  calls record-localization-run to store the build id + start time and leaves
  the step IN-FLIGHT (StepState gains a durable data dict).
- POLL: a per-release "every 10 minutes" poller automation calls
  check-localization; the pure decide() applies:
    * running and under 3h  -> wait, poll again
    * running and over 3h   -> email the release engineer (with the manual-steps
      localization doc) and hold the step
    * complete              -> parse the OneLocBuild@3 log for the
      "Pull request created with ID" line; if found, post that PR to the Code
      reviews chat for review and mark done (with the PR link); else done (no
      strings).
All decision logic is pure/tested; IO is done via NeedsSkill/decision payloads.

Adds: steps/ccd/localization.py rewrite (helpers, decide, KNOWLEDGE incl. the
eng.ms localization doc), orchestrator/commands/localization.py
(record-localization-run, check-localization), StepState.data, an interval
"every N" automation kind in automations.yaml + planner/validate (pollers are
exempt from fire_at_local single-owner accounting; may share a step with a
time-of-day trigger), and docs/refs. 124/124.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ocument orgs

Real-tenant check against build 176407869 (msazure/One) confirmed the ADO MCP
can't reach that org (TF200016) but az can. So:

- localization CONFIG carries the exact az reads (az_read: status via
  `az pipelines build show`; OneLocBuild@3 log id via `az devops invoke ...
  timeline`; log content via `... logs`). build()._trigger and the poller
  automation prompt now spell these out for msazure/One.
- extract_pr() prefers the full PR URL the OneLocBuild@3 log prints after the
  id (real form includes /DefaultCollection/), falling back to the template;
  pr_url_template updated to the DefaultCollection form.
- KNOWLEDGE explains MCP-can't-reach-msazure and the az read path.

Also document the two-org reality in EXTERNAL-REFERENCES: Engineering lives in
identitydivision (ADO MCP bound here); One lives in msazure.visualstudio.com
(az only). 125/125.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ore EOD)

When the completed localization run's PR is posted to the Code reviews chat,
the message now @mentions the release engineer (release owner) and asks them
to ensure the PR is merged before EOD. _review_post builds the Teams mention:
an <at id="0"> tag in the html content matched by a mentions[] entry
(id=owner UPN, userIdentityType=aadUser) that workiq_send_chat_message
consumes. Falls back to a plain (unmentioned) post when no owner email is set.
Tests + KNOWLEDGE updated. 126/126.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two per-step mock knobs (exercised in a real msazure/One test run, build
177042471):
- create_pr (input): overrides isCreatePrSelected on the trigger; set false to
  run the pipeline WITHOUT creating a PR.
- send_to (post): redirects the completion PR post to your own chat ('me').
  Applied by check-localization, since the post happens in the poll decider,
  not build().

step_action's payload-override now only touches kind:payload knobs, leaving
input (build) and post (poller) knobs to their proper stages. 126/126.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The 1343-line, 66 KB tools/pipelines.py is split into tools/pipelines/ (6 files,
largest 18 KB) by concern:
- _rest.py         — az/ADO REST primitives
- orchestrator.py  — Orchestrator/Checker/MRWP run discovery, stages, timeline,
                     approvals + the Engineering release-chain coordinate constants
                     (moved here from the report layer, their proper owner)
- tests_results.py — test classification, retry reconciliation, summaries, verdicts
- rc_model.py      — release_report/assemble_rc_model + version formatting
- auth_app.py      — Authenticator (msazure/One) build+UI discovery, tagging, PRs
- __init__.py      — façade: re-exports every public + underscore name in dep order

Public API is byte-identical (`tools.pipelines.<anything>` unchanged), so all ~40
consumers are untouched. Intra-package calls go through the package namespace
(`_pp.foo()`) so the ~31 test monkeypatch sites keep working with zero test edits.

349 tests pass; verified with a live ADO read through the package.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The 7068-line tests/test_engine.py is split into a shared tests/_harness.py
(all 34 helper functions + _SAFE_AGENTS + constants, auto-exporting its whole
namespace) and 12 per-area test files (test_core, test_finalize,
test_build_verify, test_readiness, test_bug_bash, test_preflight,
test_automation, test_ccd, test_schedule_state, test_sim, test_tools,
test_status_email).

Every test body is byte-identical — blocks were sliced verbatim and re-homed;
each file reproduces the original module scope via `from tests._harness import *`.
Collection = 349, run = 349 passed (exact match with the original). The existing
conftest.py (path + autouse network guard) works unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Scout/agent steps return NeedsSkill(tool, payload={followup_command}); those
engine-command names live as string literals in step code and prose in SKILL.md,
so they can silently drift from the registered CLI commands on a rename.

- orchestrator/outcomes.command_verb(): codifies the contract seam — extracts the
  engine-CLI verb from a followup_command / engine-command tool, returns None for
  MCP tools (workiq_*/microsoft_teams-*/kusto_query/azure_devops-*).
- tests/test_contract.py: asserts every followup_command and every engine-command
  NeedsSkill tool names a REGISTERED CLI command (scans steps/ + orchestrator/),
  plus a non-vacuous sanity check. Rename a command without updating the string
  -> fails loudly.

353 tests pass (349 + 4).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Automation naming: every provisioned automation now uses one standard
title format `<release-id> · <scope> — <label>` (release first, then the
phase display name, then the short purpose) so titles are consistent and
scannable. Adds automation_name() + phase_label() helpers in
orchestrator/automations.py; config/automations.yaml entries switched from
a verbose templated `name:` to a short `label:` (scope derived from the
phase, with an optional `scope:` override for non-phase automations). Skill
docs, knowledge, and the finalize step reference the new names.

Phase-table fix: in status_views._current_steps, an unopened phase now
shows EVERY not-yet-run step uniformly as "Not open yet" — the not_phase_due
check moved above the gate/scout/auto checks so scout steps no longer
mislabel as "Scout runs this — automatic" while their agent/human peers
show "Not open yet" (the confusing mix).

Tests: +4 (name-format + helpers; unopened-phase uniform vs open-phase
differentiated). 357 pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The push-reminder loop's prompt runs `next --json` to advance the release
and read `scout_pending`, but the `next` subparser never defined --json —
so it errored and Scout fell back to `next` then `status --json`. `next`
now accepts --json and, after advancing, prints status_report() (same
shape as `status --json`, carrying scout_pending), matching the docs and
collapsing the two-call dance into one.

Test: next --json emits valid JSON with scout_pending; plain next still
prints the human advance block. 358 pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Jia Le He is leaving the project. Removed from both roles:
- notice/reminder email recipients (preflight.notice, ccd.final_reminder)
  + the knowledge/EXTERNAL-REFERENCES mentions of that DL
- bug-bash always_excluded list (distribution.yaml) + the two knowledge
  prose mentions
The eligible-testers test swaps her for a neutral `excluded@x` placeholder
so exclusion-removal coverage is preserved. 358 pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The skill assumed the android-complete clone lived at C:\repos — wrong for
other users. The engine was already portable (cli_common self-locates from
__file__); the gap was the skill docs' hardcoded paths.

- New engine command `paths [--json]` reports the self-located roots
  {agent_root, repo_root, runs_root} — the source of truth for where to cd.
- SKILL.md gains a FIRST RUN block (runs once per machine, before Discover):
  recall a remembered path; else auto-detect the release-agent clone, run
  `paths --json` to canonicalize, ALWAYS confirm with the user, then
  m_remember it. Introduces <AGENT_ROOT>/<REPO_ROOT> placeholders; "Where
  things live", "start a release", and commands.md now use them.
- Headless automation prompts (push reminders, status email) instruct
  substituting the absolute confirmed path, since a placeholder can't resolve
  with no one watching.

Test: paths reports self-located roots + honors --runs-root; JSON shape. 359 pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The start flow asked two confusing questions: "which month?" (ambiguous — the
id is the CCD/work month) then "…so it's the <next month> release, right?"
(felt like a contradiction, because a release is NAMED for its ship month =
CCD month + 1). Now it's ONE coherent confirmation that shows the ship-month
name and the CCD date together, so the user never picks a bare month and then
gets told it's a different one.

- New read-only `preview-release [--month] [--count] [--json]` command +
  schedule helpers (month_add, preview_release, preview_releases) derive, for
  the current month plus the next few, the ship-month display name and the
  default CCD (2nd Wednesday) — no state, no IO.
- SKILL.md "start a release" reworked: lead with the computed default
  ("Start the October 2026 release — code-complete Wed Sep 9, 2026?"), offer
  the alternatives by name + CCD; drop the separate post-init name-confirm.
- starting-and-scheduling.md: the name is confirmed up front, not re-asked;
  set-target-month kept only as a rare override.

No engine behavior change (init/set-target-month untouched). Tests +4. 363 pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Swept all 130 files with vulture + pyflakes. Removed only confirmed-dead
code and fixed two real latent bugs; held back tested-but-uncalled helpers.

Dead code removed:
- unreachable functions: engine._first_incomplete + _iter_steps (the latter
  orphaned once its only caller went), stub_runner.get_runner/REGISTRY (engine
  calls run_stub directly), checks.check_http (+ its urllib imports),
  oneauth_common_pr._pr_url, distribute._name_map.
- unused imports across 10 modules (Optional, time, Orchestrator, _json,
  SELF_CHAT_ID, coords, Done, and the pipelines submodules' json/shutil/
  subprocess/coords). Left intentional re-exports intact (lockdown's noqa
  line; _common's K.CHECKER_DEF/ORCH_* which siblings consume).

Latent bugs fixed:
- tools/pipelines/orchestrator.py had TWO orchestrator_stage_state defs; the
  second silently shadowed the first. Removed the dead get_stages version;
  the live, tested get_timeline one serves both callers.
- schedule.py used Tuple in an annotation without importing it (masked by
  `from __future__ import annotations`) — added the import.

Also dropped two empty f-string prefixes. 363 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Return Done before rebuilding completed or skipped step actions, preserve original completion records, and refresh step-action after approval before sending. Reuse the existing step lifecycle without delivery-specific state or commands. Concurrent pending executions remain a separate follow-up.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use StepState execution ownership for standard MCP actions completed through record-step. Keep interrupted work reserved for owner-reviewed recovery, preserve repeatable telemetry observations, and use OS-managed locks instead of age-based lock stealing. Update executor instructions and status guidance without introducing a delivery subsystem.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Have the existing hourly tick produce an independent Android Core Team alert at 9 AM on the last working day before CCD and again on CCD morning while Phase 0 remains incomplete. Include owner mention, blocker details and links, policy-safe resolution guidance, retry until successful delivery acknowledgement, and keep read-only notify observational.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Require declarative cleanup rules, separate startup and on-demand pollers, and centralize cleanup planning so workers delete live Scout automations before deregistering them. Cover CCD one-shots, localization timeout, RC settled state, Bug Bash completion/sign-off, final status, schedule sync, and release completion without migration logic for prior runs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Persist APK build metadata and telemetry provenance; reject stale or mismatched result evidence.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Prevent premature reports and false passes; align RC polling and email messaging with actual readiness.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Separate RC reporting, rendering, Authenticator verification and shared MRWP logic without changing behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ions

Count each MRWP test once with any passing attempt winning; preserve complete source evidence and failure/recovery lists. Display Authenticator percentages to two decimals and a consolidated recommendation. Update knowledge and regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Project reconciled verdicts into plan configurations, preserve source provenance, and align current failure assignments and reminders. Update knowledge and regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Persist availability and preview evidence, reject stale assignment plans, and preserve agent step data through state transitions. Update skill guidance and regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Persist per-channel claims and acknowledgements, reject stale or expired delivery, finalize only after confirmed sends, and reconcile scope-aware cleanup. Route existing notification producers through the shared protocol and update knowledge, skill guidance and regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep release resource identities separate from step completion, bind checkpoints to the active release transaction, and reject incomplete or malformed paged reads.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Recover existing Broker plans instead of recreating them after errors. Route results by full tested configuration and retain Authenticator Monthly tests as report-only owner investigations. Separate source evidence, report preparation, mapping and durable fill receipts so distribution and progress consume published results without replaying earlier-phase logic.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Filter owner, resolved on-call and permanent exclusions before availability choices. Keep blocked and failed automated cases in explicit owner triage, and align case assignees with plan testers without changing outcomes. Preserve preview approval and fail incomplete assignment alignment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use America/Los_Angeles regardless of owner or runner timezone, prevent overnight starts, and show the meeting-date UTC offset in invite previews and body text.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Resolve the sent event ID through its Teams join URL to the exact meeting thread. Reject unrelated or stale chat bindings, enforce activation prerequisites, and bind both initial and recurring notifications to invitation evidence.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

1 participant