reference 注释 E 码清零(authenticated 单词等级) #27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: conformance | |
| on: | |
| push: | |
| paths: | |
| - 'standard/**' | |
| - 'reference/**' | |
| - 'conformance/**' | |
| - 'schemas/**' | |
| - 'registry/**' | |
| - 'scripts/**' | |
| - 'verify_vectors.py' | |
| pull_request: | |
| jobs: | |
| # ─── 套件 1:spec conformance(向量 + registry + metric registry) ─── | |
| spec-conformance: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: AgentMeasure test vectors | |
| env: | |
| PYTHONPATH: reference | |
| run: | | |
| python3 verify_vectors.py | |
| - name: Metric contract vectors | |
| env: | |
| PYTHONPATH: reference | |
| run: | | |
| python3 conformance/runners/run_metrics.py | |
| - name: Registry validation (entities) | |
| run: | | |
| python3 registry/validate_entities.py | |
| - name: Metric registry validation (metrics.yaml ↔ METRICS.md) | |
| run: | | |
| python3 registry/validate_metrics.py | |
| # ─── 套件 2:reference implementation ─── | |
| reference-implementation: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Core integrity tests (0.4.2 data model) | |
| env: | |
| PYTHONPATH: reference | |
| run: | | |
| python3 - <<'PY' | |
| import sys, json, tempfile, pathlib, os, subprocess | |
| sys.path.insert(0, ".") | |
| from collector.correlator.correlator import connect, store_observation, match_invocations | |
| from collector.aggregator.aggregator import compute | |
| from collector.usage import empty_observation, new_observation_id | |
| # 100 次双边调用 -> share=1.0;无 operation 证据 -> unknown resolution | |
| tmp = pathlib.Path(tempfile.mkdtemp()) | |
| conn = connect(tmp / "collector.db") | |
| for n in range(100): | |
| for side, principal in (("client", "codex-hook@t"), ("server", "mcp-wrapper@t")): | |
| o = empty_observation(); o.update(dict( | |
| observation_id=new_observation_id(), | |
| observed_at=f"2026-08-16T00:{n//60:02d}:{n%60:02d}Z", | |
| observer_principal=principal, observer_side=side, | |
| provenance="hook" if side=="client" else "wrapper", | |
| project_id="github.com/foo/bar", tool="foo.search", | |
| tool_call_id=f"tc-{n}", session_key=f"sess-{n%10}" if side=="client" else None, | |
| outcome="success", lifecycle_stage="L2")) | |
| store_observation(conn, o) | |
| match_invocations(conn) | |
| s = compute(conn, "github.com/foo/bar") | |
| assert s["logical_invocations"] == 100, s # 0.3 回退(无 operation 证据) | |
| assert s["operation_resolution"]["unknown"] == 100, s | |
| assert s["operation_resolution_coverage"] == 0.0, s | |
| assert s["corroborated_share"] == 1.0, s | |
| print("core: 100 bilateral -> share 1.0, resolution unknown (fail-closed) OK") | |
| # 单侧 -> observed(最低显示等级) | |
| o = empty_observation(); o.update(dict( | |
| observation_id=new_observation_id(), observed_at="2026-08-16T03:00:00Z", | |
| observer_principal="codex-hook@t", observer_side="client", provenance="hook", | |
| project_id="github.com/foo/bar", tool="foo.only", tool_call_id="tc-s", | |
| session_key="sess-x", outcome="unknown", lifecycle_stage="L1")) | |
| store_observation(conn, o) | |
| match_invocations(conn) | |
| ev = conn.execute("SELECT evidence FROM invocations WHERE tool='foo.only'").fetchone() | |
| assert ev["evidence"] == "observed", ev["evidence"] | |
| print("core: single observation -> observed OK") | |
| # 显式 operation_id -> 3 attempts 归并为 1 operation | |
| conn2 = connect(pathlib.Path(tempfile.mkdtemp()) / "c.db") | |
| for i, outcome in enumerate(("failure", "failure", "success")): | |
| o = empty_observation(); o.update(dict( | |
| observation_id=new_observation_id(), | |
| observed_at=f"2026-08-16T03:00:0{i}Z", | |
| observer_principal="mcp-wrapper@t", observer_side="server", | |
| provenance="wrapper", project_id="github.com/foo/bar", | |
| tool="foo.search", tool_call_id=f"tc-op-{i}", outcome=outcome, | |
| lifecycle_stage="L2", operation_id="op-1", task_id="tk-1")) | |
| store_observation(conn2, o) | |
| match_invocations(conn2) | |
| s2 = compute(conn2, "github.com/foo/bar") | |
| assert s2["logical_invocations"] == 1, s2 | |
| assert s2["attempts"] == 3, s2 | |
| assert s2["operation_resolution"]["explicit"] == 3, s2 | |
| assert s2["operation_resolution_coverage"] == 1.0, s2 | |
| print("core: explicit operation -> 3 attempts / 1 operation, coverage 1.0 OK") | |
| PY | |
| - name: Choice end-to-end (M2.2 / M2.5) | |
| env: | |
| PYTHONPATH: reference | |
| run: | | |
| python3 - <<'PY' | |
| import sys, json, tempfile, pathlib | |
| sys.path.insert(0, ".") | |
| from collector.choice import connect, ingest_choice_events, selection_metrics, conditional_choice_share | |
| tmp = pathlib.Path(tempfile.mkdtemp()) | |
| conn = connect(tmp / "choice.db") | |
| events = [ | |
| {"type": "presented", "decision_id": f"d{i}", "candidate_set_id": "c1", | |
| "project_id": "github.com/foo/bar", "tool": "Exa", "choice_mode": "exclusive", | |
| "context": "production", "validity": "normal", "ts": "2026-08-16T00:00:00Z"} | |
| for i in range(10) | |
| ] + [ | |
| {"type": "selected", "decision_id": f"d{i}", "candidate_set_id": "c1", | |
| "project_id": "github.com/foo/bar", "tool": "Exa", "choice_mode": "exclusive", | |
| "decision_authority": "model", "selection_constraint": "autonomous", | |
| "context": "production", "validity": "normal", "ts": "2026-08-16T00:01:00Z"} | |
| for i in range(4) | |
| ] | |
| p = tmp / "events.jsonl" | |
| p.write_text("\n".join(json.dumps(e) for e in events)) | |
| ingest_choice_events(conn, p) | |
| sm = selection_metrics(conn, "github.com/foo/bar") | |
| assert sm["tools"][0]["observed_selection_rate"] == 0.4, sm | |
| cs = conditional_choice_share(conn, "Exa", "Tavily", project_id="github.com/foo/bar") | |
| assert cs["co_presented_decisions"] == 0, cs # Tavily 未同台 -> fail-closed 空分母 | |
| print("choice: M2.2=0.4, M2.5 fail-closed OK") | |
| PY | |
| - name: Adapter privacy tests | |
| run: | | |
| python3 - <<'PY' | |
| import sys, json, tempfile, pathlib, os, subprocess | |
| tmp = pathlib.Path(tempfile.mkdtemp()) | |
| env = dict(os.environ, AGENTMEASURE_EVENTS_DIR=str(tmp / "hook")) | |
| subprocess.run([sys.executable, "reference/adapters/codex/hook_agent.py"], input=json.dumps({ | |
| "hook_event_name": "PostToolUse", "tool_name": "Bash", "tool_use_id": "tu-1", | |
| "session_id": "RAW-SESSION-42", | |
| "tool_input": {"command": "cat /etc/shadow"}, | |
| "tool_response": "SUPER-SECRET", | |
| "trace_id": "ignored", "is_error": True}), capture_output=True, text=True, env=env) | |
| raw = (tmp / "hook" / "codex-hook-events.jsonl").read_text() | |
| assert "RAW-SESSION-42" not in raw and "SUPER-SECRET" not in raw and "shadow" not in raw | |
| assert "trace_id" not in raw and "is_error" not in raw | |
| assert "p-" in raw | |
| print("adapter privacy OK") | |
| PY | |
| # ─── 套件 3:documentation consistency(spec-drift) ─── | |
| documentation-consistency: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Spec-drift check (legacy vocabulary + version stamps) | |
| run: | | |
| python3 scripts/spec_drift.py |