diff --git a/.agents/skills/catalog.json b/.agents/skills/catalog.json index ae6d3a522a..2bc2fd2755 100644 --- a/.agents/skills/catalog.json +++ b/.agents/skills/catalog.json @@ -11,6 +11,7 @@ "fix", "review", "task", + "prlanded", "handover", "health", "audit", diff --git a/.agents/skills/prlanded/SKILL.md b/.agents/skills/prlanded/SKILL.md new file mode 100644 index 0000000000..1a98fe861c --- /dev/null +++ b/.agents/skills/prlanded/SKILL.md @@ -0,0 +1,14 @@ +--- +name: prlanded +description: Verify a merged PR landed by content without orphaned late commits, record the landed entry in the review ledger, and plan cleanup only when explicitly requested. Use after a PR merges into main. +--- + +# PR Landed + +Follow [Landed](../../../docs/agents/pull-request-workflow.md#landed) and [the detailed procedure](../../../.claude/skills/prlanded/SKILL.md): + +1. Require an explicit ``. Run `npm run workflow:lifecycle -- --phase landed --write-evidence`, then once GitHub read access is authorized run `gh pr view --json state,mergeCommit,mergedAt` and verify `state` is `MERGED` with non-null `mergeCommit` and `mergedAt`. +2. Fetch `origin/main`, inspect `git rev-list --parents -n 1 `, and verify by content: `git merge-base --is-ancestor ^2` plus `git show --remerge-diff ` for a two-parent merge; `git diff --stat ` (or `git patch-id --stable` comparing `git diff ^ ` with `git diff $(git merge-base ^ ) ` when behind `main`) for a squash merge. +3. Check for orphaned late commits pushed after auto-merge was armed; fix-forward with a new PR if any work was missed. +4. Worktree removal, remote branch deletion, and `git branch -D` require an explicit cleanup request; empty content proof does not itself authorize deletion. +5. Record the verification via `npm run ledger:append -- --ref --head <40-char-merge-sha> --scope prlanded --outcome --checks `. diff --git a/.agents/skills/prlanded/agents/openai.yaml b/.agents/skills/prlanded/agents/openai.yaml new file mode 100644 index 0000000000..774edadd5f --- /dev/null +++ b/.agents/skills/prlanded/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "PR Landed" + short_description: "Verify a merged PR landed by content and record proof" + default_prompt: "Use $prlanded to verify that the merged pull request landed on origin/main by content and record the prlanded ledger entry." diff --git a/.claude/skills/prlanded/SKILL.md b/.claude/skills/prlanded/SKILL.md index b8e49f7081..a670ffac0b 100644 --- a/.claude/skills/prlanded/SKILL.md +++ b/.claude/skills/prlanded/SKILL.md @@ -18,13 +18,16 @@ Otherwise ask before GitHub access; never infer provider authority merely from l 1. **Confirm the merge:** `gh pr view --json state,mergeCommit,mergedAt` → `MERGED`. 2. **Verify by content, branching on the merge shape.** `git fetch --quiet origin main`, read the parent count with `git rev-list --parents -n 1 `, then run the comparison - [Landed](../../../docs/agents/pull-request-workflow.md#landed) names for that shape: `merge-base --is-ancestor` on `^2` plus - `git show --remerge-diff` for a merge commit; a two-dot - `git diff --stat ` for a squash (never three-dot). Any - unexplained remaining line is work that did not land — investigate before deleting anything. + [Landed](../../../docs/agents/pull-request-workflow.md#landed) names for that shape: for a + two-parent merge, run `git merge-base --is-ancestor ^2` + and `git show --remerge-diff `; for a squash, run the two-dot + `git diff --stat ` (never three-dot). Any unexplained + remaining line is work that did not land — investigate before deleting anything. If the branch was behind `main` when it merged (always true for a merge-queue merge), that - two-dot diff also shows `main`'s changes: compare the PR's own change with `git patch-id` - instead, exactly as [Landed](../../../docs/agents/pull-request-workflow.md#landed) describes. + two-dot diff also shows `main`'s changes: compare the explicit PR diff + `git diff ^ | git patch-id --stable` with + `git diff $(git merge-base ^ ) | git patch-id --stable`, + exactly as [Landed](../../../docs/agents/pull-request-workflow.md#landed) describes. 3. **Check for orphaned late commits** pushed after auto-merge was armed; if missing, fix-forward with a new PR — do not force-push. 4. **Prepare cleanup only after the content diff is empty.** Worktree removal, remote branch diff --git a/.gitignore b/.gitignore index 464a6c686f..4c7717758c 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ !/.agents/skills/performance/ !/.agents/skills/plan/ !/.agents/skills/privacy/ +!/.agents/skills/prlanded/ !/.agents/skills/prompt-perfector/ !/.agents/skills/rag-change-lab/ !/.agents/skills/rag/ diff --git a/data/repo-awareness-snapshot.json b/data/repo-awareness-snapshot.json index 27260505f0..6c72684ee5 100644 --- a/data/repo-awareness-snapshot.json +++ b/data/repo-awareness-snapshot.json @@ -11499,6 +11499,14 @@ "outcome": "Replayed the requested historical design-audit commit onto fresh `origin/main`. Kept current-main versions for five conflicts, including the regenerated drift manifest and current schema assertions. Fixed the duplicate sitemap-generator declaration, corrected redirect-section coverage, and restored the current `Clinical Guide` UI contract.", "checks": "`git diff --check` and `npm run sitemap:check` passed. `npm run test` was attempted twice but blocked by the repository-wide heavy-command lock held by a separate Playwright worktree; no provider-backed checks ran." }, + { + "date": "2026-10-17", + "ref": "claude/rag-ingestion-hardening", + "head": "45fc04c42f0867bc9802ffc93f0ed42fd658b371", + "scope": "prlanded", + "outcome": "PR #3596 squash-merged cleanly into main at 45fc04c42f0867bc9802ffc93f0ed42fd658b371; stable patch-id c6055c7a792f5f2a7bd96d5376a8cab43f8a1954 matches branch tip d4b592b0a0b375cbbc1df3d167dd720919afcf3f with zero orphaned commits", + "checks": "gh pr view 3596; git rev-list --parents; git patch-id --stable (c6055c7a792f5f2a7bd96d5376a8cab43f8a1954)" + }, { "date": "2026-08-11", "ref": "HEAD", @@ -16043,6 +16051,14 @@ "outcome": "Fixed: prettier format:changed; PR_POLICY_BODY sync for Clinical Governance Preflight; empty commit retriggered PR Policy after body sync race. Review threads already resolved (fb8adf92). Required checks green (PR policy, Static PR, PR required). mergeStateStatus BEHIND vs moving main — merge-tree clean.", "checks": "vitest:54/54; prettier:pass; pr-policy:pass; static-pr:pass; pr-required:pass" }, + { + "date": "2026-10-17", + "ref": "codex/cloud-policy-clarity", + "head": "7c719b2bc43688d3620336d043d1c13d98750725", + "scope": "prlanded", + "outcome": "PR #3581 (a5b118f952) and PR #3587 (7c719b2bc4) squash-merged cleanly into origin/main; content diff empty and local branch tip db82acc1df is an ancestor of merged PR head adf52eac1c; worktree and branch preserved (no cleanup requested)", + "checks": "gh pr view 3581/3587, git fetch origin, git merge-base --is-ancestor db82acc1df adf52eac1c, git diff 7c719b2bc4 adf52eac1c" + }, { "date": "2026-07-31", "ref": "origin/claude/clinical-design-system-update-e34ca9", @@ -16315,6 +16331,14 @@ "outcome": "PASS", "checks": "typecheck, vitest (filters, sheets, search band, dom panels), prettier" }, + { + "date": "2026-10-17", + "ref": "claude/add-prlanded-skill", + "head": "7e6fd2d557d53e22dfa6ea37b8921007fe4b0dfa", + "scope": "prlanded", + "outcome": "PASS (0 blocking findings; added .agents/skills/prlanded canonical skill, registered cross-surface twin in list-database-skills.mjs, updated skill inventory tests, and recorded prlanded proofs for PRs #3581/#3587 and #3596)", + "checks": "npm run check:skills, vitest run tests/database-skills.test.ts tests/repository-skill-inventory.test.ts (15/15), npm run docs:maintain:check, check-format-changed" + }, { "date": "2026-07-13", "ref": "claude/icon-glyph-refinements", diff --git a/docs/branch-review-index.md b/docs/branch-review-index.md index 5667ef695a..d5249e8369 100644 --- a/docs/branch-review-index.md +++ b/docs/branch-review-index.md @@ -15,13 +15,14 @@ Retention and rotation: [`branch-review-archival-policy.md`](branch-review-archi ## Summary -- Records: 703 -- Distinct ref cells: 452 -- Distinct reviewed heads: 685 -- Date range: `2026-08-12` to `2026-10-16` +- Records: 708 +- Distinct ref cells: 454 +- Distinct reviewed heads: 690 +- Date range: `2026-08-12` to `2026-10-17` Records per date, newest first: +- `2026-10-17` — 5 records - `2026-10-16` — 4 records - `2026-10-15` — 3 records - `2026-10-14` — 1 record @@ -78,6 +79,11 @@ Scope and outcome are truncated; follow the record link for the full six-cell ro | Date | Ref | Scope | Outcome | Record | | --- | --- | --- | --- | --- | +| 2026-10-17 | codex/cloud-policy-clarity | prlanded | PR #3581 (a5b118f952) and PR #3587 (7c719b2bc4) squash-merged cleanly… | [16df9092](branch-review-records/16df90928a34e2941ef9c2892b7f48d92e09e12f470af635ef15e4ee3677b0b9.record.md) | +| 2026-10-17 | claude/rag-ingestion-hardening | prlanded | PR #3596 squash-merged cleanly into main at 45fc04c42f0867bc9802ffc93f… | [1ae2c7f8](branch-review-records/1ae2c7f8f7762d8e1d81898ed83a701be7cbd007c80be5a3d83e39470ced9461.record.md) | +| 2026-10-17 | claude/rag-ingestion-hardening | RAG retrieval/summary/cache generation isolation and ingestion worker/edge hardening | resolved | [5349150e](branch-review-records/5349150e82f255e42866975fa7aa5e9fe76601433ebc427c75226677c5bef854.record.md) | +| 2026-10-17 | claude/rag-ingestion-hardening | RAG and Ingestion review follow-ups | Resolved PR review findings, repaired bot-applied regressions, and res… | [94a7d790](branch-review-records/94a7d7908ea7ff58edaecb6ebd9fd41f72d422ad6d345190046cfd5ed2d4372d.record.md) | +| 2026-10-17 | claude/add-prlanded-skill | Canonical prlanded skill and landed ledger records | PASS (0 blocking findings; added .agents/skills/prlanded canonical ski… | [e60fd2b5](branch-review-records/e60fd2b5f608cf1e9d5bbabab48952b87feff63f27ad911b96a1e9fc22250fa7.record.md) | | 2026-10-16 | fix/adversarial-remediation-20261016 | Adversarial assessment + parallel fix swarm + post-fix adversarial review across calculato… | All P0/P1/P2 findings fixed and verified; zero RAG files touched | [2a6b6200](branch-review-records/2a6b620065f5371039438fdbff73be97da6baf6c40dace3596e26c7bad0047dd.record.md) | | 2026-10-16 | codex/cloud-policy-clarity | Codex Cloud reasoning-effort and raw-env policy overhaul | PASS (0 blocking findings; removed all xhigh prompt-marker references… | [3dd0e7e3](branch-review-records/3dd0e7e32634c00735102bf22ba9883745ad72dc5db730b1dce2c33f03e699f0.record.md) | | 2026-10-16 | codex/cloud-policy-clarity | Codex Cloud environment script and shell-profile hardening | PASS (0 blocking findings; hardened .bashrc prepend, command-shim fall… | [7f059fca](branch-review-records/7f059fca46aac02223aa9f81e3d88a1a08f2b8a4844646d3a8eaa2cabd493c33.record.md) | diff --git a/docs/branch-review-records/16df90928a34e2941ef9c2892b7f48d92e09e12f470af635ef15e4ee3677b0b9.record.md b/docs/branch-review-records/16df90928a34e2941ef9c2892b7f48d92e09e12f470af635ef15e4ee3677b0b9.record.md new file mode 100644 index 0000000000..6bc21f1b7f --- /dev/null +++ b/docs/branch-review-records/16df90928a34e2941ef9c2892b7f48d92e09e12f470af635ef15e4ee3677b0b9.record.md @@ -0,0 +1 @@ +| 2026-10-17 | codex/cloud-policy-clarity | 7c719b2bc43688d3620336d043d1c13d98750725 | prlanded | PR #3581 (a5b118f952) and PR #3587 (7c719b2bc4) squash-merged cleanly into origin/main; content diff empty and local branch tip db82acc1df is an ancestor of merged PR head adf52eac1c; worktree and branch preserved (no cleanup requested) | gh pr view 3581/3587, git fetch origin, git merge-base --is-ancestor db82acc1df adf52eac1c, git diff 7c719b2bc4 adf52eac1c | diff --git a/docs/branch-review-records/1ae2c7f8f7762d8e1d81898ed83a701be7cbd007c80be5a3d83e39470ced9461.record.md b/docs/branch-review-records/1ae2c7f8f7762d8e1d81898ed83a701be7cbd007c80be5a3d83e39470ced9461.record.md new file mode 100644 index 0000000000..2e2986ee8b --- /dev/null +++ b/docs/branch-review-records/1ae2c7f8f7762d8e1d81898ed83a701be7cbd007c80be5a3d83e39470ced9461.record.md @@ -0,0 +1 @@ +| 2026-10-17 | claude/rag-ingestion-hardening | 45fc04c42f0867bc9802ffc93f0ed42fd658b371 | prlanded | PR #3596 squash-merged cleanly into main at 45fc04c42f0867bc9802ffc93f0ed42fd658b371; stable patch-id c6055c7a792f5f2a7bd96d5376a8cab43f8a1954 matches branch tip d4b592b0a0b375cbbc1df3d167dd720919afcf3f with zero orphaned commits | gh pr view 3596; git rev-list --parents; git patch-id --stable (c6055c7a792f5f2a7bd96d5376a8cab43f8a1954) | diff --git a/docs/branch-review-records/e60fd2b5f608cf1e9d5bbabab48952b87feff63f27ad911b96a1e9fc22250fa7.record.md b/docs/branch-review-records/e60fd2b5f608cf1e9d5bbabab48952b87feff63f27ad911b96a1e9fc22250fa7.record.md new file mode 100644 index 0000000000..7dc912a7aa --- /dev/null +++ b/docs/branch-review-records/e60fd2b5f608cf1e9d5bbabab48952b87feff63f27ad911b96a1e9fc22250fa7.record.md @@ -0,0 +1 @@ +| 2026-10-17 | claude/add-prlanded-skill | 7e6fd2d557d53e22dfa6ea37b8921007fe4b0dfa | Canonical prlanded skill and landed ledger records | PASS (0 blocking findings; added .agents/skills/prlanded canonical skill, registered cross-surface twin in list-database-skills.mjs, updated skill inventory tests, and recorded prlanded proofs for PRs #3581/#3587 and #3596) | npm run check:skills, vitest run tests/database-skills.test.ts tests/repository-skill-inventory.test.ts (15/15), npm run docs:maintain:check, check-format-changed | diff --git a/docs/productivity-workflows.md b/docs/productivity-workflows.md index 1eb33499ac..03459895d5 100644 --- a/docs/productivity-workflows.md +++ b/docs/productivity-workflows.md @@ -6,7 +6,7 @@ For a reusable task brief, one continuation record and private measurement, open [Focused tasks and continuation](agents/task-efficiency.md). Keep the current task's checkpoint canonical and use the planners below for selection and supporting evidence. -The repository exposes a validated catalog of 35 canonical Database skills. Run `npm run skills` to list them by category. `npm run check:skills` validates the 35 canonical skills, 8 compatibility aliases, and every Claude, Cursor, and PsychSift plugin `SKILL.md` for metadata, local links, npm commands, frozen-ledger discipline, provider approval boundaries, and destructive-action safeguards. +The repository exposes a validated catalog of 36 canonical Database skills. Run `npm run skills` to list them by category. `npm run check:skills` validates the 36 canonical skills, 8 compatibility aliases, and every Claude, Cursor, and PsychSift plugin `SKILL.md` for metadata, local links, npm commands, frozen-ledger discipline, provider approval boundaries, and destructive-action safeguards. The repository exposes seven offline-first workflow planners. Each planner inspects the current change through `scripts/ci-change-scope.mjs`, prints a minimal local verification sequence, and separates provider-backed commands into an explicit approval section. diff --git a/scripts/list-database-skills.mjs b/scripts/list-database-skills.mjs index 309c673e5e..65ce9081e1 100644 --- a/scripts/list-database-skills.mjs +++ b/scripts/list-database-skills.mjs @@ -16,17 +16,17 @@ export const repositorySkillSurfaces = [ { name: "PsychSift plugin", root: path.join(repositoryRoot, "plugins", "clinical-kb", "skills") }, ]; export const expectedRepositorySkillSurfaceCounts = { - Codex: 43, + Codex: 44, Claude: 9, Cursor: 15, "PsychSift plugin": 1, }; /** Same frontmatter `name` across Claude/Codex/Cursor/plugin is allowed only for - * intentional twins. Today that is `ledger` (Codex thin-pointer → Claude procedure). + * intentional twins. Today those are `ledger` and `prlanded` (Codex thin-pointer → Claude procedure). * Opposite jobs under one name (the old Claude acquisition vs Codex governance * `sources` collision) must fail closed. */ -export const CROSS_SURFACE_NAME_TWINS = new Set(["ledger"]); +export const CROSS_SURFACE_NAME_TWINS = new Set(["ledger", "prlanded"]); function wordCount(value) { return String(value || "") @@ -263,6 +263,10 @@ export function validateRepositorySkillPolicies( "require an explicit cleanup request", "does not itself authorize deletion", ]); + requireContract(".agents/skills/prlanded/SKILL.md", [ + "require an explicit cleanup request", + "does not itself authorize deletion", + ]); requireContract(".cursor/skills/release-readiness-review/SKILL.md", [ "Use `npm run verify:pr-local`", "requires user approval", diff --git a/tests/database-skills.test.ts b/tests/database-skills.test.ts index 8e660946dd..2cfba4da31 100644 --- a/tests/database-skills.test.ts +++ b/tests/database-skills.test.ts @@ -23,8 +23,8 @@ describe("Database skill catalog", () => { const result = validateSkillCatalog(); expect(result.errors).toEqual([]); - expect(result.canonical).toHaveLength(35); - expect(new Set(result.canonical.map((skill: { name: string }) => skill.name))).toHaveProperty("size", 35); + expect(result.canonical).toHaveLength(36); + expect(new Set(result.canonical.map((skill: { name: string }) => skill.name))).toHaveProperty("size", 36); expect(result.aliases).toHaveLength(8); for (const category of catalog.categories) { expect(category.skills.every((skill: unknown) => typeof skill === "string")).toBe(true); @@ -34,7 +34,7 @@ describe("Database skill catalog", () => { it("discovers each declared skill from its folder metadata", () => { const discovered = discoverSkillDefinitions(); - expect(discovered).toHaveLength(43); + expect(discovered).toHaveLength(44); for (const skill of discovered) { if (!skill) continue; const metadataPath = path.join(skillsRoot, skill.name, "agents", "openai.yaml"); @@ -90,9 +90,9 @@ describe("Database skill catalog", () => { const result = validateRepositorySkillPolicies(files); expect(result.errors).toEqual([]); - expect(files).toHaveLength(68); + expect(files).toHaveLength(69); expect(result.surfaceCounts).toEqual({ - Codex: 43, + Codex: 44, Claude: 9, Cursor: 15, "PsychSift plugin": 1, @@ -114,13 +114,19 @@ describe("Database skill catalog", () => { byName.set(name, group); } - expect(CROSS_SURFACE_NAME_TWINS).toEqual(new Set(["ledger"])); + expect(CROSS_SURFACE_NAME_TWINS).toEqual(new Set(["ledger", "prlanded"])); expect( byName .get("ledger") ?.map((skill) => skill.surface) .sort(), ).toEqual(["Claude", "Codex"]); + expect( + byName + .get("prlanded") + ?.map((skill) => skill.surface) + .sort(), + ).toEqual(["Claude", "Codex"]); expect(byName.has("source-governance")).toBe(true); expect(byName.get("source-governance")?.every((skill) => skill.surface === "Codex")).toBe(true); expect(byName.get("sources")?.every((skill) => skill.surface === "Claude")).toBe(true);