Skip to content

spec: 证据账本判定层 schema v1(standards/evidence/,W1-B1 前半) - #429

Merged
randypanding merged 1 commit into
mainfrom
w1b1-evidence-schema
Aug 29, 2026
Merged

spec: 证据账本判定层 schema v1(standards/evidence/,W1-B1 前半)#429
randypanding merged 1 commit into
mainfrom
w1b1-evidence-schema

Conversation

@randypanding

Copy link
Copy Markdown
Contributor

Card: #406

变更(C1 路径,ADR-0103)

  • standards/evidence/record.schema.yaml:判定层记录 schema v1(cloudbird/evidence-standard/record@1
  • standards/evidence/README.md:三层纪律 + OTel gen_ai.* 映射表 + 写入/验证执法面说明

要点

  • 四类判定事件(BEH-01):kind: gate/cost/approval/decision
  • subject.tenant 必填(宪法 §14a 多租户计量分离,AC-3c)
  • payload 内联 ≤4096 字节:schema 文档化 + 写入器硬执法(archive 仓,后续 PR)
  • payload_ref 轨迹层指针占位(W1-B3 协议承接)
  • 链式 hash(prev_hash/hash,INV-03 append-only 平移 ADR-0062)

后续(本卡内下一 PR)

archive 仓 evidence/ 载体 + write_evidence.py/verify_evidence.py + 月度 checkpoint(AC-3a 负向实测、AC-3b 断链红)。

ADR: ADR-0103

四类判定事件(gate/cost/approval/decision)统一记录 schema:链式 hash、
tenant 必填、payload ≤4KB 硬执法、payload_ref 轨迹层指针(W1-B3)。
字段命名对齐 OTel gen_ai.* 语义约定(映射表见同目录 README.md)。

Card: #406
Copilot AI lite review requested due to automatic review settings August 29, 2026 06:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 3 minutes.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dc770384-3639-49bc-bdd6-74fdacc62c9e

📥 Commits

Reviewing files that changed from the base of the PR and between 739afd9 and faf9fcf.

📒 Files selected for processing (2)
  • standards/evidence/README.md
  • standards/evidence/record.schema.yaml

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

定义证据账本判定记录 Schema v1

✨ Enhancement 📝 Documentation 🕐 10-20 Minutes

Grey Divider

AI Description

• 定义 gate、cost、approval、decision 四类统一判定记录契约。
• 强制租户归属、链式哈希及可追溯的大载荷引用。
• 记录三层存储纪律、OTel 映射与写入验证职责。
Diagram

graph TD
  A["Decision Events"] --> B["OTel Mapping"] --> C["Record Schema"] --> D["Archive Writer"] --> E[("Evidence Ledger")] --> F["Independent Verifier"]
  E -.-> G[("Trace Blob")]
  E --> H["Read Consumers"]
Loading
High-Level Assessment

采用单一 JSON Schema 作为四类判定事件的共享信封最符合现有 YAML/JSON 标准体系,也便于三源双写、统一查询和后续独立验证。按事件拆分 Schema 或直接内联大型 payload 会增加版本协调与 Git 存储成本,因此当前的统一记录加 payload_ref 分层方案更合适。

Files changed (2) +172 / -0

Enhancement (1) +128 / -0
record.schema.yaml新增证据账本判定记录 Schema v1 +128/-0

新增证据账本判定记录 Schema v1

• 定义四类判定事件的统一记录结构,并要求卡片与租户归属、行为者信息及链式哈希字段。支持成本归账、输入摘要、受限内联 payload 和带保留策略的轨迹层引用。

standards/evidence/record.schema.yaml

Documentation (1) +44 / -0
README.md说明证据账本分层、语义映射与执法边界 +44/-0

说明证据账本分层、语义映射与执法边界

• 新增证据账本标准说明,定义判定层、轨迹层和丢弃层的存储纪律。记录 OTel gen_ai.* 字段映射、后续写入与验证职责,以及账本的只读消费场景。

standards/evidence/README.md

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Payload limit bypass via ref 🐞 Bug ≡ Correctness
Description
Because payload_ref does not reject unknown properties, a schema-valid record can place
arbitrarily large inline content in a field such as payload_ref.data, bypassing the stated rule
that Git stores only the pointer and that inline payload is capped at 4096 UTF-8 bytes. A writer
that enforces only the documented payload check will therefore admit the exact large trace data
this three-layer split is intended to keep out of Git.
Code

standards/evidence/record.schema.yaml[R103-106]

+  payload_ref:
+    type:
+      - "null"
+      - object
Relevance

●●● Strong

Recent schema review precedent favors closing unchecked payload structures when documented contracts
constrain their contents.

PR-#47

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The trajectory-layer contract says Git stores only payload_ref and zero payload body, while the
schema defines the nested object without additionalProperties: false; the root restriction at line
128 does not close nested objects.

standards/evidence/record.schema.yaml[103-118]
standards/evidence/record.schema.yaml[128-128]
standards/evidence/README.md[10-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`payload_ref` currently permits arbitrary extra properties, allowing large inline trace data to bypass the `payload` size guard and Git-storage discipline.

## Issue Context
JSON Schema's root `additionalProperties: false` does not apply recursively to nested objects.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[103-118]

Add `additionalProperties: false` to `payload_ref` and tests proving unknown/inline-content fields are rejected.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Malformed chain links validate 🐞 Bug ≡ Correctness
Description
prev_hash accepts any string and allows null at every sequence number, so records such as `seq:
2, prev_hash: null or prev_hash: x` pass the v1 schema despite not being valid SHA-256 chain
links. This allows malformed ledger records through contract validation before the later verifier
can detect them.
Code

standards/evidence/record.schema.yaml[R119-123]

+  prev_hash:
+    type:
+      - "null"
+      - string
+    description: "链前记录 hash(首条为 null;断链=红,fail-closed)"
Relevance

●●● Strong

The repository accepted enforcing chain-related governance conditions rather than leaving them in
descriptions; malformed hashes are deterministic.

PR-#47

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new schema constrains the current hash to 64 lowercase hexadecimal characters but leaves
prev_hash unconstrained and nullable, while both the README and governing spec define broken chain
links as fail-closed errors.

standards/evidence/record.schema.yaml[119-127]
standards/evidence/README.md[32-36]
specs/IR-0006/spec.md[120-127]
PR-#47

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`prev_hash` accepts malformed strings and permits null on non-first records, contrary to the documented chain invariant.

## Issue Context
The schema can enforce the local constraints even though equality with the preceding record remains verifier responsibility.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[119-127]
- standards/evidence/record.schema.yaml[17-18]

Require non-null values to match 64 lowercase hexadecimal characters, and add an `if`/`then` constraint making `prev_hash` null exactly when `seq` is 1.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Invalid timestamps pass schema 🐞 Bug ≡ Correctness
Description
The ts regex checks only digit placement, so impossible values such as 2026-99-99T99:99:99Z
validate even though the field is declared to be an ISO 8601 UTC timestamp. This undermines
chronological queries and the spec's planned timestamp property tests.
Code

standards/evidence/record.schema.yaml[R24-27]

+  ts:
+    type: string
+    pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$"
+    description: "ISO 8601 UTC(gen_ai 事件时间戳语义)"
Relevance

●●● Strong

Recent schema reviews accepted enforcing documented format constraints; invalid timestamp values are
a deterministic correctness gap.

PR-#47

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The pattern permits every two-digit month, day, hour, minute, and second. The governing test design
explicitly calls for evidence-record property tests covering ISO timestamps, and the existing agent
event schema demonstrates the repository's date-time convention.

standards/evidence/record.schema.yaml[24-27]
specs/IR-0006/spec.md[152-157]
standards/agent/event.schema.yaml[18-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The timestamp regex accepts impossible calendar and clock values.

## Issue Context
The schema declares draft 2020-12 and the repository's event schema already uses `format: date-time`; UTC-only semantics still need the `Z` restriction.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[24-27]

Use `format: date-time` with a validator configured to assert formats, retain an explicit UTC-only constraint, and add negative tests for invalid dates and times.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View high (2)
4. Provenance digest accepts garbage 🐞 Bug ≡ Correctness
Description
inputs_digest is only typed as a string, so values such as not-a-digest pass schema validation
despite the field being defined as a 64-character SHA-256 provenance anchor. Invalid provenance
identifiers can consequently enter the ledger and cannot be used to correlate or verify decision
inputs.
Code

standards/evidence/record.schema.yaml[R91-94]

+  inputs_digest:
+    type: string
+        # 校验执法在写入器(write_evidence.py):必须为 64 位十六进制 sha256
+    description: "判定输入摘要 sha256(provenance 锚点;witness 不可伪造性由链 hash 承担)"
Relevance

●●● Strong

PR #47 specifically established that documented mandatory schema conditions must be enforced,
matching the missing digest constraint.

PR-#47

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The property has no pattern or length constraint even though its comment explicitly requires 64
hexadecimal characters and the README defines it as the provenance SHA-256 anchor.

standards/evidence/record.schema.yaml[91-94]
standards/evidence/README.md[23-25]
PR-#47

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`inputs_digest` accepts arbitrary strings instead of the documented SHA-256 representation.

## Issue Context
The intended 64-character hexadecimal rule is already stated in the adjacent comment and can be expressed directly in JSON Schema.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[91-94]

Add the same `^[0-9a-f]{64}$` pattern used by the other SHA-256 fields and add positive/negative schema fixtures.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Hash bytes are undefined 🐞 Bug ☼ Reliability
Description
The schema says to hash “canonical JSON” but defines neither a canonicalization standard nor the
exact UTF-8 bytes, leaving property ordering, number rendering, Unicode escaping, and
omitted-versus-null handling ambiguous. Independent writers and verifiers can therefore derive
different hashes for the same logical record and falsely report a broken chain.
Code

standards/evidence/record.schema.yaml[R124-127]

+  hash:
+    type: string
+    pattern: "^[0-9a-f]{64}$"
+    description: "本记录内容 hash(sha256,canonical JSON 序列化后计算——不含自身字段)"
Relevance

●● Moderate

Hash interoperability ambiguity is plausible, but no close historical precedent establishes whether
this documentation-level concern is accepted.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
No repository document beyond this line defines “canonical JSON,” yet the README requires
independent hash recomputation and the governing spec requires full-chain recomputation from old
blobs.

standards/evidence/record.schema.yaml[124-127]
standards/evidence/README.md[30-38]
specs/IR-0006/spec.md[122-128]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The hash protocol does not define the exact byte representation to hash, so independent implementations need not produce the same digest.

## Issue Context
BEH-02 requires an independent verifier to recompute the chain from archived records.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[124-127]
- standards/evidence/README.md[30-38]

Normatively select a canonicalization algorithm such as RFC 8785, specify UTF-8 encoding and exclusion of only the top-level `hash` member, and provide golden record/byte/digest vectors.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

6. Retention policy can be omitted 🐞 Bug ☼ Reliability
Description
payload_ref.required omits retention, so a trajectory pointer without any retention policy
validates even though both the three-layer contract and INV-06 define the pointer as SHA-256 plus
location plus retention policy. Such records leave lifecycle enforcement unable to determine how
long referenced evidence must remain available.
Code

standards/evidence/record.schema.yaml[108]

+    required: [sha256, store]
Relevance

●●● Strong

Omitting a documented mandatory retention field matches PR #47’s accepted required-field and
conditional-constraint precedent.

PR-#47

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The schema requires only sha256 and store, whereas the README says the pointer consists of
sha256+store+retention and INV-06 requires Git to retain digest, pointer, and retention policy.

standards/evidence/record.schema.yaml[103-118]
standards/evidence/README.md[8-12]
specs/IR-0006/spec.md[120-127]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A non-null `payload_ref` can omit the required retention-policy declaration.

## Issue Context
The README and governing spec define retention as part of every trajectory-layer pointer.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[103-118]

Add `retention` to the nested `required` list and constrain it to the vocabulary that W1-B3 consumers will implement.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 22 rules
Review mode: ⚖️ Balanced

Grey Divider

Tip of the day
💡 Did you know, you can group findings by type and pick your Finding display, from Minimal to Full

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +103 to +106
payload_ref:
type:
- "null"
- object

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Payload limit bypass via ref 🐞 Bug ≡ Correctness

Because payload_ref does not reject unknown properties, a schema-valid record can place
arbitrarily large inline content in a field such as payload_ref.data, bypassing the stated rule
that Git stores only the pointer and that inline payload is capped at 4096 UTF-8 bytes. A writer
that enforces only the documented payload check will therefore admit the exact large trace data
this three-layer split is intended to keep out of Git.
Agent Prompt
## Issue description
`payload_ref` currently permits arbitrary extra properties, allowing large inline trace data to bypass the `payload` size guard and Git-storage discipline.

## Issue Context
JSON Schema's root `additionalProperties: false` does not apply recursively to nested objects.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[103-118]

Add `additionalProperties: false` to `payload_ref` and tests proving unknown/inline-content fields are rejected.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +119 to +123
prev_hash:
type:
- "null"
- string
description: "链前记录 hash(首条为 null;断链=红,fail-closed)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Malformed chain links validate 🐞 Bug ≡ Correctness

prev_hash accepts any string and allows null at every sequence number, so records such as `seq:
2, prev_hash: null or prev_hash: x` pass the v1 schema despite not being valid SHA-256 chain
links. This allows malformed ledger records through contract validation before the later verifier
can detect them.
Agent Prompt
## Issue description
`prev_hash` accepts malformed strings and permits null on non-first records, contrary to the documented chain invariant.

## Issue Context
The schema can enforce the local constraints even though equality with the preceding record remains verifier responsibility.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[119-127]
- standards/evidence/record.schema.yaml[17-18]

Require non-null values to match 64 lowercase hexadecimal characters, and add an `if`/`then` constraint making `prev_hash` null exactly when `seq` is 1.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +24 to +27
ts:
type: string
pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$"
description: "ISO 8601 UTC(gen_ai 事件时间戳语义)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Invalid timestamps pass schema 🐞 Bug ≡ Correctness

The ts regex checks only digit placement, so impossible values such as 2026-99-99T99:99:99Z
validate even though the field is declared to be an ISO 8601 UTC timestamp. This undermines
chronological queries and the spec's planned timestamp property tests.
Agent Prompt
## Issue description
The timestamp regex accepts impossible calendar and clock values.

## Issue Context
The schema declares draft 2020-12 and the repository's event schema already uses `format: date-time`; UTC-only semantics still need the `Z` restriction.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[24-27]

Use `format: date-time` with a validator configured to assert formats, retain an explicit UTC-only constraint, and add negative tests for invalid dates and times.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +91 to +94
inputs_digest:
type: string
# 校验执法在写入器(write_evidence.py):必须为 64 位十六进制 sha256
description: "判定输入摘要 sha256(provenance 锚点;witness 不可伪造性由链 hash 承担)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Provenance digest accepts garbage 🐞 Bug ≡ Correctness

inputs_digest is only typed as a string, so values such as not-a-digest pass schema validation
despite the field being defined as a 64-character SHA-256 provenance anchor. Invalid provenance
identifiers can consequently enter the ledger and cannot be used to correlate or verify decision
inputs.
Agent Prompt
## Issue description
`inputs_digest` accepts arbitrary strings instead of the documented SHA-256 representation.

## Issue Context
The intended 64-character hexadecimal rule is already stated in the adjacent comment and can be expressed directly in JSON Schema.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[91-94]

Add the same `^[0-9a-f]{64}$` pattern used by the other SHA-256 fields and add positive/negative schema fixtures.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

- "null"
- object
description: "轨迹层指针(W1-B3 协议):blob sha256+保留策略字段;git 侧零 payload 本体"
required: [sha256, store]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

5. Retention policy can be omitted 🐞 Bug ☼ Reliability

payload_ref.required omits retention, so a trajectory pointer without any retention policy
validates even though both the three-layer contract and INV-06 define the pointer as SHA-256 plus
location plus retention policy. Such records leave lifecycle enforcement unable to determine how
long referenced evidence must remain available.
Agent Prompt
## Issue description
A non-null `payload_ref` can omit the required retention-policy declaration.

## Issue Context
The README and governing spec define retention as part of every trajectory-layer pointer.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[103-118]

Add `retention` to the nested `required` list and constrain it to the vocabulary that W1-B3 consumers will implement.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +124 to +127
hash:
type: string
pattern: "^[0-9a-f]{64}$"
description: "本记录内容 hash(sha256,canonical JSON 序列化后计算——不含自身字段)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

6. Hash bytes are undefined 🐞 Bug ☼ Reliability

The schema says to hash “canonical JSON” but defines neither a canonicalization standard nor the
exact UTF-8 bytes, leaving property ordering, number rendering, Unicode escaping, and
omitted-versus-null handling ambiguous. Independent writers and verifiers can therefore derive
different hashes for the same logical record and falsely report a broken chain.
Agent Prompt
## Issue description
The hash protocol does not define the exact byte representation to hash, so independent implementations need not produce the same digest.

## Issue Context
BEH-02 requires an independent verifier to recompute the chain from archived records.

## Fix Focus Areas
- standards/evidence/record.schema.yaml[124-127]
- standards/evidence/README.md[30-38]

Normatively select a canonicalization algorithm such as RFC 8785, specify UTF-8 encoding and exclusion of only the top-level `hash` member, and provide golden record/byte/digest vectors.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@randypanding
randypanding merged commit c07e298 into main Aug 29, 2026
15 checks passed
@randypanding
randypanding deleted the w1b1-evidence-schema branch August 29, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants