Conversation
Implements the GitHub-first project-context foundation for #62: repository-identity resolution, worktree-safe recoverable cache, operation-scoped capability and authorization, managed Issue/PR revision blocks, delivery-lifecycle projection, and the pipeline skill/adapter bindings — with offline/non-GitHub fallback intact. Covers UC-G1..UC-G10 and UC-GR1..UC-GR3. Hardened after independent design, code, coverage, and security review (fail-closed authorization binding, manifest and default-branch-ref injection defenses, managed-publisher secret gate, deterministic hash/splice CLI commands, CI coverage for the new suites). Relates to #62
Resolves #66. Periodic Git-summary retrospection did not earn a conversational skill: its trigger was a calendar interval, its subject arbitrary Git activity rather than an outcome-bearing unit, and its output a committed summary with no named downstream consumer. The value in the one existing retro came from analyzing a completed campaign, not from periodic Git statistics — a script or CI report is the right home for commit counts and churn. Removes the source skill, generated Codex adapter, routing pointer and on-demand category entry, README and README_CN inventory rows, the domain-model example in CONTEXT.md, the adapter UI descriptor, and the platform-compat expectation. Historical retro artifacts under docs/retro/ are preserved as history. Closes #66 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Resolves #41. Transcripts were judged by hand against the README criteria table. This adds a subagent judge that scores a transcript against those same criteria, without duplicating them. - parse-criteria.mjs reads the README criteria table as the single source of truth (no second copy to drift) - judge.mjs builds the grading prompt and parses the verdict; overall is recomputed from sub-verdicts so a failed criterion cannot pass, and an unparseable judge response is an error rather than a silent pass - judge.sh runs a headless claude judge over a transcript; run-test.sh gains a --judge flag to run-and-score in one step - judge.test.mjs covers the parser and verdict logic deterministically (no model), wired as test:regression-judge in CI; it also asserts prompts and criteria rows stay in one-to-one correspondence Closes #41 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Resolves #54. Codex rarely fans out on decomposable work while the Claude adapter does, because the Codex adapter shipped no orchestration guidance and Codex's manager is conservative by default. Adds an opt-in HOST_POLICY section pointing out where DevMuse work decomposes — independent mu-code tasks, mu-review lenses, mu-scope probes — expressed in Codex-native terms (manager/worker roles, git-worktree isolation, config.toml max_threads/max_depth). It is explicitly not behavior-tested on Codex, claims no parity with the Claude adapter, and never overrides the host's manager. Single source via build:adapters; platform-compat locks the opt-in constraints. Also converts the untracked root AGENTS.md — a verbatim CLAUDE.md copy — into a thin pointer to CLAUDE.md plus the Codex host-policy entry point, so the maintainer contract has one home and cannot drift. Documents the guidance in platform-support.md and its CN twin. Closes #54 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Resolves #51. mu-review described optional review "by another model" but had no executable path, and restoring the old Claude->Codex block unchanged would make the generated Codex adapter review with Codex itself. Adds a cross-review runtime that constructs a read-only, ephemeral, project-scoped reviewer invocation with quoted argument arrays (no eval, no shell, no aliases), prefers a local subscription login over an API key, and: - routes reciprocally by host — Claude Code -> Codex, Codex -> Claude Code, other hosts use a configured different-family reviewer or have none - never invokes the current host as its own reviewer and blocks recursive cross-review via a subprocess env guard (depth 1) - runs under a bounded timeout; missing CLI, auth failure, timeout, non-zero exit, or malformed output falls back without blocking the primary review - validates structured output over exit code, normalizes findings with reviewer provenance, and surfaces contradictions side by side The canonical mu-review policy references the runtime; the adapter build vendors it into mu-review and rewrites the reviewer direction and current_host per host. Fake-binary tests assert exact args/env, recursion and same-family guards, timeout/fallback, and output validation with no network. platform-compat locks the reciprocal rewrite; docs updated with CN twin. Closes #51 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…reframe (#73) Part of #63 (foundation stage). Design in docs/specs/2026-08-24-living-prd-architecture-design.md. The survey showed the target is closer than #63 implies: mu-prd is already living, mu-wiki already owns a living architecture set, and #62's manifest already nests artifacts.architecture.{index, domain_model}. So the domain model is not an orphan to relocate — it is the manifest-declared domain_model member of the architecture set. This foundation stage: - adds knowledge/principles/project-profiles.md: the smallest useful profile set plus the "common core + profile + concern-triggered sections" composition rule, with the no-empty-slot-commitment and stateless-degradation guards - extends the concern triggers (nfr-checklist.md) with the two concerns #63 names that were absent: AI/model/tool boundary, and accessibility/localization - reframes domain-model.md: CONTEXT.md is the manifest-declared architecture-set member, its modeling method runs inside the mu-prd/mu-arch flow, and mu-model is the optional dedicated tool rather than a required gate - references profiles + concerns from mu-arch's C4 positioning step Deferred to later stages (per the design's staged delivery): the mu-prd section-model rewrite, the flat project-type table replacement, CLAUDE.md wording, packaged examples, and UC-ID traceability wiring. Regenerated adapters; all suites pass. Relates to #63 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Part of #68 (design stage). Independent design review passed; all 15 use cases, 9 mu-setup contract points, 8 research tasks, and 12 acceptance criteria map to a design section. Resolves the three forks: Git-reviewable files are the canonical local backend (SQLite an optional derived index); the manifest evolves v1->v2 with an explicit `cases:` block behind a mu-setup presentation gate; cross-provider edges with no provider home are canonical in DevMuse's repository registry. mu-setup is a thin skill over a project-registry runtime that reuses #62's identity/cache/auth. Review-hardening folded in: corrected the v1->v2 degradation claim (a v1 parser returns unknown-key, not unsupported-schema, until its schema-version test is reordered — now a scoped stage-1 task); defined the content-hash revision model and result-anchored staleness; fixed the ADR-0001 mis-citation; each delivery stage is its own plan boundary. Relates to #68 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…adation (#75) Part of #68 (implementation stage 1: research + contract). Design in docs/specs/2026-08-24-case-registry-design.md. - Reorder the project-context manifest parser to test schema_version before the unknown-key screen, so a future-versioned manifest (v2's `cases:` block) degrades to `unsupported-schema` — "your DevMuse is older than this manifest" — instead of `unknown-key`, which read as corruption (UC-C8, AC#9). v1 behavior, including unknown-key detection for schema_version:1, is unchanged. - Add the plugin/runtime/project-registry contract runtime (standalone; no skill consumes it yet, so it is not vendored): - routing.mjs — five asset kinds, the `cases.routes` vocabulary, validation with default fill, and per-kind provider resolution - registry.mjs — content-hash asset revision (stable, content-only), asset validation, locators, and deterministic Git-reviewable serialize/parse that sorts by id and rejects a hand-edited revision - staleness.mjs — result-anchored coverage staleness across the four revision axes (UC-C10, AC#11) - migration.mjs — v1->v2 proposal that never writes (present-before-write) - cli.mjs / index.mjs - 8 contract tests + a v2-degradation test on the reordered parser; wired as test:project-registry in CI. Regenerated adapters (vendored manifest copies). Deferred to stage 2: the local registry file store wired into mu-setup. Relates to #68 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#76) Part of #68 (implementation stage 2). Makes the case registry usable on the repository-backed local path, with no SaaS account and no database runtime. - project-registry/store.mjs: Git-reviewable local backend — registryPath, readKind (absent = empty, not error), atomic writeKind, idempotent initRegistry (existing kind files kept, not overwritten — UC-C5), and a non-mutating registryStatus. serializeRegistryFile now validates every asset and its kind before writing, so the store never persists garbage. - CLI gains init / status / read-kind / write-kind (repo-resolved paths). - plugin/skills/mu-setup: the discover -> propose -> approve -> init/migrate workflow, reusing project-context for identity/capability/authorization and the project-registry CLI for proposal + store. Idempotent, present-before- write, stores no credentials (UC-C3/C5/C6/C7). - Registered mu-setup as an on-demand skill: build ui map, both runtimes vendored, platform-compat roster, README(+CN) inventory, bootstrap routing and on-demand list, CONTEXT.md example. - 5 store tests (init idempotency, no-overwrite rerun, empty/valid, status, invalid-asset rejection). test:project-registry now covers the directory. Regenerated adapters (13 skills). Deferred to stage 3: a reference provider adapter with fake-provider tests. Relates to #68 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…dapter (#77) Part of #68 (implementation stage 3). Proves the provider contract with one worked adapter and the outage/migration state machine, all testable with fixtures (no network). - provider.mjs: the per-kind adoption/outage/migration state machine. Its load-bearing invariant — a temporary outage moves to PendingSync and NEVER silently demotes to Local (UC-C6); the only path back to Local is an explicit, approved force-local. Migration requires approval plus a complete old->new id map, preserved on success (UC-C7). classifyOutcome separates transient unavailability (-> outage) from an auth denial (never an outage). - providers/xray.mjs: the reference adapter (Xray via Jira). Declares a design-time capability model (validated_against_live: false until a live check), builds a project-scoped read request that carries NO credentials (the transport applies auth), and normalizes a provider test record into a registry reference + revision cursor — never a drifting payload copy. - CLI + index exports; 7 provider tests (adoption/outage/migration guards, outcome classification, request has no credentials, normalization). Regenerated adapters (mu-setup vendors the runtime). Deferred to stage 4: skill wiring + UC-ID traceability through the pipeline. Relates to #68 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Part of #68 (implementation stage 4, final). Wires the case registry into the pipeline so a use case is traceable from requirement through test result. - knowledge/principles/case-registry.md: the traceability contract — five asset kinds with stable IDs, the PRD->scope->arch->plan->code->review spine (stages reference IDs, never restate prose), and result-anchored coverage staleness via the project-registry runtime. Additive: where no registry exists, stages behave as before. - mu-scope/arch/plan/code/review each reference it at their project-context binding: scope owns the delivery delta over referenced cases; arch cites case IDs; plan/code carry IDs through tasks and tests; review-coverage marks stale. - mu-reviewer's review-coverage output gains the "Stale" status: a case with a test+result reads stale, not covered, when a bound revision moved — computed with the runtime's staleness command, not by hand. - github-first-contract asserts every pipeline stage references the contract and the reviewer marks staleness. Regenerated adapters (case-registry.md vendored into all five pipeline skills). Completes the four-stage #68 implementation. Relates to #68 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(prd): #63 stage 2 — profile-composed sections and diagram selection Part of #63 (stage 2). Replaces one-size-fits-all output with profile composition, using the project-profiles.md set from stage 1. - architecture-assessment.md: the flat "Diagram Type by Project Type" table becomes "Diagram Type by Profile" — diagram selection follows the same profile lens that composes document sections, so the project is classified once and reused; profiles compose (union of diagram sets). - mu-prd: "Depth Mode Selection" becomes "Profile and Depth Selection" — two orthogonal axes. Profile selects WHICH sections exist (a client-app has IA, flows, screens, tiering; a library/CLI has a public surface and no screens; a data/AI product has data-flow and model/tool-boundary sections); depth selects HOW MUCH of each. The existing full section list is now explicitly the client-app profile, so a user-facing product behaves as before. No section is emitted for a slot the profile does not populate from evidence (UC-DR2). Regenerated adapters (project-profiles.md vendored into mu-prd). Behavioral prd-state-modeling re-validation runs in #44. Deferred to stage 3: packaged worked examples. Relates to #63 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT * feat(examples): #63 stage 3 — packaged worked examples Part of #63 (stage 3). Packages worked examples so an agent or user can see the intended shape of profile- and concern-composed output (UC-D9). - knowledge/examples/README.md + reference-booking.md: a broad stateful-service reference case exercising state, transactions, concurrency, async delivery, multitenancy, a public API, and SLOs — showing which sections the composition emits and, crucially, which it leaves out (an excluded "payment" state the profile offers but evidence does not populate). The DevMuse dogfood domain model is the repository's own CONTEXT.md, referenced not copied. - Both files carry the UC-DR3 banner: illustrative knowledge, never this repository's own product truth. - Referenced from project-profiles.md so they are discoverable and vendored. Regenerated adapters. Behavioral prd-state-modeling re-validation of the stage-2 skill-prose changes runs in #44. Relates to #63 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…action (#80) Resolves #44. Establishes the model-churn regression routine — rerun the whole prd-state-modeling suite on every default-model change, because each model release re-breaks skill triggering. - run-all.sh: runs every scenario through headless claude, auto-judges each against the README criteria via judge.sh (the #41 judge), aggregates a pass/fail summary, and exits non-zero on any regression. SCENARIOS= runs a named subset. - extract-result.mjs: pulls the assistant's final text from a `claude -p --output-format json` run, handling BOTH the single-{result} object and the stream-event ARRAY shapes (whose final type:"result" element carries the text). judge.sh used only the object shape, so it fed the judge a raw event array and every real run misjudged; both the transcript and judge-response extractions now share this helper. 4 deterministic tests. - Documented the routine in docs/testing.md and its CN twin. - test:regression-judge now covers the whole test directory. Validated on Fable 5: stateless-cli-no-trigger passes — the model classified the project as the cli-devtool profile (the #63 stage-2 framing), the object-model trigger correctly did not fire, and only the three lightweight sections were produced. Full-suite sweep recorded on the issue. Closes #44 Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Adversarial four-workstream audit after the 3.0/main split. Records the concrete gaps between the merged 3.0 work and each issue's acceptance criteria, verified against code and the installed codex/claude binaries. Living doc; update as gaps close. Five release blockers identified (open-loop registry, dead cross-review paths, judge false-pass); recommended fix sequence starts with judge integrity. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
huiyu
commented
Aug 24, 2026
…grading (#82) Addresses the release-readiness blockers on the auto-judge (#41) and model-churn routine (#44) — the judge could pass a scenario it never graded, undermining every judged result. - parseVerdict rejects an empty criteria array (B5: [].every() === true would pass) and, given an expected count, rejects a short array (H1: a judge that drops the criteria it would fail). A missing/malformed per-criterion verdict is no longer a pass. - judge.sh threads the scenario's criteria count (new `judge.mjs --count`) into `--parse`, adds `set -o pipefail`, and the CLI now exits 2 on a judge/setup fault, distinct from 1 (regression) — so run-all.sh stops mislabeling a broken judge as a skill regression (M4). - run-all.sh captures the run's OWN transcript path (run-test.sh now emits TRANSCRIPT_PATH/TRANSCRIPT_STATUS) and marks ERROR when no fresh transcript exists, instead of judge.sh auto-selecting a prior model's stale file (H2). - Split the vague-groupbuy criteria cell so its six gaps grade independently (M5, now 7 criteria); fixed extract-result.mjs's CLI guard (L1). - 5 new unit tests (empty, subset, count, malformed verdict, criteriaCount). The '9/9 Fable 5 PASS' should be re-run under this hardened judge before it is trusted. Relates to #41 #44. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
…proval gate (#83) Addresses the #68 ship-blockers from the release-readiness audit: the registry was an open loop — after mu-setup wrote a v2 manifest nothing could read it back, nothing serialized the YAML, and the CLI wrote tracked files with no approval. - **B1** project-context manifest parser now understands schema_version 1 AND 2: a v2 manifest's optional `cases:` asset-router block parses and is captured in value.cases (provider-token semantics validated downstream, not here). Only schema 3+ degrades to unsupported-schema. cases is optional and rejected under v1. - **B2** new project-registry/manifest-io.mjs: serializeManifest renders a manifest value (v1 members + cases) as YAML the parser accepts, and readRouting validates the parsed cases block into a usable router. The loop closes: propose → serialize → parse → resolveProvider. - **H3** the CLI's init/write-kind/write-manifest are now gated on `approved: true` (present-before-write, enforced in code); the false "no tracked write" claims in cli.mjs, case-registry.md, and mu-setup are corrected. New write-manifest command serializes + writes .devmuse/project.yaml, never secrets. - release.yml now runs test:project-context/project-registry/cross-review (the 3.0 features' own tests were absent from the release gate — audit MEDIUM 6). - 3 loop tests (in-memory round-trip, through-disk round-trip via CLI, approval gate) + updated manifest tests for v1/v2/v3. Relates to #68. Resolves PR #81 threads B1/B2/H3. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
huiyu
commented
Aug 24, 2026
huiyu
left a comment
Contributor
Author
There was a problem hiding this comment.
Supplemental acceptance review on 3.0 at a3e4333, after #82 and #83.
The earlier B1/B2/B5 findings are fixed. The new inline findings below are independently reproducible and should keep #62, #68, and #51 open.
Two issue-level acceptance gaps also remain:
- #63 is still not the contract defined by #63/#67. There is no shared module-card schema, four-axis selector, generated matrix, composed renderer, or positive/reverse fixture suite.
mu-prdstill says not to enumerate use cases and delegates them tomu-scope, while the case-registry contract saysmu-prdowns Product Use Cases. PRD output remainsdocs/prd/YYYY-MM-DD-*; current-state architecture still routes to standalonemu-wiki;mu-archstill emits dated change specs; and the architecture template still assumes containers, services, databases, queues, and endpoints. This is a profile-aware prose foundation, not the living PRD/architecture product loop. - #68 still lacks an end-to-end data plane.
mu-setupmentions user preferences but has no user-level store, schema, loader, writer, or precedence implementation;mu-prdhas no registry integration; the Xray module is still a descriptor with no transport/sync path; and there is no setup → PRD → scope → arch → test-result fixture. The v2 manifest loop now closes, but the issue acceptance loop does not.
Release gating should therefore require one executable end-to-end fixture for #63/#68, plus the correctness and security fixes in the inline threads. Keep PR #81 Draft until those issue contracts, rather than only the narrowed unit contracts, pass.
…capture (#84) Addresses the #51 ship-blockers: both reviewer paths were functionally dead — the Codex command used flags codex rejects, and the Claude path's output was never captured. - **B3** codex argv corrected against the installed codex 0.149.1: `--base <branch>` (a branch, extracted from the range — not `--base-ref` with a range), `--output-schema <file>`, and `CODEX_HOME` env (not `--config-home`). - **B4** output capture fixed: `--output-schema`/`--json-schema` are passed so reviewers emit structured JSON; the runner now DRAINS stdout (an un-drained pipe deadlocked the Claude path until the 180s timeout) and reads per outputMode — codex from its output file, claude from stdout. - **M1** Claude reviewer hardened: read-only tool allowlist (Read/Glob/Grep), `CLAUDE_CONFIG_DIR` env (not `--settings`). **M2** env overrides implemented (DEVMUSE_CROSS_REVIEW_BINARY / _CONFIG_HOME / _TIMEOUT_MS). **M3** runReview owns a private 0700 temp dir for the output schema + result and cleans it up. **L2** the blind adapter substitution is fixed — the Codex mu-review now reads "Codex skills invoke their vendored ..." via a dedicated build collapse. - **Live flag-acceptance smoke test** (skipped when binaries absent, but ran green here against codex 0.149.1 / claude 2.1.241): asserts every built flag is listed in the CLI's own --help — the gate the fake-spawn tests could not provide, and which would have caught B3. 18 cross-review tests pass (incl. stdout-mode drain, runReview temp-dir cleanup, env overrides, baseBranch extraction). Relates to #51. Resolves PR #81 threads B3/B4a/B4b. The trigger remains appropriately model-gated (H3). Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ection (#85) Addresses the security/correctness findings from the external review of PR #81. - **CRITICAL (#51)** cross-review no longer forwards the whole process.env to the reviewer subprocess (it held API tokens visible in the invocation and any log). buildInvocation now copies a strict allowlist (PATH/HOME/locale…) plus the recursion guard and auth home; `plan` prints only env KEY NAMES, never values. - **#51** runner: a synchronous spawn failure hit a timer temporal-dead-zone and threw ReferenceError instead of the typed fallback — the timer binding is now declared before `done`. A non-zero reviewer exit is a fallback, not trusted output. - **#68** store: `writeKind` resolves the real path and rejects a `registry` dir that symlinks outside the repo, so an approved write can never land elsewhere. - **#68** xray: baseUrl is parsed and restricted to a clean https origin+path (no userinfo/query/fragment); `since` and the record's `updated` must be ISO instants; a record key must be PROJECT-NNN — closing the JQL-injection and malformed-record surfaces. - Regression tests for each (env allowlist, sync-spawn fallback, non-zero exit, symlink escape, URL/since/record validation). Relates to #51 #68. Resolves the PR #81 env-leak, spawn-failure, symlink, and xray review threads. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Addresses the #62 correctness findings from the external review of PR #81. - **lifecycle** — a required-PR-remaining check from MergedPendingDelivery no longer transitions backward to Reviewing (that reopened review after merge and broke monotonicity); it preserves the current state. - **cache mergeCache** — progressive same-work enrichment (issue → PR → phase) now merges in place instead of returning needs-reconciliation, so the cache can evolve through the delivery lifecycle; reconciliation is reserved for a contradictory shared value or a changed work_id. - **cache acquireLock** — a broken stale lock now retries the acquire ONCE and persists the current write, rather than dropping it to memory-only and letting only the next call benefit. - **managed-block selectCurrentManagedRevision** — selection is bound to the expected workId (and issue for plans); a foreign block with a higher revision in a comment can no longer win. The CLI passes these through. - 4 regression tests (backward-transition guard, foreign-block filtering, progressive enrichment, stale-lock persistence). Relates to #62. Resolves the PR #81 lifecycle, cache, and managed-block threads. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Per the maintainer's scope decision (2026-08-25), #47 (mu-model create field-acceptance) is descoped from the 3.0 milestone and tracked post-3.0. With its PR #81 thread resolved as a scope decision, all 37 review threads across the four review passes are resolved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
…#68) (#105) Fourth-pass re-verification found campaign 4's fixes were only partial: - atomicWrite fixed the symlink-escape but left the temp file behind when the write or rename failed (the "cleanup on failure" requirement). It now removes the temp file on any failure path (never a half-written .tmp-* left behind). - providerTransition migrate rejected null/empty idMaps but still accepted an EMPTY target locator, and dropped the locator history and cross-asset links. It now requires every idMap target to be a non-empty locator, requires the old->new locator history (id -> {from,to}) for every migrated asset, requires links to be a well-formed list, and preserves history + links + provenance in the record (UC-C7). (Also fixed a latent throw: history validation short-circuits on an invalid idMap instead of calling Object.keys(null).) Tests: temp cleanup on a failed rename; empty-target / missing-history / dropped-links rejected; history + links preserved on success. Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…heuristic (#51) (#106) Completing the #51 codex-output finding that campaign 4 only partially addressed: - normalizeExternalFindings returned {status:ok} with a junk finding for {findings:[null]} (item?.severity → "minor", summary → ""). A finding must now be an object with a non-empty summary; null/shapeless entries are dropped, and a non-empty list that yields NO usable finding is `malformed-findings` (invalid), not a silent clean review. A mix keeps the valid finding and drops the junk. - extractCodexReviewFindings treated ANY text containing a clean sentinel as clean, so a long changed-format report merely mentioning "no issues" was judged clean. The clean path now also requires the text be short (<=240 chars) and carry no [P*] marker; long unfamiliar prose is unrecognized → the runner degrades. Tests: {findings:[null]} / all-shapeless → invalid; mix drops junk; long prose mentioning "no issues" → unrecognized. Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…nical guide (#54) (#107) Completing #54: campaign 4 corrected the config keys but left the design's core requirement — per-skill opt-in pointers (skills may not load HOST_POLICY) plus eligible/ineligible/declined coverage. - A single CONCURRENT_DISPATCH map is now the source of truth; both the HOST_POLICY section bullets and each eligible skill's own per-skill pointer derive from it, so they cannot drift. - The eligible skills (mu-code, mu-review, mu-scope) each carry an opt-in dispatch pointer in their Codex SKILL.md that cites the canonical HOST_POLICY guide and states the declinable/opt-in nature ("a conservative manager may decline, and concurrency is never forced"). Ineligible skills carry nothing. - platform-compat test asserts eligible-has-pointer, ineligible-has-none, the declined affordance, and that each per-skill note matches the canonical HOST_POLICY text (no drift). Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…hreads truly resolved
A per-item acceptance check found 4 of campaign 4's 6 fixes were only partial
(temp-file cleanup on failure, {findings:[null]}, empty migration target + dropped
history/links, per-skill dispatch pointers). Campaign 5 (PRs #105-#107) completed
all four with reverse tests. All 37 PR #81 threads resolved; test:acceptance green.
Lesson one level up: a GitHub "Resolved" mark is not acceptance.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
…d finding (#51) (#108) Fifth-pass re-verification found the #51 boundary still incomplete at two exact reverse cases: - extractCodexReviewFindings("No issues could be checked because the review transport changed format.") was judged clean — the sentinel was matched anywhere in short text. CODEX_CLEAN is now anchored to an allow-list: the WHOLE trimmed verdict must BE a clean phrase, so a short abnormal output merely CONTAINING "no issues" is unrecognized (degrades) rather than clean. - normalizeExternalFindings({findings:[null,{summary:"real"}]}) returned ok and silently dropped the malformed item. It now fails CLOSED: EVERY item must be a well-formed finding (object + non-empty summary), else malformed-findings (invalid). An empty array is still a clean review. Tests: the exact short-error and mixed-item reverse cases, plus whole-verdict clean phrases still recognized. Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…nce (#68) (#109) Fifth-pass re-verification found migration evidence was PRESENT but not internally consistent — three exact reverse cases returned ok: - locatorHistory[id].to disagreeing with idMap[id] (contradictory target) → now the recorded history target must AGREE with the canonical id-map target. - blank provider/provenance/history/link fields (from:"", to:" ", provenance:" ", link fields "") → all string evidence is now trim-aware non-empty. - omitting `links` was normalized to [] (can't distinguish "explicitly none" from "dropped") → `links` must now be an EXPLICIT array; an explicit [] is accepted, omission is incomplete. Tests: contradiction, blank-field, omitted-links, and explicit-empty-links reverse cases. Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…nce (#54) (#110) Fifth-pass re-verification: the static wiring tests do not satisfy #54's request for eligible/ineligible/user-declined PROMPT behavior. Add a behavioral acceptance suite that feeds a real model the ACTUAL shipped HOST_POLICY concurrent-dispatch guidance and observes the dispatch DECISION: - eligible (mu-review's independent lenses over one diff) -> PARALLEL - ineligible (mu-prd authoring one artifact) -> SINGLE - user-declined (explicit "run single-threaded") -> SINGLE Verified stable across repeated live runs. Binary-gated on `claude` (a reasoning proxy for the Codex-host decision logic; full Codex-host execution parity stays out of scope by design). Wired into test:acceptance (and the anti-drift coverage assertion). HOST_POLICY disclaimer refined to state the decision logic is now behaviorally tested while Codex-host execution is not guaranteed. Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
A per-reverse-case re-verification found 3 campaign-5 fixes still failed specific
inputs (short-error clean, {findings:[null,item]} drop; contradictory/blank/omitted
migration evidence; #54 static-only). All fixed with the exact reverse tests,
including a real model behavioral suite for #54. All 37 PR #81 threads resolved;
test:acceptance green. New residual R5: the #54 behavioral test skips in CI
(binary-gated, no claude on the runner), verified stable locally.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
huiyu
commented
Aug 25, 2026
huiyu
commented
Aug 25, 2026
huiyu
commented
Aug 25, 2026
huiyu
commented
Aug 25, 2026
huiyu
commented
Aug 25, 2026
…docs to the test:acceptance aggregate - readiness doc: the "Residual risks" section was stale (missing R5, pre-campaign-3 descriptions, and a stale "CI runs five / release runs three" line contradicting #97). Rewritten as R1–R5 plus explicit post-3.0 deferrals (#47, the PRD→registry→ scope runtime harness), and the CI/release line now states both use test:acceptance. - docs/testing.md + docs/testing_cn.md: the "Fast Deterministic Checks" block listed a stale subset of suites. Replaced with the single `npm run test:acceptance` aggregate (matching the doc's own "don't copy directory listings" philosophy), noting the binary-gated live tests skip when the model binary is absent. CN twin updated in the same commit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
#62) (#111) Sixth review pass — two blockers whose runtime was never actually changed: - replaceManagedRevision spliced ANY new block over the body's block. Four illegal transitions were accepted: cross-work (work-A→work-B), backward revision (5→1), changed attempt_id, and scope→scope-revision. It now requires the old/new blocks to share kind, work_id, issue, and attempt_id (stable identity) and a strictly newer revision (a byte-identical same-revision re-post is an idempotent no-op). - sanitizePublishable returned "safe" for password=…, sk-proj-*/sk-ant-api03-* keys, npm_* tokens, and credential-bearing postgres URLs — renderManagedRevision passes content as one string, so the object-key screen never saw them. Added value patterns for provider token prefixes, inline password assignments, and user:pass@ URLs; softened the "secret can never reach" comment to a best-effort filter (regex cannot guarantee arbitrary-secret detection). Reverse tests: all four managed-revision transitions, and the five secrets rejected end-to-end through renderManagedRevision. Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…112) Sixth review pass: the runner had no upper bounds — stdout/stderr accumulated without limit, the output file was read whole, and the timeout was whatever the caller/env supplied. - stdout/stderr are capped at 5 MB total; past the cap the child is SIGKILLed and the run falls back (output-too-large) instead of exhausting memory. - the output file is read through readCappedFile — a file over 5 MB falls back rather than being slurped in. - the timeout is clamped to [1s, 600s] via clampTimeout, so a caller or DEVMUSE_CROSS_REVIEW_TIMEOUT_MS cannot set an unbounded (or zero) timeout. Reverse tests: a >5 MB stdout flood kills the child and falls back; a >5 MB output file falls back. Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
) (#113) Sixth review pass: test:acceptance was PATH-dependent — test:codex-dispatch (and the cross-review live smoke) invoke real claude/codex when present, so the required gate behaved differently across machines. - All live/binary-invoking tests are now gated behind DEVMUSE_LIVE=1 (opt-in), so they skip in the gate regardless of which binaries are installed. - test:codex-dispatch is removed from test:acceptance; the aggregate is now fully deterministic and makes no model calls. - New `test:live` (DEVMUSE_LIVE=1) runs the cross-review smoke + codex-dispatch behavioral suite on demand / in a dedicated live gate. - workflow coverage assertion no longer requires codex-dispatch in the aggregate; docs/testing (+ CN twin) document the deterministic gate vs opt-in live split. test:cross-review now skips its 3 live tests without the flag (deterministic). Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sixth pass, minor: the go/no-go summary still said "every PR-#81 review thread is resolved (30/30)" while the PR had grown to 42 threads across six passes. Rewrote the top to state the current status is NOT release-ready, that "all resolved" has been a premature claim more than once, and to defer to the live PR thread count as the authoritative state — not a sentence in this doc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
-#113) Two blockers (managed-revision identity binding + expanded secret screen) whose runtime was never before changed, plus unbounded cross-review resources, a PATH-dependent acceptance gate (now deterministic; live tests opt-in via test:live), and a stale top summary. All 42 PR #81 threads resolved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
huiyu
commented
Aug 25, 2026
…sses (#62) (#114) Seventh review pass — the campaign-7 blocker fixes missed further bypasses: managed-revision (replaceManagedRevision): - CRLF body corruption: parseDocument normalized the source before recording index/raw length, then the splice used the original CRLF body → misalignment + stray "-->". Now the body and candidate are normalized up front and spliced in the same normalized space. - a -revision comment kind could be written into the body when no block existed → only BODY_KINDS (scope, plan) are accepted; scope-revision/plan-revision rejected. - a valid block followed by arbitrary trailing text (a second marker or password=hunter2) was spliced verbatim → the candidate must be EXACTLY one complete block (raw === trimmed source), no leading/trailing content. secret screen (inspectPublishable): - free-form assignments api_key=/client_secret=/token=/secret=/OPENAI_API_KEY= returned safe → a single pattern now mirrors the sensitive-key vocabulary for raw `key = value` text. (The "append password after a legal block" bypass is closed by the exact-envelope check above.) Reverse tests: CRLF splice, body -revision rejection, trailing-suffix rejection, and the five free-form assignments through renderManagedRevision. Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
- R3/R5 and the residual-section closing line described the live tests as "skipping in CI"; after #113 they are opt-in (DEVMUSE_LIVE / test:live) and not in test:acceptance at all. Reworded to the accurate opt-in boundary. Historical rows keep their old state. - Top summary bumped to seven passes; added the seventh-pass History row (campaign 8, PR #114 closed the reopened blockers' further bypasses). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
…ocabulary (#62) (#115) Eighth review pass — the #114 fixes still broke the body contract and left a vocabulary gap: managed-revision (replaceManagedRevision): - it normalized the WHOLE body to LF, so surrounding human text lost its CRLF. Now the block is located by its markers in the ORIGINAL body and only that span is replaced — everything around it is preserved byte-for-byte. - a byte-identical same-revision re-post now returns the ORIGINAL body unchanged (it no longer rewrites CRLF→LF). - appending a scope block to a body that already holds a plan block created two managed blocks; it now raises managed-family-conflict (reconciliation needed) instead. secret screen: - the raw-string assignment pattern used a hand-reduced vocabulary that missed authToken=, authenticationToken=, authorizationToken=, oauth_cache=, oauthCache=. Both the object-key screen and the assignment screen now derive from ONE shared SENSITIVE_KEY_WORDS source, so they cannot drift. Reverse tests: CRLF byte-preservation, idempotent-unchanged, cross-family conflict, and the five camelCase/oauth-cache assignment variants. Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ed (campaign 9, #115) The same managed-revision + secret-screen blockers reopened with subtler cases (whole-body normalization losing CRLF, idempotent rewriting line endings, cross-family two-block append; missing authToken=/oauth_cache= assignment variants). All fixed in #115. 43/43 threads resolved. These two surfaces remain the most-reopened; another pass is prudent before release. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
…vision/body (#62) (#116) Concentrated-review pass on the two most-reopened surfaces found three more gaps: - quoted secret assignments bypassed the raw-string screen: token="secret", JSON "token": "secret", dotenv/shell export TOKEN="…" all returned safe because the value char class excluded quotes and the separator had to abut the key. SENSITIVE_ASSIGNMENT now allows an optional quote around the key and the value. - a pathological revision (e.g. 400 digits) passed the unbounded /^[1-9]\d*$/ regex, parsed to Infinity, and serialized to null. Revision and issue digits are now bounded (<=9), so such a header is malformed — fail closed. - a non-string body was coerced to "" in replaceManagedRevision (and the CLI's `?? ""`), so the CLI exited 0 and silently discarded the original input. A non-string body now throws invalid-managed-body; null/undefined still mean a fresh create. The CLI passes body through so the error surfaces (non-zero exit). Reverse tests: five quoted/dotenv/JSON secret shapes; a 400-digit revision → malformed; non-string bodies → throw (function + CLI). Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…n (campaign 10, #116) The concentrated review found 3 more gaps on the two most-reopened files (quoted secret assignments, 400-digit revision -> Infinity/null, non-string body coerced to empty). All fixed in #116. 43/43 threads resolved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
…ain (#62) (#117) Concentrated follow-up on the two most-reopened files found two more gaps: - Markdown formatting bypassed the secret screen: `` `token`: … ``, **token**: …, [token]: …, <code>token</code>: … all returned safe because formatting sits between the key and separator (managed blocks ARE Markdown). The screen now scans BOTH the raw source and a conservative Markdown/HTML→plain-text projection (strips code/emphasis/reference markers, HTML tags, blockquotes). Benign Markdown (bold headings, inline-code identifiers, links, quotes) stays safe. - the renderer accepted a wider numeric domain than the parser (revision/issue up to MAX_SAFE_INTEGER), so a rendered block could be malformed to its own selector/replacer. Both now share ONE domain (1..999_999_999 via validManagedNumber, matching the parser's [1-9]\d{0,8}); and non-string/missing content is rejected instead of being stringified to [object Object]/undefined. Tests: a Markdown formatting matrix (dressed secrets rejected raw + through renderManagedRevision, benign Markdown safe) and a render→select round-trip invariant (999999999 selects, 1000000000/MAX_SAFE_INTEGER/0/1.5 refused, non-string content refused). Adapters regenerated. Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…en secret-detection architecture question Markdown-dressed secrets + render/parse domain mismatch fixed in #117. 43/43 threads resolved. Flags the standing design decision the reviewer keeps raising: regex secret detection can't be exhaustive; a structured-summary + field-allowlist redaction boundary would be the durable fix. Best-effort framing documented. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwyFyRC6pepaK6DuMK7YeT
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.
Integration branch for the DevMuse 3.0 release. The adversarial audit's blockers are now all cleared; this remains a draft pending the final release checklist (version bump, changelog, tag).
This PR collects the full DevMuse 3.0 body (GitHub-first context #62, living PRD/architecture #63, case registry + mu-setup #68, cross-model review #51, Codex dispatch #54, auto-judge #41, model-churn #44, mu-retro removal #66) on top of the v2.2.0 release.
A four-workstream adversarial audit originally found the work was "clean modules, unit-tested in isolation, wired to nothing." All 20 inline review threads are now resolved, closed by fix PRs #82–#89 (each verified against code). Full detail — including the tracked residual risks R1–R4 (post-3.0 live-integration work, not blockers) — lives in
docs/3.0-release-readiness.md.Release blockers — all cleared
B1(fixed fix(registry): close the case-registry loop (#68 B1/B2/H3) #83) 3.0: project-wide case registry and mu-setup-driven asset routing #68 — no v2 manifest parser: registry now reads back aftermu-setupwrites itB2(fixed fix(registry): close the case-registry loop (#68 B1/B2/H3) #83) 3.0: project-wide case registry and mu-setup-driven asset routing #68 — manifest serializer/writer added; write loop closes (round-trip tested)B3(fixed fix(review): make cross-review actually run (#51 B3/B4) #84) mu-review: add host-aware reciprocal cross-model review (Claude ↔ Codex) #51 — Codex flags corrected to--base <branch>/CODEX_HOME, verified against codex 0.149.1B4(fixed fix(review): make cross-review actually run (#51 B3/B4) #84) mu-review: add host-aware reciprocal cross-model review (Claude ↔ Codex) #51 —--output-schemapassed; runner drains stdout, private temp schema, rejects non-zero exitB5(fixed fix(regression): judge integrity — close false-pass vectors (#41/#44) #82) Regression suite: automated judging #41 — judge rejects empty / subset criteria arrays as judge-fault exit 2Per-issue release-readiness
test:profiles(#88)update-cachewriter + lock retry + selection/lifecycle correctness (#85/#86). Behavioral prompts still string-match (R1)Remaining before v3.0.0: release mechanics (version bump, changelog, tag) and a decision on the residual risks R1–R4 (all deferrable to release notes).
Relates to #62 #63 #68 #51 #54 #41 #44 #66