Skip to content
Merged
6 changes: 5 additions & 1 deletion .cursor/rules/hado-implementation-docs.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ alwaysApply: false
2. **ロードマップの「現状」**
- [docs/roadmap.md](docs/roadmap.md) の「このリポジトリの現状」が古くなっていたら、要約を直す(詳細は `implementation-status.md` に寄せてよい)。

3. **README / アーキテクチャ**
3. **`internal/manifest/types.go` の型を変えた場合**
- [`internal/manifest/field_docs.go`](internal/manifest/field_docs.go) に **YAML パスごとの説明**を追加・更新する(`TestManifestYAMLDocComplete` が不足・余剰キーで失敗する)。
- [`docs/hado.manifest.reference.yaml`](docs/hado.manifest.reference.yaml) を `make gen-manifest-doc` で再生成して同じ PR に含める。

4. **README / アーキテクチャ**
- 利用者向けの CLI 説明(ルート [README.md](README.md) や [docs/architecture.md](docs/architecture.md))が実装と矛盾していたら合わせる。

ゲートを `internal/gate/evaluate.go` に追加したら、**必ず** `implementation-status.md` の実装済みゲート一覧と、必要なら `roadmap.md` の Phase 3 記述を更新する。
15 changes: 9 additions & 6 deletions .cursor/skills/hado-doc-sync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,24 @@ description: >-
2. **`docs/implementation-status.md` を更新**
- 実装済みゲートの箇条書き(`internal/gate/evaluate.go` の `switch` と一致)
- coverage adapter 一覧(`internal/coverage/parse.go` の `Format*` 定数と一致)
- `hado evaluate` のフラグ・`--output` の取りうる値・終了コードの説明(`cmd/hado/main.go` と一致)
- `hado target` / `charge` / `fire` / `manifest doc` のフラグ・`--output` の取りうる値・終了コードの説明(`cmd/hado` と一致)
- MVP / 未実装として追いたい項目があれば表や箇条書きで維持(ロードマップの [docs/roadmap.md](docs/roadmap.md) と矛盾させない)

3. **`docs/roadmap.md`**
3. **`docs/hado.manifest.reference.yaml`**
- `internal/manifest/types.go` または `field_docs.go` を変えたら **`make gen-manifest-doc`** で再生成し、同じ変更セットに含める。

4. **`docs/roadmap.md`**
「このリポジトリの現状」の要約が古ければ 2〜3 文だけ直す。詳細は `implementation-status.md` に任せる。

4. **利用者向け**
ルート `README.md` の Evaluate 例やフラグ説明がずれていたら合わせる。
5. **利用者向け**
ルート `README.md` の CLI 例やフラグ説明がずれていたら合わせる。

5. **push / PR 前**
6. **push / PR 前**
`docs/` や `README.md` を触れたら `make lint`(少なくとも `make lint-markdown`)を通す。pre-push を使うなら `make setup-hooks`([docs/local-development.md](docs/local-development.md))。

## やらないこと

