# Provider Readiness Contract

`provider-readiness.v2` describes mechanical provider readiness and setup-owned runtime tooling metadata. It is an advisory setup fact, not workflow truth and not confirmed context.

Canonical fields are defined by `docs/contracts/provider-readiness.schema.json`:

- `readiness_status`: `fresh` / `stale` / `degraded` / `not-run` / `unknown`.
- `lifecycle`: independent boolean lifecycle flags.
- `repo_aligned`, `capabilities`, `limitations`, `source_read_required`, `fallback`, `next_actions`.
- `native_interfaces`, `first_generation`, `steady_state`, `usage_note`: provider-native interface and lifecycle ownership facts used as the canonical machine surface for Runtime Setup consumers. `steady_state` may also carry project-local hook readiness facts (`hook_installed`, `hook_verified`, `hook_status`, `hook_skipped_reason`) for optional refresh setup such as Graphify hooks. `hook_status=blocked` 表示有效 hook target 不属于当前项目授权域或未通过路径安全检查；它不是 Provider 核心 readiness 的别名。

Do not write semantic trust fields such as `advisory`, `evidence_candidate`, or `confirmed_context` into this contract. Workflows may promote provider output only after direct source/test/log/contract/user evidence.

## Producer And Consumer Rules

- `readiness_status` is the only provider readiness field that enters setup decision health. Lifecycle 与 `steady_state` 字段是 display/passthrough facts，用于解释核心能力与自动刷新边界；它们不单独决定 workflow health。现有 `provider-readiness.v2` schema version 与字段集保持不变，`hook_status=blocked` 是 producer/consumer 已需表达状态的枚举兼容修正。
- `lifecycle.configured` must describe durable current-host runtime artifacts, not process-local helper success. Python Graphify uses an explicit host matrix: Claude requires its project skill、nested/root instruction和settings entry；Codex requires `.codex/skills/graphify/`、`AGENTS.md` section和`.codex/hooks.json`；Cursor is rule-only at `.cursor/rules/graphify.mdc`；Kiro requires skill plus steering；Qoder is `spec-first-adapter` and must not be reported as Provider-native. Claude/Codex executable entries must reference the verified absolute Python launcher with only the expected `hook-check` subcommand.
- Provider self-reported `fresh` is not trusted as deterministic freshness. Producers must map it to `unknown` unless spec-first has direct source/test/log/probe evidence.
- Provider self-reported `stale` may map to `stale`: it is conservative, keeps the existing stale warning path alive, and still requires fallback/source confirmation.
- `repo_aligned` and `limitations` explain advisory context, but they are not the decision-path substitute for stale readiness.
- Setup-side `lifecycle.fallback_used` is not the same thing as a workflow using fallback. Consumption-side fallback is recorded with `provider_untrusted` or the workflow handoff, and ordinary plan/work/review/debug must remain able to proceed from direct evidence.
- `first_generation` and `steady_state` explain ownership boundaries: Runtime Setup may install/configure/perform explicit first generation and enable bounded project-local provider refresh setup such as CodeGraph Auto-Sync via `codegraph serve --mcp` or Graphify `graphify hook install`, while provider-native tools own steady-state refresh/use. These fields do not authorize downstream workflows to run provider generation or infer confirmed evidence. For Python Graphify, hook mutation authority only covers the effective Git hooks root after Git-native resolution and project containment. `hook_status=verified` means both post-commit/post-checkout marker blocks、verified interpreter、credential isolation block和允许的rebuild command均通过结构检查，并且没有遗留的`GRAPHIFY_OUT=.graphify`覆盖；`graphify hook status` 单独退出0不够。有效 hooks root 位于项目外时，Runtime Setup 只读 `post-commit`/`post-checkout` 两个普通文件，检测 Graphify managed marker 与 `GRAPHIFY_OUT=.graphify` legacy override；绝不 execute、`graphify hook status`、write、normalize，也不修改 `core.hooksPath` 或读取其他文件。只有 `post-commit` marker 存在且两个文件均无 legacy override 时才报告 `hook_status=verified-external` + `refresh_mode=commit-hook-external-verified`；post-checkout-only 或 marker 缺失报告 `blocked + manual-only`，legacy override 报告 `graphify-external-hook-legacy-artifact-override + manual-only`。这是对早期「不读外部 hook 内容」的受控放宽：从「不读」改为「限定文件只读验证、绝不写」。`hook_status=verified-external` 只表示 spec-first 只读确认外部 commit hook 存在，**不**等同 project-owned `verified`（interpreter/结构未验证），`hook_installed`/`hook_verified` 保持 false，external hook execution 仍标 unverified。
- Graphify project-local auto-refresh is an optional steady-state enhancement. Package identity、current-host integration、artifact integrity 与真实 query probe 是核心 readiness；hook blocked/failed/skipped 不得单独把这些成功事实改写为 Provider `degraded`。Apply/refresh 当轮有生成与 query 证据时可报告 `fresh`；普通 setup 对已有图只做 integrity/query probe 时与只读 verify 一样，没有当轮 currentness 证据，因此报告 `unknown`。Core-ready `unknown` 不触发自动 refresh，也不得被解释为 query 未验证。两种状态都继续要求 downstream 把 graph candidate 作为 advisory navigation，并通过 direct source evidence 确认结论。
- `blocked + manual-only`（external post-commit marker 缺失、post-checkout-only 或 legacy override）与 `verified-external + commit-hook-external-verified`（external post-commit marker 命中且无 legacy override）都只描述 spec-first 可只读验证的 external commit-time posture，不是 project-owned `verified`。Runtime Setup 只读 external hooks root 的 `post-commit`/`post-checkout`，绝不 write/execute/status；marker 缺失时不得据此声称外部 hook 不存在或不会执行，legacy override 命中时只能确认该文件仍可能把输出写回 `.graphify/`，必须阻止 verified claim 并交由外部 owner 修复。所有 external 状态的 human output 都必须把 execution 标为 unverified。外部 Graphify hook 若由历史操作或其他工具安装，仍可能被 Git 执行，但不进入当前项目 owned/verified readiness。
- Python Graphify first generation固定使用 `extract --code-only`。因此 `completed` 只确认本地 AST code graph；docs/images/papers semantic graph未生成，必须通过 limitation 明示，不能称为完整语义图。已有图的显式 refresh 使用官方 `graphify update <workspace>` 原位更新代码索引，并复用 Provider 的 lock、临时 graph、shrink guard 和未变节点保留语义；spec-first 不创建顶层 staging/backup。Provider 对 semantic/curated artifact 的自有保护策略仍属于 Provider 行为，不提升为 Runtime Setup 回滚合同。
- Provider installation detection may use uv/pipx standard bin paths such as `~/.local/bin/graphify` in addition to current `PATH`. Readiness must verify `graphifyy` distribution identity、pin、CLI version、absolute launcher和interpreter。若原始PATH被npm incumbent shadow但selected launcher/identity/artifact/query/hook均verified，状态可为`fresh`并携带shadowing limitation；setup不得自动删除或重指向该命令。
- Graphify第三方进程必须以`inheritEnv=false`消费显式allowlist；redaction只保护diagnostic，不能替代凭据不进入子进程。Windows `.exe` launcher的identity authority必须来自uv/pipx tool environment，不得回退到系统Python。
- Graphify mutation setup检测到npm incumbent时，只有Python package/artifact/query/current-host integration与双Git hook全部verified后才可默认cleanup。Cleanup必须先验证全局package identity、npm root和launcher realpath ownership，再卸载`@sentropic/graphify`；旧`~/.local/bin/graphify*`仅在仍为symlink、target未变化且原realpath属于该npm package时删除。Diagnostic、plan、verify-only、未知command、普通文件或其他symlink不得触发该副作用。
- Graphify Provider只接受`ecosystem=pypi`；其他dependency输入以`graphify-python-provider-required` fail closed。失败恢复使用pinned wheel重装、contained artifact backup恢复与Python readiness复验。
- `lifecycle.artifact_exists=true` is not enough to imply runtime usability. A project may have Provider-native `graphify-out/graph.json` while `lifecycle.configured=false` or while the CLI is not manually visible; consumers must keep using direct source evidence and surface the setup repair action instead of treating the graph artifact as a complete install. Current `graphify-out` 若已存在但不是非 symlink 真实目录，Runtime Setup 必须以 `graphify-artifact-root-unsafe` 在 host/runtime mutation 前 fail closed。Legacy `.graphify/graph.json` is migration-only evidence; Runtime Setup atomically renames it when it is the sole root and fails closed when both roots exist.
