From d64f94237c9a03651cee292f2a6ee224e4a7cc60 Mon Sep 17 00:00:00 2001 From: Hideyuki MORI Date: Sat, 23 May 2026 03:03:23 +0900 Subject: [PATCH] chore(dev): FT report scaffold + candidates backlog + PR templates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ergonomic 第 2 弾。boilerplate を更に畳む。 ### tools/ft-report-new.sh - usage: tools/ft-report-new.sh - docs/templates/field-trial-report.md を docs/field-trials/YYYY-MM-field-trial-N.md にコピーし、{N} / {topic} / 日付 を埋める - 既存ファイルへの overwrite を refuse (in-progress notes 保護) - 動機: 今日 5 FT 走らせて毎回 fresh で書いた、毎回同じ shape ### docs/field-trials/candidates.md - 提案 backlog の durable 化 - session 間で「次の trial 候補」を user に提示する際の primary source - カテゴリ: real-app surface / observability / structural / meta / quality - archive trail (Recently picked-up) で最近の流れも確認可能 ### .github/PULL_REQUEST_TEMPLATE/ 5 つの type 別 template: - feat.md (新機能 / framework code 変更) - docs.md (docs-only) - trial-report.md (FT report 起票時、F-N 含む) - chore.md (maintenance / tooling) - followup.md (F-N follow-up small PR) GitHub web UI の dropdown でも選べるし、AI agent (私) が PR 本文を書く際の canonical 構造として使える。"Summary / Test plan / Closes #N" を毎回手書き していた負担を排除。 ### AGENTS.md / tools/README.md - AGENTS.md "Read First" に candidates.md / PR templates / tools/README.md の cross-link 追加 - tools/README.md の table に ft-report-new.sh を追加 ### Verification - tools/ft-report-new.sh 99 dryrun-test → 生成確認 → revert - tools/ft-report-new.sh で既存 FT17 ファイルへの上書きが exit 2 で refuse - composer ci 全 step green (test 142/142 + test:http 24/24 + Phan + format) Closes #427. (Issue 未作成、本 PR で兼ねる) Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/PULL_REQUEST_TEMPLATE/chore.md | 18 +++ .github/PULL_REQUEST_TEMPLATE/docs.md | 27 +++++ .github/PULL_REQUEST_TEMPLATE/feat.md | 28 +++++ .github/PULL_REQUEST_TEMPLATE/followup.md | 17 +++ .github/PULL_REQUEST_TEMPLATE/trial-report.md | 28 +++++ AGENTS.md | 3 + docs/field-trials/candidates.md | 111 ++++++++++++++++++ tools/README.md | 1 + tools/ft-report-new.sh | 88 ++++++++++++++ 9 files changed, 321 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/chore.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/docs.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/feat.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/followup.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/trial-report.md create mode 100644 docs/field-trials/candidates.md create mode 100755 tools/ft-report-new.sh diff --git a/.github/PULL_REQUEST_TEMPLATE/chore.md b/.github/PULL_REQUEST_TEMPLATE/chore.md new file mode 100644 index 0000000..8abaf85 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/chore.md @@ -0,0 +1,18 @@ +## Summary + + + +## Scope + + + +- +- +- + +## Test plan + +- [ ] `composer ci` green +- [ ] no behavior change for end users (or: precisely scoped change documented above) + +Closes #N. diff --git a/.github/PULL_REQUEST_TEMPLATE/docs.md b/.github/PULL_REQUEST_TEMPLATE/docs.md new file mode 100644 index 0000000..5ec4c8d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/docs.md @@ -0,0 +1,27 @@ +## Summary + + + +## Files touched + + + +### New + +- + +### Updated + +- + +### Cross-links + +- + +## Test plan + +- [ ] markdown lint pass +- [ ] new / updated cross-links resolve +- [ ] no framework code changes (docs-only) + +Closes #N. diff --git a/.github/PULL_REQUEST_TEMPLATE/feat.md b/.github/PULL_REQUEST_TEMPLATE/feat.md new file mode 100644 index 0000000..4c02a8a --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/feat.md @@ -0,0 +1,28 @@ +## Summary + + + +## Code + + + +- +- +- + +## Test plan + +- [ ] `composer test` +- [ ] `composer test:http` +- [ ] `composer analyze` +- [ ] `composer format:check` +- [ ] live verify: + + + +Closes #N. diff --git a/.github/PULL_REQUEST_TEMPLATE/followup.md b/.github/PULL_REQUEST_TEMPLATE/followup.md new file mode 100644 index 0000000..e2e2847 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/followup.md @@ -0,0 +1,17 @@ +## Summary + +Follow-up to **FT{N} F-{n}** (Issue #N). + + + +## Change + +- +- + +## Test plan + +- [ ] `composer ci` green +- [ ] live verify: + +Closes #N. diff --git a/.github/PULL_REQUEST_TEMPLATE/trial-report.md b/.github/PULL_REQUEST_TEMPLATE/trial-report.md new file mode 100644 index 0000000..4eb7be5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/trial-report.md @@ -0,0 +1,28 @@ +## Summary + +Field Trial **FT{N}** (Issue #N) — {topic}. + + + +## F-N findings + + + +- **F-1** ({severity}, {kind}): {summary} → {decision} +- **F-2** (...): +- **F-3** (...): + +## Aftermath plan + +- Feat PR: +- Docs PR: +- Follow-up issues: + +## Test plan + +- [ ] live verify on the trial clone: +- [ ] `composer ci` green +- [ ] (if entity trial) probe controller exercised +- [ ] (if ADR-class) ADR draft cross-linked + +Closes #N. diff --git a/AGENTS.md b/AGENTS.md index e2616aa..b10df7c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,6 +24,9 @@ This file is the first document for AI agents and automation working on NeNe. - Current TODO: `docs/todo/current.md` - ADR index: `docs/adr/README.md` - Field trial methodology: `docs/field-trials/README.md` +- Field trial candidates (durable backlog): `docs/field-trials/candidates.md` — read first when the maintainer asks "next trial を提案して" +- PR body templates: `.github/PULL_REQUEST_TEMPLATE/` (`feat.md` / `docs.md` / `trial-report.md` / `chore.md` / `followup.md`) — copy the matching shape when writing PR descriptions +- Developer tooling: `tools/README.md` (composer scripts, helper scripts, shared composer cache) - MCP bridge (external package): [nene-mcp](https://github.com/hideyukiMORI/nene-mcp) — NeNe integration at `docs/integration/nene.md` in that repo; not part of NeNe core ## Operating Rules diff --git a/docs/field-trials/candidates.md b/docs/field-trials/candidates.md new file mode 100644 index 0000000..1582031 --- /dev/null +++ b/docs/field-trials/candidates.md @@ -0,0 +1,111 @@ +# Field Trial Candidates + +Durable backlog of trial themes worth running, with notes on why each one matters and what's blocking it. Pair with `docs/field-trials/README.md` (methodology) and `docs/field-trials/follow-ups.md` (deferred findings). + +This file is for **forward-looking** ideas — once a trial fires, its record moves to a dated `docs/field-trials/YYYY-MM-field-trial-N.md` report and the candidate row gets struck through or removed. + +## How to use this file + +- **Maintainers**: scan this list when choosing the next trial. Pick whatever fits the current bandwidth + curiosity. +- **AI agents**: when the user asks "next trial を提案して", use this list as the primary source rather than re-deriving candidates from memory. Add new candidates here whenever a session surfaces one. +- **Trim regularly**: stale candidates (≥6 months old without being picked up, or rendered moot by other work) are removed by whichever session notices them. + +## Active candidates + +### Real-app surface (FT12 / FT13 / FT16 系譜) + +#### Multi-instance session backend (Redis / DB-backed) +**Why**: Stock NeNe uses PHP file sessions, which break under a load-balancer with multiple app instances. Listed as the third concern in `REPORT_commercial_feasibility.md`. ADR-class. +**Trigger**: A real-deploy report of a multi-instance setup → forces the issue. Or proactive: next time mailpit-pattern (FT13) is fresh in memory. +**Likely shape**: `Nene\Xion\SessionStorage` interface + `RedisStorage` / `FileStorage` impls + `NENE_SESSION_DSN` env + compose Redis service. Mailpit-pattern reuse. +**Size**: medium-large. + +#### Background jobs / async work +**Why**: Mail sending, file processing, periodic cleanup all block requests today. Real-app gap. Commercial feasibility report flagged. +**Trigger**: A real app surfaces "POST /foo takes 8 seconds because it sends 3 emails" friction. +**Open design questions**: symfony/messenger vs DB queue vs lightweight cron. ADR-class. +**Size**: large. + +#### Multi-tenancy +**Why**: `users` table is single-tenant. B2B SaaS deploys need row-scoped tenant isolation. +**Trigger**: Real deploy asks for it. **Don't pre-design** — overengineering risk is high without a concrete user. +**Size**: ADR + large. + +### Observability lane (FT15 系譜) + +#### structured-logs (JSON formatter swap) +**Why**: Monolog supports JSON formatter natively. Production log aggregators (Datadog / Loki / Elasticsearch) want JSON. Currently text-only. +**Trigger**: First real deploy that wants to ship logs to an aggregator. Or pre-emptively as a small trial. +**Likely shape**: `NENE_LOG_FORMAT=json` env swap, default text. No ADR needed — pure formatter selection. +**Size**: small (~half a session). + +#### Server-Timing header +**Why**: ADR-0007 listed it as a future cross-cutting use case. Per-request timing data for browser devtools / aggregators. +**Trigger**: Real performance debugging surfaces the need. +**Size**: small. + +#### OpenTelemetry traceparent / tracestate +**Why**: Industry-standard distributed tracing. Currently `X-Request-ID` (NeNe-flavored) only. +**Trigger**: Real deploy integrates an OTel collector. **Don't pre-implement** — OTel's spec is large and pre-deploy work usually overfits. +**Size**: ADR + medium. + +### Structural / governance (FT11 / FT14 系譜) + +#### CLI command framework +**Why**: `cli/setupDatabase.php` / `initSQLite.php` / `generateSchemaSql.php` / `schemaDiff.php` each reinvent `getopt`. A common `Nene\Xion\Command` base would normalize `--help` / `--yes` / error reporting. +**Trigger**: 5th CLI script is added (currently 4). Or before next major CLI surface (`cli/migration:up`?). +**Open design questions**: hand-rolled vs symfony/console. +**Size**: medium. + +#### PHP version policy ADR +**Why**: framework pins 8.4. PHP 8.5 ships late 2026 / early 2027. No documented stance on (a) auto-accepting minor releases, (b) major version migration cadence, (c) what triggers a deprecation policy. +**Trigger**: 8.5 ships, or earlier if a `composer require` warns about minimum-php. +**Size**: ADR-only, small. + +#### Smarty selection ADR +**Why**: ADR-0001 onwards never recorded why Smarty (vs Twig / Blade). Historical context will fade. +**Trigger**: A new contributor asks "なぜ Smarty?" or migration discussion starts. +**Size**: ADR-only, retrospective. Low urgency. + +#### Constraint-changes ADR (unique / FK additions) +**Why**: ADR-0009 explicitly left constraint changes in the "warning-only" path. If real deploys hit this pattern often, escalate to ADR. +**Trigger**: 3+ operator stories of "adding a UNIQUE constraint was painful". +**Size**: ADR + medium implementation. + +### Meta / evaluation (Phase 6 系譜) + +#### ai-agent-journey +**Why**: Phase 6 thesis self-verification. Bootstrap a fresh clone with a clean AI agent and have it build a small service end-to-end using only the docs. Surface what's still confusing. +**Trigger**: After a significant docs investment (now, after FT13-17 + journal added, would be a reasonable time). +**Size**: long (4-8 hours), unique findings. + +#### docs-journey-newcomer +**Why**: Similar to ai-agent-journey but human-centered. Trial with a developer who has never seen NeNe. +**Trigger**: A real candidate volunteer appears. Hard to invent the volunteer. +**Size**: medium, time-boxed by the volunteer's availability. + +### Quality / maintenance + +#### static-analysis-baseline cleanup +**Why**: Phan baseline has 6 entries (5 DataModelBase magic + 1 PdoConnection const). Small inventory trial to either close or document why each persists. +**Trigger**: Whenever a session wants a palate cleanser (1-2 hours). +**Size**: small. + +#### DataMapperBase test补強 (#407 deferred chunk) +**Why**: FT-407 deferred the PDO-dependent unit test work. Coverage on `DataMapperBase::execute()` / `decorate()` / KEY_SID rules is thin. +**Trigger**: Whenever before a planned `DataMapperBase` refactor. +**Size**: medium (needs PDO test double design). + +--- + +## Recently picked-up (archive trail) + +When a candidate becomes a trial, move it to this section briefly so we can see the recent flow. + +- **FT17 — schema-diff CLI** (2026-05-23): ADR-0009 implementation. Closed all 4 PRs same day. +- **FT16 — agent-bearer-auth** (2026-05-22): cross-repo handoff from nene-mcp #380. ADR-0008. +- **FT15 — request-id** (2026-05-22): ADR-0007 generality validation. Resulted in `RequestId` + Monolog processor. +- **FT14 — security-headers** (2026-05-22): ADR-0007. Closed FT7 F-6 / FT8 F-4 long-standing decoration trap. +- **FT13 — email-sending** (2026-05-22): ADR-0006. `Mailer` + `MailMessage` + mailpit dev catcher. + +Older trials live in their dated reports — this archive trail is recent-context only. diff --git a/tools/README.md b/tools/README.md index 3a02116..2aff80f 100644 --- a/tools/README.md +++ b/tools/README.md @@ -7,6 +7,7 @@ Single-purpose scripts that make NeNe's day-to-day workflow less typing-heavy. E | Command | What it does | When to use | | --- | --- | --- | | `tools/nene-ft-new.sh ` | Bootstrap a new field trial clone (next FT number auto-detected, port offset, `.env`, `.claude/settings.local.json`). | Starting a new FT. | +| `tools/ft-report-new.sh ` | Copy `docs/templates/field-trial-report.md` to `docs/field-trials/YYYY-MM-field-trial-N.md` with date / FT number / topic substituted. | When the trial reaches the report-writing step. Refuses to overwrite. | | `tools/wait-healthy.sh [port] [timeout]` | Block until `/health` returns 200, with a timeout. | After `docker compose up -d app`, before running curl probes. | | `tools/trial-status.sh ` | List every Issue + PR mentioning a trial number, open and closed. | Closing-out check: "is every spawned Issue closed?" | | `php tools/error-code-add.php CODE "Message" ["notes"]` | Insert a new error code into both `config/error_codes.php` and `docs/development/error-codes.md` atomically. | Adding an error code without the manual two-file dance. | diff --git a/tools/ft-report-new.sh b/tools/ft-report-new.sh new file mode 100755 index 0000000..3f5227e --- /dev/null +++ b/tools/ft-report-new.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# +# Bootstrap a Field Trial report file from the canonical template. +# +# Usage: +# tools/ft-report-new.sh +# +# Examples: +# tools/ft-report-new.sh 18 session-storage-backend +# tools/ft-report-new.sh 19 structured-logs +# +# What it does: +# 1. Copies `docs/templates/field-trial-report.md` to +# `docs/field-trials/YYYY-MM-field-trial-.md`. +# 2. Substitutes `{N}` → trial number and `{topic}` → topic name +# in the heading line. +# 3. Fills the `YYYY-MM-DD` placeholder under `## Date` with today's date. +# 4. Refuses to overwrite an existing file (so re-running on the same +# trial does not blow away in-progress notes). +# +# Why this exists: +# Every FT report uses the same skeleton, so writing each one from +# scratch wastes the first 5 minutes of the wrap-up step. +# +# Exit codes: +# 0 report created +# 1 CLI usage error +# 2 target file already exists / template missing + +set -euo pipefail + +if [[ $# -lt 2 ]]; then + echo "usage: tools/ft-report-new.sh " >&2 + echo " e.g. tools/ft-report-new.sh 18 session-storage-backend" >&2 + exit 1 +fi + +ft_num="$1" +topic="$2" + +if ! [[ "$ft_num" =~ ^[0-9]+$ ]]; then + echo "error: FT number must be numeric (got: $ft_num)" >&2 + exit 1 +fi +if ! [[ "$topic" =~ ^[a-z][a-z0-9-]*$ ]]; then + echo "error: topic must be kebab-case lowercase (got: $topic)" >&2 + exit 1 +fi + +framework_root="$(cd "$(dirname "$0")/.." && pwd)" +template="$framework_root/docs/templates/field-trial-report.md" +year_month="$(date +%Y-%m)" +today="$(date +%Y-%m-%d)" +target="$framework_root/docs/field-trials/${year_month}-field-trial-${ft_num}.md" + +if [[ ! -f "$template" ]]; then + echo "error: template not found at $template" >&2 + exit 2 +fi +if [[ -e "$target" ]]; then + echo "error: $target already exists — refusing to overwrite" >&2 + exit 2 +fi + +# Substitute placeholders: +# {N} → trial number +# {topic} → topic (keep the topic line literal until the author fills it) +# The `YYYY-MM-DD` literal under `## Date` → today's date (first occurrence only) +awk -v num="$ft_num" -v topic="$topic" -v today="$today" ' + BEGIN { date_replaced = 0 } + { + gsub(/\{N\}/, num) + gsub(/\{topic\}/, topic) + if (!date_replaced && $0 == "YYYY-MM-DD") { + print today + date_replaced = 1 + next + } + print + } +' "$template" > "$target" + +echo "✓ created $target" +echo +echo "Next:" +echo " - Fill in Baseline / Goal / Service Built / Steps Taken" +echo " - Replace remaining {placeholders} as the trial progresses" +echo " - Commit via: git checkout -b docs/-field-trial-${ft_num}-${topic}"