Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/memory/pipeline/execution-skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Each prefix step (the `_intake` Create-Intake Procedure, `/fab-switch`, `/git-br

**PR type system**: `/git-pr` supports 7 PR types (feat, fix, refactor, docs, test, ci, chore) derived from Conventional Commits. Types are resolved via a four-step chain: explicit argument → read from `.status.yaml` → infer from fab change intake → infer from diff. The type controls the PR title prefix (`{type}: {title}`). The PR body has two layers: an agent-generated `## Summary` + optional `## Changes` (prose synthesized from `intake.md`), and a mechanically-rendered `## Meta` block. Title derivation uses intake heading when available, commit subject otherwise, regardless of type.

**Mechanical `## Meta` block via `fab pr-meta`** (rj31): As of rj31, `/git-pr` Step 3c no longer assembles the `## Meta` block from natural-language formatting prose. The entire block — the 5-column top table (`Change ID | Type | Confidence | Plan | Review`), the `**Impact**:` table + caption, the optional `**Issues**:` line, and the `**Pipeline:**` line (six fixed-order stages with ` ✓` per `done` stage and hyperlinked intake/apply labels) — is rendered deterministically by the `fab pr-meta <change> --type <type> [--issues "<space-joined IDs>"]` subcommand, whose stdout the skill pastes verbatim (omitting the block on non-zero exit / empty stdout, matching the legacy `{has_fab} = false` path). **Element order (260625-pnao layout revision):** heading → top table → Impact table + caption → optional Issues → **Pipeline (LAST)** — Pipeline moved from before Impact to the final element, with the optional Issues line sitting just above it. Each table/paragraph is blank-line separated so GitHub renders them distinctly. The top table's first header is **`Change ID`** (was `ID`); a present id is backtick-wrapped (`` `pnao` ``), the empty-fallback `—` stays bare. `**Pipeline:**` carries the colon **inside** the bold span. **Impact is one normalized, self-labeling table** (pnao, replacing the prior multi-form rendering): a single `Impact | +/− | Net` table — the compact `+/−` is the *column header* only, while the data rows carry spaced `+A / −B` figures; the first column header is `Impact` (was `Scope`), so the table needs **no separate `**Impact**:` lead-in line**. Numeric columns are right-aligned. It carries the fixed taxonomy `raw / true / impl / tests / excluded` where `raw = true + excluded` and `true = impl + tests`. `true` is ALWAYS the post-exclude diff (the bold row, always present) — fixing the prior "total flips meaning" bug where the same label denoted the raw diff in one form and the post-exclude diff in another. The table adapts by DROPPING rows, never reshaping: the `raw` row appears only when it differs from `true` (excludes engaged), and nested `└ impl` / `└ tests` rows appear only when a tests pair is present. Below the table a `<sub>` (small-text, NOT italic) provenance caption co-locates the excludes note and the fab-kit **binary** version stamp — `<sub>excludes `fab/`, `docs/` · generated by fab-kit vX.Y.Z</sub>` (excludes clause omitted when none configured; `vdev` rendered honestly on dev builds). Emphasis stays bold-only and the caption uses `<sub>` because GitHub's Markdown sanitizer strips `style`/`class` (so row backgrounds / colored numbers are impossible) but keeps `<sub>` on its HTML allowlist. Type resolution (Step 0b), issue gathering (Step 1), and the agent-generated Summary/Changes stay skill-side; the progress token remains `✓ body — meta + summary + changes`. `fab pr-meta` is self-contained — it reads `.status.yaml`, parses `plan.md` task checkboxes, reads config (`true_impact_exclude`, `test_paths`, `project.linear_workspace`), computes impact via `internal/impact`, and resolves git/`gh` context (branch, owner/repo, merge-base) itself; the skill passes only `<change>`, `--type`, and optional `--issues`. This moves the Meta block's determinism into Go (tested via golden-output tests), eliminating per-run drift (e.g., the dropped exclude-list backticks the prose previously produced). `gh` failure degrades to plain-text Pipeline labels; a missing merge-base drops only the Impact block — never a hard `/git-pr` failure. `/git-pr` no longer calls `fab impact` directly (the subcommand remains public for other consumers). Blob URLs use `https://github.com/{owner}/{repo}/blob/{branch}/...` to resolve against the feature branch instead of main. See [schemas.md](/pipeline/schemas.md) for the `true_impact` render-time `impl` residual and [the `fab pr-meta` CLI reference](../../../src/kit/skills/_cli-fab.md) for the full signature, output contract, and exit codes.
**Mechanical `## Meta` block via `fab pr-meta`** (rj31): As of rj31, `/git-pr` Step 3c no longer assembles the `## Meta` block from natural-language formatting prose. The entire block — the 5-column top table (`Change ID | Type | Confidence | Plan | Review`), the Impact table + caption, the optional `**Issues**:` line, and the `**Pipeline:**` line (six fixed-order stages with ` ✓` per `done` stage and hyperlinked intake/apply labels) — is rendered deterministically by the `fab pr-meta <change> --type <type> [--issues "<space-joined IDs>"]` subcommand, whose stdout the skill pastes verbatim (omitting the block on non-zero exit / empty stdout, matching the legacy `{has_fab} = false` path). **Element order (260625-pnao layout revision):** heading → top table → Impact table + caption → optional Issues → **Pipeline (LAST)** — Pipeline moved from before Impact to the final element, with the optional Issues line sitting just above it. Each table/paragraph is blank-line separated so GitHub renders them distinctly. The top table's first header is **`Change ID`** (was `ID`); a present id is backtick-wrapped (`` `pnao` ``), the empty-fallback `—` stays bare. `**Pipeline:**` carries the colon **inside** the bold span. **Impact is one normalized, self-labeling table** (pnao, replacing the prior multi-form rendering): a single `Impact | +/− | Net` table — the compact `+/−` is the *column header* only, while the data rows carry spaced `+A / −B` figures; the first column header is `Impact` (was `Scope`), so the table needs **no separate `**Impact**:` lead-in line**. Numeric columns are right-aligned. It carries the fixed taxonomy `raw / true / impl / tests / excluded` where `raw = true + excluded` and `true = impl + tests`. `true` is ALWAYS the post-exclude diff (the bold row, always present) — fixing the prior "total flips meaning" bug where the same label denoted the raw diff in one form and the post-exclude diff in another. The table adapts by DROPPING rows, never reshaping: the `raw` row is shown whenever `true_impact_exclude` is configured (`Excluding != nil`, even when raw equals true — a configured-but-no-op exclude still earns its own row), and is omitted only when no excludes are configured (`Excluding == nil`), where `true` is definitionally identical to `raw` so no redundant duplicate row appears *(260625-pnao follow-up — supersedes the prior "shown only when it differs from true" rule per the user's "always show raw when excludes are configured" decision)*; nested `└ impl` / `└ tests` rows appear only when a tests pair is present. Below the table a `<sub>` (small-text, NOT italic) provenance caption co-locates the excludes note and the fab-kit **binary** version stamp — `<sub>excludes `fab/`, `docs/` · generated by fab-kit vX.Y.Z</sub>` (excludes clause omitted when none configured; `vdev` rendered honestly on dev builds). Emphasis stays bold-only and the caption uses `<sub>` because GitHub's Markdown sanitizer strips `style`/`class` (so row backgrounds / colored numbers are impossible) but keeps `<sub>` on its HTML allowlist. Type resolution (Step 0b), issue gathering (Step 1), and the agent-generated Summary/Changes stay skill-side; the progress token remains `✓ body — meta + summary + changes`. `fab pr-meta` is self-contained — it reads `.status.yaml`, parses `plan.md` task checkboxes, reads config (`true_impact_exclude`, `test_paths`, `project.linear_workspace`), computes impact via `internal/impact`, and resolves git/`gh` context (branch, owner/repo, merge-base) itself; the skill passes only `<change>`, `--type`, and optional `--issues`. This moves the Meta block's determinism into Go (tested via golden-output tests), eliminating per-run drift (e.g., the dropped exclude-list backticks the prose previously produced). `gh` failure degrades to plain-text Pipeline labels; a missing merge-base drops only the Impact block — never a hard `/git-pr` failure. `/git-pr` no longer calls `fab impact` directly (the subcommand remains public for other consumers). Blob URLs use `https://github.com/{owner}/{repo}/blob/{branch}/...` to resolve against the feature branch instead of main. See [schemas.md](/pipeline/schemas.md) for the `true_impact` render-time `impl` residual and [the `fab pr-meta` CLI reference](../../../src/kit/skills/_cli-fab.md) for the full signature, output contract, and exit codes.

