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
62 changes: 59 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,62 @@

## Unreleased

- **The questionnaire asks the unread questions first.** The declaration
questionnaire promised an order — "by how much answering can move the
verdict" — and delivered the opposite of it. It ranked each question by the
effect the scan had *already inferred* for the action, and a pre-filled
proposal is offered on exactly the same condition, so the two mechanisms ran
off one signal: **every question that arrived with a draft answer outranked
every question that arrived blank.** On the fifth `adk-samples#1745` walk
that put three already-drafted mail tools at Q2–Q4 and the financial write —
the single question that produces both `critical` blockers once answered — at
Q6, behind three drafts a reader had to confirm first
([#419](https://github.com/ThreeMoonsLab/agents-shipgate/issues/419)).

*Rank by the ceiling, not by the floor.* Observed risk and "how much can
answering this move the verdict" are not the same quantity, and the header
claimed the second. An action nothing has bounded is not a low-risk action;
it is an unmeasured one, its answer can still turn out to be `destructive`,
and it is exactly where a human answer carries new information. A question
about an unbounded action now sorts above every bounded one, and the bounded
ones keep their old order among themselves — strongest first. On the same
walk the financial write moves from Q6 to Q3 and all three drafts move to the
end.

*Bounded is not the same test as draftable.* A reviewed declaration and
policy-eligible source evidence bound an action even when what they establish
is `read`, and the rule that decides whether to pre-fill a value cannot say
so: it refuses to draft `effect: read` from anything, because a confirmed
guess of `read` is the one direction that loses safety. Ranking on that rule
would send an OpenAPI `GET` named `delete_account` to the top of the file
with its name breaking the tie — the same defect inverted — so ordering asks
its own question. A heuristic reading of `read` still bounds nothing: this
resolver may not act on it, so the answer remains open.

*And a name breaks the tie among blanks.* Where nothing was observed there is
nothing to rank by, so the questionnaire falls back to the shape of the
action's name — mutating, neutral, retrieving — using the keyword vocabulary
the scanner already owns. This needs no trust and is given none: it is
consulted only among actions the scan measured nothing about, it cannot
reorder an action the scan did read, and it never reaches a claim, an issue,
or a verdict. Getting it wrong costs a reader one place in a list they have
to finish either way.

The header sentence now states the order the file actually uses — including
the heuristic-read case, where a block prints a reading and is still
unbounded — and a test renders the file and checks the two against each
other. A blank with no reading at all now says so at the block, since the
header explains that the top of the file is the unbounded half and silence
read as "nothing to see here".

*Published contract.* `report.json` /
`semantic_coverage.declaration_questions.open_questions[]` documented itself
as "highest-acting action first", which is no longer what it is. The model
docstring is emitted verbatim into the report, packet, and verifier schemas,
so it and `docs/agent-contract-current.md` now describe the ranking above and
say plainly that position is not severity: the action at the top is the one
*least* is known about. Field shapes are unchanged.

- **One action, one permission list, with no reviewed authority either.** A
manifest row that listed `scopes:` and declared no `authority:` block at
either site turned `verify --base` into `Internal error` (exit 4) on a legal
Expand Down Expand Up @@ -169,9 +225,9 @@
would let the scanner establish what only a human may (#357, #268).

*The file is numbered and counted.* Blocks carry `Question 3 of 5` banners
ordered by how much answering them can move the verdict — money, outward
communication, and destruction first, which is what reached a verdict in two
answers on the walk — and both the file header and the CLI print
ordered by how much answering them can move the verdict — two answers were
enough to reach one on the walk, and the entry above says which two the
order now leads with — and both the file header and the CLI print
`Declaration questions: 1 of 2 answered; 1 open (1 authority).` from one
rendering, so they cannot describe the same state two ways. An open question
with no blank to fill (a conflict whose repair is in the source) is still
Expand Down
2 changes: 1 addition & 1 deletion docs/agent-contract-current.md
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ In `agents-shipgate-reports/report.json`:
- `release_decision.{blockers,review_items}[].capability_refs` (v0.24+) — stable capability IDs copied from the originating finding when a policy or policy-pack rule matched a `CapabilityFactV1`. Empty for findings that are not capability-policy matches. This is audit metadata only; `release_decision.decision` remains the gate.
- `release_decision.{blockers,review_items}[].capability_trace_refs` (v0.25+) — stable local trace-evidence IDs copied from the originating finding when an existing trace/evidence check used declared local trace artifacts. Empty when no local trace row is relevant. This is audit metadata only; `release_decision.decision` remains the gate.
- `release_decision.evidence_coverage.semantic_coverage` (v0.29+) — `{total_actions, pass_eligible_actions, gap_count, review_concern_count, reason_counts}`. A non-zero semantic `gap_count` prevents `passed`; a non-zero `review_concern_count` prevents an automatic pass and routes known review concerns to human review — unscoped/ambient authority, and (v0.36+) `acknowledged_effect_override`, a declared effect a reviewer acknowledged as weaker than the evidence inferred for it. Read `reason_counts` for which; the count is of concerns, so one action can contribute more than one. Semantic gaps are not Findings and cannot be suppressed, baselined, severity-overridden, waived by `--no-heuristics`, or satisfied by `human_ack`.
- `release_decision.evidence_coverage.semantic_coverage.declaration_questions` (v0.37+) — the same action surface counted as a questionnaire: `{total, answered, open, open_by_dimension, open_questions[]}`. A *question* is one `(action, dimension)` a reviewed `action_surface.actions` row has to answer, and only `effect` and `authority` are counted — an action whose effect the scan established by itself (an OpenAPI method, an MCP annotation) was never asked and is not in `total`, and an inventory or `agent_bindings` declaration has no per-action counterfactual to score against. `answered` is exact rather than optimistic: it counts dimensions that gap when the same action is re-resolved *without* its declaration. `total == answered + open`, and `open_by_dimension` sums to `open`. `open_questions[]` is the answer order — highest-acting action first, `effect` before `authority` — and joins to `evidence_gaps[].subject_id`. Nothing here gates; it is a projection of counts the decision already made, published so a coding agent (and the generated questionnaire) can report progress instead of a gap tally.
- `release_decision.evidence_coverage.semantic_coverage.declaration_questions` (v0.37+) — the same action surface counted as a questionnaire: `{total, answered, open, open_by_dimension, open_questions[]}`. A *question* is one `(action, dimension)` a reviewed `action_surface.actions` row has to answer, and only `effect` and `authority` are counted — an action whose effect the scan established by itself (an OpenAPI method, an MCP annotation) was never asked and is not in `total`, and an inventory or `agent_bindings` declaration has no per-action counterfactual to score against. `answered` is exact rather than optimistic: it counts dimensions that gap when the same action is re-resolved *without* its declaration. `total == answered + open`, and `open_by_dimension` sums to `open`. `open_questions[]` is the answer order and joins to `evidence_gaps[].subject_id`. v0.38 ranks it by the ceiling of what an answer can establish: the actions nothing has bounded first — no effect evidence, a protocol default standing in for its absence, or only a heuristic reading the scan may not act on — then the actions a reviewed declaration or policy-eligible source evidence established, strongest-acting first, with `effect` before `authority` within one action. Position is not severity: the action at the top is the one *least* is known about. Nothing here gates; it is a projection of counts the decision already made, published so a coding agent (and the generated questionnaire) can report progress instead of a gap tally.
- `release_decision.evidence_coverage.policy_gap_count` and top-level `policy_evidence_gaps[]` (v0.33+) — policy applicability that is heuristic-only, mixed, unknown, or conflicting. These rows are outside Findings and cannot be suppressed, baselined, severity-overridden, acknowledged, or removed by `--no-heuristics`; any row prevents `passed`.
- `release_decision.evidence_coverage.identity_coverage` (v0.30+) — `{total_observations, canonical_tools, bound_tools, pass_eligible_tools, ambiguous_name_count, gap_count, reason_counts}`. Provider-scoped observations remain separate unless an exact reviewed `tool_identity.bindings[]` entry joins them. Any ambiguous selector, invalid binding, or conflicting identity prevents `passed`.
- `release_decision.evidence_coverage.evidence_gaps[]` (v0.26+; semantic kinds added v0.29) — one structured row per measurable gap: `{kind, subject, source_type, source_ref, why, next_action}`. In addition to `low_confidence_tool` and `source_warning`, v0.29 adds `incomplete_surface`, `missing_effect_evidence`, `inferred_effect_only`, `conflicting_effect_evidence`, `missing_authority_evidence`, `partial_authority_evidence`, `conflicting_authority_evidence`, and `invalid_semantic_annotation`. v0.36 adds `declaration_below_inferred_evidence`: the declared effect is weaker than evidence this scan inferred for the same action. The declaration still stands as the operative effect — heuristics never drive a verdict — but the action is not evidence-backed-pass until a reviewer raises the declared effect or adds `action_surface.actions[].override` with the `evidence` they checked and the `reason` it does not apply. An acknowledged override keeps the action pass-eligible and is reported as one semantic review concern, so the run can never read `passed`. Each acknowledgement is also emitted as a row in `release_decision.evidence_coverage.semantic_coverage.acknowledged_overrides[]` (v0.36+) naming the action, both readings, the hint source, any source evidence that agrees, and the reviewer's evidence and reason — the packet's §1 and the PR comment render it, because a count is not a review surface. The acknowledgement is consumed by policy applicability as well, so applying it reaches the review route rather than trading one gap for another. Semantic next actions use `declare_action_effect`, `declare_action_authority`, `declare_tool_inventory`, `provide_complete_inventory`, or `resolve_semantic_conflict`, include accepted values and exact source/manifest pointers, and are always human-routed. v0.37 adds `next_action.observed_readings[]` on effect rows — `{effect, sources[], observed}`, the distinct readings this scan's non-declaration evidence supports, so the row can be answered without opening `action_surface_facts`. Where those readings support one conservative answer, `next_action.declaration_template` carries it **pre-filled** instead of a `<REVIEW_REQUIRED>` blank. That value is a proposal, not an assertion: it is drawn from the closed `ActionEffect` vocabulary (never from source content), it is never weaker than any reading, and it is offered only where something was observed — a protocol default standing in for the absence of evidence, or a heuristic reading of `read`, keeps the blank. Their declaration placeholders carry `suggested_patch_kind="manual"`, `auto_apply=false`, and `requires_human_review=true`; they are not Patch objects, and a pre-filled template is still operative only once a human merges it into the manifest. v0.37 also re-routes `partial_authority_evidence`: it is raised when the *source's* authority evidence is ambiguous or incomplete, and the resolver preserves it whatever the manifest declares ("reviewed authority cannot replace ambiguous or incomplete source authority alternatives"). Its `next_action.kind` is therefore `provide_source` with no declaration template, rather than a `declare_action_authority` block that could not close the row it was printed on. It is excluded from `declaration_questions` for the same reason. Work the rows in order instead of guessing; Agents Shipgate never auto-asserts effect or authority.
Expand Down
Loading
Loading