docs: add proposed server-side policy evaluation tutorial - #338
docs: add proposed server-side policy evaluation tutorial#338pbeckham wants to merge 40 commits into
Conversation
|
Claude finished @pbeckham's task in 4m 18s —— View job Review:
|
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
The flag names the schema of the data passed to the policy as `input`, so `--input-schema` says what it does. It also stops the publish and evaluate commands sharing a word for two unrelated things: policies are now published with `--input-schema` and evaluated with `--context`, which reviewers had read as one overloaded flag. Renames the flag on `kosli create policy` and `kosli validate policy`, and the concept in prose from "input-context schema" to "input schema". No behavior change: the accepted values are still `trail` and `trails`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Drop the restatement of the async default. It was stated three times within 65 lines: the intro to the command, a paragraph below the flag table, and the --sync row of the flag table itself. The paragraph now only carries what was unique to it — --assert as the pipeline gate, and the pointer to the decisions section. - Replace "here" with "in the example below" where it pointed forward at an example rather than at nearby text, which reviewers read as referring to the paragraph they were in. - Trim the meta description from 163 to 130 characters, under the 160 search engines will show. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A policy cannot open the files attached to an attestation, which left readers asking how a SARIF file or SBOM gets evaluated at all. Documents the pattern: summarize the attachment into JSON at attestation time and pass it as --user-data, which is in the policy input, while keeping the file itself on the same attestation with --attachments. The summary is what the policy reads; the attachment is what makes the summary checkable, since an auditor can confirm it against the file it came from. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
f6a47e4 to
5b300d7
Compare
Thoughts
AI generation tells
|
Review flagged several phrases as reading like generated marketing copy rather than documentation. Each is replaced with the underlying fact. - "records the decision itself — one it can vouch for" states the claim instead of the mechanism; say what is recorded alongside the decision. Same for the comparison table's "a decision Kosli computed and can vouch for". - "The whole loop in two commands" / "That is the feature:" sells rather than informs. - "worth reading before you send feedback, so you don't spend it on something already deferred" — the Feedback section already covers this. - "Note that --context is doing real work here:" editorialises about the sentence that follows it. - "core loop" was a drafting label that meant nothing to readers; three uses replaced with what the section actually covers. - "changes what a decision means" asserted significance without saying what changed. It is who computed the decision. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
--context defaulted to the trail named by --flow / --trail. Review pointed out that the note defending the default was describing a footgun rather than removing one: with the default in place, a command that reads and writes different trails looks almost identical to one that does not. Makes --context required, the same decision already taken for --trail and for the same reason — this command does not infer trails. Every example on the page already passed it explicitly, so no example changes. This also removes the warning that existed only to manage the hazard the default created; three lines of plain description replace it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The --context cell was a ~700 character paragraph inside a table, which does not read on narrow viewports. The cell now states what the flag is and that it is required; the reference-type syntax, repeat semantics, and room for future context types move to prose under the table. Also drops a "by default the decision is recorded on the same trail whose facts you evaluate" left over from when --context had a default. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"Result" names what an evaluation produces better than "output", and pairs with the input schema: input schema in, result schema out. Renames the seven uses that mean the policy's return value, including the "Output" section heading and "output schema" in the validation list. The four that mean something else are unchanged: the --output flag on kosli list decisions and kosli get evaluation-context, OPA's print/trace output, and the draft banner's "commands, flags, and output shown". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A policy can be published as a bundle of several Rego files, but two places still assumed a single file. "Re-run a decision offline" exported the policy as one policy.rego and replayed it with --data, which cannot round-trip a multi-file bundle. The export is now a policy/ directory laid out as published, replayed with --bundle so the same command works for one file or many. Says that the layout is preserved so the digest on the decision can be verified, not just the outcome re-run. The "composable policies" scope bullet read as a description of a bundle, which is what prompted the question. It now names the distinction: composing separately published policies is out of scope, one policy spanning several files is not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The publish step offered a directory of Rego files, but every other mention of --policy said "file" only — so a reader who took up that offer had no documented way to validate or ad-hoc-evaluate what they wrote. --policy now consistently takes a single .rego file or a directory holding one policy's bundle, on create, validate and evaluate. States that a directory is one policy's bundle, not a collection of separate policies, which "a directory of them" left ambiguous. Renames "Evaluate a local policy file" to "Evaluate a local policy" since it is no longer file-only, and updates the one link to it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The validation list was written for a single file, leaving it unclear whether a multi-file bundle is checked as one unit. States that it is, without specifying the mechanism, and that publishing runs the same checks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two terms a bundle author needs that the page left implicit. Tests: the page states twice that tests are stored but never executed, which depends on Kosli telling a test file from a policy file. Names the convention (*_test.rego) so a misnamed file does not silently become evaluated policy. Roots: previously appeared only inside the policy-tab screenshot alt text, never defined. Glossed where the tab's contents are described. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two {/* TODO */} comments did not render, so the open questions they held
were visible only in source. The surrounding prose reads complete without
them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follows the earlier pass on flagged phrasing with a sweep for the same patterns elsewhere. Each cut removes a verdict about a fact, not the fact. - "the strongest form of the audit story, because it doesn't ask anyone to trust Kosli to check Kosli" — the sentence after it states the point. - "nobody has to trust that version 3 is still what version 3 was" — the preceding clause already says a digest proves the bytes. - "a summary with no attachment behind it is just another self-reported number" — a closer, after the reason was already given. - "what makes a server-side decision worth more than a self-reported one" — keeps who can do what, drops the judgement. - "This is what makes publishing safe to run" — leads with the fact: publishing is idempotent. - The control owner's question was framed twice, ~80 lines apart, in the same construction. Keeps the one in the review workflow, where it is actionable. - Drops the trade-booking analogy from the two-timestamp explanation, and a filler "Note that". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Evaluation is asynchronous by default, but the page never showed what the default returns and gave no way to observe it — every example passed --sync or --assert. Review asked what the behaviour is without --sync and how a customer checks status. The evaluation context answers both, since it exists from the moment an evaluation is queued and already holds the requested and recorded times. - Shows what the asynchronous command returns: the context that will carry the outcome. - Adds "Check an asynchronous evaluation": kosli get evaluation-context reports STATUS (queued, completed, failed) and names the decision it produced. Also documents --show-input for returning the policy input that was evaluated, matching the flag of the same name on the client-side evaluate commands so jq '.input' and kosli evaluate input keep working. - States that a typed error lands on the context, so a broken policy is distinguishable from a non-compliant artifact without --sync. Corrects the fixture export from --output fixture to --fixture. In the CLI, --output selects a format ([table, json, markdown]) and never content, so overloading it here contradicted every other kosli get. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review read "Be deliberate about which flows may satisfy a production control." as alarmist for a design preview of a feature nobody can use yet. The sentence added a directive tone without adding information — the rest of the callout already states the gap and what to do about it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review asked for the request timestamp to be stated explicitly as the query time for trail data, and for a worked example to make the model concrete. States the mechanism: Kosli fixes the trail moment (which attestations are in scope) at the requested/enqueue time, then queries and serializes that data only when the evaluation executes — always as of the fixed timestamp, not as of whatever the trail contains by then. This is what makes a queued evaluation deterministic regardless of queue delay, and is why no drift-detection or invalidation mechanism is needed for a fact that lands mid-queue: the query never looks at "now," only at the timestamp fixed at enqueue. Replaces the abstract "facts arrive mid-flight" paragraph with a worked example using the same evaluation context (ec_7f3a91c2) and timestamps already introduced in "Check an asynchronous evaluation", so the same example carries through both sections instead of introducing new arbitrary numbers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review pointed out that recommending --user-data for a summarized attachment may depend on attestation type — it's probably part of the main attestation_data for a custom attestation type schema. Checked against the CLI reference: --attestation-data exists only on kosli attest custom, documented as the custom attestation data validated against the type's schema. --user-data is documented as "additional data" on every attestation command, never the schema-validated payload. So the earlier guidance to always use --user-data was incomplete: for a custom attestation type you define, --attestation-data is the schema- validated field and the better fit for a recurring summary shape (finding counts, severities, package IDs). --user-data remains correct for built-in types (generic, snyk, sonar, and others) that have no schema field for the summary. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review asked what --dry-run's "evaluate without recording" actually adds once every other way to test a policy is accounted for: - Rego correctness and schema checks: kosli validate policy — no trail data touched, nothing recorded. - Behavioral correctness: Rego unit tests / opa test, including regression fixtures already exported from past decisions. - Behavior against real trail data: "Evaluate a local policy" already covers this. It records a decision, but the page already says to treat that as expected — the Warning right below it states these decisions cite an unpublished source, should be treated as iterating rather than audit evidence, and that the beta is soliciting feedback on marking or restricting them. Once that one real evaluation exists, its exported fixture can be re-run locally with opa eval against any number of different candidate policies, for free, with nothing further recorded. --dry-run also collided with the CLI-wide convention (--dry-run means "no data sent, exits 0 regardless of errors" everywhere else), which this turn's discussion had been trying to fix by renaming. Removing the overlapping capability is simpler than renaming it. Drops the --dry-run flag-table row, the "Run an ad-hoc evaluation" section, and the dangling --dry-run mention at the end of "Evaluate a local policy". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
What
Documentation-driven development for the server-side Kosli Evaluate project (kosli-dev/server#6267). Adds a tutorial describing the proposed V1
kosli evaluate policyflow, published so it can be shared internally and with design-partner customers for feedback before the feature is built.This is a design preview — nothing in it is runnable today. The page is marked as such throughout.
Scope (this draft)
Core happy path for a governance platform engineer:
allowmandatory).kosli evaluate policyruns server-side and records a decision against a control; synchronous.attestation_ids, policy version, params, timestamp; includes the T / T+1 / T+2 temporal-correctness case.An explicit out-of-scope-for-V1 section keeps reviewer feedback on target (managing policies, testing/validation, reporting/audit views, unhappy-path inspection, composable policies, non-trail targets, scheduled evals, risk measurement).
Design notes surfaced for feedback
kosli attest decisionandkosli evaluate trailflags.--compliantand evidence (--attachments/--user-data) are intentionally not flags — the server derives compliance and captures the policy/report/violations as output.kosli create policy, which collides with the existing environment-policy command — flagged inline as an open question.inputshape is borrowed from the client-side tutorial and may differ server-side.Draft because
Content describes proposed behavior and will change as the design firms up; opening as draft to gather review before it's merged/published.
🤖 Generated with Claude Code