**PR change metadata**: Change identity and linked issues are part of the mechanically-rendered `## Meta` block (see "Mechanical `## Meta` block via `fab pr-meta`" above). The Meta table's `Change ID` cell carries the 4-char change ID from `.status.yaml` (backtick-wrapped when present; bare `—` when absent); the optional `**Issues**:` line (rendered only when the skill passes a non-empty `--issues`, gathered via `fab status get-issues`) renders each ID as a Linear hyperlink `https://linear.app/{linear_workspace}/issue/{ISSUE_ID}` when `project.linear_workspace` is configured, bare comma-joined IDs otherwise, positioned below the Impact table + caption and above Pipeline (the pnao layout revision made Pipeline the last element). Missing fields show `—`. When the change cannot be resolved, `fab pr-meta` exits non-zero and the entire Meta block is omitted.

Expand Down
2 changes: 1 addition & 1 deletion docs/memory/pipeline/schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ Field semantics:

**Helper subcommand**: `fab impact <base> <head>` is the canonical CLI for computing the block (consumed by `WriteTrueImpact`). It emits the same YAML schema (minus `computed_at_stage` — that is the caller's responsibility) on stdout, exits non-zero with an actionable stderr message on merge-base or `git diff` failure, and reads `true_impact_exclude` from `fab/project/config.yaml` to apply the same `excluding` rule. See `_cli-fab.md` for the full CLI reference.

**`fab pr-meta` subcommand** (rj31): `fab pr-meta <change> --type <type> [--issues "<space-joined IDs>"]` renders the complete `## Meta` block of a fab-generated PR as final markdown (the 5-column top table, the `**Impact**:` table + caption, optional `**Issues**:`, and the `**Pipeline:**` line), replacing the inlined `/git-pr` Step 3c formatting prose. As of pnao (with the 260625 layout revision) the block orders as heading → top table (header `Change ID`, id backtick-wrapped, bare `—` fallback) → Impact table + caption → optional Issues → `**Pipeline:**` (LAST; colon inside the bold). The Impact block is a single normalized, self-labeling `Impact | +/− | Net` table (compact `+/−` column header, spaced `+A / −B` data figures, no separate `**Impact**:` lead-in) carrying the `raw / true / impl / tests / excluded` taxonomy (`raw = true + excluded`, `true = impl + tests`; `true` always the post-exclude diff, bold and always present) plus a `<sub>` (small-text, not italic) provenance caption stamping the **binary** version (`<sub>excludes … · generated by fab-kit vX.Y.Z</sub>`); the `raw` row drops when it equals `true`, the nested `└ impl`/`└ tests` rows appear only with a tests pair. The binary version is threaded via a pure `prmeta.Data.Version` field populated in `cmd/fab/pr_meta.go` `RunE` (not read in `Gather`, never config `fab_version`), keeping `Render` a pure function of `Data` for byte-stable golden tests. It reuses `internal/impact` (`ComputeForRepo`) for the Impact figures against an internally-resolved merge-base (HEAD vs `origin/main`, falling back to `origin/master`) rather than shelling to `fab impact`, and derives the `impl` residual at render time per the rule above. It is self-contained otherwise — reading `.status.yaml`, `plan.md` task checkboxes, and config (`true_impact_exclude`, `test_paths`, `project.linear_workspace`) directly. Non-zero exit (no fab context) or empty stdout signals `/git-pr` to omit the Meta block; `gh` failure degrades to plain-text Pipeline labels and a missing merge-base drops only the Impact block. Render logic lives in `internal/prmeta/`; see `_cli-fab.md` for the full CLI reference.
**`fab pr-meta` subcommand** (rj31): `fab pr-meta <change> --type <type> [--issues "<space-joined IDs>"]` renders the complete `## Meta` block of a fab-generated PR as final markdown (the 5-column top table, the Impact table + caption, optional `**Issues**:`, and the `**Pipeline:**` line), replacing the inlined `/git-pr` Step 3c formatting prose. As of pnao (with the 260625 layout revision) the block orders as heading → top table (header `Change ID`, id backtick-wrapped, bare `—` fallback) → Impact table + caption → optional Issues → `**Pipeline:**` (LAST; colon inside the bold). The Impact block is a single normalized, self-labeling `Impact | +/− | Net` table (compact `+/−` column header, spaced `+A / −B` data figures, no separate `**Impact**:` lead-in) carrying the `raw / true / impl / tests / excluded` taxonomy (`raw = true + excluded`, `true = impl + tests`; `true` always the post-exclude diff, bold and always present) plus a `<sub>` (small-text, not italic) provenance caption stamping the **binary** version (`<sub>excludes … · generated by fab-kit vX.Y.Z</sub>`); the `raw` row is shown whenever `true_impact_exclude` is configured (`Excluding != nil`, even when raw equals true), and is omitted only when no excludes are configured (`Excluding == nil`) since `true` is then definitionally identical to `raw` *(260625-pnao follow-up — supersedes the prior "drops when it equals true" rule)*; the nested `└ impl`/`└ tests` rows appear only with a tests pair. The binary version is threaded via a pure `prmeta.Data.Version` field populated in `cmd/fab/pr_meta.go` `RunE` (not read in `Gather`, never config `fab_version`), keeping `Render` a pure function of `Data` for byte-stable golden tests. It reuses `internal/impact` (`ComputeForRepo`) for the Impact figures against an internally-resolved merge-base (HEAD vs `origin/main`, falling back to `origin/master`) rather than shelling to `fab impact`, and derives the `impl` residual at render time per the rule above. It is self-contained otherwise — reading `.status.yaml`, `plan.md` task checkboxes, and config (`true_impact_exclude`, `test_paths`, `project.linear_workspace`) directly. Non-zero exit (no fab context) or empty stdout signals `/git-pr` to omit the Meta block; `gh` failure degrades to plain-text Pipeline labels and a missing merge-base drops only the Impact block. Render logic lives in `internal/prmeta/`; see `_cli-fab.md` for the full CLI reference.

## `.status.yaml` Identity Fields

Expand Down
7 changes: 4 additions & 3 deletions docs/specs/skills/SPEC-git-pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ Autonomously commits, pushes, and creates a draft GitHub PR. No prompts, no ques
│ │ optional **Issues** + **Pipeline:** (last) as final markdown;
│ │ Impact = one self-labeling normalized table (Impact | +/− | Net,
│ │ no lead-in line) with the raw/true/impl/tests/excluded taxonomy
│ │ (true always = post-exclude diff), rows DROP not reshape (raw only
│ │ when ≠ true; bold true always; nested └ impl/└ tests only with a
│ │ (true always = post-exclude diff), rows DROP not reshape (raw shown
│ │ whenever excludes are configured (Excluding != nil), else collapsed
│ │ into true; bold true always; nested └ impl/└ tests only with a
│ │ tests pair) + a <sub> provenance caption (excludes via actual
│ │ true_impact_exclude values, never hardcoded · generated by
│ │ fab-kit vX.Y.Z);
Expand Down Expand Up @@ -143,7 +144,7 @@ Autonomously commits, pushes, and creates a draft GitHub PR. No prompts, no ques
| Tool | Purpose |
|------|---------|
| Read | Intake (for PR title + the agent-generated `## Summary` and `## Changes` sections) |
| Bash | All git operations, gh CLI, fab status commands. Step 3c renders the body's entire `## Meta` block by calling `fab pr-meta <change> --type <type> --issues "<issues>"` and pasting its stdout verbatim — the subcommand is self-contained (reads `.status.yaml`, `plan.md`/`tasks.md`, `config.yaml`, computes impact via `internal/impact`, resolves git/`gh` context, stamps the running binary version) and renders, in element order, the table, optional Impact, optional `**Issues**`, and `**Pipeline:**` (last) deterministically. The Impact section is one self-labeling normalized table (`Impact \| +/− \| Net`, first-column header is `Impact` so there is no lead-in line, numeric columns right-aligned, Net kept) with the locked `raw / true / impl / tests / excluded` taxonomy (`true` always = the post-exclude diff — fixing the prior "total flips meaning" bug), rows dropping rather than reshaping (`raw` only when it differs from `true`; the bold `**true**` row always; nested `└ impl` / `└ tests` only when a `tests` pair exists, `impl = max(0, true − tests)` per component, clamp-annotated when net-negative), followed by a `<sub>` provenance caption (`<sub>excludes …` from the actual `true_impact_exclude` values · `generated by fab-kit vX.Y.Z</sub>`; dev builds render `fab-kit vdev`). A non-zero exit / empty stdout means the Meta block is omitted. `/git-pr` no longer calls `fab impact` directly. |
| Bash | All git operations, gh CLI, fab status commands. Step 3c renders the body's entire `## Meta` block by calling `fab pr-meta <change> --type <type> --issues "<issues>"` and pasting its stdout verbatim — the subcommand is self-contained (reads `.status.yaml`, `plan.md`/`tasks.md`, `config.yaml`, computes impact via `internal/impact`, resolves git/`gh` context, stamps the running binary version) and renders, in element order, the table, optional Impact, optional `**Issues**`, and `**Pipeline:**` (last) deterministically. The Impact section is one self-labeling normalized table (`Impact \| +/− \| Net`, first-column header is `Impact` so there is no lead-in line, numeric columns right-aligned, Net kept) with the locked `raw / true / impl / tests / excluded` taxonomy (`true` always = the post-exclude diff — fixing the prior "total flips meaning" bug), rows dropping rather than reshaping (`raw` shown whenever excludes are configured — the `Excluding` pass is present — even when its figures equal `true`; with no excludes it collapses into `true` and no duplicate row appears; the bold `**true**` row always; nested `└ impl` / `└ tests` only when a `tests` pair exists, `impl = max(0, true − tests)` per component, clamp-annotated when net-negative), followed by a `<sub>` provenance caption (`<sub>excludes …` from the actual `true_impact_exclude` values · `generated by fab-kit vX.Y.Z</sub>`; dev builds render `fab-kit vdev`). A non-zero exit / empty stdout means the Meta block is omitted. `/git-pr` no longer calls `fab impact` directly. |

### Sub-agents

Expand Down
Loading
Loading