diff --git a/bin/mega b/bin/mega index 57077d06..2030ec84 100755 --- a/bin/mega +++ b/bin/mega @@ -2,11 +2,11 @@ # bin/mega -- STABLE consumer entrypoint for the mega subsystem (SPEC-184, # ADR-0034 decision 7: every subsystem gets its bin entry). # -# Consumers reference THIS stable path, never the deep `$DWARVES_KIT/lib/mega.sh` +# Consumers reference THIS stable path, never the deep `$DWARVES_KIT/lib/mega/mega.sh` # path, so an internal lib reorg (e.g. a future promotion to lib/mega/mega.sh # when a second verb lands) never breaks them again. # # Usage: mega status [args...] set -euo pipefail SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -exec bash "$SELF_DIR/../lib/mega.sh" "$@" +exec bash "$SELF_DIR/../lib/mega/mega.sh" "$@" diff --git a/docs/consumer-contract.md b/docs/consumer-contract.md index cb7d0217..34b4f3ba 100644 --- a/docs/consumer-contract.md +++ b/docs/consumer-contract.md @@ -61,7 +61,7 @@ The adopt-injected `CLAUDE.md` block already does this for you: | `bin/gate` | `lib/gate/gate.sh` | | `bin/goal` | `lib/goal/goal.sh` | | `bin/learn` | `lib/learn/learn.sh` (`learn debt `; `propose`/`drain` refuse until SPEC-195/196) | -| `bin/mega` | `lib/mega.sh` | +| `bin/mega` | `lib/mega/mega.sh` | | `bin/queue` | `lib/queue/queue.sh` | | `bin/session` | `lib/session/session.sh` (`session `, ex the five `bin/session-*`) | | `bin/spec` | `lib/spec/spec.sh` | diff --git a/docs/verification/lib-mega-folder.md b/docs/verification/lib-mega-folder.md new file mode 100644 index 00000000..3de213a4 --- /dev/null +++ b/docs/verification/lib-mega-folder.md @@ -0,0 +1,114 @@ +# Proof of done: fold the mega engine into lib/mega/ (ID-287, sanctioned slice) + +**Change class:** behavioral (moved `.sh`/`.py` + repointed callers in `bin/`, `lib/`, `tests/`). + +**Claim.** The three loose mega-goal scripts move from `lib/` root into a cohesive +`lib/mega/` module as a unit, with every live reference repointed and every +root-assuming internal anchor re-anchored one level up: + +- `lib/mega.sh` -> `lib/mega/mega.sh` +- `lib/mega-report.py` -> `lib/mega/mega-report.py` +- `lib/mega-review.py` -> `lib/mega/mega-review.py` + +## Why this slice (and not the other loose files) + +`lib/config/module-registry.md` already registers a **`mega` module** (row :49 +"mega | Build (Execute) | spine machinery") and ADR-0034 explicitly names +`lib/mega/mega.sh` + `bin/mega` as the promotion target, so this move is sanctioned +and the three files must move together (they call each other by same-dir path). The +other four loose files (`adopt.sh`, `explain.sh`, `pitch.sh`, `precedent.sh`) are +labeled **"deliberate orphans, no cluster"** by both `lib/README.md` and +`docs/decisions/0034` (bin-less, command-invoked, not module CLIs). Foldering them +into single-file dirs conflicts with that ADR, a source-of-truth question a human +must settle, so they are deferred to a follow-up with that ruling. `onboard-detect.sh` +has no obvious module home either (lib/session vs a new lib/onboard). See the batch +report. + +## Internal anchor edits (root-assuming -> one-level-deeper) + +- `mega.sh`: `source "$self_dir/telemetry/..."` -> `"$self_dir/../telemetry/..."` (x2). + The `$self_dir/mega-review.py` / `mega-report.py` calls stay (same-dir, co-moved). +- `mega-review.py`: `os.path.join(_SELF_DIR, "gate"...)` and `"learn"...` gain a `".."`; + the `mega.sh` join stays (same-dir). +- `mega-report.py`: no internal path anchor (arg-driven), no edit. + +## Repointed live references + +`bin/mega:12` (the stable forwarder), `lib/board/board.sh:183` (computed +`$BOARD_DIR/../mega/mega.sh`), `lib/queue/orchestrate.sh:1745` + WARN string, +`tests/test-mega.sh`, `tests/test-mega-review.sh`, `tests/test-mega-report.sh`, +`lib/config/module-registry.md:113,284`, and a `lib/mega/` row added to +`lib/README.md`. Comment references in the moved files + `board.sh` + `test-tier4-close.sh` +updated for accuracy. Historical records left untouched. + +## Review disposition (review-team + fable advisor) + +| Finding | Lens | Applied? | +|---|---|---| +| `cmd_report`'s re-anchored telemetry `source` had zero red-on-wrong coverage (the mega-report tests call python directly; the one `bin/mega report` call passed no slug) | test-coverage (HIGH) | Applied, added an end-to-end `bin/mega report demo` launcher assertion in `test-mega-report.sh`; verified load-bearing (broken anchor -> 15/17, restored -> 17/17) | +| `docs/consumer-contract.md:64` `bin/mega -> lib/mega.sh` stale post-move (a live onboarding ref, not historical) | architecture (LOW) | Applied -> `lib/mega/mega.sh` | +| `mega.sh` header still framed the file as a deliberate orphan awaiting promotion; `mega-review.py:53` `_SELF_DIR` comment said "lib/ ... orphan file" | architecture (MEDIUM/LOW) + fable + security | Applied, both rewritten to describe the `lib/mega/` module | +| Re-anchoring complete/correct; taxonomy right (mega is a distinct `mega` module, not `goal`); orphan deferral correct (not over-reading ADR-0034) | architecture 8/10, fable, security 10/10 | Confirmed, no change | +| `onboard-detect.sh` absent from `lib/README.md` root-orphans row | fable/architecture | Pre-existing gap, reported for the orphan follow-up (not this branch's regression) | + +## Acceptance criteria + +| # | Criterion | Result | +|---|---|---| +| 1 | The three files live in `lib/mega/`; old `lib/mega.sh` path gone | PASS | +| 2 | `bin/mega` forwarder reaches the engine at the new path | PASS (30/30 forwarders) | +| 3 | Internal anchors resolve telemetry/gate/learn siblings from the new depth | PASS (mega suites green) | +| 4 | No live (non-doc) reference to an old `lib/mega*.{sh,py}` path remains | PASS | +| 5 | All affected suites green | PASS | + +## Confirmation run + +``` +Command: [ ! -f lib/mega.sh ] && ls lib/mega/ +Exit: 0 # mega.sh mega-report.py mega-review.py +Command: rg 'lib/mega\.sh|lib/mega-report\.py|lib/mega-review\.py' bin/ lib/ tests/ --glob '!*.md' | grep -v 'lib/mega/' +Exit: 1 # no un-repointed live ref remains +Command: bash tests/test-mega.sh +Exit: 0 +Command: bash tests/test-mega-review.sh +Exit: 0 # 26 passed +Command: bash tests/test-mega-report.sh +Exit: 0 +Command: bash tests/test-bin-forwarders.sh +Exit: 0 # all 30 passed +Command: bash tests/test-tier4-close.sh +Exit: 0 +Command: bash tests/test-meta.sh +Exit: 0 # Passed: 717 / 717 +Command: bash tests/test-hooks.sh +Exit: 0 # Passed: 487 / 487 +Verdict: PASS +``` + +## NEGATIVE CONTROL + +The `bin/mega` repoint is load-bearing. Revert only it to the old path and the +forwarder can no longer reach the engine: + +``` +# revert bin/mega:12 to ../lib/mega.sh (old path): +bash tests/test-bin-forwarders.sh + -> FAIL: mega forwarder reaches mega.sh (29 passed, 1 FAILED) [RED] +# restore ../lib/mega/mega.sh: +bash tests/test-bin-forwarders.sh + -> all 30 passed, 0 skipped [GREEN] +``` + +**Verdict: PASS.** + +## Reproduce + +``` +bash tests/test-mega.sh tests/test-mega-review.sh tests/test-mega-report.sh +bash tests/test-bin-forwarders.sh # 30/30 (the bin/mega forwarder) +bash tests/test-meta.sh # 717/717 +bash tests/test-hooks.sh # 487/487 +``` + +**Rollback:** `git revert` this commit (`git mv` back + restore the anchors/refs); no +state or data step. diff --git a/lib/README.md b/lib/README.md index eb8539bd..b8efb842 100644 --- a/lib/README.md +++ b/lib/README.md @@ -17,6 +17,7 @@ orphans with no cluster stay as bare scripts at the root. | `classify/` | `lane-classify.sh` `role-classify.sh` `significance-classify.sh` `task-type-classify.sh` `route-suggest.sh` | | `spec/` | `spec-index.sh` `spec-next.sh` | | `goal/` | `goal-drafts.sh` `goal-registry.sh` `mega-merge.sh` `stack-merge.sh` `handoff-gen` + `handoff/` (`handoff_gen.py`, `cc_compact.py`) | +| `mega/` | `mega.sh` `mega-report.py` `mega-review.py` (the mega-goal engine + its two python halves; stable entry via `bin/mega`) | | `telemetry/` | `lane-telemetry.sh` `kit-log-dir.sh` | | `session/` | `parse_transcript.py` `parse-transcript.sh` (the shared transcript parser + its tests) | | *(root)* | `adopt.sh` `explain.sh` `pitch.sh` `precedent.sh`, orphans, no cluster | diff --git a/lib/board/board.sh b/lib/board/board.sh index 40184f67..902dbb05 100755 --- a/lib/board/board.sh +++ b/lib/board/board.sh @@ -101,7 +101,7 @@ # every ACTIVE mega under # /_meta/megagoals/*/ # (>=1 unchecked sub-goal box), the -# `lib/mega.sh status +# `lib/mega/mega.sh status # --rollup-only` line (roadmap-vs-git # reconciliation, drift-flagged -- # never a re-render of the roadmap's @@ -180,7 +180,7 @@ PARSE_BOARD_SH="$BOARD_DIR/parse-board.sh" BOARD_MIRROR_SH="$BOARD_DIR/board-mirror.sh" BOARD_WRITEBACK_SH="$BOARD_DIR/board-writeback.sh" COCKPIT_PY="$(cd "$BOARD_DIR/.." && pwd)/sync/cockpit.py" # lib/sync/, the P2 sync-engine port (ID-290) -MEGA_SH="$(cd "$BOARD_DIR/.." && pwd)/mega.sh" # lib/mega.sh, one level up from lib/board/ +MEGA_SH="$(cd "$BOARD_DIR/.." && pwd)/mega/mega.sh" # lib/mega/mega.sh, one level up from lib/board/ [ -f "$BACKLOG_SH" ] || { echo "board: lib/board/backlog.sh not found at $BACKLOG_SH" >&2; exit 1; } [ -f "$PARSE_BOARD_SH" ] || { echo "board: lib/board/parse-board.sh not found at $PARSE_BOARD_SH" >&2; exit 1; } diff --git a/lib/config/module-registry.md b/lib/config/module-registry.md index e59d8383..ced7ef56 100644 --- a/lib/config/module-registry.md +++ b/lib/config/module-registry.md @@ -110,7 +110,7 @@ real reader consumes it today (all rows below are, except where noted). | - | mega.merge_autonomy | `"gated-final"` | [design] | mega | `"gated-final"` or `"full-auto"`; no env override found. | | - | mega.default_model | `"sonnet"` | [design] | mega | GLOBAL model fallback; real control is the per-sub-goal goal-file `Model:` field. Precedence: goal-file `Model:` > project cfg > this default. | | - | mega.over_test | `false` | [design] | mega | GLOBAL scaffold-rigor default; real control is per-sub-goal `Done-mode: over-test` (SPEC-112). | -| MEGAGOALS_ROOT | env-only | (none) | [impl] | mega | Root dir where mega-goal folders live; unset falls through to further path resolution in `lib/mega.sh`. | +| MEGAGOALS_ROOT | env-only | (none) | [impl] | mega | Root dir where mega-goal folders live; unset falls through to further path resolution in `lib/mega/mega.sh`. | | MEGA_MERGE_PR_INFO_CMD | env-only | (none) | [impl] | mega | Override the command used to fetch PR info at merge time; called directly when set. | | MEGA_MERGE_GATE_LEDGER | env-only | `$LIB_ROOT/gate/gate-ledger.sh` | [impl] | mega | Which `gate-ledger.sh` `mega-merge.sh` shells out to. | | MEGA_MERGE_GH | env-only | `gh` | [impl] | mega | Override the `gh` binary/wrapper used for PR ops at merge. | @@ -281,7 +281,7 @@ against any of these bare tokens as covered without a registry row. | KIT_DIR | `lib/plugin-check/tests/smoke.sh`: test-fixture scratch dir. | | KIT_KNOWN_MODULES | `install.sh`: a hardcoded bash array literal, never read from the environment. | | KIT_LIB | Script-local computed dir in most readers (e.g. `lib/telemetry/lane-telemetry.sh`); the real env-overridable cousin is `DWARVES_KIT_LIB` (Python, `lib/stats/src/stats/config.py`), which the bash-oriented seed regex cannot see (no `$` sigil in Python source) , documented here rather than silently dropped: see `lib/stats/README.md`'s own env table for `DWARVES_KIT_LIB`'s default (this repo's own `lib/`, kit-internal). | -| MEGA_SH | `lib/board/board.sh`: computed `$BOARD_DIR/../mega.sh`. | +| MEGA_SH | `lib/board/board.sh`: computed `$BOARD_DIR/../mega/mega.sh`. | | PANE_VIEWER_ALLOWED | `lib/queue/orchestrate.sh`: a hardcoded allowlist string, not itself env-read; it validates `PANE_VIEWER`. | | STATS_DB_REMOVED | Dead/vestigial test-fixture token, see its row above , no product reader exists. Kept OUT of the drift-fail set (registered above instead of silently dropped, per the scope fence) but also allowlisted so the lint does not double-count it as a live undocumented knob. | diff --git a/lib/mega-report.py b/lib/mega/mega-report.py similarity index 100% rename from lib/mega-report.py rename to lib/mega/mega-report.py diff --git a/lib/mega-review.py b/lib/mega/mega-review.py similarity index 97% rename from lib/mega-review.py rename to lib/mega/mega-review.py index c7c5eb94..bcf27031 100644 --- a/lib/mega-review.py +++ b/lib/mega/mega-review.py @@ -5,7 +5,7 @@ to this surface -- a projection, always safe to re-run, never cached): 1. ROADMAP.md truth -- this mega's sub-goal lines + each sub-goal's own goal file - (**Branch:** line). Reuses `lib/mega.sh status`'s OWN git-truth + (**Branch:** line). Reuses `lib/mega/mega.sh status`'s OWN git-truth reconciliation (OK/CLAIM-UNVERIFIED/MERGED-UNCHECKED/STALLED/ WIP/PENDING/INFO) by shelling out to it and parsing its stable, documented per-line format -- ONE classifier, not a second one @@ -34,7 +34,7 @@ source renders "-" (honest-dash), NEVER a fabricated zero -- SPEC-197 Design. Usage: mega-review.py --megagoals-root DIR --code-root DIR [--base BRANCH] [--out PATH] -Env: KIT_LOG_DIR the resolved durable ledger root (set by the lib/mega.sh `review` launcher, +Env: KIT_LOG_DIR the resolved durable ledger root (set by the lib/mega/mega.sh `review` launcher, mirroring lib/gate/proof-table-gen.sh's own KIT_ROOT/KIT_LOG_DIR export convention -- this script never re-resolves it itself, so there is one resolver, not two). """ @@ -50,14 +50,14 @@ import subprocess import sys -_SELF_DIR = os.path.dirname(os.path.abspath(__file__)) # lib/ (mega.sh's own dir; orphan file) +_SELF_DIR = os.path.dirname(os.path.abspath(__file__)) # lib/mega/ (this file's own dir; siblings resolve one level up) def _load_proof_table_gen(): """Import lib/gate/proof-table-gen.py's `parse_ledger` + `_normalize_rid` directly (same cross-subsystem sourcing convention gate-ledger.sh itself uses for lib/telemetry + lib/ledger siblings) instead of re-implementing GATE/OUTCOME line parsing a second time.""" - path = os.path.join(_SELF_DIR, "gate", "proof-table-gen.py") + path = os.path.join(_SELF_DIR, "..", "gate", "proof-table-gen.py") spec = importlib.util.spec_from_file_location("proof_table_gen", path) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) # type: ignore[union-attr] @@ -80,7 +80,7 @@ def _run(argv, cwd=None): return None -# ---- 1. ROADMAP truth + git-truth classification (delegates to lib/mega.sh status) ----------- +# ---- 1. ROADMAP truth + git-truth classification (delegates to lib/mega/mega.sh status) ----------- def parse_roadmap(roadmap_path): """[(box, sub_slug, prose)] in file order. Honest-empty: no matching lines -> [].""" @@ -96,7 +96,7 @@ def parse_roadmap(roadmap_path): def git_truth_status(mega_slug, megagoals_root, code_root, base): - """Shells out to the ALREADY-SHIPPED `lib/mega.sh status` (one classifier, not a second one) + """Shells out to the ALREADY-SHIPPED `lib/mega/mega.sh status` (one classifier, not a second one) and parses its stable per-line format into {sub_slug: {label, pr, prstate, branch, commits, openpr}}. Never fatal: a `mega.sh status` failure (e.g. no ROADMAP.md) degrades to an empty map -- every sub-goal then renders with git-truth fields honest-dash, not a crash.""" @@ -300,7 +300,7 @@ def _learned_queued(): def _unpaid_debt_count(code_root): - wb = os.path.join(_SELF_DIR, "learn", "weekend-batch.sh") + wb = os.path.join(_SELF_DIR, "..", "learn", "weekend-batch.sh") if not os.path.isfile(wb): return None res = _run(["bash", wb, "list", "--all-repos"], cwd=code_root) @@ -523,7 +523,7 @@ def main(argv=None): # lib/queue/orchestrate.sh's own locally-derived basename and a trusted local CLI # invocation, never a webhook/network trigger -- but cheap and worth closing): a slug # carrying a path separator could otherwise write REVIEW.html outside megagoals-root via - # os.path.join's own "absolute/.. wins" semantics. Same charset lib/mega.sh's ROADMAP + # os.path.join's own "absolute/.. wins" semantics. Same charset lib/mega/mega.sh's ROADMAP # sub-goal regex already requires (`[0-9]+-[A-Za-z0-9_-]+`), loosened only to allow the # mega SLUG shape (letters/digits/dot/underscore/dash, no leading number requirement). if not re.match(r"^[A-Za-z0-9._-]+$", args.slug): diff --git a/lib/mega.sh b/lib/mega/mega.sh similarity index 91% rename from lib/mega.sh rename to lib/mega/mega.sh index e0ca41be..d2cc1938 100755 --- a/lib/mega.sh +++ b/lib/mega/mega.sh @@ -8,17 +8,16 @@ # `report` (the RUN_REPORT telemetry generator: header + gate matrix + callable-stack # skeleton from the rid ledgers; --out, --rid-map). # -# ORPHAN, not a subsystem dir (SG-03's "2+-verb subsystems get a grouped `lib//.sh` -# case-dispatcher" rule): `mega` gained a second verb (`review`, SPEC-197 / harness-loop SG-07) -# but STAYS a bare orphan file here deliberately -- the directory-promotion (`lib/mega/mega.sh` + -# siblings, `bin/mega`) is explicitly ADR-0034's census target for SG-04 (the taxonomy's own -# consolidation wave), not this sub-goal's scope. `review`'s substantial composition logic lives -# in the sibling `lib/mega-review.py` (bash-launcher-to-python, the exact delegation shape -# `lib/gate/proof-table-gen.sh` -> `lib/gate/proof-table-gen.py` already established: bash 3.2 -# has no associative arrays, which the phase/token/PR joins need). Same shape as -# `lib/board/board.sh` delegating to `lib/board/board-mirror.sh` for its own heavier verbs. -# `lib/adopt.sh` / `lib/explain.sh` / `lib/pitch.sh` / `lib/precedent.sh` remain the single-verb -# orphan precedent this file no longer strictly matches; that gap is SG-04's to close. +# A subsystem dir (SG-03's "2+-verb modules get a grouped `lib//.sh`" rule): `mega` has +# two verbs (`status`, `review` -- SPEC-197 / harness-loop SG-07) and was promoted into +# `lib/mega/` (`lib/mega/mega.sh` + siblings, stable entry `bin/mega`) per ADR-0034 / ID-287. +# `review`'s substantial composition logic lives in the sibling `lib/mega/mega-review.py` +# (bash-launcher-to-python, the exact delegation shape `lib/gate/proof-table-gen.sh` -> +# `lib/gate/proof-table-gen.py` already established: bash 3.2 has no associative arrays, which +# the phase/token/PR joins need). Same shape as `lib/board/board.sh` delegating to +# `lib/board/board-mirror.sh` for its own heavier verbs. The single-verb orphans +# (`lib/adopt.sh` / `lib/explain.sh` / `lib/pitch.sh` / `lib/precedent.sh`) stay at root as +# ADR-0034 "deliberate orphans" pending their own ruling. # # WHY THIS EXISTS (provenance): a live session hit the SG-02 HANDOFF-vs-reality lie by hand -- # HANDOFF.md claimed "running" while the `kitmod-02` worktree sat at 0 commits, empty. A dumb @@ -97,7 +96,7 @@ # fence, see the goal file). Default `--out`: `//REVIEW.html` (next to # RUN_REPORT.md). A projection, never a stored source of truth (SPEC-182 discipline): safe # to re-run any time, nothing cached. The substantial logic lives in the sibling -# `lib/mega-review.py`; this verb is a thin bash launcher that resolves KIT_LOG_DIR the exact +# `lib/mega/mega-review.py`; this verb is a thin bash launcher that resolves KIT_LOG_DIR the exact # way `lib/gate/proof-table-gen.sh` already does, then execs it. # # GH_BIN / GIT_BIN override the `gh`/`git` binaries (tests point them at PATH-injected stubs @@ -213,12 +212,12 @@ _classify() { } _label() { - # DOWNSTREAM COUPLING (review finding, SPEC-197): `lib/mega-review.py`'s `_STATUS_LINE_RE` + # DOWNSTREAM COUPLING (review finding, SPEC-197): `lib/mega/mega-review.py`'s `_STATUS_LINE_RE` # regex parses `cmd_status`'s stdout by matching this exact label set literally (shelled out # to, not reimplemented -- SPEC-197 DEC-003). A cosmetic rename here degrades `mega review` # to a silent, non-fatal honest-empty read for the affected rows (never a crash, per the # composer's own "never fatal" contract) rather than a loud break -- worth a grep for - # `_STATUS_LINE_RE` in `lib/mega-review.py` before renaming any of these strings. + # `_STATUS_LINE_RE` in `lib/mega/mega-review.py` before renaming any of these strings. case "$1" in ok) echo "OK" ;; claim-unverified) echo "CLAIM-UNVERIFIED" ;; @@ -318,7 +317,7 @@ cmd_status() { # cmd_review: the bash launcher half of `mega review --html ` (SPEC-197). Resolves # KIT_LOG_DIR the exact way `lib/gate/proof-table-gen.sh` already does (source # lib/telemetry/kit-log-dir.sh, export the result) so there is ONE resolver, not a second copy, -# then execs the sibling `lib/mega-review.py` (bash 3.2 has no associative arrays, the same +# then execs the sibling `lib/mega/mega-review.py` (bash 3.2 has no associative arrays, the same # reason proof-table-gen.sh delegates to its own .py). `--html` is required: it is currently the # ONLY surface (scope fence -- no live/served variant). cmd_review() { @@ -334,7 +333,7 @@ cmd_review() { local self_dir; self_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=lib/telemetry/kit-log-dir.sh - source "$self_dir/telemetry/kit-log-dir.sh" || { echo "mega review: lib/telemetry/kit-log-dir.sh missing or unreadable" >&2; return 1; } + source "$self_dir/../telemetry/kit-log-dir.sh" || { echo "mega review: lib/telemetry/kit-log-dir.sh missing or unreadable" >&2; return 1; } export KIT_LOG_DIR; KIT_LOG_DIR="$(kit_resolve_log_dir)" || return 1 local -a py_args=("$slug" --megagoals-root "$mroot" --code-root "$croot" --base "$base") @@ -356,7 +355,7 @@ cmd_report() { local mroot; mroot="$(_resolve_megagoals_root)" local self_dir; self_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=lib/telemetry/kit-log-dir.sh - source "$self_dir/telemetry/kit-log-dir.sh" || { echo "mega report: lib/telemetry/kit-log-dir.sh missing or unreadable" >&2; return 1; } + source "$self_dir/../telemetry/kit-log-dir.sh" || { echo "mega report: lib/telemetry/kit-log-dir.sh missing or unreadable" >&2; return 1; } local log_dir; log_dir="$(kit_resolve_log_dir)" || return 1 local -a py_args=("$slug" --megagoals-root "$mroot" --log-dir "$log_dir") diff --git a/lib/queue/orchestrate.sh b/lib/queue/orchestrate.sh index 5f9c0755..34e6bbda 100755 --- a/lib/queue/orchestrate.sh +++ b/lib/queue/orchestrate.sh @@ -1742,10 +1742,10 @@ _tier4_close() { # dir roadmap local mega_slug mega_root mega_slug="$(basename "$dir")" mega_root="$(dirname "$dir")" - if bash "$LIB_ROOT/mega.sh" review "$mega_slug" --html --megagoals-root "$mega_root" --code-root "$corpus" >/dev/null 2>&1; then + if bash "$LIB_ROOT/mega/mega.sh" review "$mega_slug" --html --megagoals-root "$mega_root" --code-root "$corpus" >/dev/null 2>&1; then _say "[orchestrate] [close] mega-review dashboard rendered: $dir/REVIEW.html" else - echo "[orchestrate] [close] WARN: mega-review dashboard render failed (non-fatal; re-run 'bash lib/mega.sh review $mega_slug --html --megagoals-root $mega_root --code-root $corpus' to see the error)" >&2 + echo "[orchestrate] [close] WARN: mega-review dashboard render failed (non-fatal; re-run 'bash lib/mega/mega.sh review $mega_slug --html --megagoals-root $mega_root --code-root $corpus' to see the error)" >&2 fi local orphans rc_no=0 diff --git a/tests/test-mega-report.sh b/tests/test-mega-report.sh index e2b3c068..bec8ab0a 100644 --- a/tests/test-mega-report.sh +++ b/tests/test-mega-report.sh @@ -40,7 +40,7 @@ cat > "$LOGS/runs/feat-01-alpha-widget.log" <<'EOF' EOF LEDGER_BEFORE="$(shasum "$LOGS/runs/feat-01-alpha-widget.log")" -OUT="$(python3 "$KIT_DIR/lib/mega-report.py" demo --megagoals-root "$MROOT" --log-dir "$LOGS" 2>&1)"; RC=$? +OUT="$(python3 "$KIT_DIR/lib/mega/mega-report.py" demo --megagoals-root "$MROOT" --log-dir "$LOGS" 2>&1)"; RC=$? echo "== header + matrix from a real fixture ledger ==" [ $RC -eq 0 ] && ok "exit 0" || bad "exit $RC" @@ -60,7 +60,7 @@ assert_grep "rid-less row is flagged" "(no rid ledger matched)" "$ROW02" assert_nogrep "rid-less row has zero ● cells" "●" "$ROW02" echo "== --out + read-only contract ==" -python3 "$KIT_DIR/lib/mega-report.py" demo --megagoals-root "$MROOT" --log-dir "$LOGS" --out "$TD/r.md" >/dev/null 2>&1 +python3 "$KIT_DIR/lib/mega/mega-report.py" demo --megagoals-root "$MROOT" --log-dir "$LOGS" --out "$TD/r.md" >/dev/null 2>&1 [ -s "$TD/r.md" ] && ok "--out writes the report file" || bad "--out produced nothing" [ "$(shasum "$LOGS/runs/feat-01-alpha-widget.log")" = "$LEDGER_BEFORE" ] \ && ok "source ledger byte-identical after both runs (read-only)" \ @@ -71,6 +71,16 @@ USAGE_OUT="$(bash "$KIT_DIR/bin/mega" report 2>&1)"; URC=$? [ $URC -ne 0 ] && ok "report without a slug refuses (exit $URC)" || bad "slug-less report exited 0" assert_grep "refusal names the requirement" "a is required" "$USAGE_OUT" +# ID-287 coverage: run cmd_report END-TO-END through the bash launcher (not the direct +# python entry the tests above use), so the re-anchored `source "$self_dir/../telemetry/ +# kit-log-dir.sh"` in cmd_report is exercised. A wrong `..` after the lib/mega/ move fails +# the source and never renders the report -- this assertion goes RED, closing the blind spot +# the direct-python tests left (they bypass the launcher entirely). +echo "== launcher: bin/mega report runs cmd_report end-to-end (covers the telemetry anchor) ==" +LAUNCH_OUT="$(DWARVES_KIT_LOG_DIR="$LOGS" bash "$KIT_DIR/bin/mega" report demo --megagoals-root "$MROOT" 2>&1)"; LRC=$? +[ $LRC -eq 0 ] && ok "bin/mega report demo exits 0 (cmd_report telemetry source resolved)" || bad "bin/mega report demo exit $LRC: $LAUNCH_OUT" +assert_grep "launcher path renders the same header as the direct python path" "(1/2 built · 1 merged)" "$LAUNCH_OUT" + echo echo "TOTAL: $((PASS+FAIL)) PASS: $PASS FAIL: $FAIL" [ $FAIL -eq 0 ] diff --git a/tests/test-mega-review.sh b/tests/test-mega-review.sh index 5752be8c..62333f42 100644 --- a/tests/test-mega-review.sh +++ b/tests/test-mega-review.sh @@ -19,7 +19,7 @@ set -uo pipefail KIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -MEGA="$KIT_DIR/lib/mega.sh" +MEGA="$KIT_DIR/lib/mega/mega.sh" PASS=0; FAIL=0 ok() { PASS=$((PASS + 1)); echo "ok - $1"; } @@ -30,9 +30,9 @@ TMP="$(cd "$TMP" && pwd)" trap 'rm -rf "$TMP"' EXIT # ---- gh stub: no real network call is ever made (mirrors tests/test-mega.sh's STUBGH) ---------- -# Two DIFFERENT `gh pr view` shapes hit this one stub: `lib/mega.sh status`'s own `_pr_state` +# Two DIFFERENT `gh pr view` shapes hit this one stub: `lib/mega/mega.sh status`'s own `_pr_state` # calls `gh pr view --json state -q '.state'` (bare-string output, real gh's `-q` behavior), -# while `lib/mega-review.py`'s `pr_state()` calls `gh pr view --json state,url,mergedAt, +# while `lib/mega/mega-review.py`'s `pr_state()` calls `gh pr view --json state,url,mergedAt, # statusCheckRollup,title` with NO `-q` (full JSON). Detect `-q` in argv and branch, matching # real `gh`'s own contract instead of picking one shape and breaking the other caller. STUBGH="$TMP/gh-stub" diff --git a/tests/test-mega.sh b/tests/test-mega.sh index 178f1679..0e03fd00 100755 --- a/tests/test-mega.sh +++ b/tests/test-mega.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# test-mega.sh -- lib/mega.sh (kit-modularity sub-goal 08): `mega status ` reconciles a +# test-mega.sh -- lib/mega/mega.sh (kit-modularity sub-goal 08): `mega status ` reconciles a # mega-goal's ROADMAP.md sub-goal claims against GIT TRUTH. # # Proves the full drift-class taxonomy on a fixture mega ("testmega") with 8 sub-goals, one per @@ -23,7 +23,7 @@ set -uo pipefail KIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -MEGA="$KIT_DIR/lib/mega.sh" +MEGA="$KIT_DIR/lib/mega/mega.sh" PASS=0; FAIL=0 ok() { PASS=$((PASS + 1)); echo "ok - $1"; } diff --git a/tests/test-tier4-close.sh b/tests/test-tier4-close.sh index 3a5dab12..3988bd41 100755 --- a/tests/test-tier4-close.sh +++ b/tests/test-tier4-close.sh @@ -89,7 +89,7 @@ MERGE chmod +x "$1" } -# A `gh` stub (SPEC-197 wiring: `_tier4_close` now calls `lib/mega.sh review` -> `mega.sh +# A `gh` stub (SPEC-197 wiring: `_tier4_close` now calls `lib/mega/mega.sh review` -> `mega.sh # status` -> `_open_pr_for`, which shells to `gh pr list` unconditionally for any sub-goal with a # resolved branch). No real network call is ever made: `pr list` returns `[]` (no open PRs), # matching this fixture's reality, mirroring tests/test-mega.sh's own STUBGH convention.