feat(access): Amendment A04, a developer participates without waiting for an organization - #24
Merged
Merged
Conversation
…ation Amendment A04, policy v0.5. Organization adoption becomes optional and no protection is relaxed: three laws are added and none removed. Law XXXV is the load-bearing one. Evidence reaches Kreds either because GitHub pushed it or because a Kreds server asked GitHub, and there is no third member of that union. 26 gives the reason as arithmetic rather than distrust: anything a client is trusted to send, an attacker sends directly with curl, with no repository to evaluate. Signing does not rescue it, so nothing here verifies a signature whose key would live on the claimant's machine. A test scans every controller for a write route the law does not account for, and for a body carrying an amount, a score or an eligibility. Law IV as amended sends work with no Kreds Team behind it to a personal position rather than nowhere, and never straight to a global wallet. It is not a lighter tier: adding PERSONAL_POSITION to AccountType turned the supply equation's exhaustiveness guard into a compile error naming the missing term, before any test ran. There is a test that derives the same position from the same inputs on both sides and compares them field for field. Law XXXVI reads only the organization's own grant. Membership, first connection, repository access and public contribution are all carried on the evidence, all ignored, and each has a test quoting the law. Treasury actions re-verify, because the owner who granted authority can leave and that does not edit a row Kreds already wrote. Law XXXVII routes an unconsented obligation to a funded source or to a receivable, never onto an identity that never heard of Kreds. The guard sits where debt is written rather than where it is decided, so a future path that skipped the router still cannot charge a stranger. The reviewer earns in every case. Delegated query made personal private repositories ingestible at scale, which is a farm the earlier amendments never had to consider. Points there are capped, not refused, and no number appears in this repository: the caps arrive as configuration, and an instance without them awards nothing unobserved rather than awarding without a bound. Tokens are sealed with AES-256-GCM before they reach a query parameter, so no plaintext appears in a slow-query log. Revocation is re-checked on every provider request rather than once per poll, so a hundred-repository sweep stops between two requests instead of finishing the batch. The rate budget is per user and enforced in the WHERE clause, so two concurrent pollers cannot both spend the last request. The sign-in scope did not widen. read:user and read:org cannot read anybody's code, and the self-hosting guide's promise still holds; ingesting private work is a separate grant a user opts into, and reach is read from what GitHub granted rather than what Kreds asked for. Idempotency comes from GitHub's identifiers. Under delegated query the same merge is visible to every collaborator who authorized Kreds, so a key that varied by observer would pay one piece of work once per observer. That failure did not exist under organization webhooks. The delegated path hands GitHub's own object to the same normalizer the webhook uses, so the two channels cannot drift into two keys. Work is priced by the provider's timestamp. Backfill is ordinary now, and pricing by ingestion time would reprice history at today's rules. Two tests had a rules version as a literal and went red on the bump for the wrong reason. They read the policy now, which is what they meant.
The law repository moved from a2b694c to d58c95a while this was being built: an adversarial pass over A04 itself closed one breach and five gaps. The policy JSON is byte-identical and its checksum still matches, so nothing about pricing changed. The prose did, and two of the changes made working code wrong. Settling in the dark was the breach, and this repository had implemented the superseded sentence verbatim. 26 previously said settlement "does not require further provider access", which made revocation a laundering step: merge eligible work, revoke, revert everything unobserved, and let the reward settle on evidence Kreds could no longer re-check. The window exists to catch exactly those closures and reverts, so it cannot run blind. Pending value now settles only while its evidentiary context is observable, and otherwise locks rather than being lost. Going dark is legitimate; settling in the dark is not. An observer is a person, not a property of a repository. The first version here lifted the Contribution Point cap on public visibility or the presence of collaborators, and 24 now fixes the standard at the validating reviewer's: a distinct, eligible, human identity that is not a controlled alternate account. Adding your own second account as a collaborator was one API call, which is the bypass the chapter names. Both toggles are gone, and there is a test that the type offers no way to lift the cap that is not a person. The consent table changed shape. A connected contributor has consented everywhere they act, which is now first and is the common case. An unconnected owner's own repository is no longer an exception: 09 is blunt that someone who never connected never consented to anything, including their own repository becoming a place they can be charged. The waterfall is scoped. Review Fund and Credit Facility are organization features, so in a personal position it collapses to author then receivable. The funding argument is accepted and ignored there rather than trusted, because the caller is the place that would eventually wire reserve credit into a scope no authority consented to. Stale claims expire by versioned policy or not at all. A claim that never expires is a fictitious asset on a reviewer's profile; one that vanishes quietly is their work disappearing with no record. Binding is forward-only. Delegated query makes backfill ordinary, so a sweep of last year's merges must not walk somebody's earlier personal earnings into an organization's books. Also fixed a name collision this introduced: an `UNOBSERVED` quality signal already existed, and the first pass at the duplicate deleted the original export instead of renaming the newcomer.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Amendment A04, policy
v0.5. Organization adoption becomes optional and no protection is relaxed: three laws are added and none removed.Built in two passes. The law repository moved from
a2b694ctod58c95amid-implementation, an adversarial audit of A04 itself, and two of its findings made working code wrong. Both commits are here.Law XXXV, evidence comes from the provider
Two channels, and the union has no third member. A test scans every controller for a write route the law does not account for, and for a body carrying an amount, a score or an eligibility.
Nothing verifies a signature whose key would live on the claimant's machine, because 26 forecloses that in advance: "There is no cryptographic arrangement in which the beneficiary of a claim is also its only attestor."
Idempotency comes from GitHub's identifiers. Under delegated query the same merge is visible to every collaborator who authorized Kreds, so a key that varied by observer would pay one piece of work once per observer. That failure did not exist under organization webhooks. The delegated path hands GitHub's own object to the same normalizer the webhook uses, so the two channels cannot drift into two keys.
Law IV as amended, and the supply equation
Adding
PERSONAL_POSITIONtoAccountTypeturned the supply equation's exhaustiveness guard into a compile error naming the missing term, before any test ran. It is not a lighter tier, and there is a test that derives the same position from the same inputs on both sides and compares them field for field.Law XXXVI, only organization authority binds
Membership, first connection, repository access and public contribution are all carried on the evidence, all ignored, and each has a test quoting the law. Treasury actions re-verify.
Law XXXVII, liability requires a consenting context
An unconsented obligation goes to a funded source or to a receivable, never onto an identity that never heard of Kreds. The guard sits where debt is written rather than where it is decided.
What the audit round changed
Settling in the dark was the breach, and this repository had implemented the superseded sentence verbatim: settlement "does not require further provider access" made revocation a laundering step. Pending value now settles only while its evidentiary context is observable, and otherwise locks rather than being lost.
An observer is a person. The first pass lifted the Contribution Point cap on public visibility or the presence of collaborators. Both are toggles the author controls, and adding your own second account as a collaborator was the one-API-call bypass 24 names.
The waterfall is scoped. Review Fund and Credit Facility are organization features; a personal position collapses to author then receivable, and the funding argument is accepted and ignored there rather than trusted.
Plus versioned claim expiry and forward-only binding.
Tokens
AES-256-GCM before the value reaches a query parameter, so no plaintext appears in a slow-query log. Revocation is re-checked on every provider request rather than once per poll. The rate budget is per user and enforced in the WHERE clause, so two concurrent pollers cannot both spend the last request.
The sign-in scope did not widen:
read:user read:orgcannot read anybody's code and the self-hosting guide's promise still holds. Ingesting private work is a separate grant, and reach is read from what GitHub granted rather than what Kreds asked for.Not shipped in this repository
The unobserved-context caps. They are operational policy and are not published, and this repository is public. They load as configuration, and an instance without them awards nothing unobserved rather than awarding without a bound. Raised in the verdict as a real tension with 24's "not refused".