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
18 changes: 18 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/chore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Summary

<!-- 1-3 sentences: what this maintenance / tooling change does and why. -->

## Scope

<!-- What was touched, grouped by area. Keep additive / reversible. -->

-
-
-

## Test plan

- [ ] `composer ci` green
- [ ] no behavior change for end users (or: precisely scoped change documented above)

Closes #N.
27 changes: 27 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Summary

<!-- 1-3 sentences: what doc this adds / updates and what surface it covers. -->

## Files touched

<!-- Group by intent — new docs, updates, cross-link adds. -->

### New

-

### Updated

-

### Cross-links

-

## Test plan

- [ ] markdown lint pass
- [ ] new / updated cross-links resolve
- [ ] no framework code changes (docs-only)

Closes #N.
28 changes: 28 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/feat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## Summary

<!-- 1-3 sentences: what surface this adds and why. Mention the trial / ADR it traces to (e.g. "FT17 implementation per ADR-0009"). -->

## Code

<!-- New / modified files grouped by area. Keep it tight — code already lives in the diff. -->

-
-
-

## Test plan

- [ ] `composer test`
- [ ] `composer test:http`
- [ ] `composer analyze`
- [ ] `composer format:check`
- [ ] live verify: <!-- specific curl / interaction that exercises the new surface -->

<!-- For changes that affect docs/review/*.md surfaces, also open the relevant checklist:
- File uploads → docs/review/file-upload.md
- Security headers / response decoration → docs/review/security-headers.md
- Agent / MCP Bearer → docs/development/agent-bearer-auth.md
- Schema changes → docs/development/schema-migrations.md
-->

Closes #N.
17 changes: 17 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/followup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Summary

Follow-up to **FT{N} F-{n}** (Issue #N).

<!-- 1-2 sentences: which finding this closes and how. The trial report already explained the friction; here just record the fix. -->

## Change

-
-

## Test plan

- [ ] `composer ci` green
- [ ] live verify: <!-- the specific scenario that surfaced the finding now passes -->

Closes #N.
28 changes: 28 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/trial-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## Summary

Field Trial **FT{N}** (Issue #N) — {topic}.

<!-- 1-3 sentences: what the trial verified, what surfaced. Anchor to the trial's central question. -->

## F-N findings

<!-- One line per finding. Reference the report's F-N table. -->

- **F-1** ({severity}, {kind}): {summary} → {decision}
- **F-2** (...):
- **F-3** (...):

## Aftermath plan

- Feat PR: <!-- what gets ported to framework, 1 line -->
- Docs PR: <!-- new doc / ADR cross-links, 1 line -->
- Follow-up issues: <!-- list, or "none" -->

## Test plan

- [ ] live verify on the trial clone: <!-- the central acceptance scenario -->
- [ ] `composer ci` green
- [ ] (if entity trial) probe controller exercised
- [ ] (if ADR-class) ADR draft cross-linked

Closes #N.
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
111 changes: 111 additions & 0 deletions docs/field-trials/candidates.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <topic>` | 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 <FT-N> <topic>` | 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 <FT-N>` | 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" <http-status> ["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. |
Expand Down
88 changes: 88 additions & 0 deletions tools/ft-report-new.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
#
# Bootstrap a Field Trial report file from the canonical template.
#
# Usage:
# tools/ft-report-new.sh <FT-number> <topic-kebab>
#
# 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-<N>.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 <FT-number> <topic-kebab>" >&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/<issue>-field-trial-${ft_num}-${topic}"
Loading