feat: enforce canonical pair ordering, and commit the first commit-history artifact (META-297 L1) - #29
Conversation
Reviewer's GuideThis PR tightens the producer conformance suite to actually enforce canonical coChange pair ordering and distinguish unmeasured properties, and introduces the first Sequence diagram for canonical coChange pair ordering checksequenceDiagram
participant Candidate
participant ConformanceScript as check_producer_conformance_mjs
participant Reporter as createReporter_check
Candidate->>ConformanceScript: runDirect(candidate, repo)
ConformanceScript->>Reporter: createReporter()
ConformanceScript->>ConformanceScript: extract coChange
ConformanceScript->>ConformanceScript: filter observationEntries
alt no observation entries
ConformanceScript->>Reporter: check.notMeasured("canonical pair ordering ...")
else has observation entries
ConformanceScript->>ConformanceScript: compareUtf8(a, b)
ConformanceScript->>Reporter: check("every emitted coChange entry carries a two-string files pair", malformed.length === 0, detail)
ConformanceScript->>Reporter: check("every emitted coChange pair is ordered by ascending UTF-8 bytes", misordered.length === 0, detail)
ConformanceScript->>Reporter: check("no emitted coChange entry stores a derived rate", observationEntries.every(...), detail)
end
ConformanceScript->>ConformanceScript: summarize state.pass, state.fail, state.notMeasured
ConformanceScript-->>Candidate: exit(status = state.fail ? 1 : 0)
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
| Filename | Overview |
|---|---|
| scripts/check-producer-conformance.mjs | Adds producer-scoped structural, canonical ordering, and no-derived-rate checks while reporting absent observation evidence separately. |
| scripts/producer-conformance-lib.mjs | Extends the reporter with a distinct notMeasured collection without changing failure accounting. |
| docs/conformance.md | Updates the documented enforcement boundary to match the new executable producer checks. |
| .agents/workspace.json | Adds a schema-valid, pinned history-derived artifact containing observation-form co-change evidence. |
| .agents/RECEIPT.md | Documents artifact provenance, candidate-package limitations, verification results, and standing usage boundaries. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Run candidate producer] --> B[Read generated coChange]
B --> C{Observation entries present?}
C -- No --> D[Record NOT MEASURED]
C -- Yes --> E[Check two-string files pairs]
E --> F[Check ascending UTF-8 byte order]
F --> G[Check derived rate is absent]
D --> H[Report pass, fail, and not-measured totals]
G --> H
Reviews (4): Last reviewed commit: "feat(evidence): commit the first artifac..." | Re-trigger Greptile
7170e39 to
2f01493
Compare
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In the canonical pair ordering check, consider explicitly handling coChange entries whose
filesis not an array of length 2 (e.g., by asserting or reporting them as malformed) so that structurally invalid observations cannot silently bypass ordering validation. - The UTF-8 comparison helper currently round-trips through
TextEncoderandBuffer.from; you could simplify and reduce allocations by using a direct encoding/compare approach (for example,Buffer.compare(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8'))) and, if reused later, factoring it into a small utility.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the canonical pair ordering check, consider explicitly handling coChange entries whose `files` is not an array of length 2 (e.g., by asserting or reporting them as malformed) so that structurally invalid observations cannot silently bypass ordering validation.
- The UTF-8 comparison helper currently round-trips through `TextEncoder` and `Buffer.from`; you could simplify and reduce allocations by using a direct encoding/compare approach (for example, `Buffer.compare(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8'))`) and, if reused later, factoring it into a small utility.
## Individual Comments
### Comment 1
<location path=".agents/RECEIPT.md" line_range="131" />
<code_context>
+| Standard examples | 11/11 positive, 12/12 negative |
+| Producer conformance | 28 passed, 0 failed, **1 not measured** |
+
+Watched-red against the pinned candidates, each mutation rebuilt, repacked and
+clean-installed before measurement:
+
</code_context>
<issue_to_address>
**suggestion (typo):** The phrase "Watched-red" looks like a typo or unclear jargon.
This wording is likely confusing; “Watched-red” isn’t a standard term and looks like a typo. If it’s intentional jargon, please rephrase to a clearer description (e.g., “observed as failing against the pinned candidates”) so the behavior under test is immediately understandable.
Suggested implementation:
```
Observed as failing against the pinned candidates; each mutation was rebuilt, repacked, and
clean-installed before measurement:
```
If there is any surrounding explanation that relies on the term "Watched-red" (e.g., earlier definitions or references to "watching red/green"), those should be updated to use the clearer wording ("observed as failing" or similar) for consistency. Also verify line wrapping in the Markdown file so the sentence reads naturally in rendered form—adjust where the line break occurs if needed.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
…ured properties `docs/conformance.md` stated that canonical pair ordering was enforced by the candidate-producer conformance suite. The suite examined `coChange[].files` not at all, so a producer emitting reversed endpoints passed a gate that advertised the check. Found by review on #26. The gate is added rather than the claim softened. Two checks, both scoped to producers: - every emitted observation-form pair is ordered by ascending UTF-8 bytes. A real byte comparison, not `<` — a bare string comparison is UTF-16 code unit order, and the two disagree on supplementary-plane characters, so `<` would accept an ordering the rule forbids; - no emitted entry stores a derived `rate`. Readers are untouched: pairs remain unordered with set semantics, reversed documents stay valid, and joins are by membership. This is a producer obligation only. A candidate that emits no observation-form entries is recorded as NOT MEASURED and counted SEPARATELY from passes. A property that could not be exercised has not been demonstrated, and folding it into the pass total would inflate the denominator with a check that measured nothing — the failure this suite exists to refuse. Watched-red: injecting a candidate output carrying a reversed pair and a stored rate turns the suite red (29 passed, 1 failed of 30, naming the ordering check); reverting returns 28 passed, 0 failed, 1 not measured. The current CLI candidate reports NOT MEASURED because the conformance fixture carries no git history and `generate` does not mine by default — exercising it needs a fixture with history and a public mining flag, which is a later increment. Gates: spec 264/264, rules 173/173, examples 11/11 + 12/12, typecheck, build, architecture, schema, corpus, docs, adr, packed all green.
2f01493 to
da891fc
Compare
Reviewer findings reconciled — head
|
|
@sourcery-ai review |
…change evidence The first `workspace.json` anywhere in this lineage whose `generated.coChange` was produced by reading the commit graph. Every prior artifact was a working-tree scan; `generated.coChange` was specified by the schema and emitted by nothing. Candidate interoperability, NOT published-package interoperability. The published @workspacejson/spec@0.4.4 and @workspacejson/rules@0.4.4 REJECT this artifact — their schema predates ADR-003 A-009 and still requires `rate` while forbidding `support`. It was produced and validated against candidate builds packed from pinned source revisions, and it is reproducible from those revisions rather than from the registry. Producer candidate: workspacejson/cli @ 44d374b4dedfa7c61b14f06512d30dd751b3f508 Standard candidate: workspacejson/standard @ 8e08c8c Both packed from clean detached worktrees at those revisions, so the build inputs are exactly the committed source. The install graph was verified to carry no registry substitution: every @workspacejson entry resolves `file:`, zero registry URLs, one spec copy. Version strings could not have distinguished candidate from registry, so the suite asserts the installed schema's SHAPE instead — including that the validator the producer calls accepts the observation form. History completeness: not shallow; 90 first-parent transitions available against a 500-transition window, so the window did not bind and the full first-parent history was analyzed. Artifact: sha256 9fff32e0c015a7ffc3411342afa4374e5fc63db3cd1c53c8618233b8cf92c81b basisRevision 8e08c8c entries 50 (threshold support >= 3, ranked, capped at 50; min emitted 4) validation valid, 0 errors History-block sha256: 7012352617df37f442a627b8dfc334ed17d63dd2a69bb2d875f759bfddcc7b4f That block digest is the receipt that matters. The whole-file digest includes `generatedAt`, which records the generation run rather than the evidence; `basisRevision` is the authoritative freshness and provenance pin. All 50 entries carry exactly `files`, `occurrences`, `support` — no derived value, and no `generated` classification flag, because this producer implements no deterministic classifier and A-010 defines absence as unclassified. Every pair is ordered by ascending UTF-8 bytes; `support <= occurrences` throughout. Two runs are byte-identical. The second-ranked pair is packages/spec/schema/v1.json and packages/spec/src/schema.ts — the two schema mirrors. There is no import edge between them; neither file imports the other. The measured claim is the counts: of the 11 qualifying commits touching either file, 10 touched both. Whether that generalises beyond this repository is not established here. `.agents/RECEIPT.md` records the full provenance, verification counts, watched-red results and standing limits. No publication is authorized by this artifact, and no outreach may cite it beyond what is measured.
da891fc to
49ae90d
Compare
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The UTF-8 ordering check currently allocates new Buffers for every comparison; if this starts touching larger datasets, consider extracting a reusable helper or using a more efficient comparison strategy to avoid repeated allocations on hot paths.
- The new
check.notMeasuredreporting path is only surfaced in the producer suite; if other callers construct reporters, make sure they are updated to use the new API or explicitly ignorenotMeasuredto avoid inconsistent result handling.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The UTF-8 ordering check currently allocates new Buffers for every comparison; if this starts touching larger datasets, consider extracting a reusable helper or using a more efficient comparison strategy to avoid repeated allocations on hot paths.
- The new `check.notMeasured` reporting path is only surfaced in the producer suite; if other callers construct reporters, make sure they are updated to use the new API or explicitly ignore `notMeasured` to avoid inconsistent result handling.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Sourcery findings dispositioned — head
|
| Step | State |
|---|---|
| 1. Required CI on current head | test (20), test (22), Four-path producer conformance — 3/3 SUCCESS |
| 2. Greptile completed on current head | SUCCESS, 5/5 — "no blocking failure remains" |
| 3. Sourcery explicitly requested, tied to head | COMPLETED, review commit=49ae90d |
| 4. Findings individually reconciled | 2 of 2 dispositioned; no bulk resolve |
| 5. Conversations resolved | 0 unresolved |
| 6. Fresh thread-aware read | done |
| 7. Head satisfies every gate | yes |
Proceeding to a normal squash merge. No admin bypass — META-319 removed required code-owner approval, and the point of that change was that a legitimate PR reaches mergeable through CI, current-head Greptile and conversation resolution alone. Carrying the old bootstrap exception forward by habit would defeat it.
Two logical increments, committed separately.
1.
850a4d4— conformance suite enforces canonical pair orderingdocs/conformance.mdsaid canonical pair ordering was enforced by the candidate-producer conformance suite. The suite examinedcoChange[].filesnot at all, so a producer emitting reversed endpoints passed a gate that advertised the check. Found by review on #26. The gate was added rather than the claim softened.Three producer-scoped checks:
<is UTF-16 code unit order and the two disagree on supplementary-plane characters;filespair;rate.The well-formedness check is separate on purpose, and that came out of review on this PR: an earlier version folded it into the ordering filter, so an entry whose
fileswas not a two-string array could never be counted as misordered and silently passed. A structurally invalid observation was buying itself an exemption from the rule it could not be evaluated against.Readers are untouched: pairs stay unordered with set semantics, reversed documents stay valid, joins are by membership.
A candidate emitting no observation-form entries is recorded
NOT MEASURED, counted separately from passes — a property that could not be exercised has not been demonstrated.Watched-red: injecting a candidate output with a one-element
filesarray plus a reversed pair fails both checks — 29 passed / 2 failed of 31. Reverting returns 28 passed, 0 failed, 1 not measured.2.
49ae90d— the first artifact carrying commit-history evidenceThe first
workspace.jsonin this lineage whosegenerated.coChangecame from reading the commit graph.Candidate interoperability, not published-package interoperability. Published
spec@0.4.4/rules@0.4.4reject it — their schema predates A-009. Produced and validated against candidates packed from pinned revisions.workspacejson/cli @ 031c3504a0977b8d90ac518c82a39a2f4ec741a9— merged tomain(PR #20)workspacejson/standard @ 8e08c8c5cd110e7f95bbd52246ea295c22b072e3spectarballsha256:2e0c326e7d8b50d3e3fa801944659803cd95d13dc253e65e1ace8dfccf949111rulestarballsha256:548dd788725899ccaded6568121a271eeb593f143c581ec7e4714b50d9e5dbb7clitarballsha256:aa0ab7526a8f8fc6316f8b809d2ee5cdd04c80c5483a29d39e8dfbcc2e15ad18Packed from clean detached worktrees, so build inputs are exactly the committed source. Tarball digests are pack-specific (gzip carries mtimes) and are recorded as such rather than as reproducible hashes; the durable identity is the two source revisions.
The producer was refreshed; the evidence basis was not
An earlier build used producer
44d374b, which carried a Greptile P1: an explicitly requested refresh that could not complete fell back to the recorded block silently. Fixed in031c350and merged; the artifact was regenerated with the corrected producer against the same8e08c8cbasis.Refreshing the evidence to a newer
standardrevision was deliberately not done.basisRevisionmeans "these observations were computed from this revision" — advancing it becausemainmoved would claim a measurement never taken. A pin that lagsmainreads as stale, which is accurate.This doubles as a perturbation test. The fix changes only refusal signalling on the unsuccessful path, so the successful path must produce identical output:
44d374b)031c350)basisRevision8e08c8c…sha2567012352617df…coChangegeneratedAt,hygiene.scannedAtonlyHad the block moved, this receipt would not have been written.
The artifact
No registry substitution: every
@workspacejsonentry resolvesfile:, zero registry URLs, onespeccopy. Version strings could not distinguish candidate from registry, so the suite asserts the installed schema's shape, including that the validator the producer calls accepts the observation form.History completeness: not shallow; 90 first-parent transitions against a 500 window, so the window did not bind — full first-parent history.
basisRevision8e08c8c5cd110e7f95bbd52246ea295c22b072e3support >= 3, ranked, capped; min emitted 4)sha2567012352617df37f442a627b8dfc334ed17d63dd2a69bb2d875f759bfddcc7b4fThe block digest is the receipt that matters — the whole-file digest includes
generatedAt, which records the generation run, not the evidence.All 50 entries carry exactly
files/occurrences/support: no derived value, nogeneratedflag (no deterministic classifier exists; A-010 defines absence as unclassified), canonical UTF-8 order,support <= occurrences.The second-ranked pair is
packages/spec/schema/v1.jsonandpackages/spec/src/schema.ts— the two schema mirrors. There is no import edge between them. The measured claim is the counts: of the 11 qualifying commits touching either file, 10 touched both. Whether that generalises beyond this repository is not established here..agents/RECEIPT.mdcarries the full provenance and standing limits.Verification
031c350Watched-red against pinned candidates (rebuilt, repacked, clean-installed each time): drop carry-forward 7 failed; advance pin 6 failed; recompute on ordinary generate 1 failed; drop refresh-outcome field 2 failed; hardcode
mined: true1 failed; restored 22/22.Boundaries
No publication. No outreach. The artifact authorizes neither, and
RECEIPT.mdrecords that limit.Summary by Sourcery
Enforce canonical ordering and structural validation of co-change pairs in the producer conformance suite and add the first commit-history based workspace artifact with a detailed provenance receipt.
New Features:
Enhancements: