docs(specs): four-layer property-alignment framing + catalog-graduation RFC#5761
Merged
Conversation
…endar time-bomb)
`acquire_rights` rejected a campaign when `new Date(end_date).getTime() < Date.now()`.
`new Date('YYYY-MM-DD')` parses to 00:00:00Z, so the instant midnight UTC ticks
over on the end date, a campaign ending *today* was wrongly judged "in the past"
and rejected — even though the success path sets valid_until to that day's
23:59:59Z (end_date is inclusive). On 2026-06-30 this turned the
`brand-sandbox-tools` test red and, via the precommit hook + CI, blocked commits
repo-wide.
- Reject only once the whole end day is past: compare against the start of today
(UTC), so a campaign ending today stays licensable.
- Make the `rights_constraint uses date-time format` test use a next-calendar-year
window instead of a hardcoded date, so it exercises the success path durably
rather than rotting into a time-bomb.
Note (follow-up, not fixed here): the hardcoded default `campaign.end_date ||
'2026-06-30'` (brand-handlers.ts) is stale — a no-end_date acquisition gets a
past expiry — but it's applied after the guard so it can't cause a rejection or
break a test; replacing it needs a product call on the default window.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on RFC Two WG design docs that turn this work's thinking into something the working group can act on, and frame #5750/#5752 as two points on one authority spine. - specs/property-definition-alignment.md — the reframe (alignment = convergence on evidence with a domain-rooted spine + reversible mistakes, not consensus on a value), the four layers and their distinct trust roots (ontology / referential identity / authority / boundary), the two invariants (origin wins + alias-not-delete; unilateral disavow, never unilateral claim), where #5750/#5752 sit, what AAO is NOT (registrar-of-last-resort, not a registrar), and detect-not-prevent. - specs/property-catalog-graduation.md — RFC to graduate the catalog from Draft to normative-but-non-authoritative: property_rid as a non-authoritative surrogate, the two-axis evidence/confidence model, owner-declared boundary (declare-don't-derive; ESPN as a tree), ontology-evolution governance (the one genuine layer-1 gap), signed cross-attestation as the already-deferred cross-publisher path, and resolutions for catalog open questions #3/#4. Both are grounded against specs/registry-authorization-model.md (the shipped evidence/disputed/seq_no model) and reviewed by the protocol expert; the RFC restates catalog Design Principle #6 (registry is identity-of-last-resort, never authority-to-sell) and includes a 3.2 migration/versioning impact statement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
Contributor
There was a problem hiding this comment.
Approving. Clean inclusive-day expiry fix plus two faithful WG framing docs — no wire surface touched, so the whole PR is non-authoritative by construction.
Things I checked
- Boundary logic,
server/src/training-agent/brand-handlers.ts:940-952. New check isendMs < startOfTodayMswherestartOfTodayMs = Date.UTC(getUTCFullYear, getUTCMonth, getUTCDate). A campaign ending today (new Date('YYYY-MM-DD')→ UTC midnight) is==, not<, so it stays licensable; yesterday is<and rejects. Both sides strictly UTC —getUTC*accessors, not local — so no timezone drift. Matches the success path's inclusivevalid_until = ${endDate}T23:59:59Zatbrand-handlers.ts:1098. The oldendMs < Date.now()falsely expired same-day grants the instant UTC midnight ticked over. Real bug, right fix. - NaN guard preserved.
!Number.isNaN(endMs)carried through unchanged — a malformedend_datestill falls through rather than rejecting on aNaN < xcomparison. - Test time-bomb removed,
tests/addie/brand-sandbox-tools.test.ts:319-334. Hardcodedend_date: '2026-06-30'sat exactly on today's boundary and would flip to rejection (returningerrors, notrights_constraint). Now computes next calendar year viagetUTCFullYear()+1— matches the handler's UTC basis — while preserving the exactT00:00:00Z/T23:59:59Zformat assertions. - Spec coherence against the shipped model.
ad-tech-protocol-expertverified every factual claim in both docs against ground truth: the two-axis split (authorizationevidence ∈ {adagents_json, agent_claim, community}perregistry-authorization-model.md:82-84,155vs. identifier-linkingconfidence ∈ {authoritative, strong, medium, weak}perproperty-registry-catalog.md:413,460), thedisputedboolean,seq_norotation-on-tombstone, the adagents_json-only snapshot default, the new-evidence-value extension path, and the Design Principle #6 restatement. Verdict: sound. The PR body's claim that a prior review caught a fabricated single-ladder evidence model is borne out —property-catalog-graduation.md:39-50now reads "Two trust axes, not one ladder," no residue. - No changeset needed. No
static/schemas/source/**, nodocs/reference/**, no wire shape.specs/*.mdare non-normative WG proposals. Correctly fenced as proposal-vs-current-state throughout (graded Wikidata rank,candidate_edges,part_of,signed_attestation, the N=3 enum gate all labeled proposed/deferred).
Follow-ups (non-blocking — file as issues)
property-catalog-graduation.mdopen-question #4 conflates two failure modes. The §"Resolved open questions" resolution for catalog Q#4 (domain re-registration / hand-off,property-registry-catalog.md:651) leans on the authorization model's refresh-on-crawl + soft-delete — but that machinery covers manifest-stopped-declaring lapse, not adversarial domain-changed-hands detection. Don't strike Q#4 from the catalog spec on merge as the doc proposes; tighten the wording before this graduates to normative so a reader doesn't infer re-registration is auto-detected. Q#3's resolution is fully closed and fine to strike.- The alignment doc's AAO "registrar-of-last-resort" framing and the grad doc's "moderator-curated
communitytier" describe the same trust state from two angles — a one-line cross-reference would stop a reader treating them as distinct.
Minor nits (non-blocking)
- Redundant
Datewrap.brand-handlers.ts:941—new Date(Date.now())is equivalent tonew Date(). Cosmetic.
LGTM. Follow-ups noted below.
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.
Two WG design docs that turn this work's thinking into something the working group can act on, and frame #5750/#5752 as two points on one authority spine.
Docs
specs/property-definition-alignment.md— the reframe (alignment = convergence on evidence with a domain-rooted spine + reversible mistakes, not consensus on a value), the four layers and their distinct trust roots (ontology / referential identity / authority / boundary), the two invariants (origin wins + alias-not-delete; unilateral disavow, never unilateral claim), where fix(registry): enforce identity-not-authorization on property-save (#5749 gap #2) #5750/feat(registry): domain claim + bind-on-verify ownership (#5749 gap #1) #5752 sit, what AAO is NOT (registrar-of-last-resort, not a registrar), and detect-not-prevent.specs/property-catalog-graduation.md— RFC to graduate the catalog from Draft to normative-but-non-authoritative:property_ridas a non-authoritative surrogate, the two-axisevidence/confidencemodel, owner-declared boundary (declare-don't-derive; ESPN as a tree), ontology-evolution governance (the one genuine layer-1 gap), signed cross-attestation as the already-deferred cross-publisher path, and resolutions for catalog open questions Improve documentation framework and remove premature certification references #3/Add foundational publisher formats and extension mechanism #4.Review
Reviewed by the protocol expert against
specs/registry-authorization-model.md(the shippedevidence/disputed/seq_nomodel). It caught two factual errors I'd have shipped — a fabricated singleevidenceladder (the real model is two axes: authorizationevidence ∈ {adagents_json, agent_claim, community}+ separate identifierconfidence) and over-scoping #5750 — both corrected. The RFC explicitly restates catalog Design Principle #6 (registry is identity-of-last-resort, never authority-to-sell) and includes a 3.2 migration/versioning impact statement.These are proposals for WG discussion, not normative changes — no wire/schema change.
🤖 Generated with Claude Code