infiquetra/mission-control
Portable mission-control package: SDLC management for Infiquetra's Operations, Asgard, and CAMPPS boards — one shared CLI plus seven Agent Skills covering prepared issue drafts, live schema sync, board schemas, labels, project fields, flow helpers, metrics, milestones, rollout tracking, and card validation, derived from infiquetra-claude-plugins at the 2.15.2 revision. Claude Code files live under the com.infiquetra.claude client extension directory; the portable manifest, the package README, and the runnability enforcement are authored here.
Changelog
[2.15.2] - 2026-08-30
Fixed - retire the CAMPPS ladder from the board skill and kanban reference (unit W19, issue infiquetra/infiquetra-sdlc#100)
skills/board/SKILL.mdandskills/board/references/kanban-workflow.mdno longer document the retired CAMPPS ladder as current. CAMPPS is documented with the sharedstage_flowworkflow (Intake -> Shaping -> Planning -> Active -> Verify -> Retro), whose stages and per-stage Status sets are transcribed fromconfig/sdlc-schema.jsonat schema version2026-08-29. No active board carries a pause column; a paused card is expressed through labels and issue state.- Command examples now name flags and values that exist:
board moveexamples use livestage_flowStatus values, the Stage-column example usesflow set-field --field Stage, and the CAMPPS archive and standup-review prose follow the schema (Ready to closeis the terminal status). - The Mount Olympus legacy timeline facts are preserved as pointers to
LIVE_LEGACY_STATUS_ALIASESinsdlc_manager.pyinstead of hand-copied value lists. - Document Review cycle 1 dropped the kanban-reference claim that CAMPPS uses "the same
six stages as Operations and Asgard." That phrase was schema-true and contradicted the
still-stale Operations/Asgard
intent_flowsection in the same file. The CAMPPS section now statesstage_flowand points at the deferred correction, matching the board skill.
[2.15.1] - 2026-08-30
Fixed - prepared-issue starting Status derives from Stage (unit W10 repair, issue infiquetra/infiquetra-sdlc#91)
- The prepared-issue starting-status rule no longer keys off the team. The
retired
_TEAM_SAFE_STATUSEStable (asgard → Shaping,campps → Idea) made readiness unsatisfiable: neither name exists in the live Status vocabulary, so every author-supplied Status was refused and the default was unwritable. - Starting Status is now author-supplied, with its default derived from the
declared Stage: the schema's
workflows.stage_flowentry option (first name of the stage's list, R49 — Intake→Capturing, Shaping→Discovering, Planning→Designing, Active→Implementing, Verify→Awaiting verification, Retro→Gathering evidence). The map resolves through_resolve_sdlc_schema()(GitHub main → vendored → local), so the vocabulary lives in one versioned source. Readiness accepts any Status configured WITHIN the declared Stage plus the cross-cuttingBlocked, and refuses retired, unknown, and out-of-Stage values (operator ruling of 2026-08-30 settling cycle-5 F-2; the entry option is a default, not a closed set). A declared Stage outsidestage_statusesblocks instead of silently skipping the Status rule. - The
issue prepare/create-preparedoperator docs no longer teach the retired team-keyed starting statuses (Asgard Shaping/CAMPPS Idea): the issues skill, README, and sdlc-operator prompt now state the Stage-derived entry-option default and the in-Stage acceptance rule (F-1). - The vendored
config/sdlc-schema.jsonwas refreshed to the authoritative 2026-08-29 file from infiquetra-sdlc main — the previous vendored copy was 2026-06-17 with nostage_flowblock at all, which masked the defect online and degraded it silently offline. _resolve_sdlc_schema()'s remote branch now degrades on ANYghfailure or undecodable payload (matchingload_config's remote fallback) instead of escaping asUnicodeDecodeError/JSONDecodeError.- A stage-less prepare no longer emits a
status:front-matter line (the default is not derivable without a Stage); the draft stays blocked on the missingStage. The R3b fill-in may now addstage:alone: an empty Status with a declared Stage is defaulted to the entry option on read, before readiness evaluates.
[2.15.0] - 2026-08-29
Added - the Intake exit initializes both lifecycle fields (unit W10, issue infiquetra/infiquetra-sdlc#91)
issue create-preparedcreates the issue, adds it to the correct project, and then performs TWO sequential constrained lifecycle writes —Stagefirst, thenStatus— through the sameflow_set_fieldcall site (W6's cross-board mutation), stopping at the first failure; each step is removed fromremaining_stepsand persisted only after its own write returns, so the existingpost_create_pendingresume state recovers a partial run without creating a duplicate issue.PreparedIssuecarries an author-suppliedstagewith no default and no handoff-maturity mapping (operator ruling on sdlc#91 OQ1). A prepared draft missing or holding an emptyStagefails readiness blocking, before any GitHub issue is created;issue preparestill emits the draft file so the author can fillstage:in (R3b — CLI prepare has no--stageflag by settled decision). The draft writer emits thestage:front-matter line only when a value is present, so the naive front-matter splitter can never store the literal stringNoneas an authored Stage.- A still-blocked
None-approval sidecar whose re-read readiness now passes (the R3b fill-in path) is STAMPED into the U11 approval gate even when--skip-approvalis passed — the stamp and the per-invocation bypass are separate decisions — and the refusal then honors--skip-approvalfor that invocation only. A stopped run (e.g. mapping_pending) therefore leaves a durable gate record, and a later create without the flag refuses instead of falling through as a pre-U11 legacy draft.ready_to_createsidecars withNoneproceed unchanged (deliberate pre-U11 back-compat). - The mutation plan shown for confirmation names both writes (
set-stagebeforeset-status). - A legacy
post_create_pendingsidecar whose remaining lifecycle steps lack a"stage"token is migrated: the Stage write is inserted before"status"and still runs on resume (flow_set_fieldis idempotent).
Changed
- The interactive
issue createpath prints a non-blocking NOTE immediately after the pasted issue number — before the card-contract gate — reporting that the issue was created outside the Intake exit and that the prepared-path initialization of bothStageandStatusdid not run. It never claimsStatusis unset. Abort, decline-browser, no-number, and--skip-metadatastay silent (no issue exists on those paths).
[2.14.0] - 2026-08-29
Added - identity-preserving single-select option-set helper (issue infiquetra/infiquetra-sdlc#94)
fields set-options --project <p> --field <f> --options-file <json> [--dry-run]: replaces a single-select field's option set viaupdate_field_single_select_options, which refuses — before any mutation is sent — a submission that is not the COMPLETE desired list, drops a live option, or omits an existing optionidon a retained or renamed option (singleSelectOptionsoverwrites the whole set; omitting an id mints a new option and clears every item value pointing at the old one).fields create-optioncorrected: it has never mutated anything; its doc, help, and runtime output now say so plainly, and the destructive one-optionQUERY_CREATE_FIELD_OPTIONreference example was removed fromskills/board/references/graphql-queries.md.QUERY_GET_PROJECT_FIELDSnow returns optioncoloranddescriptionalongsideidandname, so the helper has the full live attribute set when composing a submission. The--options-fileitself must still be a JSON array of option objects ([{name, color, description?, id?}]), not the discover command's printed report (whose shape is{project, fields}): runfields discoverto read the current names, ids, colours and descriptions, then write the complete list file by hand.
[2.13.0] - 2026-08-28
Added - one constrained lifecycle-field mutation, atomic across every board carrying the issue (#87)
- Added the constrained cross-board lifecycle mutation in
sdlc_manager.py(_set_lifecycle_field_cross_board): it writesStageandStatus— and only those fields — to EVERY project board carrying the issue, discovered from the issue's ownprojectItems(QUERY_GET_LIFECYCLE_FIELD_BOARDS), never from a repo-to-board mapping. Reuses the existingassert_correction_field/correction_identitycorrection seam, so the emitted identity strings stay byte-identical to saga's ledger key. Proves acceptance examples AE3/AE9/AE27/AE37 (infiquetra/infiquetra-sdlc#87). - Atomicity is apply-then-compensate: every carrying board is preflighted (field + option resolve there) before the first write; a failed write restores each already-written board's captured prior value; a board whose prior value was unset counts as a FAILED restore (no clear primitive exists). A failed compensation halts with a named divergence (
LifecycleMutationHaltError, carryingboard_state) — non-zero exit, no silent retry, never swallowed by the prepared-issue loop'sexcept RuntimeError. - Added
--reasontoflow set-field(optional; recorded verbatim per board; omitted writes the explicitreason-not-suppliedsentinel, never a fabricated justification). - Added tests:
test_lifecycle_field_boards.py,test_lifecycle_field_mutation.py,test_lifecycle_field_routing.py,test_lifecycle_field_identity.py, and the KTD12 AST writer-census gatetest_lifecycle_writer_census.py.
Changed - flow set-field and board move blast radius for Status/Stage (KTD10/KTD13)
flow set-field(andflow_set_fields_bulk, hence every--numbers/repeated---fieldpath) now routes EVERYStatus/Stagewrite — with or without--correction— through the cross-board mutation, selected by field name, not by flag. A single-boardStatus/Stagewrite is no longer possible:--projectis validated as a carrying board, never obeyed as a restriction. Affected callers: saga's board writer (board_progression.py, unchanged argv, now cross-board), the issue-create post-step, and the prepared-issue field loop.board move(KTD13/D2): the per-project best-effort write loop is gone;board moveroutes itsStatuswrite through the constrained cross-board mutation and no longer continues past a failed board.#609holds: an ordinary failure still returnsFalseand exits 1 via the CLI arm; a compensation halt raises instead.- Non-lifecycle fields (
Initiative,Objective,Priority, ...) keep the exact previous single-board behavior.
[2.12.9] - 2026-08-26
Removed - dead rollout update subcommand and beads-config write claims (#821)
- Removed the dead
rollout updatesubcommand parser, therollout_update()function, the dispatch arm, the module-docstring example, the reader-list comment mention, and documented invocations acrossREADME.mdandskills/rollout/SKILL.mdper operator ruling C2. - Left the
legacy_rollout_configmechanism and its three surviving readers (board_wip,rollout_status,config_show) intact and gracefully degrading to{}on missing files. - Added
TestMissionControlRolloutSurfaceGuardintests/test_mission_control.pyverifying thatrollout --helplists exactly five subcommands with noupdate,rollout updateis rejected as an argparse invalid choice, no document namesbeads-config.jsonas a write target, the three readers handle missing configs gracefully, and mutation tests fail on reintroducing the dead command or write claims.
[2.12.8] - 2026-08-26
Fixed - add flow row to skills table in README (#820)
- Added the
flowrow to the "Skill | Activates When..." table inREADME.mdwith activation text consistent withskills/flow/SKILL.md(Project field assignment, sub-issue linking, label verification, card validation), restoring complete alignment between shipped skills and the README activation map. - Added
TestMissionControlSkillsTableBijectionGuardintests/test_mission_control.pyasserting a bidirectional 1-to-1 match (bijection) between directories underplugins/mission-control/skills/and README table rows, ensuring failure messages name specific missing or extra skills, verifying activation content, and mutation-proving that removing theflowrow or altering skills fails the guard.
[2.12.7] - 2026-08-26
Fixed - delete self-referential alias clauses in issue command docs (#819)
- Deleted the self-referential compatibility alias clause from
commands/issue.mdand historical changelog entries, restoring clarity that/issueis the primary issue command surface with no unrecoverable rename claim or nonexistent compatibility alias. - Added focused assertions in test suite verifying that no sentence names a command as its own compatibility alias, that neither repaired sentence carries an alias clause, and that the plugin ships exactly four commands (
board,issue,metrics,triage).
[2.12.6] - 2026-08-26
Fixed - update-surviving installed script paths in docs and commands (#818)
- Replaced six version-pinned installed script paths (pinned to legacy cache directories) in
README.md,commands/board.md,commands/issue.md,commands/metrics.md, andcommands/triage.mdwith the settled convention"$CLAUDE_PLUGIN_ROOT/scripts/sdlc_manager.py"(noskills/segment). - Added drift guards in
tests/test_mission_control.pyverifying no version-pinned paths exist across tracked Mission Control documents, confirming all six sites use the$CLAUDE_PLUGIN_ROOTinvocation form, mutation-proving that restoring a pinned path fails the guard, and confirmingagents/sdlc-operator.mdremains unaffected.
[2.12.5] - 2026-08-26
Fixed - dynamic package-root resolution in sync_template_docs.py (#822)
- Replaced fixed
REPO_ROOT = Path(__file__).resolve().parents[3]atsync_template_docs.py:16with dynamic_find_package_root()discovering.claude-plugin/plugin.json, adopting the identical package-root resolution pattern established in issue #829. - Updated derived paths (
REFERENCE_PATHandCONTRACT_DATA_PATH) to resolve relative toPACKAGE_ROOT, enabling relocated and staged copies ofmission-controlto run entrypoints including--helpand--checkregardless of directory depth. - Maintained fail-loud behavior naming the resolved path when
.claude-plugin/plugin.jsonor required data files are missing. - Added relocated-copy guard tests and mutation proof in
tests/test_mission_control.pyandplugins/mission-control/tests/test_template_sync.pyverifying--help,--check, missing-file fail-loud behavior, and failure of the staticparents[3]pattern.
[2.12.4] - 2026-08-26
Fixed - defer module-scope PyYAML import in sdlc_manager.py (#828)
- Moved
import yamlfrom module scope into_load_live_mimir_coverage(), allowing--helpand every YAML-free subcommand to run on an interpreter without PyYAML installed. - When PyYAML is absent, invoking Team Mimir coverage validation raises a clear
RuntimeErrornaming the missingPyYAMLdependency rather than failing at module import with an unhandledModuleNotFoundError. - Behavior with PyYAML present is unchanged; PyYAML remains a declared dependency.
- Added
test_sdlc_manager_optional_deps.pywith unimportable-yaml simulations and an AST/mutation proof.
[2.12.3] - 2026-08-25
Added - field-named Status/Stage correction identity on flow set-field (#812)
flow set-field --correctionrejects any project field other than Status (and Stage by name). Operator writes of Initiative / Objective / other live fields omit the flag and are unchanged. No new operation.- Correction results carry the field name in operation, authorization, and retry identity
so a saga submission and a retried write name the same field. The reported retry identity
is byte-identical to saga's ledger key
(
reversibility_certificate.idempotency_key), so the two sides correlate on one string. --correctionnow also covers the bulk (--numbers/ repeated--field) path: the restriction is enforced insideflow_set_fields_bulkrather than only in the CLI parser, and a bulk correction is marked in its result with per-card identity.
[2.12.2] - 2026-08-24
Fixed - GraphQL project fields pagination, query-scoped pagination lint, and explicit live parity skip (#584)
- Paginated
QUERY_GET_PROJECT_FIELDSwith cursor andpageInfoviapaginate_or_raiseinget_project_fieldsandboard_census.py:fetch_project_fields_census, eliminating silent field truncation on boards with >30 fields (R1). - Made
check_pagination.pyquery-scoped so unpaginatedfirst:query literals inside files that paginate elsewhere are flagged (R2). - Updated
check_issue_contract_parity.pyto explicitly printSKIPPED live parity leg: <reason>on the default (no--live) path instead of silently omitting the leg (R3 residual). - Verified R4 fail-loud behavior is satisfied by existing #609 test suite.
- Made the query-scoped GraphQL guard fail safe rather than fail open: the literal extractor now backreferences its triple-quote delimiter (a stray
'''previously desynchronized every literal after it) and anyfirst:it cannot place inside a query block still gets the original whole-file check, so the narrowed guard is never weaker than the file-scoped one it replaces. - Recorded a reason on each
# pagination-lint: allowsuppression, matching the convention the helper's own suppression already used.
[2.12.1] - 2026-08-24
Fixed - prepared-issue draft revision replacement semantics and multi-fence readiness validation (#785)
- Fixed
sdlc_manager.pydraft preparation write paths to strip existing YAML front matter and top-level H1 titles from source text and prior drafts, ensuring draft revision replaces prior content instead of accumulating duplicate front-matter blocks and titles. - Added readiness validation blocking check that flags multi-fence drafts (fences > 2) and duplicated section headers (
###duplicates and##/###duplicate section pairs) before creation. - Defensively stripped front-matter fences and H1 titles from
_issue_body_for_githubto guarantee created GitHub issue bodies are clean.
[2.12.0] - 2026-08-16
Changed - retire the hermes-task / hermes-not-actionable dispatch markers
_ISSUE_TYPE_LABELSno longer applies either marker. The Hermes orchestrator that read them was frozen on 2026-07-18 (empty repository list, plan phase off, webhook relay stopped and disabled), so they marked cards for a consumer that cannot run.- Interactive
issue createnow applies the canonical type labels instead. That path previously guaranteed only the dispatch marker — not even the type label — so a card whose browser template failed to prefill landed untyped. _HERMES_ACTIONABLE_TYPESrenamed to_CONTRACT_ISSUE_TYPES: it names the types that carry the eight-section card contract, which is what it has actually meant since the orchestrator froze.- Generated template reference:
Hermes actionable: yes/nobecomesCard contract: required/not required. - Prompts, skills, the operator agent, and the triage command updated to match. The claim that "the orchestrator silently skips cards without
hermes-task" is removed — nothing filters on the label any more.
Paired with the infiquetra-sdlc change that removes both labels from the five issue templates. Writers stop here; the label definitions and the GitHub-side labels are retired separately.
[2.11.0] - 2026-08-15
Fixed - interactive issue create now validates the body before carding it
issue create-preparedhas always refused a draft with blocking readiness gaps. Interactiveissue createhad no equivalent: it opened the browser template, took the pasted issue number, and applied labels + board membership with no body check in between, so a blank or half-filled template landed on the board wearing the same labels as a conformant card.- Adds
_gate_created_issue_body, called between paste-back and metadata, reusing the existingvalidate_card_body_for_contextrather than adding a second contract. - Scoped to the Hermes-actionable types —
explorationandcontext-updateship different field sets by design and are not checked. - A failed issue fetch proceeds with a warning: an API hiccup is not a validation failure and must not strand a good issue.
- Under
--format jsonit emits a structured refusal and never prompts, so non-interactive callers cannot hang. - A failing body is a stop, not a veto: the operator sees the specific gaps plus the exact
gh issue editandflow validate-cardcommands, and must opt in explicitly to card it anyway.
[2.10.2] - 2026-08-08
Added - house-style presentation contract on the SDLC operator agent (#704)
sdlc-operatoragent definition gains a "Presentation contract (Infiquetra house style)" section, copied verbatim fromplugins/house-style/references/subagent-presentation-preamble.md.
[2.10.1] - 2026-07-16
Fixed
- Make
board moveexit nonzero after reporting all project results when an item, Status field or option, or mutation is unavailable. Invalid Status requests still list provider-read options and never call the mutation.
[2.10.0] - 2026-07-14
Added
- Add idempotent
flow assign-mimir --repo REPO --number N. Before its only mutation it reads Team Mimir's exact live coverage from authenticated GitHub, requires an active issue route, an open issue, triage-or-higher operator authority, and the repository's existingintake:mimirlabel. Success is emitted only after issue readback and includes trigger state, coverage route, issue URL, and live Objective project-field values when present. - Fail closed for unsupported repositories, closed issues, insufficient authority, missing or malformed policy, missing trigger labels, API failures, and failed mutation readback. The command creates no labels, comments, repository admissions, or alternate credential paths.
[2.9.0] - 2026-07-14
Added - ship-policy intent envelope at issue capture (#380)
sdlc_manager.py issue intent-envelope— renders the schema-validated ship-policy envelope block (### Intent envelope+ a fencedintent-envelopeJSON block) for embedding in an issue body at capture time, so the operator's autonomy answers are recorded ONCE on the issue and/outcome startskips its run-start interview (ask-once, S-22). Answer values are typed against the fleet interview's closed vocabulary (canonical schema: fleet-corefleet_commons/intent_envelope.py, loaded through the vendored shim) — off-vocabulary values fail loudly at render, never silently coerce.- Prepared-issue readiness validates the envelope —
_readiness_for_prepared_issuetreats a present-but-invalidintent-envelopeblock as a BLOCKING gap (fail closed at capture: a ship policy a downstream/outcome startwill trust must be schema-valid the moment it is authored). An absent block stays fine — the envelope is optional at capture.
[2.8.0] - 2026-07-14
Fixed
- Route every mission-control REST list-fetch (labels, milestones) and GraphQL cursor-paginated
fetch (project items, issue timelines) through a shared
paginate_or_raise/_rest_list_paginatedhelper that raisesPaginationExhaustedErrorinstead of silently returning a partial page when a paginated fetch never reaches a real terminal signal — closes the "item-list pagination silently truncating at 200 of 375 items" fleet defect pattern (#424).
Added
- Add
board_census.py: a live-derived board schema census (field/option shape, mirroring the context-library'scontext_census.pypattern) committed asconfig/board-schema.json, with a--checkmode that fails on drift from a fresh live derivation and prints an explicit SKIPPED line (never a silent pass) when live GitHub Projects access is unavailable. - Add
check_pagination.py: a static lint over mission-control's own scripts, skills, commands, and agent docs for unguardedghlist invocations, bare per-page REST fetches, and GraphQL queries that set a page-size arg without ever checkinghasNextPage. - Add a third,
--live-gated reconciliation leg tocheck_issue_contract_parity.py(live_status_option_errors) that resolves each tracked board's live Status field options and flags anysdlc-schema.json-declared status that no longer resolves upstream — a genuine three-way match (source schema, generated shim, live GitHub) where the prior gate only reconciled the first two.
[2.7.0] - 2026-07-10
Changed
- Retire Objective as a creatable issue type across the CLI and guidance. Objectives are project field options plus Outcome Scorecard docs; Capabilities are top-level by default.
- Make the interactive parent prompt default to no parent and describe native sub-issues as decomposition rather than Objective grouping.
Added
- Add idempotent
flow unlink-sub-issuefor removing accidental or retired parent layers without closing either issue.
[2.6.3] - 2026-07-08
Fixed
- Validate the loaded SDLC label taxonomy before
labels deploycalls GitHub, surfacing overlong descriptions and missing mission-control issue-taxonomy labels as one clear preflight error.
[2.6.2] - 2026-07-08
Fixed
- Add
flow set-field --numbers <n1,n2,...>plus repeated--field/--optionpairs for bulk project-field updates in one CLI invocation. Bulk mode reuses one field-discovery and project-item discovery pass, reports per-item/per-field failures, and exits non-zero after reporting when any requested update fails.
[2.6.1] - 2026-07-08
Fixed
- Normalize mission-control repo arguments at the CLI boundary so
--repo infiquetra/<repo>behaves like--repo <repo>across board, issue, label, milestone, rollout, and flow commands. Repos qualified with a non-Infiquetra owner now fail clearly before any GitHub call.
[2.6.0] - 2026-07-06
Added — auto-stamped Recommended Tier Band on created issues (#368 AC5)
derive_tier_band(issue_type): type→band map mirroring the shared tier registry's work-shape bands — defect/capability →opus/high, enhancement/context-update →sonnet/medium, exploration →sonnet/low;objective(parent tracking card) carries none.- The compile path (
_source_to_issue_body) stamps the derived band as an auto-populated### Recommended Tier Bandbody section (mirroring the Lifecycle Origin discipline: compile-time, never author-required). Idempotent — a body already carrying the band is not double-stamped, so prepare/compile round-trips are safe. - The card validator needs no change: it checks required H3 sections only, so the extra
auto-populated section is accepted as-is. Saga's
tier_defaults.parse_tier_bandis the consumer (format contract covered by a cross-plugin roundtrip test).
[2.5.1] - 2026-07-05
Reformat CHANGELOG title and date separator to canonical grammar (#429)
- Drop the plugin-name suffix from the file title and switch version-heading date separators from em dash to hyphen-minus, as part of the release-surface single-source generator work.
[2.5.0] - 2026-07-04
Executor-profile lint against the fleet tier palette (#463)
- New standalone
scripts/executor_profile_lint.py: parses aRecommended Executor Profileblock from--body-fileor stdin, validates model/effort membership against the canonical fleet-core tier palette (resolved through the new vendoredscripts/fleet_commons_shim.py), and enforces the above-sonnet-requires-justification rule via the palette's ordering. Exit codes: 0 pass, 1 named findings, 2 no-profile-block. No gh calls — callers pipe the issue body in (gh issue view N --json body -q .body | ...).
[2.4.0] - 2026-06-29
Issue-write verbs for autonomous /outcome board-sync (#279)
- New idempotent
issuesubcommands:close/reopen(PATCHstate, naturally idempotent),comment(plain POST; coalescing is the consumer's ledger job), and standalonelabel-add/label-remove(DELETE; swallowsApiNotFoundError404 = label already absent, propagates other errors for the consumer's retry path). Added a_rest_deleteREST helper. - These are the reversible board ops that saga's reversibility certificate authorizes and the
/outcomeboard-sync consumer drives across the saga↔mission-control boundary. Pairs with saga 0.42.0.
[2.3.1] - 2026-06-28
Fixed
- Fixed
issue create-preparedpost-create recovery by resolving issue/PR nodes withissueOrPullRequest(number:), keeping GraphQL mutation failures strict, and recording resumable sidecar state when board-add or Status assignment fails after issue creation.
[2.3.0] - 2026-06-27
Migration notes
- GitHub Project #3 was renamed from Jeff Intent to Operations. The
--projectvalue is nowoperations(wasjeff-intent) across all board / metrics / flow / triage commands, and the internal board key isoperations(wasjeff_intent). Update any saved invocations or scripts that passed--project jeff-intent. Project number (#3), node id, and the sharedintent_flowworkflow are unchanged, so existing cards stay on the board.
Changed
- Renamed the project surface
jeff-intent/jeff_intent/ "Jeff Intent" →operations/ "Operations" acrossproject-mappings.json,sdlc-schema.json,sdlc_manager.py(PROJECT_CHOICES), command and skill guidance, and thesdlc-operatoragent prompt. Mirrors the canonical rename ininfiquetra-sdlc. Dated provenance and migration notes preserve the former name as historical record.
[2.2.0] - 2026-06-21
Changed
sdlc-operatoragent: pinmodel: sonnet(wasinherit). Orchestration work is structured/mechanical — Sonnet is the right cost-quality tier (R1/R2a tiering).
[2.1.0] - 2026-06-17
Migration notes
- Mission Control now treats Jeff Intent, Asgard, and CAMPPS as the active board surfaces. Mount Olympus remains historical context in the vendored SDLC schema and should not be used as an active routing target for new work.
sdlc-schema.jsonresolves frominfiquetra-sdlcon GitHubmainbefore falling back to the vendored snapshot, so operators are less likely to read stale local checkout state.
Changed
- Re-vendored the current
infiquetra-sdlcschema snapshot atschema_version: 2026-06-17. - Prepared actionable issue drafts now compile fallback bodies from generated SDLC issue-contract data instead of hand-written prompt template sections.
- Readiness validation now applies issue-type and risk-aware required fields, including high-risk sections and empty-section rejection.
- Updated issue command and skill guidance to route through
issue preparefor generated contract bodies. - Bumped plugin and marketplace metadata to
2.1.0.
[1.6.1] - 2026-05-31
Changed
- Tracked the
infiquetra-loop→sagarename: updated the ignored runtime-state path to.claude/saga/and refreshed plugin references in/issue, thesdlc-operatoragent, and theissuesskill.
[Unreleased]
Added
- Added
/issueas the primary issue command surface. - Added prepared-issue handoff maturity metadata and source artifact resolution for local files, GitHub issue/PR URLs, branch refs, and natural hints such as "from the brainstorm".
Changed
- Synced the vendored SDLC schema and Asgard prepared-issue readiness with the corrected Asgard/Olympus model: sibling target boards with explicit cross-team transfer, not an implied Asgard-to-Olympus promotion path.
[1.6.0] - 2026-05-30
Added
- Added
issue prepareto write team-aware Asgard or Mount Olympus issue drafts underdocs/sdlc-issue-drafts/with JSON readiness sidecars. - Added
issue create-preparedto re-run readiness, render a full mutation plan, ask for final confirmation, repair missing labels/templates, add issues to the requested project, set safe starting status, and record the created issue back onto the draft. - Added Asgard and Olympus readiness profiles. Asgard accepts shaping-quality drafts with mode,
constraints, risk, and transfer notes; Olympus requires the strict actionable card body,
expected labels, project presence, author-visible risk, and safe
Backlogstatus. - Added mocked tests for blocked create, declined confirmation, direct create, missing labels/templates, missing mapping PR stop, and mapping override creation.
Changed
- Updated
issues,/issue,sdlc-operator, README, and release metadata so natural-language requests like "create an Olympus issue from this text" route through prepared drafts instead of bypassing readiness checks. - Bumped plugin and marketplace metadata to
1.6.0.
[1.5.0] - 2026-05-30
Migration notes
- No breaking CLI changes. Existing commands continue to work. Operators should update
installed cache paths from
mission-control/1.0.0or1.4.0tomission-control/1.5.0after installing this release. - Current actionable issue templates use
hermes-task,needs-plan, and the type label.needs-analysisandneeds-triageremain documented only as legacy auto-label fallback labels fromlabels.json.
Changed
- Added vendored
config/sdlc-schema.jsonand taught board/metric helpers to consume schema-backed boards, workflows, WIP limits, and terminal statuses. - Added live Jeff Intent (#3) and Asgard (#2) project mappings plus explicit
--projecttargeting for board add/move. - Refreshed board, metrics, milestones, labels, rollout, and operator guidance around Jeff Intent, Asgard, Olympus, direct project fields, and deployment-state separation.
- Preserved read compatibility for live/legacy Olympus statuses such as
In Progress,In Development, andDeployedwhile guiding new movement to the current schema. - Synced
issuestemplate guidance with canonical issue forms ininfiquetra-sdlc, including current Hermes actionable labels and required card sections. - Added a deterministic template documentation generator plus drift guard tests for
templates-reference.md. - Restored legacy rollout WIP-limit fallback when schema-backed limits are absent.
- Aligned
sdlc-operator,/triage, and issue/label references so prompts no longer teach stale actionable labels or initiative/objective labels as current practice. - Bumped plugin and marketplace metadata to
1.5.0.
[1.4.0] - 2026-05-04
Migration notes
- No breaking changes. The
sdlc-operatorClaude Code subagent (agents/sdlc-operator.md) was rewritten to reflect 2026-05-04 reality (Phase C minimum-viable + foundation + interactive flow are all merged). Operators using the prior subagent will see the same trigger phrases but newer command examples.
Changed (Phase C deferred — sdlc-operator subagent rewrite)
agents/sdlc-operator.md— full rewrite. The previous version was authored before Phase C; it referenced removed concepts:- Beads/Dolt CLI (
bd ready,bd claim, etc. — removed in PR #114; coordination is now Redis pub/sub + GitHub Projects v2 + Discord per-card threads) - "2 project boards" (Strategic Direction + Mount Olympus — Strategic Direction was dropped in PR #16 from
infiquetra-sdlc; Mount Olympus is the only board) labels sync-fieldscommand (deprecated — Initiative/Objective are project fields, not labels per PR #16 ininfiquetra-sdlc. The command itself still exists in the script for back-compat;flow set-fieldis the canonical mechanism. Removing the command is queued for a follow-up after a deprecation cycle.)initiative:*/objective:*colon-prefixed labels (anti-pattern; removed in PR #11)
- Beads/Dolt CLI (
- The rewrite reflects the cumulative Phase C work — references the
flowsubcommand group (PR #114), per-user defaults file + typed exceptions (PR #115), the sub-issue-first interactiveissue createflow (PR #116). Each workflow pattern (full issue lifecycle, board grooming, new initiative/objective setup, objective tracking, blueprint-driven batch creation, triage) updated to use the canonicalflow set-field/flow link-sub-issue/flow verify-label/flow validate-cardhelpers. - The
Today's reality (2026-05-04)callout is repeated in the agent's docstring + the issue-create workflow section — an operator using the agent learns immediately that today onlyStatusis a single-select field on the Olympus board, and theflowhelpers will silently skip prompts for the other fields until they're created via the runbook.
Plugin manifest: 1.3.0 → 1.4.0. All deferred Phase C items are now closed.
[1.3.0] - 2026-05-04
Migration notes
- No breaking changes. Existing
issue create --repo X --type Yinvocations work identically; new behavior is additive. - The new flow is interactive by default. Pass
--skip-metadatafor the prior thin-wrapper behavior (just open browser, no post-create work). - Operators who ran
config init-defaults(Phase C foundation) get personalized prompt defaults automatically.
Added (Phase C deferred — Interactive issue create rewrite)
The issue create subcommand was rewritten as a sub-issue-first, per-project-schema-aware, defaults-driven, capability-adaptive interactive flow. Replaces the previous thin wrapper that just deferred to gh issue create --web.
The 10-step flow:
- Determine type (decision-tree prompt if
--typenot set; default from~/.claude/sdlc-defaults.jsonif present) - Sub-issue-first prompt: every new card has a parent by default. Operator pastes a
repo#Nref or typesnofor free-floating - Discover which project the repo maps to (per-user
default_projectpreferred, else first match) - Per-project schema discovery: for each candidate field (Initiative, Objective, Status, plus capability-adaptive ones), check if the project actually exposes the field. Silently skip prompts for fields that don't exist
- Prompt for field values, defaults seeded from
~/.claude/sdlc-defaults.json(e.g.,default_initiative,default_objective) - Capability-adaptive fields: for
capabilityorobjectivetypes only, AND only when the project exposes them, prompt forCapability Size,Business Value,Technical Risk,Target Quarter - Open
gh issue create --repo X --template <type>.yml --webin the browser; operator fills the body - Operator pastes back the issue number (URL or bare integer accepted); skip post-create metadata if blank
- Apply post-create metadata, each step isolated:
hermes-taskfor actionable types /hermes-not-actionablefor objectiveboard addto the project boardflow set-fieldfor each gathered field valueflow link-sub-issueif a parent was set
- Paired-card prompt (opt-in, default no): create a sibling card on a different repo with the same parent. Useful for cross-service capabilities (backend + Flutter app)
New CLI flags
--parent-ref <repo#N>: pre-supply the parent ref (skips the sub-issue prompt — useful for batch-create scripts)--skip-metadata: skip steps 2-10 entirely, just open the browser. Returns to the prior thin-wrapper UX
New helpers (composable for tests + scripts)
_select_issue_type(default=None)— decision-tree prompt with EOF-safe fallback_prompt_parent_issue()— sub-issue-first prompt; parsesrepo#Noryesfollowed by ref_project_field_options(project_name, field_name)— per-project schema discovery; returns None if field doesn't exist (caller skips silently)_prompt_choice(label, options, default)— generic field-value prompt with options listed + default +-to skip_open_gh_issue_create_web(repo, issue_type)— browser launch helper_prompt_issue_number(repo)— captures URL or bare int from operator_apply_post_create_metadata(...)— orchestrates label / board / fields / sub-issue link with per-step error isolation_prompt_paired_card(repo, issue_number)— opt-in paired-card prompt; returns target/title/body deltas or None
Tests
- 23 new tests in
tests/test_issue_create_interactive.pycovering each helper in isolation:_select_issue_type: typed choice, default-on-blank, garbage-fallback, EOF-safe_prompt_parent_issue: direct ref, yes-then-ref, blank-then-ref, no, garbage-warns, EOF_prompt_choice: skip-when-no-field, valid option, default-on-blank, dash-skip, invalid-warns_prompt_paired_card: default-no, yes-collects-deltas, yes-empty-target-aborts_apply_post_create_metadata: hermes-task for actionable, hermes-not-actionable for objective, label-failure-doesnt-abort-others, no-project-skips-fields-but-keeps-link_PARENT_REF_RE: realistic refs accepted;#42,repo-only, garbage rejected
- Total: 92 / 92 passing
[1.2.0] - 2026-05-04
Migration notes
- No breaking changes. Existing CLI invocations work identically.
- Recommended one-time setup: run
python3 sdlc_manager.py config init-defaultsafter upgrading to seed~/.claude/sdlc-defaults.jsonwith your gh login + project defaults. Future Phase C PRs will read these as suggestion values in the interactiveissue createflow. - External override still wins: if you have
$INFIQUETRA_SDLC_PATH/config/project-mappings.json, it continues to take precedence over the new vendored copy. - Exception class names changed (PEP 8 / N818):
ApiNotFound→ApiNotFoundError,ApiAlreadyExists→ApiAlreadyExistsError,ApiRateLimited→ApiRateLimitedError. Backward-compat aliases retained for the old names; can be removed in a follow-up after a deprecation cycle.
Added (Phase C deferred — Foundation)
- Typed exception classes (
GhApiError,ApiNotFound,ApiAlreadyExists,ApiRateLimited,ApiAuthError,CardValidationError)._ghnow raises the appropriate subclass via_classify_gh_errorinstead of bareRuntimeErrorwith a stringy message. Replaces the fragile"422" in str(e)substring matching pattern. Downstream callers catch by type:Thetry: _rest_post(...) except ApiAlreadyExists: # idempotent re-run — treat as successflow_link_sub_issueandflow_verify_labelhelpers were refactored to use this pattern.flow_verify_labelalso now handles a real race (two operators creating the same label simultaneously) viaApiAlreadyExistson POST. - Per-user defaults file at
~/.claude/sdlc-defaults.json. Stores:assignee(gh login fromgh api user --jq .login— not OS$USER),default_project,default_status,default_priority,default_initiative,default_objective,preferred_repos. Sticky across CLI invocations; future interactive flows read defaults as suggestion values.load_user_defaults()/save_user_defaults()helpers (atomic write via tempfile + rename; tolerant of missing file + malformed JSON)get_default(key)convenience reader- New subcommands:
config show-defaults— display current per-user defaultsconfig init-defaults [--non-interactive]— first-run wizard. Interactive by default;--non-interactiveseeds fromgh api user+ auto-detectsdefault_projectif exactly one project is mapped (no guessing on multi-project orgs).
- Vendored
project-mappings.jsonatplugins/mission-control/config/project-mappings.json. The plugin now works without an externalinfiquetra-sdlccheckout for canonical Infiquetra projects.- New
_resolve_project_mappings(sdlc_path)helper implements the documented resolution order: external override ($INFIQUETRA_SDLC_PATH/config/project-mappings.json) → vendored canonical → remotegh apifallback. - Project node IDs captured in the vendored file are best-effort + verified 2026-05-04. Field/option IDs are NEVER cached; always fetched live.
- New
Tests
- 33 new tests across 3 new test files:
test_typed_exceptions.py(15 tests) — status-code parsing (404/401/403/429/422 disambiguation), 422-already-exists vs 422-validation-failure distinction, integration withflow_link_sub_issue+flow_verify_label(including race detection)test_user_defaults.py(13 tests) — read-side (missing file, malformed JSON, non-object root, unset key), write-side (atomic via tmpfile+rename, parent-dir auto-create, round-trip),--non-interactivewizard (gh-login seeded, multi-project no-guess, preserves unknown future keys)test_project_mappings_resolution.py(5 tests) — override wins over vendored, vendored used when no override, remote fallback when neither, empty dict on all-three failure, vendored file declares expected canonical state
- Updated 3 PR #114 tests in
test_flow_subcommands.pyto use typed exceptions instead of bareRuntimeErrorwith string-matching (the old pattern was testing the old implementation; new tests test the new contract). - Total: 64 / 64 passing locally.
[1.1.0] - 2026-05-04
Fixed (during PR #114 review)
validate_card_bodyheader text: was"Out-of-scope or non-goals"(with "or"); home-lab card_validator.py and ALL actionable issue templates use"Out-of-scope / non-goals"(with "/"). Every real card would have failed validation with a phantom missing-section error. Corrected to match home-lab exactly. Same iteration also corrects_PATH_LINE_RE(now accepts plain filenames + bullet-prefixed paths matching home-lab) and_CHECKLIST_RE(now requires\Safter[ ]and accepts*bullets matching home-lab).- Drift-guard test: added
test_required_headers_match_actual_issue_templatesthat loads the real issue templates and verifies every_REQUIRED_H3_HEADERSentry has a matchinglabel:in capability/enhancement/defect.yml. This is the test that would have caught the original "or" vs "/" bug. - Pre-existing test breakage:
tests/test_sdlc_manager.pyhad aTestBeadsClaimclass referencing the deletedbeads_claimfunction. Class deleted; CHANGELOG note added in the test file. - WIP-limits test fixture: was using the old
beads_configconfig-key (which now degrades to{}); the override test passed only by coincidence. Renamed fixture tolegacy_rollout_config; tightened assertion to verify the OVERRIDDEN column (Ready) renders with the override limit, not just any column happening to have a "5" in its render. flow_validate_cardexit-code path: was callingsys.exit(1)directly, bypassing main()'s formatted-error path and breaking programmatic callers. Now raisesCardValidationError(RuntimeError subclass) which main() catches; preserves the standard CLI exit code behavior + lets future callers inspect the failure._resolve_project_fielderror message: now includes a hint pointing at the field-creation runbook ininfiquetra-sdlc/docs/operations/operational-reference.mdwhen a field doesn't exist.- Stale
# BEADSbanner: removed (Beads removal had left an empty banner in the argparse section). - Duplicate
import re: removed (validator block had a redundant import; top-levelimport reat line 61 already covers it). - Unused
project_id_checkvariable: replaced with_, items = ...discard idiom (consistent withboard_wippattern). - README.md: removed the "Beads coordination" capability bullet + stale
bdCLI prerequisite + staleBeads Operationssection + staleconfig/beads-config.jsonrow. AddedFlow Operationssection with the 6 new commands.
Added
- New
flowsubcommand group — operator-facing GraphQL + REST helpers:flow set-field— set a single-select project field on a card (Initiative, Objective, Status, etc.)flow field-options— list current options for a project field (live discovery, IDs not cached)flow discover-project— resolve which project a repo maps toflow link-sub-issue— link child as native sub-issue of parent (cross-repo, idempotent)flow verify-label— self-healing label create (404 → create, exists → no-op, other errors raise)flow validate-card— pre-flight check an existing issue body against the card_validator schema
- New
validate_card_body()Python helper — mirrors home-lab card_validator.py's high-leverage checks (6 required H3 headers, AC has ≥1 checklist, Verification has ≥1 fenced code block, Files-expected has ≥1 path-like line, no placeholder-only sections) - New
flowskill (SKILL.md) describing theflowcommands + idempotency contract + hard rules + integration with the blueprint-to-issue workflow - 20 tests in
tests/test_card_validator.pyandtests/test_flow_subcommands.pycovering: validator schema rules, idempotency contracts, error classification (404 vs auth vs server), live-discovery vs cached, helpful error messages with current options listed
Changed
- Renamed
beads_configconfig-key tolegacy_rollout_configinload_configand downstream readers (board_wip,rollout_status,rollout_update,config_show). The underlying file (beads-config.json) was already removed from infiquetra-sdlc on 2026-04-26; the key now degrades gracefully to{}for back-compat. Comment inload_configdocuments the migration.
Removed
beadssubcommand group (ready,claim,update,complete,status)_bdshell helper for invoking thebdCLI- All
beads_*Python functions - The Beads/Dolt coordination layer was removed from Mount Olympus on 2026-04-26 (see
infiquetra-sdlc/docs/engineering-journal/narratives/2026-04-26-beads-dolt-removed.md); the agent fleet now coordinates via Redis pub/sub + GitHub Projects v2 + Discord per-card threads. The plugin'sbeadscommands targeted infrastructure that no longer exists.
Migration notes
- Operators previously running
sdlc_manager.py beads <action>will get anargparseerror. There is no replacement — the underlying coordination has moved off Beads entirely. Usegh+ the newflowcommands for direct board operations. - The
flow set-fieldcommand is the canonical mechanism for Initiative + Objective assignment per the 2026-05-03 DECISION (seeinfiquetra-sdlc/docs/engineering-journal/DECISIONS.md). The fields don't exist on the Olympus board today; create them via the operator runbook inoperational-reference.mdbefore usingflow set-field.
[1.0.0] - 2026-03-29
Added
- Initial release of mission-control plugin for the Mount Olympus agent team
- Updated wording to use Infiquetra conventions consistently
- 6 skills: board, issues, labels, metrics, milestones, rollout
- 4 commands: /board, /issue, /metrics, /triage
- 1 agent: sdlc-operator
- Python CLI: sdlc_manager.py (zero external dependencies, gh CLI wrapper)
- New: beads resource group for Beads/Dolt task coordination
- Removed: Rally sync, GHE hostname requirements, Chainproofers/Identifiers team split
- Coordination model: Beads-first with GitHub Issues as backing store
- Notifications: Discord (not Slack)
- 2 project boards: Strategic Direction + Mount Olympus Operations