- `make docstatus` や Go 製ジェネレータは**ない**(手書き+この Skill
- `make docstatus` のような別コマンドは**ない**。Manifest の参考 YAML(コメント付き)は **`make gen-manifest-doc`**(`hado manifest doc`)で生成し、それ以外は手書き+この Skill。
- 実装と無関係な長いロードマップの書き換えは、ユーザーが求めた範囲に留める。

## 参照
Expand Down
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help setup setup-hooks bootstrap-go ensure-go build check-docker ci-lint lint lint-go lint-yaml lint-markdown fmt fmt-go fmt-check test readiness-check pre-pr
.PHONY: help setup setup-hooks bootstrap-go ensure-go build check-docker ci-lint lint lint-go lint-yaml lint-markdown fmt fmt-go fmt-check test readiness-check pre-pr gen-manifest-doc

# Optional local toolchain: official tarball under .gitignored .tools/go (see bootstrap-go).
# Prefer it when present so Make works without a global install; otherwise use `go` on PATH.
Expand Down Expand Up @@ -28,6 +28,7 @@ help:
@echo " make fmt # Format Go source files"
@echo " make fmt-check # Used in make ci-lint (does not run go test)"
@echo " make test # Run Go tests"
@echo " make gen-manifest-doc # Regenerate docs/hado.manifest.reference.yaml (commented reference manifest)"
@echo " make readiness-check # Generate HADO coverage evidence and run charge/fire"
@echo " make ci-lint # fmt-check + lint (GitHub Lint job + pre-push; no go test)"
@echo " make setup-hooks # pre-push runs: make ci-lint"
Expand Down Expand Up @@ -84,6 +85,11 @@ build: ensure-go
@mkdir -p bin
$(GO_CMD) build -o "$(BINARY)" ./cmd/hado

gen-manifest-doc: ensure-go
@mkdir -p bin
$(GO_CMD) run ./cmd/hado manifest doc --out docs/hado.manifest.reference.yaml
@echo "Wrote docs/hado.manifest.reference.yaml"

check-docker:
@command -v docker >/dev/null 2>&1 || { echo "docker is required for YAML/Markdown lint."; exit 1; }

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ HADO という名前は「波動砲」から来ています。波動砲は、日

- [Project HADO ドキュメント](docs/README.md)
- [実装状況(手保守; Cursor Skill `hado-doc-sync`)](docs/implementation-status.md)
- [HADO Manifest 参考(型から生成するコメント付き YAML)](docs/hado.manifest.reference.yaml)(`make gen-manifest-doc` で再生成)
- [ローカル開発コマンド](docs/local-development.md)

## Build and run
Expand Down
12 changes: 9 additions & 3 deletions cmd/hado/fire/observability_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,15 @@ gates:
manifestPath := writeFile(t, dir, "hado.yaml", `version: v1
evidence:
observability:
slo: slo.yaml
monitors: monitors.tf
dashboard: https://example.com/board/1
slos:
- name: slo
url: https://app.datadoghq.com/slo/manage?slo_id=x
monitors:
- name: mon
url: https://app.datadoghq.com/monitors/1
dashboards:
- name: dash
url: https://example.com/board/1
`)

var stdout, stderr bytes.Buffer
Expand Down
6 changes: 3 additions & 3 deletions cmd/hado/fire/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ func applyManifestEvidence(metrics *gate.Metrics, hadoManifest manifest.Manifest
metrics.OperationsRunbook = strings.TrimSpace(op.Runbook)
}
if obs := hadoManifest.Evidence.Observability; obs != nil {
metrics.ObservabilitySLO = strings.TrimSpace(obs.SLO)
metrics.ObservabilityMonitors = strings.TrimSpace(obs.Monitors)
metrics.ObservabilityDashboard = strings.TrimSpace(obs.Dashboard)
metrics.ObservabilitySLOPresent = manifest.ObservabilityLinksHaveURL(obs.SLOs)
metrics.ObservabilityMonitorsPresent = manifest.ObservabilityLinksHaveURL(obs.Monitors)
metrics.ObservabilityDashboardPresent = manifest.ObservabilityLinksHaveURL(obs.Dashboards)
}
if rel := hadoManifest.Evidence.Release; rel != nil {
metrics.ReleaseRollbackPlan = strings.TrimSpace(rel.RollbackPlan)
Expand Down
5 changes: 4 additions & 1 deletion cmd/hado/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

chargecmd "github.com/keyskey/hado/cmd/hado/charge"
firecmd "github.com/keyskey/hado/cmd/hado/fire"
manifestcmd "github.com/keyskey/hado/cmd/hado/manifestcmd"
targetcmd "github.com/keyskey/hado/cmd/hado/target"
)

Expand All @@ -22,7 +23,7 @@ func main() {

func run(args []string, stdout, stderr io.Writer) (int, error) {
if len(args) == 0 {
fmt.Fprintln(stdout, "hado: production readiness CLI")
fmt.Fprintln(stdout, "hado: production readiness CLI (try: charge, fire, target, manifest doc)")
return 0, nil
}

Expand All @@ -36,6 +37,8 @@ func run(args []string, stdout, stderr io.Writer) (int, error) {
return firecmd.Run(args[1:], stdout, stderr)
case "target":
return targetcmd.Run(args[1:], os.Stdin, stdout, stderr)
case "manifest":
return manifestcmd.Run(args[1:], stdout, stderr)
default:
return 2, fmt.Errorf("unknown command %q", args[0])
}
Expand Down
43 changes: 43 additions & 0 deletions cmd/hado/manifestcmd/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package manifestcmd

import (
"errors"
"flag"
"fmt"
"io"
"os"

"github.com/keyskey/hado/internal/manifest"
)

// Run handles "hado manifest doc" and related subcommands.
func Run(args []string, stdout, stderr io.Writer) (int, error) {
if len(args) == 0 {
return 2, errors.New("usage: hado manifest doc [--out path] # writes commented reference YAML")
}
if args[0] != "doc" {
return 2, fmt.Errorf("unknown manifest subcommand %q (try: doc)", args[0])
}
fs := flag.NewFlagSet("manifest doc", flag.ContinueOnError)
fs.SetOutput(stderr)
outPath := fs.String("out", "", "write reference YAML to this file (default: stdout)")
if err := fs.Parse(args[1:]); err != nil {
return 2, err
}

var w io.Writer = stdout
var f *os.File
if *outPath != "" {
var err error
f, err = os.Create(*outPath)
if err != nil {
return 2, err
}
defer f.Close()
w = f
}
if err := manifest.WriteManifestReferenceYAML(w); err != nil {
return 2, err
}
return 0, nil
}
12 changes: 8 additions & 4 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,22 @@ Project HADO は、サービスを本番環境へリリースする前に「本

コードとの対応を手で保守する。実装変更時は Cursor Rule `hado-implementation-docs` と Skill `hado-doc-sync` に従い更新する。

6. [Go C1 カバレッジ計測ツール](gobce.md)
6. [HADO Manifest 参考 YAML(コメント付き; `make gen-manifest-doc`)](hado.manifest.reference.yaml)

`internal/manifest` の型と `field_docs.go` から生成する。手編集しない。

7. [Go C1 カバレッジ計測ツール](gobce.md)

最初から別リポジトリとして開発する `gobce` の目的、スコープ、HADO 連携方針をまとめる。

7. [Infrastructure Readiness とマニフェスト設計](infrastructure-readiness-and-manifest-design.md)
8. [Infrastructure Readiness とマニフェスト設計](infrastructure-readiness-and-manifest-design.md)

本体を薄く保ちつつ、Readiness Standard を組織・サービスタイプ・実行基盤・Tier ごとに細かく定義できるようにし、HADO Manifest のスキーマを安定させるための設計指針(腐敗防止層、Standard の分割・合成、Manifest の形)をまとめる。

8. [未解決課題](open-design-decisions.md)
9. [未解決課題](open-design-decisions.md)

Open Design Decisions、未解決の命名・設計・実装方針をまとめる。

9. [ローカル開発コマンド](local-development.md)
10. [ローカル開発コマンド](local-development.md)

`Makefile` で提供している `lint` / `format` / `test` 系コマンドと事前準備をまとめる。
2 changes: 2 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ Report

`hado.yaml` は、評価対象サービスが自分自身と evidence の場所を宣言するファイルである。単なる設定ではなく、リリース準備状態の入口になる manifest として扱う。

**コメント付きの全プロパティ一覧:** [hado.manifest.reference.yaml](hado.manifest.reference.yaml) を `make gen-manifest-doc`(`hado manifest doc`)で再生成する。

**実装済みのトップレベル(v1):** `service`(`id` / `name`)と `standard`(`id`:Readiness Standard の論理 id または標準 YAML へのパス)は `hado target` が書き込める。`evidence` 以下の形はこのリポジトリの [実装状況](implementation-status.md) に従う。

```yaml
Expand Down
66 changes: 66 additions & 0 deletions docs/hado.manifest.reference.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# HADO manifest reference — GENERATED FILE; do not edit by hand.
# Regenerate: make gen-manifest-doc (or: go run ./cmd/hado manifest doc --out docs/hado.manifest.reference.yaml)
# Types: internal/manifest/types.go Descriptions: internal/manifest/field_docs.go

# Manifest スキーマの版。現行は `v1` を使う。 (論理型: string)
version: "v1"
# 評価対象サービスの識別子(ブロック全体は任意)。 (論理型: object)
service:
# サービス ID。未指定時は `target` で `service.name` と同じにできる。 (論理型: string)
id: ""
# サービス名。 (論理型: string)
name: ""
# 適用する Readiness Standard への参照(ブロック)。 (論理型: object)
standard:
# Standard のファイル名(例: `web-service.yaml`)またはパス。`standards-dir` / manifest 隣の `standards/` から解決される。 (論理型: string)
id: ""
# 本番準備の証跡宣言。ゲートごとに必要なブロックだけでよい(各サブブロックは多くが `omitempty`)。 (論理型: object)
evidence:
# カバレッジ成果物と adapter(ブロック)。C0/C1 ゲートがある standard で必要。 (論理型: object)
coverage:
# `CoverageInput` の配列。 (論理型: array of object)
inputs:
# パーサ名。`hado-json` / `go-coverprofile` / `gobce-json` など(実装は `internal/coverage`)。 (論理型: string)
- adapter: "hado-json"
# リポジトリまたは manifest 相対の成果物パス。 (論理型: string)
path: "coverage-metrics.json"
# 運用責任と障害対応の入口(ブロック)。 (論理型: object)
operations:
# オーナー(チーム名・Slack チャンネル等)。`operations.owner_exists` で非空判定。 (論理型: string)
owner: ""
# Runbook の URL またはパス。`operations.runbook_exists` で非空判定。 (論理型: string)
runbook: ""
# 観測可能性の証跡(ブロック)。SLO / モニター / ダッシュボードは **ベンダー UI 等で辿れる URL** のリストで宣言する(監査・運用オペ向け)。 (論理型: object)
observability:
# SLO / SLI への名前付きリンクの配列。`observability.slo_exists` はいずれか 1 件の `url`(trim 後非空)で PASS。 (論理型: array of object)
slos:
# 人間可読な表示名(任意)。 (論理型: string)
- name: ""
# ブラウザで開ける SLO の URL(例: Datadog SLO の管理画面)。 (論理型: string)
url: ""
# モニターへの名前付きリンクの配列。`observability.monitor_exists` はいずれか 1 件の `url` で PASS。 (論理型: array of object)
monitors:
# 人間可読な表示名(任意)。 (論理型: string)
- name: ""
# モニターの URL(例: Datadog monitor)。 (論理型: string)
url: ""
# ダッシュボードへの名前付きリンクの配列。`observability.dashboard_exists` はいずれか 1 件の `url` で PASS。 (論理型: array of object)
dashboards:
# 人間可読な表示名(任意)。 (論理型: string)
- name: ""
# ダッシュボードの URL。 (論理型: string)
url: ""
# インフラ関連の参照(ブロック)。 (論理型: object)
infra:
# デプロイ仕様の参照(パス・URL・カタログ ID)。`infra.deployment_spec_exists`。 (論理型: string)
deployment_spec: ""
# リリース・ロールバック(ブロック)。 (論理型: object)
release:
# ロールバック手順の参照。`release.rollback_plan_exists`。 (論理型: string)
rollback_plan: ""
# 自動リリースパイプライン(ブロック)。 (論理型: object)
automation:
# ワークフロー識別子のリスト(文字列の配列)。1 件以上非空で `release.automation_declared`。 (論理型: array of string)
workflow_refs: []
# 任意メタデータ(例: `github_actions`)。現行ゲートでは未使用。 (論理型: array of string)
systems: []
Loading
Loading